Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions tests/Tests.FeatureManagement/FeatureManagementTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,13 @@ public async Task TimeWindow()
Environment.SetEnvironmentVariable("feature_management:feature_flags:6:conditions:client_filters:0:parameters:Start", DateTimeOffset.UtcNow.AddDays(-2).ToString("r"));
Environment.SetEnvironmentVariable("feature_management:feature_flags:6:conditions:client_filters:0:parameters:End", DateTimeOffset.UtcNow.AddDays(-1).ToString("r"));
Environment.SetEnvironmentVariable("feature_management:feature_flags:6:conditions:client_filters:0:parameters:Recurrence:Pattern:Type", "Weekly");
Environment.SetEnvironmentVariable("feature_management:feature_flags:6:conditions:client_filters:0:parameters:Recurrence:Pattern:DaysOfWeek:0", "Monday");
Environment.SetEnvironmentVariable("feature_management:feature_flags:6:conditions:client_filters:0:parameters:Recurrence:Pattern:DaysOfWeek:1", "Tuesday");
Environment.SetEnvironmentVariable("feature_management:feature_flags:6:conditions:client_filters:0:parameters:Recurrence:Pattern:DaysOfWeek:2", "Wednesday");
Environment.SetEnvironmentVariable("feature_management:feature_flags:6:conditions:client_filters:0:parameters:Recurrence:Pattern:DaysOfWeek:3", "Thursday");
Environment.SetEnvironmentVariable("feature_management:feature_flags:6:conditions:client_filters:0:parameters:Recurrence:Pattern:DaysOfWeek:4", "Friday");
Environment.SetEnvironmentVariable("feature_management:feature_flags:6:conditions:client_filters:0:parameters:Recurrence:Pattern:DaysOfWeek:5", "Saturday");
Environment.SetEnvironmentVariable("feature_management:feature_flags:6:conditions:client_filters:0:parameters:Recurrence:Pattern:DaysOfWeek:6", "Sunday");
Environment.SetEnvironmentVariable("feature_management:feature_flags:6:conditions:client_filters:0:parameters:Recurrence:Range:Type", "NoEnd");

foreach (DayOfWeek day in Enum.GetValues(typeof(DayOfWeek)))
Expand All @@ -874,11 +881,7 @@ public async Task TimeWindow()
Assert.False(await featureManager.IsEnabledAsync(feature4));
Assert.True(await featureManager.IsEnabledAsync(feature5));
Assert.False(await featureManager.IsEnabledAsync(feature6));

for (int i = 0; i < 10; i++)
{
Assert.True(await featureManager.IsEnabledAsync(feature7));
}
Assert.True(await featureManager.IsEnabledAsync(feature7));
}

[Fact]
Expand Down
192 changes: 134 additions & 58 deletions tests/Tests.FeatureManagement/RecurrenceEvaluation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1617,17 +1617,17 @@ public void FindWeeklyClosestStartTest()
[Fact]
public async Task RecurrenceEvaluationThroughCacheTest()
{
OnDemandClock mockedTimeProvider = new OnDemandClock();
var mockedTimeProvider = new OnDemandClock();

var mockedTimeWindowFilter = new TimeWindowFilter()
using (var cache = new TestCache())
{
Cache = new MemoryCache(new MemoryCacheOptions()),
SystemClock = mockedTimeProvider
};
var mockedTimeWindowFilter = new TimeWindowFilter()
{
Cache = cache,
SystemClock = mockedTimeProvider
};

var context = new FeatureFilterEvaluationContext()
{
Settings = new TimeWindowFilterSettings()
TimeWindowFilterSettings settings = new TimeWindowFilterSettings()
{
Start = DateTimeOffset.Parse("2024-2-1T00:00:00+08:00"), // Thursday
End = DateTimeOffset.Parse("2024-2-1T12:00:00+08:00"),
Expand All @@ -1644,43 +1644,80 @@ public async Task RecurrenceEvaluationThroughCacheTest()
EndDate = DateTimeOffset.Parse("2024-2-5T12:00:00+08:00")
}
}
}
};
};

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-2T23:00:00+08:00");
var context = new FeatureFilterEvaluationContext()
{
Settings = settings
};

Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
DateTimeOffset? closestStart;
Assert.False(cache.TryGetValue(settings, out closestStart));
Assert.Equal(0, cache.CountOfEntryCreation);

for (int i = 0; i < 12; i++)
{
mockedTimeProvider.UtcNow = mockedTimeProvider.UtcNow.AddHours(1);
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
}
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-2T23:00:00+08:00");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make these tests more readable if we switched this out for "StartTimeStamp.PlusDays(1)" or something similar. Not sure if it would lead to issues.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it easier to see the date directly, I used to open a calendar and check whether a date hits a recurrence. With"StartTimeStamp.PlusDays(1)", I need to do some extra calculation in my mind.

Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-3T00:00:00+08:00"), closestStart);
Assert.Equal(1, cache.CountOfEntryCreation);

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-3T11:59:59+08:00");
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
for (int i = 0; i < 12; i++)
{
mockedTimeProvider.UtcNow = mockedTimeProvider.UtcNow.AddHours(1);
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-3T00:00:00+08:00"), closestStart);
Assert.Equal(1, cache.CountOfEntryCreation);
}

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-3T12:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-3T11:59:59+08:00");
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-3T00:00:00+08:00"), closestStart);
Assert.Equal(1, cache.CountOfEntryCreation);

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-5T00:00:00+08:00");
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-3T12:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-5T00:00:00+08:00"), closestStart);

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-5T12:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-5T00:00:00+08:00");
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-5T00:00:00+08:00"), closestStart);
Assert.Equal(2, cache.CountOfEntryCreation);

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-7T00:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-5T12:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Null(closestStart);
Assert.Equal(3, cache.CountOfEntryCreation);

