Skip to content

Commit

Permalink
fix: Add tests for empty body with ok status; Fix race (#211)
Browse files Browse the repository at this point in the history
* chore: Add tests for empty body with ok status

* fix: Race in 2016/day01 solution

* chore: Don't use cache for regression tests

* fix: Handle empty response

* chore: Add message to error

* fix: Check error if it was not expected
  • Loading branch information
obalunenko committed Dec 1, 2022
1 parent 57b53ca commit 26edee0
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 133 deletions.
2 changes: 1 addition & 1 deletion internal/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func Run(ctx context.Context, year, day string) (puzzles.Result, error) {
Day: day,
}, SessionFromContext(ctx))
if err != nil {
return puzzles.Result{}, err
return puzzles.Result{}, fmt.Errorf("failed to get input for puzzle: %w", err)
}

opts := OptionsFromContext(ctx)
Expand Down
125 changes: 98 additions & 27 deletions internal/command/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,34 @@ type mockHTTPClient struct {
MockDo dofunc
}

type returnParams struct {
status int
body io.ReadCloser
}

func newMockHTTPClient(p returnParams) *mockHTTPClient {
return &mockHTTPClient{
MockDo: func(req *http.Request) (*http.Response, error) {
return &http.Response{
Status: http.StatusText(p.status),
StatusCode: p.status,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
Header: nil,
Body: p.body,
ContentLength: 0,
TransferEncoding: nil,
Close: false,
Uncompressed: false,
Trailer: nil,
Request: nil,
TLS: nil,
}, nil
},
}
}

// Overriding what the Do function should "do" in our MockClient
func (m *mockHTTPClient) Do(req *http.Request) (*http.Response, error) {
return m.MockDo(req)
Expand Down Expand Up @@ -89,36 +117,79 @@ func TestRun(t *testing.T) {
puzzles.UnregisterAllSolvers(t)
})

r := io.NopCloser(strings.NewReader("1,2,3"))
type expected struct {
result puzzles.Result
wantErr assert.ErrorAssertionFunc
}

