Skip to content

Commit

Permalink
add testcases & use method name GetServiceAsync
Browse files Browse the repository at this point in the history
  • Loading branch information
zhiyuanliang-ms committed Jan 22, 2024
1 parent 18ae0eb commit f48767c
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/Microsoft.FeatureManagement/IVariantServiceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ public interface IVariantServiceProvider<TService> where TService : class
/// </summary>
/// <param name="cancellationToken">The cancellation token to cancel the operation.</param>
/// <returns>An implementation of TService.</returns>
ValueTask<TService> GetAsync(CancellationToken cancellationToken);
ValueTask<TService> GetServiceAsync(CancellationToken cancellationToken);
}
}
10 changes: 8 additions & 2 deletions src/Microsoft.FeatureManagement/VariantServiceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ internal class VariantServiceProvider<TService> : IVariantServiceProvider<TServi
private readonly IVariantFeatureManager _featureManager;
private readonly string _variantFeatureName;


/// <summary>
/// Creates a variant service provider.
/// </summary>
/// <param name="services">The provider of feature flag definitions.</param>
/// <param name="featureManager">Options controlling the behavior of the feature manager.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="services"/> is null.</exception>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="featureManager"/> is null.</exception>
public VariantServiceProvider(IEnumerable<TService> services, IVariantFeatureManager featureManager)
{
_services = services ?? throw new ArgumentNullException(nameof(services));
Expand All @@ -44,7 +50,7 @@ public string VariantFeatureName
/// </summary>
/// <param name="cancellationToken">The cancellation token to cancel the operation.</param>
/// <returns>An implementation matched with the assigned variant. If there is no matched implementation, it will return null.</returns>
public async ValueTask<TService> GetAsync(CancellationToken cancellationToken)
public async ValueTask<TService> GetServiceAsync(CancellationToken cancellationToken)
{
Debug.Assert(_variantFeatureName != null);

Expand Down
67 changes: 67 additions & 0 deletions tests/Tests.FeatureManagement/FeatureManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1262,5 +1262,72 @@ public async Task VariantsInvalidScenarios()
Assert.Equal(FeatureManagementError.InvalidConfigurationSetting, e.Error);
Assert.Contains(ConfigurationFields.PercentileAllocationFrom, e.Message);
}

[Fact]
public async Task VariantBasedInjection()
{
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();

IServiceCollection services = new ServiceCollection();

services.AddSingleton<IAlgorithm, AlgorithmBeta>();
services.AddSingleton<IAlgorithm, AlgorithmSigma>();
services.AddSingleton<IAlgorithm>(sp => new AlgorithmOmega("OMEGA"));

services.AddSingleton(configuration)
.AddFeatureManagement()
.AddFeatureFilter<TargetingFilter>()
.AddVariantServiceProvider<IAlgorithm>(Features.VariantImplementationFeature);

var targetingContextAccessor = new OnDemandTargetingContextAccessor();

services.AddSingleton<ITargetingContextAccessor>(targetingContextAccessor);

ServiceProvider serviceProvider = services.BuildServiceProvider();

IVariantFeatureManager featureManager = serviceProvider.GetRequiredService<IVariantFeatureManager>();

IVariantServiceProvider<IAlgorithm> featuredAlgorithm = serviceProvider.GetRequiredService<IVariantServiceProvider<IAlgorithm>>();

targetingContextAccessor.Current = new TargetingContext
{
UserId = "Guest"
};

IAlgorithm algorithm = await featuredAlgorithm.GetServiceAsync(CancellationToken.None);

Assert.Null(algorithm);

targetingContextAccessor.Current = new TargetingContext
{
UserId = "UserSigma"
};

algorithm = await featuredAlgorithm.GetServiceAsync(CancellationToken.None);

Assert.Null(algorithm);

targetingContextAccessor.Current = new TargetingContext
{
UserId = "UserBeta"
};

algorithm = await featuredAlgorithm.GetServiceAsync(CancellationToken.None);

Assert.NotNull(algorithm);
Assert.Equal("Beta", algorithm.Style);

targetingContextAccessor.Current = new TargetingContext
{
UserId = "UserOmega"
};

algorithm = await featuredAlgorithm.GetServiceAsync(CancellationToken.None);

Assert.NotNull(algorithm);
Assert.Equal("OMEGA", algorithm.Style);
}
}
}
1 change: 1 addition & 0 deletions tests/Tests.FeatureManagement/Features.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ static class Features
public const string VariantFeatureBothConfigurations = "VariantFeatureBothConfigurations";
public const string VariantFeatureInvalidStatusOverride = "VariantFeatureInvalidStatusOverride";
public const string VariantFeatureInvalidFromTo = "VariantFeatureInvalidFromTo";
public const string VariantImplementationFeature = "VariantImplementationFeature";
}
}
40 changes: 40 additions & 0 deletions tests/Tests.FeatureManagement/VariantServices.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Microsoft.FeatureManagement;

namespace Tests.FeatureManagement
{
interface IAlgorithm
{
public string Style { get; }
}

class AlgorithmBeta : IAlgorithm
{
public string Style { get; set; }

public AlgorithmBeta()
{
Style = "Beta";
}
}

class AlgorithmSigma : IAlgorithm
{
public string Style { get; set; }

public AlgorithmSigma()
{
Style = "Sigma";
}
}

[VariantServiceAlias("Omega")]
class AlgorithmOmega : IAlgorithm
{
public string Style { get; set; }

public AlgorithmOmega(string style)
{
Style = style;
}
}
}
48 changes: 48 additions & 0 deletions tests/Tests.FeatureManagement/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,54 @@
"Name": "On"
}
]
},
"VariantImplementationFeature": {
"EnabledFor": [
{
"Name": "Targeting",
"Parameters": {
"Audience": {
"Users": [
"UserOmega", "UserSigma", "UserBeta"
]
}
}
}
],
"Variants": [
{
"Name": "AlgorithmBeta"
},
{
"Name": "Sigma",
"ConfigurationValue": "AlgorithmSigma"
},
{
"Name": "Omega"
}
],
"Allocation": {
"User": [
{
"Variant": "AlgorithmBeta",
"Users": [
"UserBeta"
]
},
{
"Variant": "Omega",
"Users": [
"UserOmega"
]
},
{
"Variant": "Sigma",
"Users": [
"UserSigma"
]
}
]
}
}
}
}

0 comments on commit f48767c

Please sign in to comment.