Adds a client and tests for the handlers
This commit is contained in:
parent
eaca9c1691
commit
3335cfe795
4 changed files with 139 additions and 0 deletions
91
client/client.go
Normal file
91
client/client.go
Normal 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
17
client/options.go
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,12 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.ctrlz.es/mgdelacroix/birthdaybot/client"
|
||||||
"git.ctrlz.es/mgdelacroix/birthdaybot/model"
|
"git.ctrlz.es/mgdelacroix/birthdaybot/model"
|
||||||
"git.ctrlz.es/mgdelacroix/birthdaybot/notification"
|
"git.ctrlz.es/mgdelacroix/birthdaybot/notification"
|
||||||
notification_mocks "git.ctrlz.es/mgdelacroix/birthdaybot/notification/mocks"
|
notification_mocks "git.ctrlz.es/mgdelacroix/birthdaybot/notification/mocks"
|
||||||
|
@ -20,6 +22,7 @@ type TestHelper struct {
|
||||||
mockNotificationService *notification_mocks.MockNotificationService
|
mockNotificationService *notification_mocks.MockNotificationService
|
||||||
mockWorker *server_mocks.MockWorker
|
mockWorker *server_mocks.MockWorker
|
||||||
srv *Server
|
srv *Server
|
||||||
|
client *client.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func testConfig(t *testing.T) *model.Config {
|
func testConfig(t *testing.T) *model.Config {
|
||||||
|
@ -71,6 +74,10 @@ func SetupTestHelper(t *testing.T, opts ...Option) *TestHelper {
|
||||||
|
|
||||||
th.srv.Start()
|
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
|
return th
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -13,3 +14,26 @@ func TestPort(t *testing.T) {
|
||||||
port := th.srv.WebServer.Port()
|
port := th.srv.WebServer.Port()
|
||||||
require.NotEmpty(t, 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue