diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dd9788c..11967c5 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,12 +9,11 @@ check-generate: script: - nix-shell --run "make generate && git diff --quiet" -check-lint: +check-fmt: stage: format image: nixos/nix:latest script: - nix-shell --run "make fmt && git diff --quiet" - - nix-shell --run "make lint" check-gomod: stage: format diff --git a/Makefile b/Makefile index 7060845..428f401 100644 --- a/Makefile +++ b/Makefile @@ -11,9 +11,6 @@ test-watch: fmt: go fmt ./... -lint: - golangci-lint run ./... - run: go run ./cmd/birthdaybot -config example-config.yml diff --git a/README.md b/README.md index 74daf59..e55c522 100644 --- a/README.md +++ b/README.md @@ -24,11 +24,6 @@ Template Format, and has the following properties available: - `.MonthOfBirth`: the month that the person was born, as number. - `.DayOfBirth`: the day that the person was born, as number. -There are as well some functions available to be used: - -- `getYearsOld`: receives the year that a user was born, and returns - how old the user is getting. - ### Pictures Alongside the notification for each birthday, the bot can send a @@ -70,12 +65,6 @@ $ make run - [X] Reduce logger verbosity (through levels) - [X] Add pictures to birthday notifications - [X] Create a configurable template to fill with each notification -- [X] Add some endpoints - - [X] Health endpoint - - [X] Next birthdays endpoint - - [ ] Birthday list endpoint -- [X] Allow to use a random port in web tests -- [X] Web server should be optional - [ ] Create different message systems to use with the bot - [X] Telegram - [ ] Email diff --git a/birthdays.csv b/birthdays.csv index eda11db..1450480 100644 --- a/birthdays.csv +++ b/birthdays.csv @@ -1,3 +1,2 @@ John Doe,john@doe.com,12345,17/04/2192 -John Doe The Second,john@doesecond.com,12543,17/04/2192 Jane Doe,jane@doe.com,54321,10/11/2020 \ No newline at end of file diff --git a/client/client.go b/client/client.go deleted file mode 100644 index e4246a9..0000000 --- a/client/client.go +++ /dev/null @@ -1,91 +0,0 @@ -package client - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/url" - "strings" - - "git.ctrlz.es/mgdelacroix/birthdaybot/model" -) - -var ( - ErrEmptyURL = errors.New("URL cannot be empty") -) - -type Client struct { - url string - httpClient *http.Client - headers map[string]string -} - -func New(opts ...Option) (*Client, error) { - client := &Client{ - httpClient: &http.Client{}, - } - - for _, opt := range opts { - client = opt(client) - } - - if client.url == "" { - return nil, ErrEmptyURL - } - - return client, nil -} - -func (c *Client) Do(ctx context.Context, method, path, data string, headers map[string]string) (*http.Response, error) { - url, err := url.JoinPath(c.url, path) - if err != nil { - return nil, fmt.Errorf("cannot build request url: %w", err) - } - - req, err := http.NewRequestWithContext(ctx, method, url, strings.NewReader(data)) - if err != nil { - return nil, fmt.Errorf("cannot create request: %w", err) - } - - for k, v := range c.headers { - req.Header.Set(k, v) - } - - for k, v := range headers { - req.Header.Set(k, v) - } - - resp, err := c.httpClient.Do(req) - if err != nil { - return nil, fmt.Errorf("cannot do request: %w", err) - } - - return resp, nil -} - -func (c *Client) Health(ctx context.Context) (bool, error) { - resp, err := c.Do(ctx, http.MethodGet, "/health", "", nil) - if err != nil { - return false, err - } - defer resp.Body.Close() - - return resp.StatusCode == 200, nil -} - -func (c *Client) NextBirthdays(ctx context.Context) ([]*model.Birthday, error) { - resp, err := c.Do(ctx, http.MethodGet, "/next_birthdays", "", nil) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - var birthdays []*model.Birthday - if err := json.NewDecoder(resp.Body).Decode(&birthdays); err != nil { - return nil, fmt.Errorf("cannot decode birthdays: %w", err) - } - - return birthdays, nil -} diff --git a/client/options.go b/client/options.go deleted file mode 100644 index 80554ba..0000000 --- a/client/options.go +++ /dev/null @@ -1,17 +0,0 @@ -package client - -type Option func(*Client) *Client - -func WithURL(url string) Option { - return func(client *Client) *Client { - client.url = url - return client - } -} - -func WithHeaders(headers map[string]string) Option { - return func(client *Client) *Client { - client.headers = headers - return client - } -} diff --git a/cmd/birthdaybot/main.go b/cmd/birthdaybot/main.go index fbdb1c6..dbbe9cc 100644 --- a/cmd/birthdaybot/main.go +++ b/cmd/birthdaybot/main.go @@ -47,16 +47,8 @@ func main() { c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) - if err := srv.Start(); err != nil { - fmt.Fprintf(os.Stderr, "ERROR: cannot start server: %s\n", err) - os.Exit(1) - } - + srv.Start() s := <-c srv.Logger.Info("received signal, stopping", "signal", s) - - if err := srv.Stop(); err != nil { - fmt.Fprintf(os.Stderr, "ERROR: cannot stop server: %s\n", err) - os.Exit(1) - } + srv.Stop() } diff --git a/example-config.yml b/example-config.yml index d59be78..34d1a22 100644 --- a/example-config.yml +++ b/example-config.yml @@ -1,8 +1,4 @@ --- -web: - enabled: true - port: 8080 - birthdays: file: birthdays.csv template: ./birthday_message.tmpl diff --git a/model/birthdays.go b/model/birthdays.go index 818d646..cbd64d6 100644 --- a/model/birthdays.go +++ b/model/birthdays.go @@ -4,7 +4,6 @@ import ( "fmt" "strconv" "strings" - "time" ) type Birthday struct { @@ -20,8 +19,15 @@ func (b *Birthday) Filename() string { return fmt.Sprintf("%d_%d_%d_%s.png", b.YearOfBirth, b.MonthOfBirth, b.DayOfBirth, b.Phone) } -func (b *Birthday) Time() time.Time { - return time.Date(b.YearOfBirth, time.Month(b.MonthOfBirth), b.DayOfBirth, 0, 0, 0, 0, time.Now().Location()) +func (b *Birthday) ToMap() map[string]any { + return map[string]any{ + "Name": b.Name, + "Email": b.Email, + "Phone": b.Phone, + "YearOfBirth": b.YearOfBirth, + "MonthOfBirth": b.MonthOfBirth, + "DayOfBirth": b.DayOfBirth, + } } func NewBirthdayFromRecord(record []string) (*Birthday, error) { @@ -102,36 +108,3 @@ func FilterByDate(birthdays []*Birthday, day, month, year int) []*Birthday { } return filteredBirthdays } - -func NextBirthdayDate(birthdays []*Birthday, now time.Time) (int, int, int) { - nowRounded := now.Round(24 * time.Hour) - - var nextBirthday *Birthday - for _, birthday := range birthdays { - if nextBirthday == nil { - nextBirthday = birthday - continue - } - - birthdayTime := birthday.Time() - nextBirthdayTime := nextBirthday.Time() - - if nextBirthdayTime.Before(nowRounded) && birthdayTime.After(nowRounded) { - nextBirthday = birthday - continue - } - - if birthdayTime.Before(nextBirthdayTime) { - if birthdayTime.After(nowRounded) || nextBirthdayTime.Before(nowRounded) { - nextBirthday = birthday - } - } - } - - return nextBirthday.DayOfBirth, nextBirthday.MonthOfBirth, nextBirthday.YearOfBirth -} - -func NextBirthdays(birthdays []*Birthday, now time.Time) []*Birthday { - day, month, year := NextBirthdayDate(birthdays, now) - return FilterByDate(birthdays, day, month, year) -} diff --git a/model/birthdays_test.go b/model/birthdays_test.go index 260ed7a..2570b45 100644 --- a/model/birthdays_test.go +++ b/model/birthdays_test.go @@ -2,7 +2,6 @@ package model import ( "testing" - "time" "github.com/stretchr/testify/require" ) @@ -56,68 +55,3 @@ func TestFilename(t *testing.T) { require.Equal(t, "2022_4_6_123456789.png", birthday.Filename()) } - -func TestNextBirthdayDate(t *testing.T) { - firstBirthday := &Birthday{ - YearOfBirth: 1900, - MonthOfBirth: 2, - DayOfBirth: 1, - } - - secondBirthday := &Birthday{ - YearOfBirth: 1900, - MonthOfBirth: 8, - DayOfBirth: 1, - } - - birthdays := []*Birthday{firstBirthday, secondBirthday} - birthdaysReversed := []*Birthday{secondBirthday, firstBirthday} - - testCases := []struct { - Name string - Now time.Time - Birthdays []*Birthday - ExpectedDay int - ExpectedMonth int - ExpectedYear int - }{ - { - Name: "should find first birthday", - Now: time.Date(1900, time.Month(1), 1, 0, 0, 0, 0, time.Now().Location()), - ExpectedDay: 1, - ExpectedMonth: 2, - ExpectedYear: 1900, - }, - { - Name: "should find second birthday", - Now: time.Date(1900, time.Month(4), 1, 0, 0, 0, 0, time.Now().Location()), - ExpectedDay: 1, - ExpectedMonth: 8, - ExpectedYear: 1900, - }, - { - Name: "should find first birthday for next year", - Now: time.Date(1900, time.Month(10), 1, 0, 0, 0, 0, time.Now().Location()), - ExpectedDay: 1, - ExpectedMonth: 2, - ExpectedYear: 1900, - }, - } - - for _, tc := range testCases { - t.Run(tc.Name, func(t *testing.T) { - t.Run("with birthdays sorted", func(t *testing.T) { - day, month, year := NextBirthdayDate(birthdays, tc.Now) - require.Equal(t, tc.ExpectedDay, day) - require.Equal(t, tc.ExpectedMonth, month) - require.Equal(t, tc.ExpectedYear, year) - }) - t.Run("with birthdays reversed", func(t *testing.T) { - day, month, year := NextBirthdayDate(birthdaysReversed, tc.Now) - require.Equal(t, tc.ExpectedDay, day) - require.Equal(t, tc.ExpectedMonth, month) - require.Equal(t, tc.ExpectedYear, year) - }) - }) - } -} diff --git a/model/config.go b/model/config.go index c732011..a0adc7e 100644 --- a/model/config.go +++ b/model/config.go @@ -3,7 +3,7 @@ package model import ( "errors" "fmt" - "os" + "io/ioutil" "strings" "gopkg.in/yaml.v3" @@ -19,7 +19,6 @@ var ( type Config struct { Birthdays *BirthdaysConfig `yaml:"birthdays"` Logger *LoggerConfig `yaml:"logger"` - Web *WebConfig `yaml:"web"` TelegramNotifications *TelegramNotificationsConfig `yaml:"telegram_notifications"` } @@ -32,10 +31,6 @@ func (c *Config) IsValid() error { return fmt.Errorf("invalid logger config: %w", err) } - if err := c.Web.IsValid(); err != nil { - return fmt.Errorf("invalid web config: %w", err) - } - if c.TelegramNotifications != nil { if err := c.TelegramNotifications.IsValid(); err != nil { return fmt.Errorf("invalid telegram notifications config: %w", err) @@ -58,12 +53,6 @@ func (c *Config) SetDefaults() { c.Logger.SetDefaults() - if c.Web == nil { - c.Web = &WebConfig{} - } - - c.Web.SetDefaults() - if c.TelegramNotifications != nil { c.TelegramNotifications.SetDefaults() } @@ -110,17 +99,6 @@ func (lc *LoggerConfig) IsValid() error { return nil } -type WebConfig struct { - Enabled bool `yaml:"enabled"` - Port int `yaml:"port"` -} - -func (wc *WebConfig) SetDefaults() {} - -func (wc *WebConfig) IsValid() error { - return nil -} - type TelegramNotificationsConfig struct { BotToken string `yaml:"bot_token"` ChannelID string `yaml:"channel_id"` @@ -141,7 +119,7 @@ func (tnc *TelegramNotificationsConfig) IsValid() error { } func ReadConfig(path string) (*Config, error) { - fileBytes, err := os.ReadFile(path) + fileBytes, err := ioutil.ReadFile(path) if err != nil { return nil, err } diff --git a/model/config_test.go b/model/config_test.go index 81f88af..b744133 100644 --- a/model/config_test.go +++ b/model/config_test.go @@ -2,6 +2,7 @@ package model import ( "io" + "io/ioutil" "os" "testing" @@ -10,7 +11,7 @@ import ( func TestReadConfig(t *testing.T) { t.Run("should correctly read a configuration file", func(t *testing.T) { - f, err := os.CreateTemp("", "birthdaybot-") + f, err := ioutil.TempFile("", "birthdaybot-") require.NoError(t, err) defer os.Remove(f.Name()) @@ -24,7 +25,7 @@ func TestReadConfig(t *testing.T) { }) t.Run("should fail if the file doesn't exist", func(t *testing.T) { - f, err := os.CreateTemp("", "birthdaybot-") + f, err := ioutil.TempFile("", "birthdaybot-") require.NoError(t, err) f.Close() os.Remove(f.Name()) diff --git a/notification/service_telegram.go b/notification/service_telegram.go index 0dffdb8..f41c9f4 100644 --- a/notification/service_telegram.go +++ b/notification/service_telegram.go @@ -43,7 +43,7 @@ func (tns *TelegramNotificationService) Notify(birthday *model.Birthday, templat var msgText string if template != nil { var stringBuffer bytes.Buffer - if err := template.Execute(&stringBuffer, birthday); err != nil { + if err := template.Execute(&stringBuffer, birthday.ToMap()); err != nil { return fmt.Errorf("cannot execute template for birthday: %w", err) } diff --git a/parser/csv_parser_test.go b/parser/csv_parser_test.go index f4ae075..d0b977b 100644 --- a/parser/csv_parser_test.go +++ b/parser/csv_parser_test.go @@ -2,7 +2,7 @@ package parser import ( "io" - "os" + "io/ioutil" "testing" "github.com/stretchr/testify/require" @@ -10,7 +10,7 @@ import ( func TestParseCsv(t *testing.T) { t.Run("should correctly parse a valid CSV file", func(t *testing.T) { - f, err := os.CreateTemp("", "birthdaybot-") + f, err := ioutil.TempFile("", "birthdaybot-") require.NoError(t, err) _, werr := io.WriteString(f, "John Doe , john@doe.com, 1234, 17/04/2192\nJane Doe,jane@doe.com,4321,15/01/2020\n") diff --git a/sample.tmpl b/sample.tmpl index 0b40e71..54ebaef 100644 --- a/sample.tmpl +++ b/sample.tmpl @@ -1 +1 @@ -¡Mañana es el cumpleaños de {{.Name}}! Cumple {{getYearsOld .YearOfBirth}} años, puedes felicitarle o bien escribiendo a {{.Email}} o bien llamando al número {{.Phone}} \ No newline at end of file +¡Mañana es el cumpleaños de {{.Name}}! Puedes felicitarle o bien escribiendo a {{.Email}} o bien llamando al número {{.Phone}} \ No newline at end of file diff --git a/server/helpers_test.go b/server/helpers_test.go index d198be6..1cdc576 100644 --- a/server/helpers_test.go +++ b/server/helpers_test.go @@ -1,11 +1,10 @@ package server import ( - "fmt" + "io/ioutil" "os" "testing" - "git.ctrlz.es/mgdelacroix/birthdaybot/client" "git.ctrlz.es/mgdelacroix/birthdaybot/model" "git.ctrlz.es/mgdelacroix/birthdaybot/notification" notification_mocks "git.ctrlz.es/mgdelacroix/birthdaybot/notification/mocks" @@ -21,22 +20,18 @@ type TestHelper struct { mockNotificationService *notification_mocks.MockNotificationService mockWorker *server_mocks.MockWorker srv *Server - client *client.Client } func testConfig(t *testing.T) *model.Config { - f, err := os.CreateTemp("", "birthdaybot-") + f, err := ioutil.TempFile("", "birthdaybot-") require.NoError(t, err) require.NoError(t, f.Close()) require.NoError(t, os.Remove(f.Name())) - return &model.Config{ - Web: &model.WebConfig{Enabled: true, Port: 0}, - Birthdays: &model.BirthdaysConfig{File: f.Name()}, - } + return &model.Config{Birthdays: &model.BirthdaysConfig{File: f.Name()}} } -func SetupTestHelper(t *testing.T, opts ...Option) *TestHelper { +func SetupTestHelper(t *testing.T) *TestHelper { th := &TestHelper{t: t} th.ctrl = gomock.NewController(t) @@ -59,28 +54,22 @@ func SetupTestHelper(t *testing.T, opts ...Option) *TestHelper { }, } - serverOpts := append([]Option{ + var err error + th.srv, err = New( WithConfig(testConfig(t)), WithLogger(log.New(os.Stderr)), WithBirthdays(birthdays), WithNotificationServices(notificationServices), WithWorkers(workers), - }, opts...) - - var err error - th.srv, err = New(serverOpts...) + ) require.NoError(t, err) - require.NoError(t, th.srv.Start()) - - client, err := client.New(client.WithURL(fmt.Sprintf("http://127.0.0.1:%d", th.srv.WebServer.Port()))) - require.NoError(t, err) - th.client = client + th.srv.Start() return th } func (th *TestHelper) TearDown() { - require.NoError(th.t, th.srv.Stop()) + th.srv.Stop() th.ctrl.Finish() } diff --git a/server/server.go b/server/server.go index 46254df..ead52aa 100644 --- a/server/server.go +++ b/server/server.go @@ -3,9 +3,7 @@ package server import ( "errors" "fmt" - "path" "text/template" - "time" "git.ctrlz.es/mgdelacroix/birthdaybot/model" "git.ctrlz.es/mgdelacroix/birthdaybot/notification" @@ -22,7 +20,6 @@ var ( type Server struct { Logger *log.Logger Config *model.Config - WebServer *WebServer workers []Worker birthdays []*model.Birthday notificationServices []notification.NotificationService @@ -92,70 +89,30 @@ func New(options ...Option) (*Server, error) { if srv.Config.Birthdays.Template != "" { srv.Logger.Debug("parsing birthday template", "file", srv.Config.Birthdays.Template) - funcs := template.FuncMap{ - "getYearsOld": func(yearOfBirth int) int { - return time.Now().Year() - yearOfBirth - }, - } - var err error - srv.tmpl, err = template. - New(path.Base(srv.Config.Birthdays.Template)). - Funcs(funcs). - ParseFiles(srv.Config.Birthdays.Template) + srv.tmpl, err = template.ParseFiles(srv.Config.Birthdays.Template) if err != nil { return nil, fmt.Errorf("cannot parse template file %q: %w", srv.Config.Birthdays.Template, err) } } - if srv.WebServer == nil && srv.Config.Web.Enabled { - srv.Logger.Debug("creating web server") - - ws, err := NewWebServer(srv) - if err != nil { - return nil, fmt.Errorf("cannot create web server: %w", err) - } - - srv.WebServer = ws - } - return srv, nil } -func (s *Server) Start() error { +func (s *Server) Start() { s.Logger.Info("starting server") - - if s.WebServer != nil { - if err := s.WebServer.Start(); err != nil { - return fmt.Errorf("cannot start web server: %w", err) - } - } - for _, worker := range s.workers { worker.Start() } - s.Logger.Debug("server started", "workers", len(s.workers)) - - return nil } -func (s *Server) Stop() error { +func (s *Server) Stop() { s.Logger.Info("stopping server") - - if s.WebServer != nil { - if err := s.WebServer.Stop(); err != nil { - return fmt.Errorf("cannot stop web server: %w", err) - } - } - for _, worker := range s.workers { worker.Stop() } - s.Logger.Debug("server stopped", "workers", len(s.workers)) - - return nil } func (s *Server) Notify(birthday *model.Birthday) error { @@ -176,7 +133,3 @@ func (s *Server) Notify(birthday *model.Birthday) error { func (s *Server) Birthdays() []*model.Birthday { return s.birthdays } - -func (s *Server) NextBirthdays() []*model.Birthday { - return model.NextBirthdays(s.birthdays, time.Now()) -} diff --git a/server/server_test.go b/server/server_test.go index 8d76cb1..6d8d5d9 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -1,21 +1,15 @@ package server import ( - "bytes" "errors" - "fmt" - "os" "testing" - "time" - "git.ctrlz.es/mgdelacroix/birthdaybot/model" "github.com/stretchr/testify/require" ) func TestNotify(t *testing.T) { th := SetupTestHelper(t) defer th.TearDown() - t.Run("should correctly use the notification services to notify", func(t *testing.T) { birthday := th.srv.birthdays[0] th.mockNotificationService. @@ -41,53 +35,3 @@ func TestNotify(t *testing.T) { require.ErrorIs(t, err, mockErr) }) } - -func TestTemplate(t *testing.T) { - t.Run("template should work with birthday data", func(t *testing.T) { - // create a template file and populate it - f, err := os.CreateTemp("", "birthdaybot-config-") - require.NoError(t, err) - _, werr := fmt.Fprint(f, "My name is {{.Name}}") - require.NoError(t, werr) - require.NoError(t, f.Close()) - - // create a test config and set the template - config := testConfig(t) - config.Birthdays.Template = f.Name() - - // create the test helper with the custom config - th := SetupTestHelper(t, WithConfig(config)) - defer th.TearDown() - - birthday := &model.Birthday{Name: "Jane Doe"} - expectedString := "My name is Jane Doe" - - var stringBuffer bytes.Buffer - require.NoError(t, th.srv.tmpl.Execute(&stringBuffer, birthday)) - require.Equal(t, expectedString, stringBuffer.String()) - }) - - t.Run("template should work with custom functions", func(t *testing.T) { - // create a template file and populate it - f, err := os.CreateTemp("", "birthdaybot-config-") - require.NoError(t, err) - _, werr := fmt.Fprint(f, "I'm getting {{getYearsOld .YearOfBirth}} years old") - require.NoError(t, werr) - require.NoError(t, f.Close()) - - // create a test config and set the template - config := testConfig(t) - config.Birthdays.Template = f.Name() - - // create the test helper with the custom config - th := SetupTestHelper(t, WithConfig(config)) - defer th.TearDown() - - birthday := &model.Birthday{YearOfBirth: 1980} - expectedString := fmt.Sprintf("I'm getting %d years old", time.Now().Year()-birthday.YearOfBirth) - - var stringBuffer bytes.Buffer - require.NoError(t, th.srv.tmpl.Execute(&stringBuffer, birthday)) - require.Equal(t, expectedString, stringBuffer.String()) - }) -} diff --git a/server/web.go b/server/web.go deleted file mode 100644 index 176ffc6..0000000 --- a/server/web.go +++ /dev/null @@ -1,88 +0,0 @@ -package server - -import ( - "encoding/json" - "errors" - "fmt" - "net" - "net/http" - - "github.com/charmbracelet/log" -) - -type WebServer struct { - server *Server - listener net.Listener - logger *log.Logger - httpServer *http.Server -} - -func NewWebServer(server *Server) (*WebServer, error) { - listener, err := net.Listen("tcp", fmt.Sprintf(":%d", server.Config.Web.Port)) - if err != nil { - return nil, fmt.Errorf("cannot create listener: %w", err) - } - - ws := &WebServer{ - server: server, - listener: listener, - logger: server.Logger, - } - - mux := http.NewServeMux() - mux.HandleFunc("/health", ws.healthHandler) - mux.HandleFunc("/next_birthdays", ws.nextBirthdayHandler) - - ws.httpServer = &http.Server{Handler: mux} - - return ws, nil -} - -func (ws *WebServer) Start() error { - ws.logger.Debug("starting web server") - - go func() { - if err := ws.httpServer.Serve(ws.listener); err != nil && !errors.Is(err, http.ErrServerClosed) { - ws.logger.Fatal("cannot start web server", "error", err) - } - }() - - return nil -} - -func (ws *WebServer) Stop() error { - ws.logger.Debug("stopping web server") - - if err := ws.httpServer.Close(); err != nil { - return fmt.Errorf("cannot stop web server: %w", err) - } - - return nil -} - -func (ws *WebServer) Port() int { - return ws.listener.Addr().(*net.TCPAddr).Port -} - -func (ws *WebServer) healthHandler(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, "OK") -} - -func (ws *WebServer) nextBirthdayHandler(w http.ResponseWriter, r *http.Request) { - ws.JSON(w, http.StatusOK, ws.server.NextBirthdays()) -} - -func (ws *WebServer) JSON(w http.ResponseWriter, statusCode int, data any) { - b, err := json.Marshal(data) - if err != nil { - ws.logger.Error("cannot marshal data", "error", err) - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - return - } - - w.WriteHeader(statusCode) - if _, err := w.Write(b); err != nil { - ws.logger.Error("cannot write to response writer", "error", err) - http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) - } -} diff --git a/server/web_test.go b/server/web_test.go deleted file mode 100644 index fc2c935..0000000 --- a/server/web_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package server - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestPort(t *testing.T) { - th := SetupTestHelper(t) - defer th.TearDown() - - port := th.srv.WebServer.Port() - require.NotEmpty(t, port) -} - -func TestHealthHandler(t *testing.T) { - th := SetupTestHelper(t) - defer th.TearDown() - - t.Run("should return ok if the server is up and running", func(t *testing.T) { - health, err := th.client.Health(context.Background()) - require.NoError(t, err) - require.True(t, health) - }) -} - -func TestNextBirthdaysHandler(t *testing.T) { - th := SetupTestHelper(t) - defer th.TearDown() - - t.Run("should return a list if the server is up and running", func(t *testing.T) { - birthdays, err := th.client.NextBirthdays(context.Background()) - require.NoError(t, err) - require.Len(t, birthdays, 1) - require.Equal(t, "john@doe.com", birthdays[0].Email) - }) -} diff --git a/server/worker.go b/server/worker.go index 99b7658..1676454 100644 --- a/server/worker.go +++ b/server/worker.go @@ -48,9 +48,7 @@ func (w *SimpleWorker) notifyDay(year, month, day int) { for _, b := range birthdays { w.logger.Info("notifying for birthday", "name", b.Name) - if err := w.server.Notify(b); err != nil { - w.logger.Error("error notifying for birthday", "name", b.Name, "error", err) - } + w.server.Notify(b) } } diff --git a/shell.nix b/shell.nix index c83ebbf..dd84f05 100644 --- a/shell.nix +++ b/shell.nix @@ -15,7 +15,6 @@ pkgs.mkShell { gnumake modd mockgen - golangci-lint ]; shellHook = ''