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
47 changes: 34 additions & 13 deletions build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,22 @@ string ToolsExePath(string exeFileName) {
return exePath;
}

string PatchStrykerConfig(string path, Action<Newtonsoft.Json.Linq.JObject> patch)
{
var json = System.IO.File.ReadAllText(path);
var config = Newtonsoft.Json.Linq.JObject.Parse(json);

patch(config.Value<Newtonsoft.Json.Linq.JObject>("stryker-config"));

// Create a new file to avoid polluting the Git tree
var tempPath = System.IO.Path.GetTempFileName();
tempPath = System.IO.Path.ChangeExtension(tempPath, "json");

System.IO.File.WriteAllText(tempPath, config.ToString());

return tempPath;
}

void RunMutationTests(FilePath target, FilePath testProject)
{
var mutationScore = XmlPeek(target, "/Project/PropertyGroup/MutationScore/text()", new XmlPeekSettings { SuppressWarning = true });
Expand All @@ -294,6 +310,12 @@ void RunMutationTests(FilePath target, FilePath testProject)
var isGitHubActions = Environment.GetEnvironmentVariable("GITHUB_ACTIONS") == "true";
var dashboardUrl = string.Empty;
var moduleName = target.GetFilenameWithoutExtension().ToString();
var strykerConfigPath = strykerConfig.FullPath;

if (moduleName == "Polly.Testing")
{
strykerConfigPath = PatchStrykerConfig(strykerConfigPath, (config) => config.Remove("ignore-mutations"));
}

if (isGitHubActions &&
!string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("STRYKER_DASHBOARD_API_KEY")))
Expand All @@ -303,28 +325,27 @@ void RunMutationTests(FilePath target, FilePath testProject)

dashboardUrl = $"https://dashboard.stryker-mutator.io/reports/{projectName}/{version}#mutant/{moduleName}";

var config = Newtonsoft.Json.Linq.JObject.Parse(System.IO.File.ReadAllText(strykerConfig.FullPath));

var reporters = config["stryker-config"].Value<Newtonsoft.Json.Linq.JArray>("reporters");
reporters.Add("dashboard");

config["stryker-config"]["reporters"] = reporters;
config["stryker-config"]["project-info"] = new Newtonsoft.Json.Linq.JObject()
strykerConfigPath = PatchStrykerConfig(strykerConfigPath, (config) =>
{
["module"] = moduleName,
["name"] = projectName,
["version"] = version
};
var reporters = config.Value<Newtonsoft.Json.Linq.JArray>("reporters");
reporters.Add("dashboard");

System.IO.File.WriteAllText(strykerConfig.FullPath, config.ToString());
config["reporters"] = reporters;
config["project-info"] = new Newtonsoft.Json.Linq.JObject()
{
["module"] = moduleName,
["name"] = projectName,
["version"] = version
};
});

Information("Configured Stryker dashboard.");
Information($"Mutation report will be available at {dashboardUrl}");
}

Information($"Running mutation tests for '{targetFileName}'. Test Project: '{testProject}'");

var args = $"stryker --project {targetFileName} --test-project {testProject.FullPath} --break-at {score} --config-file {strykerConfig} --output {strykerOutput}/{targetFileName}";
var args = $"stryker --project {targetFileName} --test-project {testProject.FullPath} --break-at {score} --config-file {strykerConfigPath} --output {strykerOutput}/{targetFileName}";

