Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose HTTP details of last run #17

Merged
merged 3 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,28 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.22.x
go-version: 1.23.x
- uses: actions/checkout@v2
- name: golangci-lint
uses: golangci/golangci-lint-action@v6.0.1
uses: golangci/golangci-lint-action@v6.1.0
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.59.1
version: v1.61.0

# Optional: working directory, useful for monorepos
# working-directory: somedir

# Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0

# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true

# Optional: if set to true then the action will use pre-installed Go.
# skip-go-installation: true

# Optional: if set to true then the action don't cache or restore ~/go/pkg.
# skip-pkg-cache: true

# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
# skip-build-cache: true
2 changes: 1 addition & 1 deletion .github/workflows/gorelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ concurrency:
cancel-in-progress: true

env:
GO_VERSION: 1.22.x
GO_VERSION: 1.23.x
jobs:
gorelease:
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-unit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
test:
strategy:
matrix:
go-version: [ 1.13.x, 1.21.x, 1.22.x ]
go-version: [ 1.13.x, 1.22.x, 1.23.x ]
runs-on: ubuntu-latest
steps:
- name: Install Go stable
Expand Down
9 changes: 5 additions & 4 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ linters:
- ireturn
- exhaustruct
- nonamedreturns
- structcheck
- testableexamples
- dupword
- depguard
Expand All @@ -51,21 +50,23 @@ issues:
- linters:
- staticcheck
path: ".go"
text: "\"io/ioutil\" has been deprecated since Go 1.16" # Keeping backwards compatibility with go1.13.
text: "\"io/ioutil\" has been deprecated since" # Keeping backwards compatibility with go1.13.
- linters:
- gomnd
- mnd
- goconst
- goerr113
- noctx
- funlen
- dupl
- structcheck
- unused
- unparam
- nosnakecase
path: "_test.go"
- linters:
- errcheck # Error checking omitted for brevity.
- gosec
path: "example_"
- linters:
- revive
text: "unused-parameter: parameter"

2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#GOLANGCI_LINT_VERSION := "v1.59.1" # Optional configuration to pinpoint golangci-lint version.
#GOLANGCI_LINT_VERSION := "v1.61.0" # Optional configuration to pinpoint golangci-lint version.

# The head of Makefile determines location of dev-go to include standard targets.
GO ?= go
Expand Down
94 changes: 79 additions & 15 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@

ctx context.Context //nolint:containedctx // Context is configured separately.

req *http.Request
resp *http.Response
respBody []byte

attempt int
retryDelays []time.Duration

reqHeaders map[string]string
reqCookies map[string]string
reqQueryParams url.Values
Expand Down Expand Up @@ -114,6 +118,38 @@
return c
}

// HTTPValue contains information about request and response.
type HTTPValue struct {
Req *http.Request
ReqBody []byte

Resp *http.Response
RespBody []byte

OtherResp *http.Response
OtherRespBody []byte

Attempt int
RetryDelays []time.Duration
}

// Details returns HTTP request and response information of last run.
func (c *Client) Details() HTTPValue {
return HTTPValue{
Req: c.req,
ReqBody: c.reqBody,

Resp: c.resp,
RespBody: c.respBody,

OtherResp: c.otherResp,
OtherRespBody: c.otherRespBody,

Attempt: c.attempt,
RetryDelays: c.retryDelays,
}
}

// SetBaseURL changes baseURL configured with constructor.
func (c *Client) SetBaseURL(baseURL string) {
if !strings.HasPrefix(baseURL, "http://") && !strings.HasPrefix(baseURL, "https://") {
Expand All @@ -132,6 +168,8 @@
c.reqQueryParams = map[string][]string{}
c.reqFormDataParams = map[string][]string{}

c.req = nil

c.resp = nil
c.respBody = nil

Expand All @@ -147,6 +185,9 @@
c.otherRespBody = nil
c.otherRespExpected = false

c.attempt = 0
c.retryDelays = nil

return c
}

Expand All @@ -158,7 +199,7 @@
// This method enables context-driven concurrent access to shared base Client.
func (c *Client) Fork(ctx context.Context) (context.Context, *Client) {
// Pointer to current Client is used as context key
// to enable multiple different clients in sam context.
// to enable multiple different clients in same context.
if fc, ok := ctx.Value(c).(*Client); ok {
return ctx, fc
}
Expand Down Expand Up @@ -261,7 +302,9 @@
return c
}

func (c *Client) do() (err error) {
func (c *Client) do() (err error) { //nolint:funlen
c.attempt++

if c.reqConcurrency < 1 {
c.reqConcurrency = 1
}
Expand Down Expand Up @@ -289,7 +332,7 @@
wg.Done()
}()

resp, er := c.doOnce()
req, resp, er := c.doOnce()
if er != nil {
return
}
Expand All @@ -305,6 +348,10 @@
}

mu.Lock()
if c.req == nil {
c.req = req
}

if _, ok := statusCodeCount[resp.StatusCode]; !ok {
resps[resp.StatusCode] = resp
bodies[resp.StatusCode] = body
Expand All @@ -315,6 +362,7 @@
mu.Unlock()
}()
}

