Adds a client and tests for the handlers

This commit is contained in:
Miguel de la Cruz 2023-07-11 16:29:57 +02:00
parent eaca9c1691
commit 3335cfe795
4 changed files with 139 additions and 0 deletions

91
client/client.go Normal file
View file

@ -0,0 +1,91 @@
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
}

17
client/options.go Normal file
View file

@ -0,0 +1,17 @@
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
}
}

View file

@ -1,10 +1,12 @@
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"
@ -20,6 +22,7 @@ type TestHelper struct {
mockNotificationService *notification_mocks.MockNotificationService
mockWorker *server_mocks.MockWorker
srv *Server
client *client.Client
}
func testConfig(t *testing.T) *model.Config {
@ -71,6 +74,10 @@ func SetupTestHelper(t *testing.T, opts ...Option) *TestHelper {
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
return th
}

View file

@ -1,6 +1,7 @@
package server
import (
"context"
"testing"
"github.com/stretchr/testify/require"
@ -13,3 +14,26 @@ func TestPort(t *testing.T) {
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)
})
}