Skip to content

Commit

Permalink
Refactor http handler, now just called Handler (#23)
Browse files Browse the repository at this point in the history
Also:
- Accept interface instead of queue implementation in handler (fixes
#20)
- Added more tests for the handler.
- Refactored JSON parsing.
  • Loading branch information
markuswustenberg authored Mar 7, 2024
2 parents 43814d7 + ee68342 commit 8b81c02
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 21 deletions.
47 changes: 31 additions & 16 deletions http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,30 @@
package http

import (
"context"
"encoding/json"
"net/http"
"time"

"github.com/maragudk/goqite"
)

func GoqiteHandler(q *goqite.Queue) http.HandlerFunc {
type request struct {
Message goqite.Message
}
type queue interface {
Send(ctx context.Context, m goqite.Message) error
Receive(ctx context.Context) (*goqite.Message, error)
Extend(ctx context.Context, id goqite.ID, delay time.Duration) error
Delete(ctx context.Context, id goqite.ID) error
}

type response struct {
Message *goqite.Message
}
type request struct {
Message goqite.Message
}

type response struct {
Message *goqite.Message
}

func Handler(q queue) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
Expand All @@ -41,9 +50,8 @@ func GoqiteHandler(q *goqite.Queue) http.HandlerFunc {
}

case http.MethodPost:
var req request
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "error decoding request: "+err.Error(), http.StatusBadRequest)
req, ok := fromJson(w, r)
if !ok {
return
}

Expand All @@ -58,9 +66,8 @@ func GoqiteHandler(q *goqite.Queue) http.HandlerFunc {
}

case http.MethodPut:
var req request
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "error decoding request: "+err.Error(), http.StatusBadRequest)
req, ok := fromJson(w, r)
if !ok {
return
}

Expand All @@ -80,9 +87,8 @@ func GoqiteHandler(q *goqite.Queue) http.HandlerFunc {
}

case http.MethodDelete:
var req request
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "error decoding request: "+err.Error(), http.StatusBadRequest)
req, ok := fromJson(w, r)
if !ok {
return
}

Expand All @@ -98,3 +104,12 @@ func GoqiteHandler(q *goqite.Queue) http.HandlerFunc {
}
}
}

func fromJson(w http.ResponseWriter, r *http.Request) (request, bool) {
var req request
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "error decoding request: "+err.Error(), http.StatusBadRequest)
return req, false
}
return req, true
}
88 changes: 83 additions & 5 deletions http/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package http_test

import (
"bytes"
"context"
"database/sql"
"encoding/json"
"errors"
"io"
"net/http"
"net/http/httptest"
Expand All @@ -23,17 +25,62 @@ type wrapper struct {
Message goqite.Message
}

func TestGoqiteHandler_Get(t *testing.T) {
type queueMock struct {
err error
}

func (q *queueMock) Send(ctx context.Context, m goqite.Message) error {
return q.err
}

func (q *queueMock) Receive(ctx context.Context) (*goqite.Message, error) {
return nil, q.err
}

func (q *queueMock) Extend(ctx context.Context, id goqite.ID, delay time.Duration) error {
return q.err
}

func (q *queueMock) Delete(ctx context.Context, id goqite.ID) error {
return q.err
}

func TestHandler(t *testing.T) {
t.Run("errors if cannot decode request", func(t *testing.T) {
q := &queueMock{}
h := qhttp.Handler(q)

for _, method := range []string{http.MethodPost, http.MethodPut, http.MethodDelete} {
t.Run(method, func(t *testing.T) {
r := httptest.NewRequest(method, "/", strings.NewReader(`{`))
w := httptest.NewRecorder()
h(w, r)

is.Equal(t, http.StatusBadRequest, w.Code)
})
}
})
}

func TestHandler_Get(t *testing.T) {
t.Run("receives nothing if there is no message", func(t *testing.T) {
h := newH(t, goqite.NewOpts{})

code, body, _ := newRequest(t, h, http.MethodGet, nil)
is.Equal(t, http.StatusNoContent, code)
is.Equal(t, "", body)
})

t.Run("errors if cannot receive from queue", func(t *testing.T) {
q := &queueMock{err: errors.New("oh no")}
h := qhttp.Handler(q)

code, _, _ := newRequest(t, h, http.MethodGet, nil)
is.Equal(t, http.StatusInternalServerError, code)
})
}

func TestGoqiteHandler_Post(t *testing.T) {
func TestHandler_Post(t *testing.T) {
t.Run("posts and receives a message", func(t *testing.T) {
h := newH(t, goqite.NewOpts{})

Expand All @@ -57,9 +104,19 @@ func TestGoqiteHandler_Post(t *testing.T) {
is.Equal(t, http.StatusBadRequest, code)
is.Equal(t, "delay cannot be negative", body)
})

t.Run("errors if cannot send to queue", func(t *testing.T) {
q := &queueMock{err: errors.New("oh no")}
h := qhttp.Handler(q)

code, _, _ := newRequest(t, h, http.MethodPost, &goqite.Message{
Body: []byte("yo"),
})
is.Equal(t, http.StatusInternalServerError, code)
})
}

func TestGoqiteHandler_Put(t *testing.T) {
func TestHandler_Put(t *testing.T) {
t.Run("can extend a message timeout", func(t *testing.T) {
h := newH(t, goqite.NewOpts{Timeout: time.Millisecond})

Expand Down Expand Up @@ -104,9 +161,20 @@ func TestGoqiteHandler_Put(t *testing.T) {
is.Equal(t, http.StatusBadRequest, code)
is.Equal(t, "ID cannot be empty", body)
})

t.Run("errors if cannot extend in queue", func(t *testing.T) {
q := &queueMock{err: errors.New("oh no")}
h := qhttp.Handler(q)

code, _, _ := newRequest(t, h, http.MethodPut, &goqite.Message{
ID: "1",
Delay: 1,
})
is.Equal(t, http.StatusInternalServerError, code)
})
}

func TestGoqiteHandler_Delete(t *testing.T) {
func TestHandler_Delete(t *testing.T) {
t.Run("deletes a message", func(t *testing.T) {
h := newH(t, goqite.NewOpts{})

Expand All @@ -133,6 +201,16 @@ func TestGoqiteHandler_Delete(t *testing.T) {
is.Equal(t, http.StatusBadRequest, code)
is.Equal(t, "ID cannot be empty", body)
})

t.Run("errors if cannot delete from queue", func(t *testing.T) {
q := &queueMock{err: errors.New("oh no")}
h := qhttp.Handler(q)

code, _, _ := newRequest(t, h, http.MethodDelete, &goqite.Message{
ID: "1",
})
is.Equal(t, http.StatusInternalServerError, code)
})
}

func newRequest(t testing.TB, h http.HandlerFunc, method string, m *goqite.Message) (int, string, *wrapper) {
Expand Down Expand Up @@ -161,7 +239,7 @@ func newH(t testing.TB, opts goqite.NewOpts) http.HandlerFunc {
t.Helper()

q := newQ(t, opts)
return qhttp.GoqiteHandler(q)
return qhttp.Handler(q)
}

func newQ(t testing.TB, opts goqite.NewOpts) *goqite.Queue {
Expand Down

0 comments on commit 8b81c02

Please sign in to comment.