Skip to content

Commit

Permalink
Adds edge case for EvaluateAsync call that doesn't use context from F…
Browse files Browse the repository at this point in the history
…eatureManager (#246) (#247)

* Adds edge case for EvaluateAsync call that doesn't use context from FeatureManager
  • Loading branch information
rossgrambo authored Jun 27, 2023
1 parent 1622bca commit 3b0c61b
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<PropertyGroup>
<MajorVersion>2</MajorVersion>
<MinorVersion>6</MinorVersion>
<PatchVersion>0</PatchVersion>
<PatchVersion>1</PatchVersion>
</PropertyGroup>

<Import Project="..\..\build\Versioning.props" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ public object BindParameters(IConfiguration filterParameters)
/// <returns>True if the feature is enabled, false otherwise.</returns>
public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
{
PercentageFilterSettings settings = (PercentageFilterSettings)context.Settings;
//
// Check if prebound settings available, otherwise bind from parameters.
PercentageFilterSettings settings = (PercentageFilterSettings)context.Settings ?? (PercentageFilterSettings)BindParameters(context.Parameters);

bool result = true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ public object BindParameters(IConfiguration filterParameters)
/// <returns>True if the feature is enabled, false otherwise.</returns>
public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
{
TimeWindowFilterSettings settings = (TimeWindowFilterSettings)context.Settings;
//
// Check if prebound settings available, otherwise bind from parameters.
TimeWindowFilterSettings settings = (TimeWindowFilterSettings)context.Settings ?? (TimeWindowFilterSettings)BindParameters(context.Parameters);

DateTimeOffset now = DateTimeOffset.UtcNow;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<PropertyGroup>
<MajorVersion>2</MajorVersion>
<MinorVersion>6</MinorVersion>
<PatchVersion>0</PatchVersion>
<PatchVersion>1</PatchVersion>
</PropertyGroup>

<Import Project="..\..\build\Versioning.props" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context, ITargeti
throw new ArgumentNullException(nameof(targetingContext));
}

TargetingFilterSettings settings = (TargetingFilterSettings)context.Settings;
//
// Check if prebound settings available, otherwise bind from parameters.
TargetingFilterSettings settings = (TargetingFilterSettings)context.Settings ?? (TargetingFilterSettings)BindParameters(context.Parameters);

if (!TryValidateSettings(settings, out string paramName, out string message))
{
Expand Down
32 changes: 32 additions & 0 deletions tests/Tests.FeatureManagement/CustomTargetingFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.FeatureManagement;
using Microsoft.FeatureManagement.FeatureFilters;
using System;
using System.Threading.Tasks;

namespace Tests.FeatureManagement
{
[FilterAlias(Alias)]
class CustomTargetingFilter : IFeatureFilter
{
private const string Alias = "CustomTargetingFilter";
private readonly ContextualTargetingFilter _contextualFilter;

public CustomTargetingFilter(IOptions<TargetingEvaluationOptions> options, ILoggerFactory loggerFactory)
{
_contextualFilter = new ContextualTargetingFilter(options, loggerFactory);
}

public Func<FeatureFilterEvaluationContext, Task<bool>> Callback { get; set; }

public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
{
return _contextualFilter.EvaluateAsync(context, new TargetingContext(){ UserId = "Jeff" });
}
}
}
24 changes: 23 additions & 1 deletion tests/Tests.FeatureManagement/FeatureManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,29 @@ public async Task GatesFeatures()
Assert.Equal(HttpStatusCode.NotFound, gateAllResponse.StatusCode);
Assert.Equal(HttpStatusCode.NotFound, gateAnyResponse.StatusCode);
}


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

ServiceCollection services = new ServiceCollection();

var targetingContextAccessor = new OnDemandTargetingContextAccessor();
services.AddSingleton<ITargetingContextAccessor>(targetingContextAccessor);

services
.AddSingleton(config)
.AddFeatureManagement()
.AddFeatureFilter<CustomTargetingFilter>();

ServiceProvider provider = services.BuildServiceProvider();

IFeatureManager featureManager = provider.GetRequiredService<IFeatureManager>();

Assert.True(await featureManager.IsEnabledAsync("CustomFilterFeature"));
}

[Fact]
public async Task GatesRazorPageFeatures()
{
Expand Down
14 changes: 14 additions & 0 deletions tests/Tests.FeatureManagement/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,20 @@
}
]
},
"CustomFilterFeature": {
"EnabledFor": [
{
"Name": "CustomTargetingFilter",
"Parameters": {
"Audience": {
"Users": [
"Jeff"
]
}
}
}
]
},
"ConditionalFeature": {
"EnabledFor": [
{
Expand Down

0 comments on commit 3b0c61b

Please sign in to comment.