diff --git a/README.md b/README.md
index c8a7449..83e8507 100644
--- a/README.md
+++ b/README.md
@@ -71,6 +71,27 @@ When your application shuts down, remember to dispose the unleash instance.
unleash?.Dispose()
```
+### Handling events
+Currently supported events:
+- [Impression data events](https://docs.getunleash.io/advanced/impression-data#impression-event-data)
+
+```csharp
+
+var settings = new UnleashSettings()
+{
+ // ...
+};
+
+var unleash = new DefaultUnleash(settings);
+
+// Set up handling of impression events
+unleash.ConfigureEvents(cfg =>
+{
+ cfg.ImpressionEvent = evt => { Console.WriteLine($"{evt.FeatureName}: {evt.Enabled}"); };
+});
+
+```
+
### Configuring projects in unleash client
If you're organizing your feature toggles in `Projects` in Unleash Enterprise, you can specify the `ProjectId` on the `UnleashSettings` to select which project to fetch feature toggles for.
diff --git a/src/Unleash/DefaultUnleash.cs b/src/Unleash/DefaultUnleash.cs
index 6c81cdf..f65ec93 100644
--- a/src/Unleash/DefaultUnleash.cs
+++ b/src/Unleash/DefaultUnleash.cs
@@ -78,6 +78,8 @@ public DefaultUnleash(UnleashSettings settings, bool overrideDefaultStrategies,
///
public ICollection FeatureToggles => services.ToggleCollection.Instance.Features;
+ private EventCallbackConfig EventConfig { get; set; }
+
///
public bool IsEnabled(string toggleName)
{
@@ -125,6 +127,9 @@ private bool CheckIsEnabled(string toggleName, UnleashContext context, bool defa
}
RegisterCount(toggleName, enabled);
+
+ if (featureToggle?.ImpressionData ?? false) EmitImpressionEvent("isEnabled", context, enabled, featureToggle.Name);
+
return enabled;
}
@@ -146,6 +151,9 @@ public Variant GetVariant(string toggleName, UnleashContext context, Variant def
var variant = enabled ? VariantUtils.SelectVariant(toggle, context, defaultValue) : defaultValue;
RegisterVariant(toggleName, variant);
+
+ if (toggle?.ImpressionData ?? false) EmitImpressionEvent("getVariant", context, enabled, toggle.Name, variant.Name);
+
return variant;
}
@@ -235,6 +243,52 @@ private IEnumerable ResolveConstraints(ActivationStrategy activation
}
}
+ public void ConfigureEvents(Action callback)
+ {
+ if (callback == null)
+ {
+ Logger.Error($"UNLEASH: Unleash->ConfigureEvents parameter callback is null");
+ return;
+ }
+
+ try
+ {
+ var evtConfig = new EventCallbackConfig();
+ callback(evtConfig);
+ EventConfig = evtConfig;
+ }
+ catch (Exception ex)
+ {
+ Logger.Error($"UNLEASH: Unleash->ConfigureEvents executing callback threw exception: {ex.Message}");
+ }
+ }
+
+ private void EmitImpressionEvent(string type, UnleashContext context, bool enabled, string name, string variant = null)
+ {
+ if (EventConfig.ImpressionEvent == null)
+ {
+ Logger.Error($"UNLEASH: Unleash->ImpressionData callback is null, unable to emit event");
+ return;
+ }
+
+ try
+ {
+ EventConfig.ImpressionEvent(new ImpressionEvent
+ {
+ Type = type,
+ Context = context,
+ EventId = Guid.NewGuid().ToString(),
+ Enabled = enabled,
+ FeatureName = name,
+ Variant = variant
+ });
+ }
+ catch (Exception ex)
+ {
+ Logger.Error($"UNLEASH: Emitting impression event callback threw exception: {ex.Message}");
+ }
+ }
+
public void Dispose()
{
services?.Dispose();
diff --git a/src/Unleash/IUnleash.cs b/src/Unleash/IUnleash.cs
index e9e21da..4d05887 100644
--- a/src/Unleash/IUnleash.cs
+++ b/src/Unleash/IUnleash.cs
@@ -82,5 +82,7 @@ public interface IUnleash : IDisposable
/// /// The Unleash context to evaluate the toggle state against.
/// A list of available variants.
IEnumerable GetVariants(string toggleName, UnleashContext context);
+
+ void ConfigureEvents(Action config);
}
}
\ No newline at end of file
diff --git a/src/Unleash/Internal/EventCallbackConfig.cs b/src/Unleash/Internal/EventCallbackConfig.cs
new file mode 100644
index 0000000..bf8053a
--- /dev/null
+++ b/src/Unleash/Internal/EventCallbackConfig.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Unleash.Internal
+{
+ public class EventCallbackConfig
+ {
+ public Action ImpressionEvent { get; set; }
+ }
+}
diff --git a/src/Unleash/Internal/FeatureToggle.cs b/src/Unleash/Internal/FeatureToggle.cs
index 4f3c456..f56c8c5 100644
--- a/src/Unleash/Internal/FeatureToggle.cs
+++ b/src/Unleash/Internal/FeatureToggle.cs
@@ -5,11 +5,12 @@ namespace Unleash.Internal
{
public class FeatureToggle
{
- public FeatureToggle(string name, string type, bool enabled, List strategies, List variants = null)
+ public FeatureToggle(string name, string type, bool enabled, bool impressionData, List strategies, List variants = null)
{
Name = name;
Type = type;
Enabled = enabled;
+ ImpressionData = impressionData;
Strategies = strategies;
Variants = variants ?? new List();
}
@@ -17,13 +18,15 @@ public FeatureToggle(string name, string type, bool enabled, List Strategies { get; }
public List Variants { get; }
public override string ToString()
{
- return $"FeatureToggle{{name=\'{Name}{'\''}, enabled={Enabled}, strategies=\'{Strategies}{'\''}{'}'}";
+ return $"FeatureToggle{{name=\'{Name}{'\''}, enabled={Enabled}, impressionData={ImpressionData}, strategies=\'{Strategies}{'\''}{'}'}";
}
}
}
\ No newline at end of file
diff --git a/src/Unleash/Internal/ImpressionEvent.cs b/src/Unleash/Internal/ImpressionEvent.cs
new file mode 100644
index 0000000..52ccf7f
--- /dev/null
+++ b/src/Unleash/Internal/ImpressionEvent.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Unleash.Internal
+{
+ public class ImpressionEvent
+ {
+ public string Type { get; set; }
+ public string EventId { get; set; }
+ public UnleashContext Context { get; set; }
+ public bool Enabled { get; set; }
+ public string FeatureName { get; set; }
+ public string Variant { get; set; }
+ }
+}
diff --git a/src/Unleash/Serialization/JsonSerializerTester.cs b/src/Unleash/Serialization/JsonSerializerTester.cs
index 5ebf706..f21d8ff 100644
--- a/src/Unleash/Serialization/JsonSerializerTester.cs
+++ b/src/Unleash/Serialization/JsonSerializerTester.cs
@@ -14,14 +14,14 @@ public static class JsonSerializerTester
{
private static readonly ToggleCollection Toggles = new ToggleCollection(new List
{
- new FeatureToggle("Feature1", "release", true, new List()
+ new FeatureToggle("Feature1", "release", true, false, new List()
{
new ActivationStrategy("remoteAddress", new Dictionary()
{
{"IPs", "127.0.0.1"}
})
}),
- new FeatureToggle("feature2", "release", false, new List()
+ new FeatureToggle("feature2", "release", false, false, new List()
{
new ActivationStrategy("userWithId", new Dictionary()
{
diff --git a/tests/Unleash.Tests/App_Data/impressiondata-v2.json b/tests/Unleash.Tests/App_Data/impressiondata-v2.json
new file mode 100644
index 0000000..f9cd99d
--- /dev/null
+++ b/tests/Unleash.Tests/App_Data/impressiondata-v2.json
@@ -0,0 +1,30 @@
+{
+ "version": 2,
+ "features": [
+ {
+ "name": "Tests only",
+ "description": "Where name has test in it",
+ "enabled": true,
+ "impressionData": true,
+ "strategies": [
+ {
+ "name": "default",
+ "parameters": {},
+ "segments": [ 1 ]
+ }
+ ]
+ }
+ ],
+ "segments": [
+ {
+ "id": 1,
+ "constraints": [
+ {
+ "contextName": "name",
+ "operator": "STR_CONTAINS",
+ "value": "test"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/tests/Unleash.Tests/DefaultUnleashTests.cs b/tests/Unleash.Tests/DefaultUnleashTests.cs
new file mode 100644
index 0000000..edcc393
--- /dev/null
+++ b/tests/Unleash.Tests/DefaultUnleashTests.cs
@@ -0,0 +1,31 @@
+using FluentAssertions;
+using NUnit.Framework;
+using System;
+
+namespace Unleash.Tests
+{
+ public class DefaultUnleashTests
+ {
+ [Test]
+ public void ConfigureEvents_should_invoke_callback()
+ {
+ // Arrange
+ var settings = new UnleashSettings
+ {
+ AppName = "testapp",
+ };
+
+ var unleash = new DefaultUnleash(settings);
+ var callbackCalled = false;
+
+ // Act
+ unleash.ConfigureEvents(cfg =>
+ {
+ callbackCalled = true;
+ });
+
+ // Assert
+ callbackCalled.Should().BeTrue();
+ }
+ }
+}
diff --git a/tests/Unleash.Tests/Internal/CachedFilesLoader_Bootstrap_Tests.cs b/tests/Unleash.Tests/Internal/CachedFilesLoader_Bootstrap_Tests.cs
index 698dbad..2529116 100644
--- a/tests/Unleash.Tests/Internal/CachedFilesLoader_Bootstrap_Tests.cs
+++ b/tests/Unleash.Tests/Internal/CachedFilesLoader_Bootstrap_Tests.cs
@@ -17,7 +17,7 @@ private static ToggleCollection GetTestToggles()
{
return new ToggleCollection(new List
{
- new FeatureToggle("one-enabled", "release", true, new List()
+ new FeatureToggle("one-enabled", "release", true, false, new List()
{
new ActivationStrategy("userWithId", new Dictionary(){
{"userIds", "userA" }
@@ -29,7 +29,7 @@ private static ToggleCollection GetTestToggles()
new VariantDefinition("Ab", 34, null, new List{ new VariantOverride("context", new[] { "a", "b"}) }),
}
),
- new FeatureToggle("one-disabled", "release", false, new List()
+ new FeatureToggle("one-disabled", "release", false, false, new List()
{
new ActivationStrategy("userWithId", new Dictionary()
{
diff --git a/tests/Unleash.Tests/Internal/ImpressionData_Tests.cs b/tests/Unleash.Tests/Internal/ImpressionData_Tests.cs
new file mode 100644
index 0000000..d5d3a6a
--- /dev/null
+++ b/tests/Unleash.Tests/Internal/ImpressionData_Tests.cs
@@ -0,0 +1,212 @@
+using FakeItEasy;
+using FluentAssertions;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http.Headers;
+using System.Net.Http;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+using static Unleash.Tests.Specifications.TestFactory;
+using Unleash.Tests.Mock;
+using Unleash.Internal;
+using Unleash.Scheduling;
+using System.Threading;
+using Unleash.Variants;
+
+namespace Unleash.Tests.Internal
+{
+ public class ImpressionData_Tests
+ {
+ [Test]
+ public void Impression_Event_Gets_Called_For_IsEnabled()
+ {
+ // Arrange
+ ImpressionEvent callbackEvent = null;
+ var appname = "testapp";
+ var strategy = new ActivationStrategy("default", new Dictionary(), new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "1") });
+ var toggles = new List()
+ {
+ new FeatureToggle("item", "release", true, true, new List() { strategy })
+ };
+
+
+ var state = new ToggleCollection(toggles);
+ state.Version = 2;
+ var unleash = CreateUnleash(appname, state);
+ unleash.ConfigureEvents(cfg =>
+ {
+ cfg.ImpressionEvent = evt => { callbackEvent = evt; };
+ });
+
+ // Act
+ var result = unleash.IsEnabled("item");
+ unleash.Dispose();
+
+ // Assert
+ result.Should().BeTrue();
+ callbackEvent.Should().NotBeNull();
+ callbackEvent.Enabled.Should().BeTrue();
+ callbackEvent.Variant.Should().BeNull();
+ }
+
+ [Test]
+ public void Impression_Event_Does_Not_Get_Called_When_Not_Opted_In()
+ {
+ // Arrange
+ ImpressionEvent callbackEvent = null;
+ var appname = "testapp";
+ var strategy = new ActivationStrategy("default", new Dictionary(), new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "1") });
+ var toggles = new List()
+ {
+ new FeatureToggle("item", "release", true, false, new List() { strategy })
+ };
+
+
+ var state = new ToggleCollection(toggles);
+ state.Version = 2;
+ var unleash = CreateUnleash(appname, state);
+ unleash.ConfigureEvents(cfg =>
+ {
+ cfg.ImpressionEvent = evt => { callbackEvent = evt; };
+ });
+
+ // Act
+ var result = unleash.IsEnabled("item");
+ unleash.Dispose();
+
+ // Assert
+ result.Should().BeTrue();
+ callbackEvent.Should().BeNull();
+ }
+
+ [Test]
+ public void Impression_Event_Callback_Invoker_Catches_Exception()
+ {
+ // Arrange
+ var appname = "testapp";
+ var strategy = new ActivationStrategy("default", new Dictionary(), new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "1") });
+ var toggles = new List()
+ {
+ new FeatureToggle("item", "release", true, true, new List() { strategy })
+ };
+
+
+ var state = new ToggleCollection(toggles);
+ state.Version = 2;
+ var unleash = CreateUnleash(appname, state);
+ unleash.ConfigureEvents(cfg =>
+ {
+ cfg.ImpressionEvent = evt => { throw new Exception("Something bad just happened!"); };
+ });
+
+ // Act, Assert
+ Assert.DoesNotThrow(() => { unleash.IsEnabled("item"); });
+ unleash.Dispose();
+ }
+
+ [Test]
+ public void Impression_Event_Callback_Null_Does_Not_Throw()
+ {
+ // Arrange
+ var appname = "testapp";
+ var strategy = new ActivationStrategy("default", new Dictionary(), new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "1") });
+ var toggles = new List()
+ {
+ new FeatureToggle("item", "release", true, true, new List() { strategy })
+ };
+
+
+ var state = new ToggleCollection(toggles);
+ state.Version = 2;
+ var unleash = CreateUnleash(appname, state);
+ unleash.ConfigureEvents(cfg =>
+ {
+ cfg.ImpressionEvent = null;
+ });
+
+ // Act, Assert
+ Assert.DoesNotThrow(() => { unleash.IsEnabled("item"); });
+ unleash.Dispose();
+ }
+
+ [Test]
+ public void Impression_Event_Gets_Called_For_Variants()
+ {
+ // Arrange
+ ImpressionEvent callbackEvent = null;
+ var appname = "testapp";
+ var strategy = new ActivationStrategy("default", new Dictionary(), new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "1") });
+ var payload = new Payload("string", "val1");
+ var variant = new VariantDefinition("blue", 100, payload);
+ var toggles = new List()
+ {
+ new FeatureToggle("item", "release", true, true, new List() { strategy }, new List() { variant })
+ };
+
+
+ var state = new ToggleCollection(toggles);
+ state.Version = 2;
+ var unleash = CreateUnleash(appname, state);
+ unleash.ConfigureEvents(cfg =>
+ {
+ cfg.ImpressionEvent = evt => { callbackEvent = evt; };
+ });
+
+ // Act
+ var result = unleash.GetVariant("item");
+ unleash.Dispose();
+
+ // Assert
+ result.Name.Should().Be("blue");
+ callbackEvent.Should().NotBeNull();
+ callbackEvent.Enabled.Should().BeTrue();
+ callbackEvent.Variant.Should().Be("blue");
+ }
+
+ public static IUnleash CreateUnleash(string name, ToggleCollection state)
+ {
+ var fakeHttpClientFactory = A.Fake();
+ var fakeHttpMessageHandler = new TestHttpMessageHandler();
+ var httpClient = new HttpClient(fakeHttpMessageHandler) { BaseAddress = new Uri("http://localhost") };
+ var fakeScheduler = A.Fake();
+ var fakeFileSystem = new MockFileSystem();
+ var toggleState = Newtonsoft.Json.JsonConvert.SerializeObject(state);
+
+ A.CallTo(() => fakeHttpClientFactory.Create(A._)).Returns(httpClient);
+ A.CallTo(() => fakeScheduler.Configure(A>._, A._)).Invokes(action =>
+ {
+ var task = ((IEnumerable)action.Arguments[0]).First();
+ task.ExecuteAsync((CancellationToken)action.Arguments[1]).Wait();
+ });
+
+ fakeHttpMessageHandler.Response = new HttpResponseMessage
+ {
+ StatusCode = HttpStatusCode.OK,
+ Content = new StringContent(toggleState, Encoding.UTF8, "application/json"),
+ Headers =
+ {
+ ETag = new EntityTagHeaderValue("\"123\"")
+ }
+ };
+
+ var contextBuilder = new UnleashContext.Builder();
+ contextBuilder.AddProperty("item-id", "1");
+
+ var settings = new UnleashSettings
+ {
+ AppName = name,
+ UnleashContextProvider = new DefaultUnleashContextProvider(contextBuilder.Build()),
+ HttpClientFactory = fakeHttpClientFactory,
+ ScheduledTaskManager = fakeScheduler,
+ FileSystem = fakeFileSystem
+ };
+
+ var unleash = new DefaultUnleash(settings);
+
+ return unleash;
+ }
+ }
+}
diff --git a/tests/Unleash.Tests/Mock/MockApiClient.cs b/tests/Unleash.Tests/Mock/MockApiClient.cs
index 761bddd..008fe9f 100644
--- a/tests/Unleash.Tests/Mock/MockApiClient.cs
+++ b/tests/Unleash.Tests/Mock/MockApiClient.cs
@@ -12,7 +12,7 @@ internal class MockApiClient : IUnleashApiClient
{
private static readonly ToggleCollection Toggles = new ToggleCollection(new List
{
- new FeatureToggle("one-enabled", "release", true, new List()
+ new FeatureToggle("one-enabled", "release", true, false, new List()
{
new ActivationStrategy("userWithId", new Dictionary(){
{"userIds", "userA" }
@@ -24,7 +24,7 @@ internal class MockApiClient : IUnleashApiClient
new VariantDefinition("Ab", 34, null, new List{ new VariantOverride("context", new[] { "a", "b"}) }),
}
),
- new FeatureToggle("one-disabled", "release", false, new List()
+ new FeatureToggle("one-disabled", "release", false, false, new List()
{
new ActivationStrategy("userWithId", new Dictionary()
{
diff --git a/tests/Unleash.Tests/Serialization/DynamicJsonSerializerTests.cs b/tests/Unleash.Tests/Serialization/DynamicJsonSerializerTests.cs
index aa0403d..4490b0b 100644
--- a/tests/Unleash.Tests/Serialization/DynamicJsonSerializerTests.cs
+++ b/tests/Unleash.Tests/Serialization/DynamicJsonSerializerTests.cs
@@ -7,6 +7,8 @@
using NUnit.Framework;
using Unleash.Serialization;
using Unleash.Internal;
+using System.Linq;
+using System.Collections.ObjectModel;
namespace Unleash.Tests.Serialization
{
@@ -53,13 +55,13 @@ public void Serialize_SameAsNewtonSoft(Type type)
var collection = new ToggleCollection(new List()
{
- new FeatureToggle("one", "release", true, new List()
+ new FeatureToggle("one", "release", true, false, new List()
{
new ActivationStrategy("userByName", new Dictionary(){
{"Demo", "Demo" }
})
}),
- new FeatureToggle("two", "release", false, new List()
+ new FeatureToggle("two", "release", false, false, new List()
{
new ActivationStrategy("userByName2", new Dictionary()
{
@@ -99,5 +101,40 @@ public void Serialize_SameAsNewtonSoft(Type type)
resultingJson.Should().Be(expected);
}
}
+
+ [Test]
+ public void Deserializes_ImpressionData_Property()
+ {
+ // Arrange
+ var path = Path.Combine(TestContext.CurrentContext.TestDirectory, "App_Data", "impressiondata-v2.json");
+ var originalJson = File.ReadAllText(path);
+
+ // Act
+ var deserialized = JsonConvert.DeserializeObject(originalJson);
+ var toggle = deserialized.Features.First();
+ toggle.Should().NotBeNull();
+ toggle.ImpressionData.Should().BeTrue();
+ }
+
+ [Test]
+ public void Serializes_ImpressionData_Property()
+ {
+ // Arrange
+ var strategy = new ActivationStrategy("default", new Dictionary(), new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "1") });
+ var toggles = new List()
+ {
+ new FeatureToggle("item", "release", true, true, new List() { strategy })
+ };
+
+ var state = new ToggleCollection(toggles);
+ state.Version = 2;
+
+ // Act
+ var serialized = JsonConvert.SerializeObject(toggles, new JsonSerializerSettings());
+
+ // Assert
+ var contains = serialized.IndexOf("\"ImpressionData\":true") >= 0;
+ contains.Should().BeTrue();
+ }
}
}
\ No newline at end of file
diff --git a/tests/Unleash.Tests/Strategy/Segments_Tests.cs b/tests/Unleash.Tests/Strategy/Segments_Tests.cs
index d348bad..3ac5009 100644
--- a/tests/Unleash.Tests/Strategy/Segments_Tests.cs
+++ b/tests/Unleash.Tests/Strategy/Segments_Tests.cs
@@ -27,7 +27,7 @@ public void Two_Constraints_With_Item_Id_Equals_1_And_Context_Item_Id_Equals_1_S
var segmentIds = new List() { "1", "2" };
var toggles = new List()
{
- new FeatureToggle("item", "release", true, new List() { new ActivationStrategy("default", new Dictionary(), null, segmentIds) })
+ new FeatureToggle("item", "release", true, false, new List() { new ActivationStrategy("default", new Dictionary(), null, segmentIds) })
};
var segments = segmentIds.Select(id => new Segment(id, new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "1") })).ToList();
@@ -52,7 +52,7 @@ public void Two_Constraints_One_Correct_In_Segment_One_Wrong_In_Strategy_Should_
var segmentIds = new List() { "1" };
var toggles = new List()
{
- new FeatureToggle("item", "release", true, new List() { new ActivationStrategy("default", new Dictionary(), new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "15") }, segmentIds) })
+ new FeatureToggle("item", "release", true, false, new List() { new ActivationStrategy("default", new Dictionary(), new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "15") }, segmentIds) })
};
var segments = segmentIds.Select(id => new Segment(id, new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "1") })).ToList();
@@ -77,7 +77,7 @@ public void Two_Constraints_One_In_Segment_One_In_Strategy_Both_Correct_Should_E
var segmentIds = new List() { "1" };
var toggles = new List()
{
- new FeatureToggle("item", "release", true, new List() { new ActivationStrategy("default", new Dictionary(), new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "1") }, segmentIds) })
+ new FeatureToggle("item", "release", true, false, new List() { new ActivationStrategy("default", new Dictionary(), new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "1") }, segmentIds) })
};
var segments = segmentIds.Select(id => new Segment(id, new List() { new Constraint("item-id", Operator.NUM_EQ, false, false, "1") })).ToList();
diff --git a/tests/Unleash.Tests/Unleash.Tests.csproj b/tests/Unleash.Tests/Unleash.Tests.csproj
index 93431b2..c426485 100644
--- a/tests/Unleash.Tests/Unleash.Tests.csproj
+++ b/tests/Unleash.Tests/Unleash.Tests.csproj
@@ -84,6 +84,7 @@
+
@@ -107,6 +108,7 @@
+
@@ -116,6 +118,9 @@
+
+ PreserveNewest
+
PreserveNewest
diff --git a/tests/Unleash.Tests/Variants/VariantUtilsTests.cs b/tests/Unleash.Tests/Variants/VariantUtilsTests.cs
index a86bad7..31d4035 100644
--- a/tests/Unleash.Tests/Variants/VariantUtilsTests.cs
+++ b/tests/Unleash.Tests/Variants/VariantUtilsTests.cs
@@ -16,7 +16,7 @@ public class VariantUtilsTests
public void ShouldReturnDefaultVariantWhenToggleHasNoVariants()
{
// Arrange
- var toggle = new FeatureToggle("test.variants", "release", true, new List { defaultStrategy });
+ var toggle = new FeatureToggle("test.variants", "release", true, false, new List { defaultStrategy });
var context = new UnleashContext
{
UserId = "userA",
@@ -44,6 +44,7 @@ public void ShouldReturnVariant1()
"test.variants",
"release",
true,
+ false,
new List { defaultStrategy },
new List { v1, v2, v3 });
@@ -76,6 +77,7 @@ public void ShouldReturnVariant2()
"test.variants",
"release",
true,
+ false,
new List { defaultStrategy },
new List { v1, v2, v3 });
@@ -106,6 +108,7 @@ public void ShouldReturnVariant3()
"test.variants",
"release",
true,
+ false,
new List { defaultStrategy },
new List { v1, v2, v3 });
@@ -137,6 +140,7 @@ public void ShouldReturnVariantOverride()
"test.variants",
"release",
true,
+ false,
new List { defaultStrategy },
new List { v1, v2, v3 });
@@ -168,6 +172,7 @@ public void ShouldReturnVariantOverrideOnRemoteAdress()
"test.variants",
"release",
true,
+ false,
new List { defaultStrategy },
new List { v1, v2, v3 });
@@ -201,6 +206,7 @@ public void ShouldReturnVariantOverrideOnCustomProperty()
"test.variants",
"release",
true,
+ false,
new List { defaultStrategy },
new List { v1, v2, v3 });
@@ -235,6 +241,7 @@ public void ShouldReturnVariantOverrideOnSessionId()
"test.variants",
"release",
true,
+ false,
new List { defaultStrategy },
new List { v1, v2, v3 });
@@ -268,6 +275,7 @@ public void Custom_Stickiness_CustomField_528_Yields_Blue()
"Feature.flexible.rollout.custom.stickiness_100",
"release",
true,
+ false,
new List { defaultStrategy },
new List { blue, red, green, yellow });
@@ -301,6 +309,7 @@ public void Custom_Stickiness_CustomField_16_Yields_Blue()
"Feature.flexible.rollout.custom.stickiness_100",
"release",
true,
+ false,
new List { defaultStrategy },
new List { blue, red, green, yellow });
@@ -334,6 +343,7 @@ public void Custom_Stickiness_CustomField_198_Yields_Red()
"Feature.flexible.rollout.custom.stickiness_100",
"release",
true,
+ false,
new List { defaultStrategy },
new List { blue, red, green, yellow });
@@ -367,6 +377,7 @@ public void Custom_Stickiness_CustomField_43_Yields_Green()
"Feature.flexible.rollout.custom.stickiness_100",
"release",
true,
+ false,
new List { defaultStrategy },
new List { blue, red, green, yellow });
@@ -400,6 +411,7 @@ public void Custom_Stickiness_CustomField_112_Yields_Yellow()
"Feature.flexible.rollout.custom.stickiness_100",
"release",
true,
+ false,
new List { defaultStrategy },
new List { blue, red, green, yellow });