wg.Wait()

if err != nil {
Expand All @@ -329,6 +377,14 @@
return check()
}

if len(c.reqBody) == 0 && len(c.reqFormDataParams) > 0 {
c.reqBody = []byte(c.reqFormDataParams.Encode())

if c.reqMethod == "" {
c.reqMethod = http.MethodPost
}
}

if c.retryBackOff != nil {
for {
if err = c.do(); err == nil {
Expand All @@ -343,6 +399,8 @@
return err
}

c.retryDelays = append(c.retryDelays, dur)

time.Sleep(dur)
}
}
Expand Down Expand Up @@ -433,15 +491,17 @@
return uri, nil
}

type readSeekNopCloser struct {
io.ReadSeeker
}

func (r *readSeekNopCloser) Close() error {
return nil
}

func (c *Client) buildBody() io.Reader {
if len(c.reqBody) > 0 {
return bytes.NewBuffer(c.reqBody)
} else if len(c.reqFormDataParams) > 0 {
if c.reqMethod == "" {
c.reqMethod = http.MethodPost
}

return strings.NewReader(c.reqFormDataParams.Encode())
return &readSeekNopCloser{ReadSeeker: bytes.NewReader(c.reqBody)}
}

return nil
Expand Down Expand Up @@ -486,17 +546,17 @@
}
}

func (c *Client) doOnce() (*http.Response, error) {
func (c *Client) doOnce() (*http.Request, *http.Response, error) {
uri, err := c.buildURI()
if err != nil {
return nil, err
return nil, nil, err

Check notice on line 552 in client.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

1 statement(s) on lines 551:553 are not covered by tests.
}

body := c.buildBody()

req, err := http.NewRequestWithContext(c.ctx, c.reqMethod, uri, body)
if err != nil {
return nil, err
return nil, nil, err

Check notice on line 559 in client.go

View workflow job for this annotation

GitHub Actions / test (1.22.x)

1 statement(s) on lines 558:560 are not covered by tests.
}

c.applyHeaders(req)
Expand All @@ -513,10 +573,14 @@
cl.Transport = tr
cl.Jar = j

return cl.Do(req)
resp, err := cl.Do(req)

return req, resp, err
}

return tr.RoundTrip(req)
resp, err := tr.RoundTrip(req)

return req, resp, err
}

// ExpectResponseStatus sets expected response status code.
Expand Down
11 changes: 11 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ func TestNewClient(t *testing.T) {
val, found := vars.Get("$var1")
assert.True(t, found)
assert.Equal(t, "abc", val)

details := c.Details()
assert.NotNil(t, details.Req)
assert.NotNil(t, details.Resp)
assert.NotNil(t, details.OtherResp)

assert.Equal(t, http.StatusAccepted, details.Resp.StatusCode)
assert.Equal(t, http.StatusConflict, details.OtherResp.StatusCode)

assert.Equal(t, 1, details.Attempt)
assert.Empty(t, details.RetryDelays)
}

func TestNewClient_failedExpectation(t *testing.T) {
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ module github.com/bool64/httpmock
go 1.18

require (
github.com/bool64/dev v0.2.35
github.com/bool64/dev v0.2.36
github.com/bool64/shared v0.1.5
github.com/stretchr/testify v1.8.2
github.com/swaggest/assertjson v1.8.1
github.com/swaggest/assertjson v1.9.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/iancoleman/orderedmap v0.2.0 // indirect
github.com/iancoleman/orderedmap v0.3.0 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
github.com/bool64/dev v0.2.35 h1:M17TLsO/pV2J7PYI/gpe3Ua26ETkzZGb+dC06eoMqlk=
github.com/bool64/dev v0.2.35/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/dev v0.2.36 h1:yU3bbOTujoxhWnt8ig8t94PVmZXIkCaRj9C57OtqJBY=
github.com/bool64/dev v0.2.36/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg=
github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E=
github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA=
github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc=
github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
Expand All @@ -33,8 +33,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/swaggest/assertjson v1.8.1 h1:Be2EHY9S2qwKWV+xWZB747Cd7Y79YK6JLdeyrgFvyMo=
github.com/swaggest/assertjson v1.8.1/go.mod h1:/8kNRmDZAZfavS5VeWYtCimLGebn0Ak1/iErFUi+DEM=
github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ=
github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU=
github.com/yosuke-furukawa/json5 v0.1.2-0.20201207051438-cf7bb3f354ff h1:7YqG491bE4vstXRz1lD38rbSgbXnirvROz1lZiOnPO8=
github.com/yosuke-furukawa/json5 v0.1.2-0.20201207051438-cf7bb3f354ff/go.mod h1:sw49aWDqNdRJ6DYUtIQiaA3xyj2IL9tjeNYmX2ixwcU=
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
Expand Down
Loading