package testsuite import ( "context" "reflect" "sync" "testing" "forge.cadoles.com/cadoles/bouncer/internal/store" "github.com/pkg/errors" ) type proxyRepositoryTestCase struct { Name string Do func(repo store.ProxyRepository) error } var proxyRepositoryTestCases = []proxyRepositoryTestCase{ { Name: "Create proxy", Do: func(repo store.ProxyRepository) error { ctx := context.Background() to := "http://example.com" proxy, err := repo.CreateProxy(ctx, "create_proxy", to, "*:*") if err != nil { return errors.WithStack(err) } if proxy == nil { return errors.Errorf("proxy should not be nil") } if proxy.Name == "" { return errors.Errorf("proxy.Name should not be empty") } if proxy.To == "" { return errors.Errorf("proxy.To should not be empty") } if e, g := to, proxy.To; e != g { return errors.Errorf("proxy.To: expected '%v', got '%v'", to, proxy.To) } if proxy.CreatedAt.IsZero() { return errors.Errorf("proxy.CreatedAt should not be zero value") } if proxy.UpdatedAt.IsZero() { return errors.Errorf("proxy.UpdatedAt should not be zero value") } if proxy.Revision != 0 { return errors.Errorf("proxy.Revision should be zero") } return nil }, }, { Name: "Create then get proxy", Do: func(repo store.ProxyRepository) error { ctx := context.Background() to := "http://example.com" createdProxy, err := repo.CreateProxy(ctx, "create_then_get_proxy", to, "127.0.0.1:*", "localhost:*") if err != nil { return errors.WithStack(err) } foundProxy, err := repo.GetProxy(ctx, createdProxy.Name) if err != nil { return errors.WithStack(err) } if e, g := createdProxy.Name, foundProxy.Name; e != g { return errors.Errorf("foundProxy.Name: expected '%v', got '%v'", createdProxy.Name, foundProxy.Name) } if e, g := createdProxy.From, foundProxy.From; !reflect.DeepEqual(e, g) { return errors.Errorf("foundProxy.From: expected '%v', got '%v'", createdProxy.From, foundProxy.From) } if e, g := createdProxy.To, foundProxy.To; e != g { return errors.Errorf("foundProxy.To: expected '%v', got '%v'", createdProxy.To, foundProxy.To) } if e, g := createdProxy.Enabled, foundProxy.Enabled; e != g { return errors.Errorf("foundProxy.Enabled: expected '%v', got '%v'", createdProxy.Enabled, foundProxy.Enabled) } if e, g := createdProxy.Weight, foundProxy.Weight; e != g { return errors.Errorf("foundProxy.Weight: expected '%v', got '%v'", createdProxy.Weight, foundProxy.Weight) } if e, g := createdProxy.CreatedAt, foundProxy.CreatedAt; e != g { return errors.Errorf("foundProxy.CreatedAt: expected '%v', got '%v'", createdProxy.CreatedAt, foundProxy.CreatedAt) } if e, g := createdProxy.UpdatedAt, foundProxy.UpdatedAt; e != g { return errors.Errorf("foundProxy.UpdatedAt: expected '%v', got '%v'", createdProxy.UpdatedAt, foundProxy.UpdatedAt) } if foundProxy.Revision != 0 { return errors.Errorf("foundProxy.Revision should be zero") } return nil }, }, { Name: "Create then delete proxy", Do: func(repo store.ProxyRepository) error { ctx := context.Background() to := "http://example.com" createdProxy, err := repo.CreateProxy(ctx, "create_then_delete_proxy", to, "127.0.0.1:*", "localhost:*") if err != nil { return errors.WithStack(err) } if err := repo.DeleteProxy(ctx, createdProxy.Name); err != nil { return errors.WithStack(err) } foundProxy, err := repo.GetProxy(ctx, createdProxy.Name) if err == nil { return errors.New("err should not be nil") } if !errors.Is(err, store.ErrNotFound) { return errors.Errorf("err should be store.ErrNotFound, got '%+v'", err) } if foundProxy != nil { return errors.Errorf("foundProxy should be nil, got '%v'", foundProxy) } return nil }, }, { Name: "Create then query layer", Do: func(repo store.ProxyRepository) error { ctx := context.Background() to := "http://example.com" createdProxy, err := repo.CreateProxy(ctx, "create_then_query", to, "127.0.0.1:*", "localhost:*") if err != nil { return errors.WithStack(err) } headers, err := repo.QueryProxy(ctx) if err != nil { return errors.WithStack(err) } if len(headers) < 1 { return errors.Errorf("len(headers): expected value > 1, got '%v'", len(headers)) } found := false for _, h := range headers { if h.Name == createdProxy.Name { found = true break } } if !found { return errors.New("could not find created proxy in query results") } return nil }, }, { Name: "Create already existing proxy", Do: func(repo store.ProxyRepository) error { ctx := context.Background() to := "http://example.com" var name store.ProxyName = "create_already_existing_proxy" _, err := repo.CreateProxy(ctx, name, to, "127.0.0.1:*", "localhost:*") if err != nil { return errors.WithStack(err) } _, err = repo.CreateProxy(ctx, name, to, "127.0.0.1:*") if err == nil { return errors.New("err should not be nil") } if !errors.Is(err, store.ErrAlreadyExist) { return errors.Errorf("err: expected store.ErrAlreadyExists, got '%+v'", err) } return nil }, }, { Name: "Create then update proxy", Do: func(repo store.ProxyRepository) error { ctx := context.Background() to := "http://example.com" var name store.ProxyName = "create_then_update_proxy" createdProxy, err := repo.CreateProxy(ctx, name, to, "127.0.0.1:*", "localhost:*") if err != nil { return errors.Wrap(err, "err should be nil") } if createdProxy.Revision != 0 { return errors.Errorf("createdProxy.Revision should be zero") } updatedProxy, err := repo.UpdateProxy(ctx, name) if err != nil { return errors.Wrap(err, "err should be nil") } if e, g := 1, updatedProxy.Revision; e != g { return errors.Errorf("updatedProxy.Revision: expected '%v', got '%v'", e, g) } return nil }, }, { Name: "Update proxy concurrently", Do: func(repo store.ProxyRepository) error { ctx := context.Background() to := "http://example.com" var name store.ProxyName = "update_proxy_concurrently" createdProxy, err := repo.CreateProxy(ctx, name, to, "127.0.0.1:*", "localhost:*") if err != nil { return errors.Wrap(err, "err should be nil") } if createdProxy.Revision != 0 { return errors.Errorf("createdProxy.Revision should be zero") } var wg sync.WaitGroup total := 100 wg.Add(total) for i := 0; i < total; i++ { go func(i int) { defer wg.Done() if _, err := repo.UpdateProxy(ctx, name); err != nil { panic(errors.Wrap(err, "err should be nil")) } }(i) } wg.Wait() proxy, err := repo.GetProxy(ctx, name) if err != nil { return errors.Wrap(err, "err should be nil") } if e, g := total, proxy.Revision; e != g { return errors.Errorf("proxy.Revision: expected '%v', got '%v'", e, g) } return nil }, }, } func TestProxyRepository(t *testing.T, repo store.ProxyRepository) { for _, tc := range proxyRepositoryTestCases { func(tc proxyRepositoryTestCase) { t.Run(tc.Name, func(t *testing.T) { if err := tc.Do(repo); err != nil { t.Fatalf("%+v", errors.WithStack(err)) } }) }(tc) } }