Skip to content

Commit

Permalink
iter: test bad responses
Browse files Browse the repository at this point in the history
  • Loading branch information
aviau committed Sep 14, 2024
1 parent 6e4d008 commit 32ba34c
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 50 deletions.
89 changes: 39 additions & 50 deletions api_client_iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,72 +17,61 @@ type IterResult struct {
Next string
}

func createPagingIterator(
func getIterResult(
fetchPage func(from string) (*http.Response, error),
) iter.Seq2[*IterResult, error] {
cursor string,
) (*IterResult, error) {
response, err := fetchPage(cursor)
if err != nil {
return nil, fmt.Errorf("failed to fetch next page: %w", err)
}

defer response.Body.Close()

body, err := io.ReadAll(response.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response: %w", err)
}

type ResponseWithNext struct {
Next string `json:"next"`
}
var responseWithNext ResponseWithNext
if err := json.Unmarshal(body, &responseWithNext); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}

cursor := ""
response.Body = io.NopCloser(bytes.NewReader(body))

iterResult := &IterResult{
Response: response,
Next: responseWithNext.Next,
}

return iterResult, nil
}

func createPagingIterator(
fetchPage func(from string) (*http.Response, error),
) iter.Seq2[*IterResult, error] {
cursor := ""
return func(yield func(*IterResult, error) bool) {
for {
// Fire the request
response, err := fetchPage(cursor)
iterResult, err := getIterResult(
fetchPage,
cursor,
)
if err != nil {
yield(nil, err)
return
}

// Read the body
body, err := io.ReadAll(response.Body)
if err != nil {
yield(
nil,
fmt.Errorf("failed to read response: %w", err),
)
return
}

// Close the body
if err := response.Body.Close(); err != nil {
yield(
nil,
fmt.Errorf("failed to close http response: %w", err),
)
cursor = iterResult.Next
if !yield(iterResult, err) {
return
}

// Look for the next token
var responseWithNext ResponseWithNext
if err := json.Unmarshal(body, &responseWithNext); err != nil {
yield(
nil,
fmt.Errorf("failed to unmarshal response: %w", err),
)
if cursor == "" {
return
}

// Replace the body and return the response
response.Body = io.NopCloser(bytes.NewReader(body))
if !yield(
&IterResult{
Response: response,
Next: responseWithNext.Next,
},
nil,
) {
return
}

// Was this the last page?
if responseWithNext.Next == "" {
return
}

// Set the cursor for next page
cursor = responseWithNext.Next
}
}
}
Expand Down
27 changes: 27 additions & 0 deletions api_client_iter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,33 @@ func TestIterGet(t *testing.T) {

}

func TestIterGetBadResponse(t *testing.T) {
ct := newClientTest(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/leaksdb/sources", r.URL.Path)
w.Write([]byte(`{"next": 11, "items": []}`))
}),
)
defer ct.Close()

lastPageIndex := 0

for result, err := range ct.apiClient.IterGet(
"/leaksdb/sources",
nil,
) {
lastPageIndex = lastPageIndex + 1
if lastPageIndex > 2 {
// We are going crazy here...
break
}
assert.ErrorContains(t, err, "failed to unmarshal", "Bad next token should trigger an error")
assert.Nil(t, result, "bad response should not contain a result")
}

assert.Equal(t, 1, lastPageIndex, "Didn't get the expected number of pages")
}

func TestIterPostJson(t *testing.T) {
ct := newClientTest(
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand Down

0 comments on commit 32ba34c

Please sign in to comment.