input.Client = &mockHTTPClient{
MockDo: func(req *http.Request) (*http.Response, error) {
return &http.Response{
Status: http.StatusText(http.StatusOK),
StatusCode: http.StatusOK,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
Header: nil,
Body: r,
ContentLength: 0,
TransferEncoding: nil,
Close: false,
Uncompressed: false,
Trailer: nil,
Request: nil,
TLS: nil,
}, nil
var tests = []struct {
name string
returnParams returnParams
expected expected
}{
{
name: "",
returnParams: returnParams{
status: http.StatusOK,
body: io.NopCloser(strings.NewReader("1,2,3")),
},
expected: expected{
result: puzzles.Result{
Year: "1992",
Name: "31",
Part1: "2",
Part2: "3",
},
wantErr: assert.NoError,
},
},
{
name: "",
returnParams: returnParams{
status: http.StatusNotFound,
body: http.NoBody,
},
expected: expected{
result: puzzles.Result{},
wantErr: assert.Error,
},
},
{
name: "",
returnParams: returnParams{
status: http.StatusUnauthorized,
body: http.NoBody,
},
expected: expected{
result: puzzles.Result{},
wantErr: assert.Error,
},
},
{
name: "",
returnParams: returnParams{
status: http.StatusOK,
body: http.NoBody,
},
expected: expected{
result: puzzles.Result{},
wantErr: assert.Error,
},
},
}

got, err := command.Run(ctx, year, day)
assert.NoError(t, err)
for i := range tests {
tt := tests[i]

t.Run(tt.name, func(t *testing.T) {
input.Client = newMockHTTPClient(tt.returnParams)

assert.Equal(t, puzzles.Result{
Year: "1992",
Name: "31",
Part1: "2",
Part2: "3",
}, got)
got, err := command.Run(ctx, year, day)
if !tt.expected.wantErr(t, err) {
return
}

assert.Equal(t, tt.expected.result, got)
})
}
}
7 changes: 6 additions & 1 deletion internal/puzzles/input/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/http"
"net/url"
"path"
"strings"
"time"

"github.com/obalunenko/logger"
Expand Down Expand Up @@ -73,6 +74,10 @@ func Get(ctx context.Context, d Date, session string) ([]byte, error) {

switch resp.StatusCode {
case http.StatusOK:
if strings.TrimSpace(string(body)) == "" {
return nil, fmt.Errorf("empty response received")
}

return body, nil
case http.StatusNotFound:
return nil, fmt.Errorf("[%s]: %w", d, ErrNotFound)
Expand Down Expand Up @@ -101,7 +106,7 @@ func createInputReq(ctx context.Context, d Date, sessionID string) (*http.Reques

req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), http.NoBody)
if err != nil {
return nil, err
return nil, fmt.Errorf("create request: %w", err)
}

req.AddCookie(&http.Cookie{
Expand Down
165 changes: 66 additions & 99 deletions internal/puzzles/input/content_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,34 @@ type mockHTTPClient struct {
MockDo dofunc
}

type returnParams struct {
status int
body io.ReadCloser
}

func newMockHTTPClient(p returnParams) *mockHTTPClient {
return &mockHTTPClient{
MockDo: func(req *http.Request) (*http.Response, error) {
return &http.Response{
Status: http.StatusText(p.status),
StatusCode: p.status,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
Header: nil,
Body: p.body,
ContentLength: 0,
TransferEncoding: nil,
Close: false,
Uncompressed: false,
Trailer: nil,
Request: nil,
TLS: nil,
}, nil
},
}
}

// Overriding what the Do function should "do" in our MockClient
func (m *mockHTTPClient) Do(req *http.Request) (*http.Response, error) {
return m.MockDo(req)
Expand Down Expand Up @@ -54,26 +82,10 @@ func TestGet(t *testing.T) {
{
name: "",
client: client{
ClientDo: &mockHTTPClient{
MockDo: func(req *http.Request) (*http.Response, error) {
return &http.Response{
Status: http.StatusText(http.StatusOK),
StatusCode: http.StatusOK,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
Header: nil,
Body: io.NopCloser(strings.NewReader("test")),
ContentLength: 0,
TransferEncoding: nil,
Close: false,
Uncompressed: false,
Trailer: nil,
Request: nil,
TLS: nil,
}, nil
},
},
ClientDo: newMockHTTPClient(returnParams{
status: http.StatusOK,
body: io.NopCloser(strings.NewReader("test")),
}),
},
args: args{
ctx: context.Background(),
Expand All @@ -89,26 +101,10 @@ func TestGet(t *testing.T) {
{
name: "",
client: client{
ClientDo: &mockHTTPClient{
MockDo: func(req *http.Request) (*http.Response, error) {
return &http.Response{
Status: http.StatusText(http.StatusNotFound),
StatusCode: http.StatusNotFound,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
Header: nil,
Body: http.NoBody,
ContentLength: 0,
TransferEncoding: nil,
Close: false,
Uncompressed: false,
Trailer: nil,
Request: nil,
TLS: nil,
}, nil
},
},
ClientDo: newMockHTTPClient(returnParams{
status: http.StatusOK,
body: io.NopCloser(strings.NewReader("")),
}),
},
args: args{
ctx: context.Background(),
Expand All @@ -124,26 +120,10 @@ func TestGet(t *testing.T) {
{
name: "",
client: client{
ClientDo: &mockHTTPClient{
MockDo: func(req *http.Request) (*http.Response, error) {
return &http.Response{
Status: http.StatusText(http.StatusBadRequest),
StatusCode: http.StatusBadRequest,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
Header: nil,
Body: io.NopCloser(strings.NewReader("no session")),
ContentLength: 0,
TransferEncoding: nil,
Close: false,
Uncompressed: false,
Trailer: nil,
Request: nil,
TLS: nil,
}, nil
},
},
ClientDo: newMockHTTPClient(returnParams{
status: http.StatusNotFound,
body: http.NoBody,
}),
},
args: args{
ctx: context.Background(),
Expand All @@ -159,26 +139,29 @@ func TestGet(t *testing.T) {
{
name: "",
client: client{
ClientDo: &mockHTTPClient{
MockDo: func(req *http.Request) (*http.Response, error) {
return &http.Response{
Status: http.StatusText(http.StatusInternalServerError),
StatusCode: http.StatusInternalServerError,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
Header: nil,
Body: io.NopCloser(strings.NewReader("no session")),
ContentLength: 0,
TransferEncoding: nil,
Close: false,
Uncompressed: false,
Trailer: nil,
Request: nil,
TLS: nil,
}, nil
},
ClientDo: newMockHTTPClient(returnParams{
status: http.StatusBadRequest,
body: io.NopCloser(strings.NewReader("no session")),
}),
},
args: args{
ctx: context.Background(),
d: input.Date{
Year: "2021",
Day: "25",
},
session: "123",
},
want: nil,
wantErr: assert.Error,
},
{
name: "",
client: client{
ClientDo: newMockHTTPClient(returnParams{
status: http.StatusInternalServerError,
body: io.NopCloser(strings.NewReader("no session")),
}),
},
args: args{
ctx: context.Background(),
Expand Down Expand Up @@ -214,26 +197,10 @@ func TestGet(t *testing.T) {
{
name: "",
client: client{
ClientDo: &mockHTTPClient{
MockDo: func(req *http.Request) (*http.Response, error) {
return &http.Response{
Status: http.StatusText(http.StatusOK),
StatusCode: http.StatusOK,
Proto: "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 0,
Header: nil,
Body: io.NopCloser(iotest.ErrReader(errors.New("custom error"))),
ContentLength: 0,
TransferEncoding: nil,
Close: false,
Uncompressed: false,
Trailer: nil,
Request: nil,
TLS: nil,
}, nil
},
},
ClientDo: newMockHTTPClient(returnParams{
status: http.StatusOK,
body: io.NopCloser(iotest.ErrReader(errors.New("custom error"))),
}),
},
args: args{
ctx: context.Background(),
Expand Down
Loading

0 comments on commit 26edee0

Please sign in to comment.