-
Notifications
You must be signed in to change notification settings - Fork 21
fix(experimental): Functions for putting/getting an LDScopedClient from context.Context #305
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package ldclient | ||
|
||
import "context" | ||
|
||
type scopedClientKey struct{} | ||
|
||
// GoContextWithScopedClient adds a scoped client to the Go context. This can be | ||
// used to pass a scoped client to a function or goroutine that might not | ||
// otherwise have access to it: | ||
// | ||
// scopedClient := ld.NewScopedClient(client, ldUserContext) | ||
// ctx := ld.GoContextWithScopedClient(context.Background(), scopedClient) | ||
// otherFunction(ctx) | ||
// | ||
// This function is not stable, and not subject to any backwards compatibility | ||
// guarantees or semantic versioning. It is not suitable for production usage. Do | ||
// not use it. You have been warned. | ||
func GoContextWithScopedClient(ctx context.Context, client *LDScopedClient) context.Context { | ||
return context.WithValue(ctx, scopedClientKey{}, client) | ||
} | ||
|
||
// GetScopedClient retrieves a scoped client from the Go context that was set | ||
// with GoContextWithScopedClient, if present. If not present, returns nil and | ||
// false. | ||
// | ||
// func logicWithFeatureFlag(ctx context.Context) { | ||
// scopedClient, ok := ld.GetScopedClient(ctx) | ||
// isFeatureEnabled := false // default value if scoped client is not available | ||
// if ok { | ||
// isFeatureEnabled, err = scopedClient.BoolVariation("my-flag", false) | ||
// // handle err as appropriate... | ||
// } | ||
// } | ||
// | ||
// This function is not stable, and not subject to any backwards compatibility | ||
// guarantees or semantic versioning. It is not suitable for production usage. Do | ||
// not use it. You have been warned. | ||
func GetScopedClient(ctx context.Context) (*LDScopedClient, bool) { | ||
client, ok := ctx.Value(scopedClientKey{}).(*LDScopedClient) | ||
return client, ok | ||
} | ||
|
||
// MustGetScopedClient retrieves a scoped client from the Go context that was set | ||
// with GoContextWithScopedClient, or panics if not present. | ||
// | ||
// func logicWithFeatureFlag(ctx context.Context) { | ||
// scopedClient := ld.MustGetScopedClient(ctx) | ||
// isFeatureEnabled, err := scopedClient.BoolVariation("my-flag", false) | ||
// // handle err as appropriate... | ||
// } | ||
// | ||
// This function is not stable, and not subject to any backwards compatibility | ||
// guarantees or semantic versioning. It is not suitable for production usage. Do | ||
// not use it. You have been warned. | ||
func MustGetScopedClient(ctx context.Context) *LDScopedClient { | ||
client, ok := GetScopedClient(ctx) | ||
if !ok { | ||
panic("No scoped client found in context") | ||
} | ||
return client | ||
} | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package ldclient | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestGetScopedClient(t *testing.T) { | ||
t.Run("returns client from context", func(t *testing.T) { | ||
origCtx := context.Background() | ||
sc := &LDScopedClient{} | ||
|
||
newCtx := GoContextWithScopedClient(origCtx, sc) | ||
retrieved, ok := GetScopedClient(newCtx) | ||
|
||
assert.True(t, ok, "expected to find scoped client in context") | ||
assert.Equal(t, sc, retrieved, "retrieved client should match original") | ||
}) | ||
|
||
t.Run("returns nil when not present", func(t *testing.T) { | ||
retrieved, ok := GetScopedClient(context.Background()) | ||
assert.False(t, ok, "should not find scoped client in empty context") | ||
assert.Nil(t, retrieved, "retrieved client should be nil when not present") | ||
}) | ||
} | ||
|
||
func TestMustGetScopedClient(t *testing.T) { | ||
sc := &LDScopedClient{} | ||
ctxWith := GoContextWithScopedClient(context.Background(), sc) | ||
|
||
// Should return the client without panicking when present | ||
assert.Equal(t, sc, MustGetScopedClient(ctxWith)) | ||
|
||
// Should panic when the client is not present | ||
assert.Panics(t, func() { | ||
MustGetScopedClient(context.Background()) | ||
}) | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Nil Client in Context Causes Panic
MustGetScopedClient
returnsnil
without panicking if a typednil *LDScopedClient
is stored in the context. This occurs becauseGetScopedClient
returnsok=true
for a typednil
value, andGoContextWithScopedClient
allows storingnil
. Consequently, callers receivenil
instead of a panic, leading to a later nil dereference at the point of use and defeating the "must" contract.Additional Locations (1)
ldclient_gocontext.go#L37-L41