diff --git a/data/service/service/client_test.go b/data/service/service/client_test.go deleted file mode 100644 index 9a8a94e85d..0000000000 --- a/data/service/service/client_test.go +++ /dev/null @@ -1,8 +0,0 @@ -package service_test - -import ( - . "github.com/onsi/ginkgo/v2" -) - -var _ = Describe("Client", func() { -}) diff --git a/data/service/service/service_suite_test.go b/data/service/service/service_suite_test.go deleted file mode 100644 index f257c20c7d..0000000000 --- a/data/service/service/service_suite_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package service_test - -import ( - "testing" - - "github.com/tidepool-org/platform/test" -) - -func TestSuite(t *testing.T) { - test.Test(t) -} diff --git a/data/service/service/standard.go b/data/service/service/standard.go index 80911f4b20..c22dc93792 100644 --- a/data/service/service/standard.go +++ b/data/service/service/standard.go @@ -5,12 +5,12 @@ import ( "log" "os" - "github.com/tidepool-org/platform/clinics" - "github.com/IBM/sarama" + eventsCommon "github.com/tidepool-org/go-common/events" "github.com/tidepool-org/platform/application" + "github.com/tidepool-org/platform/clinics" dataDeduplicatorDeduplicator "github.com/tidepool-org/platform/data/deduplicator/deduplicator" dataDeduplicatorFactory "github.com/tidepool-org/platform/data/deduplicator/factory" dataEvents "github.com/tidepool-org/platform/data/events" @@ -34,7 +34,7 @@ import ( ) type Standard struct { - *service.DEPRECATEDService + *service.Authenticated metricClient *metricClient.Client permissionClient *permissionClient.Client dataDeduplicatorFactory *dataDeduplicatorFactory.Factory @@ -51,12 +51,15 @@ type Standard struct { func NewStandard() *Standard { return &Standard{ - DEPRECATEDService: service.NewDEPRECATEDService(), + Authenticated: service.NewAuthenticated(), } } func (s *Standard) Initialize(provider application.Provider) error { - if err := s.DEPRECATEDService.Initialize(provider); err != nil { + if err := s.Service.Initialize(provider); err != nil { + return err + } + if err := s.Authenticated.Initialize(provider); err != nil { return err } @@ -128,7 +131,7 @@ func (s *Standard) Terminate() { s.permissionClient = nil s.metricClient = nil - s.DEPRECATEDService.Terminate() + s.Authenticated.Terminate() } func (s *Standard) Run() error { diff --git a/data/service/service/standard_test.go b/data/service/service/standard_test.go index 0f13ddfc85..55ce32f251 100644 --- a/data/service/service/standard_test.go +++ b/data/service/service/standard_test.go @@ -1,8 +1,95 @@ -package service_test +package service import ( - . "github.com/onsi/ginkgo/v2" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/tidepool-org/platform/application" + netTest "github.com/tidepool-org/platform/net/test" + "github.com/tidepool-org/platform/test" ) -var _ = Describe("Standard", func() { -}) +func TestAuthClientIsInitialized(t *testing.T) { + tt := newStandardTest(t) + tt.Setenv("SECRET", "something secret") + tt.Setenv("SERVER_ADDRESS", "somehost") + tt.SetenvToFilePath("SERVER_TLS_CERTIFICATE_FILE", "contents") + tt.SetenvToFilePath("SERVER_TLS_KEY_FILE", "contents") + tt.Setenv("AUTH_CLIENT_ADDRESS", "something secret") + tt.Setenv("AUTH_CLIENT_EXTERNAL_ADDRESS", "something secret") + tt.Setenv("AUTH_CLIENT_SERVICE_SECRET", "something secret") + tt.Setenv("AUTH_CLIENT_EXTERNAL_SERVICE_SECRET", "something secret") + tt.Setenv("AUTH_CLIENT_SERVER_SESSION_TOKEN_SECRET", "something secret") + tt.Setenv("AUTH_CLIENT_EXTERNAL_SERVER_SESSION_TOKEN_SECRET", "something secret") + tt.Setenv("METRIC_CLIENT_ADDRESS", "something secret") + tt.Setenv("PERMISSION_CLIENT_ADDRESS", "something secret") + tt.Setenv("DEPRECATED_DATA_STORE_DATABASE", "test_data_database") + tt.Setenv("SYNC_TASK_STORE_DATABASE", "test_sync_task_database") + // These have no prefixes + t.Setenv("KAFKA_BROKERS", "somehost") + t.Setenv("KAFKA_TOPIC_PREFIX", "somehost") + t.Setenv("KAFKA_REQUIRE_SSL", "false") + t.Setenv("KAFKA_VERSION", "2.5.0") + + std := NewStandard() + err := std.Initialize(tt.Provider) + if err != nil { + t.Errorf("expected successful initialization, got %s", err) + } +} + +type standardTest struct { + Prefix string + Name string + Scopes []string + Provider application.Provider + + t testing.TB + tempDir string +} + +func newStandardTest(t *testing.T) *standardTest { + prefix := test.RandomStringFromRangeAndCharset(4, 8, test.CharsetUppercase) + name := test.RandomStringFromRangeAndCharset(4, 8, test.CharsetAlphaNumeric) + scopes := test.RandomStringArrayFromRangeAndCharset(0, 2, test.CharsetAlphaNumeric) + + t.Setenv(fmt.Sprintf("%s_LOGGER_LEVEL", prefix), "error") + oldName := os.Args[0] + os.Args[0] = name + t.Cleanup(func() { os.Args[0] = oldName }) + + application.VersionBase = netTest.RandomSemanticVersion() + application.VersionFullCommit = test.RandomStringFromRangeAndCharset(40, 40, test.CharsetHexidecimalLowercase) + application.VersionShortCommit = application.VersionFullCommit[0:8] + + provider, err := application.NewProvider(prefix, scopes...) + if err != nil { + t.Fatalf("unable to initialize provider") + } + + return &standardTest{ + Prefix: prefix, + Name: name, + Scopes: scopes, + Provider: provider, + + t: t, + tempDir: t.TempDir(), + } +} + +func (t *standardTest) Setenv(keySuffix, value string) { + baseKey := strings.Join(append([]string{t.Prefix, t.Name}, t.Scopes...), "_") + t.t.Setenv(strings.ToUpper(baseKey+"_"+keySuffix), value) +} + +func (t *standardTest) SetenvToFilePath(keySuffix, contents string) { + filename := filepath.Join(t.tempDir, keySuffix) + if err := os.WriteFile(filename, []byte(contents), 0600); err != nil { + t.t.Fatalf("opening tempfile %q: %s", filename, err) + } + t.Setenv(keySuffix, filename) +} diff --git a/service/service/DEPRECATED_service.go b/service/service/DEPRECATED_service.go deleted file mode 100644 index 5240c8f40e..0000000000 --- a/service/service/DEPRECATED_service.go +++ /dev/null @@ -1,93 +0,0 @@ -package service - -import ( - "github.com/tidepool-org/platform/application" - "github.com/tidepool-org/platform/auth" - authClient "github.com/tidepool-org/platform/auth/client" - "github.com/tidepool-org/platform/errors" - "github.com/tidepool-org/platform/platform" -) - -type DEPRECATEDService struct { - *application.Application - secret string - authClient *authClient.Client -} - -func NewDEPRECATEDService() *DEPRECATEDService { - return &DEPRECATEDService{ - Application: application.New(), - } -} - -func (d *DEPRECATEDService) Initialize(provider application.Provider) error { - if err := d.Application.Initialize(provider); err != nil { - return err - } - - if err := d.initializeSecret(); err != nil { - return err - } - return d.initializeAuthClient() -} - -func (d *DEPRECATEDService) Terminate() { - if d.authClient != nil { - d.authClient.Close() - d.authClient = nil - } - d.secret = "" - - d.Application.Terminate() -} - -func (d *DEPRECATEDService) Secret() string { - return d.secret -} - -func (d *DEPRECATEDService) AuthClient() auth.Client { - return d.authClient -} - -func (d *DEPRECATEDService) initializeSecret() error { - d.Logger().Debug("Initializing secret") - - secret := d.ConfigReporter().GetWithDefault("secret", "") - if secret == "" { - return errors.New("secret is missing") - } - d.secret = secret - - return nil -} - -func (d *DEPRECATEDService) initializeAuthClient() error { - d.Logger().Debug("Loading auth client config") - - cfg := authClient.NewConfig() - cfg.UserAgent = d.UserAgent() - cfg.ExternalConfig.UserAgent = d.UserAgent() - reporter := d.ConfigReporter().WithScopes("auth", "client") - ext := authClient.NewExternalConfigReporterLoader(reporter.WithScopes("external")) - plt := platform.NewConfigReporterLoader(reporter) - loader := authClient.NewConfigLoader(ext, plt) - if err := cfg.Load(loader); err != nil { - return errors.Wrap(err, "unable to load auth client config") - } - - d.Logger().Debug("Creating auth client") - - clnt, err := authClient.NewClient(cfg, platform.AuthorizeAsService, d.Name(), d.Logger()) - if err != nil { - return errors.Wrap(err, "unable to create auth client") - } - d.authClient = clnt - - d.Logger().Debug("Starting auth client") - - if err = d.authClient.Start(); err != nil { - return errors.Wrap(err, "unable to start auth client") - } - - return nil -} diff --git a/service/service/DEPRECATED_service_test.go b/service/service/DEPRECATED_service_test.go deleted file mode 100644 index 95e148f7be..0000000000 --- a/service/service/DEPRECATED_service_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package service_test - -import ( - "net/http" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - . "github.com/onsi/gomega/ghttp" - - applicationTest "github.com/tidepool-org/platform/application/test" - authTest "github.com/tidepool-org/platform/auth/test" - configTest "github.com/tidepool-org/platform/config/test" - serviceService "github.com/tidepool-org/platform/service/service" -) - -var _ = Describe("DEPRECATEDService", func() { - Context("NewDEPRECATEDService", func() { - It("returns successfully", func() { - Expect(serviceService.NewDEPRECATEDService()).ToNot(BeNil()) - }) - }) - - Context("with started server, config reporter, and new service", func() { - var provider *applicationTest.Provider - var svc *serviceService.DEPRECATEDService - var serverSecret string - var sessionToken string - var server *Server - var authClientConfig map[string]interface{} - var serviceConfig map[string]interface{} - - BeforeEach(func() { - provider = applicationTest.NewProviderWithDefaults() - - serverSecret = authTest.NewServiceSecret() - sessionToken = authTest.NewSessionToken() - - server = NewServer() - Expect(server).ToNot(BeNil()) - server.AppendHandlers( - CombineHandlers( - VerifyRequest("POST", "/auth/serverlogin"), - VerifyHeaderKV("X-Tidepool-Server-Name", *provider.NameOutput), - VerifyHeaderKV("X-Tidepool-Server-Secret", serverSecret), - VerifyBody(nil), - RespondWith(http.StatusOK, nil, http.Header{"X-Tidepool-Session-Token": []string{sessionToken}})), - ) - - authClientConfig = map[string]interface{}{ - "address": server.URL(), - "server_token_secret": authTest.NewServiceSecret(), - "external": map[string]interface{}{ - "address": server.URL(), - "server_session_token_secret": serverSecret, - }, - } - serviceConfig = map[string]interface{}{ - "secret": authTest.NewServiceSecret(), - "auth": map[string]interface{}{ - "client": authClientConfig, - }, - } - (*provider.ConfigReporterOutput).(*configTest.Reporter).Config = serviceConfig - - svc = serviceService.NewDEPRECATEDService() - Expect(svc).ToNot(BeNil()) - }) - - AfterEach(func() { - if server != nil { - server.Close() - } - provider.AssertOutputsEmpty() - }) - - Context("with Terminate after", func() { - AfterEach(func() { - svc.Terminate() - }) - - Context("Initialize", func() { - It("returns an error when the provider is missing", func() { - Expect(svc.Initialize(nil)).To(MatchError("provider is missing")) - }) - - It("returns an error when the secret is missing", func() { - delete(serviceConfig, "secret") - Expect(svc.Initialize(provider)).To(MatchError("secret is missing")) - }) - - It("returns an error when the auth client cannot be initialized", func() { - delete(authClientConfig, "address") - Expect(svc.Initialize(provider)).To(MatchError("unable to create auth client; config is invalid; address is missing")) - }) - - It("returns successfully", func() { - Expect(svc.Initialize(provider)).To(Succeed()) - }) - }) - - Context("with Initialize before", func() { - BeforeEach(func() { - Expect(svc.Initialize(provider)).To(Succeed()) - }) - - Context("Terminate", func() { - It("returns successfully", func() { - svc.Terminate() - }) - }) - - Context("Secret", func() { - It("returns the secret", func() { - Expect(svc.Secret()).To(Equal(serviceConfig["secret"])) - }) - }) - - Context("AuthClient", func() { - It("returns successfully with server token", func() { - authClient := svc.AuthClient() - Expect(authClient).ToNot(BeNil()) - Eventually(authClient.ServerSessionToken).Should(Equal(sessionToken)) - }) - }) - }) - }) - }) -}) diff --git a/service/service/authenticated_test.go b/service/service/authenticated_test.go index 21c74ce196..9617b59173 100644 --- a/service/service/authenticated_test.go +++ b/service/service/authenticated_test.go @@ -1,8 +1,88 @@ package service_test import ( + "net/http" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/ghttp" + + applicationTest "github.com/tidepool-org/platform/application/test" + authTest "github.com/tidepool-org/platform/auth/test" + configTest "github.com/tidepool-org/platform/config/test" + serviceService "github.com/tidepool-org/platform/service/service" ) var _ = Describe("Authenticated", func() { + + var provider *applicationTest.Provider + var svc *serviceService.Authenticated + var serverSecret string + var sessionToken string + var authClientConfig map[string]interface{} + var serviceConfig map[string]interface{} + var serverConfig map[string]interface{} + var testServer *Server + + BeforeEach(func() { + provider = applicationTest.NewProviderWithDefaults() + + serverSecret = authTest.NewServiceSecret() + sessionToken = authTest.NewSessionToken() + + testServer = NewServer() + testServer.AppendHandlers( + CombineHandlers( + VerifyRequest("POST", "/auth/serverlogin"), + VerifyHeaderKV("X-Tidepool-Server-Name", *provider.NameOutput), + VerifyHeaderKV("X-Tidepool-Server-Secret", serverSecret), + VerifyBody(nil), + RespondWith(http.StatusOK, nil, http.Header{"X-Tidepool-Session-Token": []string{sessionToken}})), + ) + + authClientConfig = map[string]interface{}{ + "address": testServer.URL(), + "server_token_secret": authTest.NewServiceSecret(), + "external": map[string]interface{}{ + "address": testServer.URL(), + "server_session_token_secret": serverSecret, + }, + } + serverConfig = map[string]interface{}{ + "address": testServer.URL(), + "tls": "false", + } + serviceConfig = map[string]interface{}{ + "secret": authTest.NewServiceSecret(), + "server": serverConfig, + "auth": map[string]interface{}{ + "client": authClientConfig, + }, + } + (*provider.ConfigReporterOutput).(*configTest.Reporter).Config = serviceConfig + + svc = serviceService.NewAuthenticated() + Expect(svc).ToNot(BeNil()) + + Expect(svc.Initialize(provider)).To(Succeed()) + }) + + AfterEach(func() { + if svc != nil { + svc.Terminate() + } + provider.AssertOutputsEmpty() + }) + + It("returns the secret", func() { + Expect(svc.Secret()).To(Equal(serviceConfig["secret"])) + }) + + Context("AuthClient", func() { + It("returns successfully with server token", func() { + authClient := svc.AuthClient() + Expect(authClient).ToNot(BeNil()) + Eventually(authClient.ServerSessionToken).Should(Equal(sessionToken)) + }) + }) })