Skip to content

Commit

Permalink
httphandlers/GetRecords: handle context expiry and cancellation
Browse files Browse the repository at this point in the history
  • Loading branch information
micvbang committed Jul 5, 2024
1 parent 6bd0977 commit 9abde5a
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 10 deletions.
24 changes: 14 additions & 10 deletions internal/httphandlers/getrecords.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ func GetRecords(log logger.Logger, s RecordsGetter) http.HandlerFunc {
WithField("max-records", maxRecords).
WithField("timeout", timeout)

var errIsContext bool
records, err := s.GetRecords(ctx, topicName, offset, maxRecords, softMaxBytes)
if err != nil {
if errors.Is(err, seb.ErrTopicNotFound) {
Expand All @@ -84,23 +85,26 @@ func GetRecords(log logger.Logger, s RecordsGetter) http.HandlerFunc {
return
}

if errors.Is(err, context.DeadlineExceeded) {
// there was no error, there is just no content
w.Header().Add("Content-Type", multipartFormData)

log.Debugf("deadline exceeded: %s", err)
w.WriteHeader(http.StatusPartialContent)
fmt.Fprintf(w, "deadline exceeded")
errIsContext = errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled)
if !errIsContext {
log.Errorf("reading record: %s", err.Error())
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "failed to read record '%d': %s", offset, err)
return
}

log.Errorf("reading record: %s", err.Error())
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "failed to read record '%d': %s", offset, err)
// NOTE: continues from here!
}

mw := multipart.NewWriter(w)
w.Header().Set("Content-Type", mw.FormDataContentType())

if errIsContext {
log.Debugf("context ended: %s", err)
w.WriteHeader(http.StatusPartialContent)
return
}

for localOffset, record := range records {
fw, err := mw.CreateFormField(fmt.Sprintf("%d", offset+uint64(localOffset)))
if err != nil {
Expand Down
60 changes: 60 additions & 0 deletions internal/httphandlers/getrecords_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package httphandlers_test

import (
"context"
"fmt"
"io"
"mime"
Expand All @@ -10,6 +11,8 @@ import (
"testing"

"github.com/micvbang/go-helpy/uint64y"
seb "github.com/micvbang/simple-event-broker"
"github.com/micvbang/simple-event-broker/internal/httphandlers"
"github.com/micvbang/simple-event-broker/internal/infrastructure/httphelpers"
"github.com/micvbang/simple-event-broker/internal/infrastructure/tester"
"github.com/micvbang/simple-event-broker/internal/sebrecords"
Expand Down Expand Up @@ -290,3 +293,60 @@ func TestGetRecordsMultipartFormData(t *testing.T) {
})
}
}

// TestGetRecordsErrors verifies that the expected status codes are returned
// when GetRecords() returns certain errors.
func TestGetRecordsErrors(t *testing.T) {
deps := &httphandlers.MockDependencies{}

server := tester.HTTPServer(t, tester.HTTPDependencies(deps))
defer server.Close()

tests := map[string]struct {
getRecordsErr error
statusCode int
}{
"deadline exceeded": {
getRecordsErr: context.DeadlineExceeded,
statusCode: http.StatusPartialContent,
},
"deadline cancelled": {
getRecordsErr: context.DeadlineExceeded,
statusCode: http.StatusPartialContent,
},
"topic not found": {
getRecordsErr: seb.ErrTopicNotFound,
statusCode: http.StatusNotFound,
},
"out of bounds": {
getRecordsErr: seb.ErrOutOfBounds,
statusCode: http.StatusNotFound,
},
"nil": {
getRecordsErr: nil,
statusCode: http.StatusOK,
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
deps.GetRecordsMock = func(ctx context.Context, topicName string, offset uint64, maxRecords, softMaxBytes int) ([]sebrecords.Record, error) {
return nil, test.getRecordsErr
}

r := httptest.NewRequest("GET", "/records", nil)
r.Header.Add("Accept", "multipart/form-data")
httphelpers.AddQueryParams(r, map[string]string{
"topic-name": "some-topic",
"offset": "0",
"timeout": "5s",
})

// Act
response := server.DoWithAuth(r)

// Assert
require.Equal(t, test.statusCode, response.StatusCode)
})
}
}

0 comments on commit 9abde5a

Please sign in to comment.