From 6bf8ec160ee29984928bb7320ddd1f6f8580d7a9 Mon Sep 17 00:00:00 2001 From: Todd Anderson <127344469+tanderson-ld@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:17:49 -0500 Subject: [PATCH] =?UTF-8?q?fix:=20fixes=20issue=20where=20first=20flag=20l?= =?UTF-8?q?istener=20callback=20was=20not=20triggered=E2=80=A6=20(#97)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … if active context is a multicontext **Requirements** - [x] I have added test coverage for new or changed functionality - [x] I have followed the repository's [pull request submission guidelines](../blob/main/CONTRIBUTING.md#submitting-pull-requests) - [x] I have validated my changes against all supported platform versions **Related issues** https://github.com/launchdarkly/dotnet-client-sdk/issues/70 **Describe the solution you've provided** Key should have been FullyQualifiedKey. This was a bug introduced during the users to context work. --- scripts/start-contract-test-service.sh | 2 +- .../DataSources/DataSourceUpdateSinkImpl.cs | 5 ++-- .../DataSourceUpdateSinkImplTest.cs | 5 ++-- .../LDClientEndToEndTests.cs | 4 +-- .../LdClientEventTests.cs | 8 ++--- .../LdClientTests.cs | 30 +++++++++---------- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/scripts/start-contract-test-service.sh b/scripts/start-contract-test-service.sh index 74cbc37c..392d2a1c 100755 --- a/scripts/start-contract-test-service.sh +++ b/scripts/start-contract-test-service.sh @@ -1,2 +1,2 @@ #!/bin/bash -cd contract-tests && dotnet bin/Debug/${TESTFRAMEWORK:-net6.0}/ContractTestService.dll +cd contract-tests && dotnet bin/Debug/${TESTFRAMEWORK:-net7.0}/ContractTestService.dll diff --git a/src/LaunchDarkly.ClientSdk/Internal/DataSources/DataSourceUpdateSinkImpl.cs b/src/LaunchDarkly.ClientSdk/Internal/DataSources/DataSourceUpdateSinkImpl.cs index 57402c9a..6c63db4e 100644 --- a/src/LaunchDarkly.ClientSdk/Internal/DataSources/DataSourceUpdateSinkImpl.cs +++ b/src/LaunchDarkly.ClientSdk/Internal/DataSources/DataSourceUpdateSinkImpl.cs @@ -52,9 +52,10 @@ public void Init(Context context, FullDataSet data) _dataStore.Init(context, data, true); ImmutableDictionary oldValues, newValues; + var contextKey = context.FullyQualifiedKey; lock (_lastValuesLock) { - _lastValues.TryGetValue(context.Key, out oldValues); + _lastValues.TryGetValue(contextKey, out oldValues); var builder = ImmutableDictionary.CreateBuilder(); foreach (var newEntry in data.Items) { @@ -65,7 +66,7 @@ public void Init(Context context, FullDataSet data) } } newValues = builder.ToImmutable(); - _lastValues = _lastValues.SetItem(context.Key, newValues); + _lastValues = _lastValues.SetItem(contextKey, newValues); } UpdateStatus(DataSourceState.Valid, null); diff --git a/tests/LaunchDarkly.ClientSdk.Tests/Internal/DataSources/DataSourceUpdateSinkImplTest.cs b/tests/LaunchDarkly.ClientSdk.Tests/Internal/DataSources/DataSourceUpdateSinkImplTest.cs index 0ba5e6a5..f20cb263 100644 --- a/tests/LaunchDarkly.ClientSdk.Tests/Internal/DataSources/DataSourceUpdateSinkImplTest.cs +++ b/tests/LaunchDarkly.ClientSdk.Tests/Internal/DataSources/DataSourceUpdateSinkImplTest.cs @@ -13,8 +13,9 @@ public class DataSourceUpdateSinkImplTest : BaseTest private readonly FlagDataManager _store; private readonly FlagTrackerImpl _flagTracker; private readonly DataSourceUpdateSinkImpl _updateSink; - private readonly Context _basicUser = Context.New("user-key"); - private readonly Context _otherUser = Context.New("other-key"); + + private readonly Context _basicUser = Context.NewMulti(Context.New(ContextKind.Of("user"), "user-key1"), Context.New(ContextKind.Of("custom-kind"), "custom-key1")); + private readonly Context _otherUser = Context.NewMulti(Context.New(ContextKind.Of("user"), "user-key2"), Context.New(ContextKind.Of("custom-kind"), "custom-key2")); public DataSourceUpdateSinkImplTest(ITestOutputHelper testOutput) : base(testOutput) { diff --git a/tests/LaunchDarkly.ClientSdk.Tests/LDClientEndToEndTests.cs b/tests/LaunchDarkly.ClientSdk.Tests/LDClientEndToEndTests.cs index 15781c4d..6f8f3634 100644 --- a/tests/LaunchDarkly.ClientSdk.Tests/LDClientEndToEndTests.cs +++ b/tests/LaunchDarkly.ClientSdk.Tests/LDClientEndToEndTests.cs @@ -182,7 +182,7 @@ public void IdentifySwitchesUserAndGetsFlagsSync(UpdateMode mode) var success = client.Identify(_otherUser, TimeSpan.FromSeconds(5)); Assert.True(success); Assert.True(client.Initialized); - Assert.Equal(_otherUser.Key, client.Context.Key); // don't compare entire user, because SDK may have added device/os attributes + Assert.Equal(_otherUser.FullyQualifiedKey, client.Context.FullyQualifiedKey); // don't compare entire user, because SDK may have added device/os attributes var req2 = VerifyRequest(server.Recorder, mode); Assert.NotEqual(user1RequestPath, req2.Path); @@ -211,7 +211,7 @@ public async Task IdentifySwitchesUserAndGetsFlagsAsync(UpdateMode mode) var success = await client.IdentifyAsync(_otherUser); Assert.True(success); Assert.True(client.Initialized); - Assert.Equal(_otherUser.Key, client.Context.Key); // don't compare entire user, because SDK may have added device/os attributes + Assert.Equal(_otherUser.FullyQualifiedKey, client.Context.FullyQualifiedKey); // don't compare entire user, because SDK may have added device/os attributes var req2 = VerifyRequest(server.Recorder, mode); Assert.NotEqual(user1RequestPath, req2.Path); diff --git a/tests/LaunchDarkly.ClientSdk.Tests/LdClientEventTests.cs b/tests/LaunchDarkly.ClientSdk.Tests/LdClientEventTests.cs index 15740ba6..58236b1d 100644 --- a/tests/LaunchDarkly.ClientSdk.Tests/LdClientEventTests.cs +++ b/tests/LaunchDarkly.ClientSdk.Tests/LdClientEventTests.cs @@ -48,7 +48,7 @@ public void TrackSendsCustomEvent() e => { CustomEvent ce = Assert.IsType(e); Assert.Equal("eventkey", ce.EventKey); - Assert.Equal(user.Key, ce.Context.Key); + Assert.Equal(user.FullyQualifiedKey, ce.Context.FullyQualifiedKey); Assert.Equal(LdValue.Null, ce.Data); Assert.Null(ce.MetricValue); Assert.NotEqual(0, ce.Timestamp.Value); @@ -68,7 +68,7 @@ public void TrackWithDataSendsCustomEvent() e => { CustomEvent ce = Assert.IsType(e); Assert.Equal("eventkey", ce.EventKey); - Assert.Equal(user.Key, ce.Context.Key); + Assert.Equal(user.FullyQualifiedKey, ce.Context.FullyQualifiedKey); Assert.Equal(data, ce.Data); Assert.Null(ce.MetricValue); Assert.NotEqual(0, ce.Timestamp.Value); @@ -89,7 +89,7 @@ public void TrackWithMetricValueSendsCustomEvent() e => { CustomEvent ce = Assert.IsType(e); Assert.Equal("eventkey", ce.EventKey); - Assert.Equal(user.Key, ce.Context.Key); + Assert.Equal(user.FullyQualifiedKey, ce.Context.FullyQualifiedKey); Assert.Equal(data, ce.Data); Assert.Equal(metricValue, ce.MetricValue); Assert.NotEqual(0, ce.Timestamp.Value); @@ -336,7 +336,7 @@ public void VariationSendsFeatureEventWithReasonForUnknownFlagWhenClientIsNotIni private void CheckIdentifyEvent(object e, Context c) { IdentifyEvent ie = Assert.IsType(e); - Assert.Equal(c.Key, ie.Context.Key); + Assert.Equal(c.FullyQualifiedKey, ie.Context.FullyQualifiedKey); Assert.NotEqual(0, ie.Timestamp.Value); } } diff --git a/tests/LaunchDarkly.ClientSdk.Tests/LdClientTests.cs b/tests/LaunchDarkly.ClientSdk.Tests/LdClientTests.cs index d432c0ad..43eb879d 100644 --- a/tests/LaunchDarkly.ClientSdk.Tests/LdClientTests.cs +++ b/tests/LaunchDarkly.ClientSdk.Tests/LdClientTests.cs @@ -66,7 +66,7 @@ public async Task InitWithAnonUserAddsRandomizedKey() using (var client = await TestUtil.CreateClientAsync(config, AnonUser)) { - key1 = client.Context.Key; + key1 = client.Context.FullyQualifiedKey; Assert.NotNull(key1); Assert.NotEqual("", key1); AssertHelpers.ContextsEqual( @@ -77,7 +77,7 @@ public async Task InitWithAnonUserAddsRandomizedKey() // Starting again should generate a new key, since we've turned off persistence using (var client = await TestUtil.CreateClientAsync(config, AnonUser)) { - var key2 = client.Context.Key; + var key2 = client.Context.FullyQualifiedKey; Assert.NotNull(key2); Assert.NotEqual("", key2); Assert.NotEqual(key1, key2); @@ -112,7 +112,7 @@ public async Task InitWithAnonUserCanReusePreviousRandomizedKey() using (var client = await TestUtil.CreateClientAsync(config, AnonUser)) { - key1 = client.Context.Key; + key1 = client.Context.FullyQualifiedKey; Assert.NotNull(key1); Assert.NotEqual("", key1); AssertHelpers.ContextsEqual( @@ -123,7 +123,7 @@ public async Task InitWithAnonUserCanReusePreviousRandomizedKey() // Starting again should reuse the persisted key using (var client = await TestUtil.CreateClientAsync(config, AnonUser)) { - Assert.Equal(key1, client.Context.Key); + Assert.Equal(key1, client.Context.FullyQualifiedKey); AssertHelpers.ContextsEqual( Context.BuilderFromContext(AnonUser).Key(key1).Build(), client.Context); @@ -147,7 +147,7 @@ public async void InitWithAnonUserPassesGeneratedUserToDataSource() Assert.NotEqual(AnonUser, receivedContext); Assert.Equal(client.Context, receivedContext); AssertHelpers.ContextsEqual( - Context.BuilderFromContext(AnonUser).Key(receivedContext.Key).Build(), + Context.BuilderFromContext(AnonUser).Key(receivedContext.FullyQualifiedKey).Build(), receivedContext); } } @@ -187,7 +187,7 @@ public async void InitWithAutoEnvAttributesDisabledNoAddedContexts() Assert.NotEqual(AnonUser, receivedContext); Assert.Equal(client.Context, receivedContext); AssertHelpers.ContextsEqual( - Context.BuilderFromContext(AnonUser).Key(receivedContext.Key).Build(), + Context.BuilderFromContext(AnonUser).Key(receivedContext.FullyQualifiedKey).Build(), receivedContext); } } @@ -200,7 +200,7 @@ public void IdentifyUpdatesTheUser() var updatedUser = Context.New("some new key"); var success = client.Identify(updatedUser, TimeSpan.FromSeconds(1)); Assert.True(success); - Assert.Equal(client.Context.Key, updatedUser.Key); // don't compare entire user, because SDK may have added device/os attributes + Assert.Equal(client.Context.FullyQualifiedKey, updatedUser.FullyQualifiedKey); // don't compare entire user, because SDK may have added device/os attributes } } @@ -230,7 +230,7 @@ private async Task IdentifyCompletesOnlyWhenNewFlagsAreAvailable(Func(ctx => new MockDataSourceFromLambda(ctx.CurrentContext, async () => { - switch (ctx.CurrentContext.Key) + switch (ctx.CurrentContext.FullyQualifiedKey) { case "a": ctx.DataSourceUpdateSink.Init(ctx.CurrentContext, userAFlags); @@ -308,7 +308,7 @@ public async Task IdentifyWithAnonUserAddsRandomizedKey() { await client.IdentifyAsync(AnonUser); - key1 = client.Context.Key; + key1 = client.Context.FullyQualifiedKey; Assert.NotNull(key1); Assert.NotEqual("", key1); AssertHelpers.ContextsEqual( @@ -317,7 +317,7 @@ public async Task IdentifyWithAnonUserAddsRandomizedKey() var anonUser2 = TestUtil.BuildAutoContext().Name("other").Build(); await client.IdentifyAsync(anonUser2); - var key2 = client.Context.Key; + var key2 = client.Context.FullyQualifiedKey; Assert.Equal(key1, key2); // Even though persistence is disabled, the key is stable during the lifetime of the SDK client. AssertHelpers.ContextsEqual( Context.BuilderFromContext(anonUser2).Key(key2).Build(), @@ -328,7 +328,7 @@ public async Task IdentifyWithAnonUserAddsRandomizedKey() { await client.IdentifyAsync(AnonUser); - var key3 = client.Context.Key; + var key3 = client.Context.FullyQualifiedKey; Assert.NotNull(key3); Assert.NotEqual("", key3); Assert.NotEqual(key1, key3); // The previously generated key was discarded with the previous client. @@ -365,7 +365,7 @@ public async Task IdentifyWithAnonUserCanReusePersistedRandomizedKey() { await client.IdentifyAsync(AnonUser); - key1 = client.Context.Key; + key1 = client.Context.FullyQualifiedKey; Assert.NotNull(key1); Assert.NotEqual("", key1); AssertHelpers.ContextsEqual( @@ -377,7 +377,7 @@ public async Task IdentifyWithAnonUserCanReusePersistedRandomizedKey() { await client.IdentifyAsync(AnonUser); - var key2 = client.Context.Key; + var key2 = client.Context.FullyQualifiedKey; Assert.Equal(key1, key2); AssertHelpers.ContextsEqual( Context.BuilderFromContext(AnonUser).Key(key2).Build(), @@ -404,7 +404,7 @@ public async void IdentifyWithAnonUserPassesGeneratedUserToDataSource() Assert.NotEqual(AnonUser, receivedContext); Assert.Equal(client.Context, receivedContext); AssertHelpers.ContextsEqual( - Context.BuilderFromContext(AnonUser).Key(client.Context.Key).Build(), + Context.BuilderFromContext(AnonUser).Key(client.Context.FullyQualifiedKey).Build(), receivedContext); } } @@ -448,7 +448,7 @@ public async void IdentifyWithAutoEnvAttributesDisabledNoAddedContexts() Assert.NotEqual(AnonUser, receivedContext); Assert.Equal(client.Context, receivedContext); AssertHelpers.ContextsEqual( - Context.BuilderFromContext(AnonUser).Key(receivedContext.Key).Build(), + Context.BuilderFromContext(AnonUser).Key(receivedContext.FullyQualifiedKey).Build(), receivedContext); } }