var result = StartProcess("dotnet", args);
if (result != 0)
Expand Down
7 changes: 5 additions & 2 deletions src/Polly.Testing/ResiliencePipelineExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ private static ResiliencePipelineDescriptor GetPipelineDescriptorCore<T>(Pipelin
var components = new List<PipelineComponent>();
component.ExpandComponents(components);

var descriptors = components.OfType<BridgeComponentBase>().Select(s => new ResilienceStrategyDescriptor(s.Options, GetStrategyInstance<T>(s))).ToList().AsReadOnly();
var descriptors = components
.OfType<BridgeComponentBase>()
.Select(s => new ResilienceStrategyDescriptor(s.Options, GetStrategyInstance<T>(s)))
.ToList()
.AsReadOnly();

return new ResiliencePipelineDescriptor(
descriptors,
Expand Down Expand Up @@ -73,7 +77,6 @@ private static void ExpandComponents(this PipelineComponent component, List<Pipe
}
else if (component is ExecutionTrackingComponent tracking)
{
components.Add(tracking);
ExpandComponents(tracking.Component, components);
}
else if (component is ComponentWithDisposeCallbacks callbacks)
Expand Down
56 changes: 39 additions & 17 deletions test/Polly.Testing.Tests/ResiliencePipelineExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,22 @@ namespace Polly.Testing.Tests;

public class ResiliencePipelineExtensionsTests
{
[Fact]
public void GetPipelineDescriptor_Throws_If_Pipeline_Null()
{
// Arrange
ResiliencePipeline pipeline = null!;
ResiliencePipeline<string> pipelineGeneric = null!;

// Act and Assert
Should.Throw<ArgumentNullException>(() => pipeline.GetPipelineDescriptor()).ParamName.ShouldBe("pipeline");
Should.Throw<ArgumentNullException>(() => pipelineGeneric.GetPipelineDescriptor()).ParamName.ShouldBe("pipeline");
}

[Fact]
public void GetPipelineDescriptor_Generic_Ok()
{
// arrange
// Arrange
var strategy = new ResiliencePipelineBuilder<string>()
.AddFallback(new()
{
Expand All @@ -29,10 +41,11 @@ public void GetPipelineDescriptor_Generic_Ok()
.ConfigureTelemetry(NullLoggerFactory.Instance)
.Build();

// act
// Act
var descriptor = strategy.GetPipelineDescriptor();

// assert
// Assert
descriptor.ShouldNotBeNull();
descriptor.IsReloadable.ShouldBeFalse();
descriptor.Strategies.Count.ShouldBe(7);
descriptor.FirstStrategy.Options.ShouldBeOfType<FallbackStrategyOptions<string>>();
Expand All @@ -58,7 +71,7 @@ public void GetPipelineDescriptor_Generic_Ok()
[Fact]
public void GetPipelineDescriptor_NonGeneric_Ok()
{
// arrange
// Arrange
var strategy = new ResiliencePipelineBuilder()
.AddRetry(new())
.AddCircuitBreaker(new())
Expand All @@ -68,10 +81,11 @@ public void GetPipelineDescriptor_NonGeneric_Ok()
.ConfigureTelemetry(NullLoggerFactory.Instance)
.Build();

// act
// Act
var descriptor = strategy.GetPipelineDescriptor();

// assert
// Assert
descriptor.ShouldNotBeNull();
descriptor.IsReloadable.ShouldBeFalse();
descriptor.Strategies.Count.ShouldBe(5);
descriptor.Strategies[0].Options.ShouldBeOfType<RetryStrategyOptions>();
Expand All @@ -92,15 +106,16 @@ public void GetPipelineDescriptor_NonGeneric_Ok()
[Fact]
public void GetPipelineDescriptor_SingleStrategy_Ok()
{
// arrange
// Arrange
var strategy = new ResiliencePipelineBuilder<string>()
.AddTimeout(TimeSpan.FromSeconds(1))
.Build();

// act
// Act
var descriptor = strategy.GetPipelineDescriptor();

// assert
// Assert
descriptor.ShouldNotBeNull();
descriptor.IsReloadable.ShouldBeFalse();
descriptor.Strategies.Count.ShouldBe(1);
descriptor.Strategies[0].Options.ShouldBeOfType<TimeoutStrategyOptions>();
Expand All @@ -109,10 +124,11 @@ public void GetPipelineDescriptor_SingleStrategy_Ok()
[Fact]
public async Task GetPipelineDescriptor_Reloadable_Ok()
{
// arrange
// Arrange
using var source = new CancellationTokenSource();
await using var registry = new ResiliencePipelineRegistry<string>();
var strategy = registry.GetOrAddPipeline("dummy", (builder, context) =>

var pipeline = registry.GetOrAddPipeline("first", (builder, context) =>
{
context.OnPipelineDisposed(() => { });
context.AddReloadToken(source.Token);
Expand All @@ -122,10 +138,11 @@ public async Task GetPipelineDescriptor_Reloadable_Ok()
.AddStrategy(_ => new CustomStrategy(), new TestOptions());
});

// act
var descriptor = strategy.GetPipelineDescriptor();
// Act
var descriptor = pipeline.GetPipelineDescriptor();

// assert
// Assert
descriptor.ShouldNotBeNull();
descriptor.IsReloadable.ShouldBeTrue();
descriptor.Strategies.Count.ShouldBe(2);
descriptor.Strategies[0].Options.ShouldBeOfType<RateLimiterStrategyOptions>();
Expand All @@ -135,11 +152,16 @@ public async Task GetPipelineDescriptor_Reloadable_Ok()
[Fact]
public void GetPipelineDescriptor_InnerPipeline_Ok()
{
var descriptor = new ResiliencePipelineBuilder()
// Arrange
var pipeline = new ResiliencePipelineBuilder()
.AddPipeline(new ResiliencePipelineBuilder().AddConcurrencyLimiter(1).Build())
.Build()
.GetPipelineDescriptor();
.Build();

// Act
var descriptor = pipeline.GetPipelineDescriptor();

// Assert
descriptor.ShouldNotBeNull();
descriptor.Strategies.Count.ShouldBe(1);
descriptor.Strategies[0].Options.ShouldBeOfType<RateLimiterStrategyOptions>();
}
Expand Down