for (int i = 0; i < 10; i++)
{
mockedTimeProvider.UtcNow = mockedTimeProvider.UtcNow.AddDays(1);
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-7T00:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Null(closestStart);
Assert.Equal(3, cache.CountOfEntryCreation);

for (int i = 0; i < 10; i++)
{
mockedTimeProvider.UtcNow = mockedTimeProvider.UtcNow.AddDays(1);
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Null(closestStart);
Assert.Equal(3, cache.CountOfEntryCreation);
}
}

context = new FeatureFilterEvaluationContext()
using (var cache = new TestCache())
{
Settings = new TimeWindowFilterSettings()
var mockedTimeWindowFilter = new TimeWindowFilter()
{
Cache = cache,
SystemClock = mockedTimeProvider
};

var settings = new TimeWindowFilterSettings()
{
Start = DateTimeOffset.Parse("2024-2-1T00:00:00+08:00"), // Thursday
End = DateTimeOffset.Parse("2024-2-1T12:00:00+08:00"),
Expand All @@ -1698,43 +1735,82 @@ public async Task RecurrenceEvaluationThroughCacheTest()
NumberOfOccurrences = 2
}
}
}
};
};

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-1-31T23:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
var context = new FeatureFilterEvaluationContext()
{
Settings = settings
};

for (int i = 0; i < 12; i++)
{
mockedTimeProvider.UtcNow = mockedTimeProvider.UtcNow.AddHours(1);
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
}
DateTimeOffset? closestStart;
Assert.False(cache.TryGetValue(settings, out closestStart));
Assert.Equal(0, cache.CountOfEntryCreation);

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-1T11:59:59+08:00");
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-1-31T23:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-1T00:00:00+08:00"), closestStart);
Assert.Equal(1, cache.CountOfEntryCreation);

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-1T12:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
for (int i = 0; i < 12; i++)
{
mockedTimeProvider.UtcNow = mockedTimeProvider.UtcNow.AddHours(1);
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-1T00:00:00+08:00"), closestStart);
Assert.Equal(1, cache.CountOfEntryCreation);
}

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-2T00:00:00+08:00"); // Friday
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-1T11:59:59+08:00");
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-1T00:00:00+08:00"), closestStart);
Assert.Equal(1, cache.CountOfEntryCreation);

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-4T00:00:00+08:00"); // Sunday
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-1T12:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-4T00:00:00+08:00"), closestStart);
Assert.Equal(2, cache.CountOfEntryCreation);

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-4T06:00:00+08:00");
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-2T00:00:00+08:00"); // Friday
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-4T00:00:00+08:00"), closestStart);
Assert.Equal(2, cache.CountOfEntryCreation);

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-4T12:01:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-4T00:00:00+08:00"); // Sunday
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-4T00:00:00+08:00"), closestStart);
Assert.Equal(2, cache.CountOfEntryCreation);

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-8T00:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-4T06:00:00+08:00");
Assert.True(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Equal(DateTimeOffset.Parse("2024-2-4T00:00:00+08:00"), closestStart);
Assert.Equal(2, cache.CountOfEntryCreation);

for (int i = 0; i < 10; i++)
{
mockedTimeProvider.UtcNow = mockedTimeProvider.UtcNow.AddDays(1);
mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-4T12:01:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Null(closestStart);
Assert.Equal(3, cache.CountOfEntryCreation);

mockedTimeProvider.UtcNow = DateTimeOffset.Parse("2024-2-8T00:00:00+08:00");
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Null(closestStart);
Assert.Equal(3, cache.CountOfEntryCreation);

for (int i = 0; i < 10; i++)
{
mockedTimeProvider.UtcNow = mockedTimeProvider.UtcNow.AddDays(1);
Assert.False(await mockedTimeWindowFilter.EvaluateAsync(context));
Assert.True(cache.TryGetValue(settings, out closestStart));
Assert.Null(closestStart);
Assert.Equal(3, cache.CountOfEntryCreation);
}
}
}
}
Expand Down
45 changes: 45 additions & 0 deletions tests/Tests.FeatureManagement/TestCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
//
using Microsoft.Extensions.Caching.Memory;

namespace Tests.FeatureManagement
{
class TestCache : IMemoryCache
{
private readonly IMemoryCache _cache;
private int _countOfEntryCreation;

public TestCache()
{
_cache = new MemoryCache(new MemoryCacheOptions());
}

public int CountOfEntryCreation
{
get => _countOfEntryCreation;
}

public bool TryGetValue(object key, out object value)
{
return _cache.TryGetValue(key, out value);
}

public ICacheEntry CreateEntry(object key)
{
_countOfEntryCreation += 1;

return _cache.CreateEntry(key);
}

public void Remove(object key)
{
_cache.Remove(key);
}

public void Dispose()
{
_cache.Dispose();
}
}
}
Loading