From a5ca88faae46c0a924ee0c148141d93c71770e43 Mon Sep 17 00:00:00 2001 From: Eric Wollesen Date: Thu, 2 Nov 2023 11:14:50 -0600 Subject: [PATCH] adds an alerts client BACK-2500 --- alerts/client.go | 80 +++++++++++++++++++++++++++++++++++++++++++ alerts/client_test.go | 78 +++++++++++++++++++++++++++++++++++++++++ alerts/repo.go | 1 - 3 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 alerts/client.go create mode 100644 alerts/client_test.go delete mode 100644 alerts/repo.go diff --git a/alerts/client.go b/alerts/client.go new file mode 100644 index 0000000000..213c9df7a0 --- /dev/null +++ b/alerts/client.go @@ -0,0 +1,80 @@ +package alerts + +import ( + "context" + "net/http" + + "github.com/kelseyhightower/envconfig" + + "github.com/tidepool-org/platform/client" + "github.com/tidepool-org/platform/platform" +) + +// Client for managing alerts configs. +type Client struct { + client *platform.Client +} + +// NewClient builds an alerts client. +func NewClient(cfg *ClientConfig) (*Client, error) { + client, err := platform.NewClient(cfg.Config, platform.AuthorizeAsService) + if err != nil { + return nil, err + } + + return &Client{ + client: client, + }, nil +} + +// Upsert updates cfg in the service if it exists, or creates it if it doesn't. +func (c *Client) Upsert(ctx context.Context, cfg *Config) error { + url := c.client.ConstructURL("v1", "alerts", cfg.UserID, cfg.FollowedUserID) + return c.client.RequestData(ctx, http.MethodPost, url, nil, cfg, nil) +} + +// Delete the alerts config. +func (c *Client) Delete(ctx context.Context, cfg *Config) error { + url := c.client.ConstructURL("v1", "alerts", cfg.UserID, cfg.FollowedUserID) + return c.client.RequestData(ctx, http.MethodDelete, url, nil, nil, nil) +} + +// ClientConfig leverages platform.Config for the alerts client. +type ClientConfig struct { + *platform.Config + Address string `envconfig:"TIDEPOOL_DATA_CLIENT_ADDRESS"` +} + +// ConfigLoader abstracts the method by which config values are loaded. +type ConfigLoader interface { + Load(cfg *ClientConfig) error +} + +// envconfigLoader adapts envconfig to implement ConfigLoader. +type envconfigLoader struct { + ConfigLoader platform.ConfigLoader +} + +// NewEnvconfigLoader loads values via envconfig. +// +// If loader is nil, it defaults to envconfig for platform values. +func NewEnvconfigLoader(loader platform.ConfigLoader) *envconfigLoader { + if loader == nil { + loader = platform.NewEnvconfigLoader(nil) + } + return &envconfigLoader{ + ConfigLoader: loader, + } +} + +// Load implements ConfigLoader. +func (l *envconfigLoader) Load(cfg *ClientConfig) error { + if err := l.ConfigLoader.Load(cfg.Config); err != nil { + return err + } + if err := envconfig.Process(client.EnvconfigEmptyPrefix, cfg); err != nil { + return err + } + cfg.Config.Address = cfg.Address + return nil +} diff --git a/alerts/client_test.go b/alerts/client_test.go new file mode 100644 index 0000000000..51ac12476c --- /dev/null +++ b/alerts/client_test.go @@ -0,0 +1,78 @@ +package alerts + +import ( + "context" + "net/http" + "net/http/httptest" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/tidepool-org/platform/client" + "github.com/tidepool-org/platform/log" + "github.com/tidepool-org/platform/log/null" + "github.com/tidepool-org/platform/platform" +) + +var _ = Describe("Client", func() { + test404Server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) + })) + GinkgoT().Cleanup(test404Server.Close) + test200Server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + http.Error(w, http.StatusText(http.StatusOK), http.StatusOK) + })) + GinkgoT().Cleanup(test200Server.Close) + + Context("Delete", func() { + It("returns an error on non-200 responses", func() { + client, ctx := newAlertsClientTest(test404Server) + err := client.Delete(ctx, &Config{}) + Expect(err).Should(HaveOccurred()) + Expect(err).To(MatchError(ContainSubstring("resource not found"))) + }) + + It("returns nil on success", func() { + client, ctx := newAlertsClientTest(test200Server) + err := client.Delete(ctx, &Config{}) + Expect(err).ShouldNot(HaveOccurred()) + }) + }) + + Context("Upsert", func() { + It("returns an error on non-200 responses", func() { + client, ctx := newAlertsClientTest(test404Server) + err := client.Upsert(ctx, &Config{}) + Expect(err).Should(HaveOccurred()) + Expect(err).To(MatchError(ContainSubstring("resource not found"))) + }) + + It("returns nil on success", func() { + client, ctx := newAlertsClientTest(test200Server) + err := client.Upsert(ctx, &Config{}) + Expect(err).ShouldNot(HaveOccurred()) + }) + }) + +}) + +func buildTestClient(s *httptest.Server) *Client { + pCfg := &platform.Config{ + ServiceSecret: "foo", + Config: &client.Config{ + Address: s.URL, + UserAgent: "foo", + }, + } + client, err := NewClient(&ClientConfig{Address: s.URL, Config: pCfg}) + Expect(err).ShouldNot(HaveOccurred()) + return client +} + +func newAlertsClientTest(server *httptest.Server) (*Client, context.Context) { + return buildTestClient(server), contextWithNullLogger() +} + +func contextWithNullLogger() context.Context { + return log.NewContextWithLogger(context.Background(), null.NewLogger()) +} diff --git a/alerts/repo.go b/alerts/repo.go deleted file mode 100644 index 3dc80686f0..0000000000 --- a/alerts/repo.go +++ /dev/null @@ -1 +0,0 @@ -package alerts