Skip to content

Commit

Permalink
Add ctx fork for concurrent access (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
vearutop authored May 8, 2023
1 parent 99ea1fe commit 0778af4
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 3 deletions.
29 changes: 29 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,35 @@ func (c *Client) Reset() *Client {
return c
}

// Fork checks ctx for an existing clone of this Client.
// If one is found, it is returned together with unmodified context.
// Otherwise, a clone of Client is created and put into a new derived context,
// then both new context and cloned Client are returned.
//
// 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.
if fc, ok := ctx.Value(c).(*Client); ok {
return ctx, fc
}

// Making a copy of this Client.
cc := *c
fc := &cc
fc.JSONComparer = c.JSONComparer

fc.Reset().WithContext(ctx)

if c.JSONComparer.Vars != nil {
ctx, fc.JSONComparer.Vars = c.JSONComparer.Vars.Fork(ctx)
}

ctx = context.WithValue(ctx, c, fc)

return ctx, fc
}

// FollowRedirects enables automatic following of Location header.
func (c *Client) FollowRedirects() *Client {
c.followRedirects = true
Expand Down
57 changes: 57 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import (
"io/ioutil"
"net/http"
"net/http/httptest"
"sync"
"sync/atomic"
"testing"
"time"

"github.com/bool64/httpmock"
"github.com/bool64/shared"
Expand Down Expand Up @@ -194,3 +196,58 @@ func TestNewClient_formData(t *testing.T) {
assert.EqualError(t, c.ExpectResponseBody([]byte(`{"foo":"bar}"`)),
"unexpected body, expected: \"{\\\"foo\\\":\\\"bar}\\\"\", received: \"{\\\"bar\\\":\\\"foo\\\"}\"")
}

func TestClient_Fork(t *testing.T) {
c1 := httpmock.NewClient("https://one")
c2 := httpmock.NewClient("https://two")

c1.JSONComparer.Vars = &shared.Vars{}
c1.JSONComparer.Vars.Set("foo", 123)

wg := sync.WaitGroup{}
for i := 0; i < 100; i++ {
wg.Add(1)

go func() {
defer wg.Done()

ctx := context.Background()

ctx, fc1 := c1.Fork(ctx)
assert.NotNil(t, fc1)
fc1.WithMethod(http.MethodGet)

fc1.JSONComparer.Vars.Set("bar", 345)
foo, ok := fc1.JSONComparer.Vars.Get("foo")
assert.True(t, ok)
assert.Equal(t, 123, foo)

ctx, fc2 := c2.Fork(ctx)
assert.NotNil(t, fc2)
fc2.WithMethod(http.MethodPost)

ctx1, fc1a := c1.Fork(ctx)
assert.Equal(t, fc1a, fc1)
assert.True(t, c1 != fc1)
assert.Equal(t, ctx, ctx1)

ctx2, fc2a := c2.Fork(ctx)
assert.Equal(t, fc2a, fc2)
assert.True(t, c2 != fc2)
assert.Equal(t, ctx, ctx2)
}()
}

done := make(chan struct{})

go func() {
wg.Wait()
close(done)
}()

select {
case <-time.After(10 * time.Second):
assert.Fail(t, "could not wait for goroutines to finish")
case <-done:
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/bool64/dev v0.2.27
github.com/bool64/shared v0.1.5
github.com/stretchr/testify v1.8.2
github.com/swaggest/assertjson v1.8.0
github.com/swaggest/assertjson v1.8.1
)

require (
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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.0 h1:XSg4p6iOZMjtpV2tW2SXfD1GsOOTsWcm+sOADODu/DU=
github.com/swaggest/assertjson v1.8.0/go.mod h1:/8kNRmDZAZfavS5VeWYtCimLGebn0Ak1/iErFUi+DEM=
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/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

0 comments on commit 0778af4

Please sign in to comment.