Skip to content

Commit

Permalink
Merge pull request #45 from Polly-Contrib/v0_2
Browse files Browse the repository at this point in the history
V0.2
  • Loading branch information
vany0114 authored Jul 30, 2019
2 parents 1ec059c + 30c82ac commit 2ade7ef
Show file tree
Hide file tree
Showing 30 changed files with 2,342 additions and 348 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
## 0.2.0
- Makes InjectLatency policies cancellable (both sync and async)
- Add support for cancellation on async configuration-providing delegates

## 0.1.0
- Initial launch
- Initial launch
2 changes: 1 addition & 1 deletion GitVersionConfig.yaml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
next-version: 0.1.0
next-version: 0.2.0
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,27 +43,27 @@ Simmy offers the following chaos-injection policies:
## Inject fault
```csharp
var chaosPolicy = MonkeyPolicy.InjectFault(
Exception | Func<Context, Exception> fault,
double | Func<Context, double> injectionRate,
Func<bool> | Func<Context, bool> enabled
Exception | Func<Context, CancellationToken, Exception> fault,
double | Func<Context, CancellationToken, double> injectionRate,
Func<bool> | Func<Context, CancellationToken, bool> enabled
);
```

## Inject latency
```csharp
var chaosPolicy = MonkeyPolicy.InjectLatency(
TimeSpan | Func<Context, Timespan> latency,
double | Func<Context, double> injectionRate,
Func<bool> | Func<Context, bool> enabled
TimeSpan | Func<Context, CancellationToken, Timespan> latency,
double | Func<Context, CancellationToken, double> injectionRate,
Func<bool> | Func<Context, CancellationToken, bool> enabled
);
```

## Inject behavior
```csharp
var chaosPolicy = MonkeyPolicy.InjectBehaviour(
Action | Action<Context> behaviour,
double | Func<Context, double> injectionRate,
Func<bool> | Func<Context, bool> enabled
Action | Action<Context, CancellationToken> behaviour,
double | Func<Context, CancellationToken, double> injectionRate,
Func<bool> | Func<Context, CancellationToken, bool> enabled
);
```

Expand Down Expand Up @@ -183,4 +183,4 @@ Simmy was [the brainchild of](https://github.com/App-vNext/Polly/issues/499) [@m
### Samples
* [Dylan Reisenberger](http://www.thepollyproject.org/author/dylan/) presents an [intentionally simple example](https://github.com/Polly-Contrib/Polly.Contrib.SimmyDemo_WebApi) .NET Core WebAPI app demonstrating how we can set up Simmy chaos policies for certain environments and without changing any existing configuration code injecting faults or chaos by modifying external configuration.

* [Geovanny Alzate Sandoval](https://github.com/vany0114) made a [microservices based sample application](https://github.com/vany0114/chaos-injection-using-simmy) to demonstrate how chaos engineering works with Simmy using chaos policies in a distributed system and how we can inject even a custom behavior given our needs or infrastructure, this time injecting custom behavior to generate chaos in our Service Fabric Cluster.
* [Geovanny Alzate Sandoval](https://github.com/vany0114) made a [microservices based sample application](https://github.com/vany0114/chaos-injection-using-simmy) to demonstrate how chaos engineering works with Simmy using chaos policies in a distributed system and how we can inject even a custom behavior given our needs or infrastructure, this time injecting custom behavior to generate chaos in our Service Fabric Cluster.
242 changes: 231 additions & 11 deletions src/Polly.Contrib.Simmy.Specs/Fault/InjectFaultAsyncSpecs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void InjectFault_With_Context_Should_not_execute_user_delegate_async()
var policy = MonkeyPolicy.InjectFaultAsync(
new Exception("test"),
0.6,
async (ctx) =>
async (ctx, ct) =>
{
return await Task.FromResult((bool)ctx["ShouldFail"]);
});
Expand All @@ -89,7 +89,7 @@ public void InjectFault_With_Context_Should_execute_user_delegate_async()
var policy = MonkeyPolicy.InjectFaultAsync(
new Exception("test"),
0.4,
async (ctx) =>
async (ctx, ct) =>
{
return await Task.FromResult((bool)ctx["ShouldFail"]);
});
Expand All @@ -108,7 +108,7 @@ public void InjectFault_With_Context_Should_execute_user_delegate_async_with_ena
var policy = MonkeyPolicy.InjectFaultAsync(
new Exception("test"),
0.6,
async (ctx) =>
async (ctx, ct) =>
{
return await Task.FromResult((bool)ctx["ShouldFail"]);
});
Expand All @@ -128,8 +128,8 @@ public void InjectFault_should_throw_if_injection_rate_is_out_of_range_too_low()
Context context = new Context();

Func<Context, CancellationToken, Task<Exception>> fault = (ctx, cts) => Task.FromResult(new Exception());
Func<Context, Task<bool>> enabled = (ctx) => Task.FromResult(true);
Func<Context, Task<Double>> injectionRate = (ctx) => Task.FromResult(-0.1);
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) => Task.FromResult(true);
Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) => Task.FromResult(-0.1);
var policy = MonkeyPolicy.InjectFaultAsync(fault, injectionRate, enabled);

Func<Context, Task> actionAsync = (_) => { executed = true; return TaskHelper.EmptyTask; };
Expand All @@ -144,8 +144,8 @@ public void InjectFault_should_throw_if_injection_rate_is_out_of_range_too_high(
Context context = new Context();

Func<Context, CancellationToken, Task<Exception>> fault = (ctx, cts) => Task.FromResult(new Exception());
Func<Context, Task<bool>> enabled = (ctx) => Task.FromResult(true);
Func<Context, Task<Double>> injectionRate = (ctx) => Task.FromResult(1.01);
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) => Task.FromResult(true);
Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) => Task.FromResult(1.01);
var policy = MonkeyPolicy.InjectFaultAsync(fault, injectionRate, enabled);

Func<Context, Task> actionAsync = (_) => { executed = true; return TaskHelper.EmptyTask; };
Expand All @@ -160,8 +160,8 @@ public void InjectFault_With_Context_Should_not_execute_user_delegate_async_basi
Context context = new Context();

Func<Context, CancellationToken, Task<Exception>> fault = (ctx, cts) => Task.FromResult(new Exception());
Func<Context, Task<bool>> enabled = (ctx) => Task.FromResult(true);
Func<Context, Task<Double>> injectionRate = (ctx) => Task.FromResult(0.6);
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) => Task.FromResult(true);
Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) => Task.FromResult(0.6);
var policy = MonkeyPolicy.InjectFaultAsync(fault, injectionRate, enabled);

Func<Context, Task> actionAsync = (_) => { executed = true; return TaskHelper.EmptyTask; };
Expand Down Expand Up @@ -190,7 +190,7 @@ public void InjectFault_With_Context_Should_not_execute_user_delegate_async_with
return Task.FromResult(new Exception());
};

Func<Context, Task<Double>> injectionRate = (ctx) =>
Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) =>
{
double rate = 0;
if (ctx["InjectionRate"] != null)
Expand All @@ -201,7 +201,7 @@ public void InjectFault_With_Context_Should_not_execute_user_delegate_async_with
return Task.FromResult(rate);
};

Func<Context, Task<bool>> enabled = (ctx) =>
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) =>
{
return Task.FromResult((bool)ctx["ShouldFail"]);
};
Expand All @@ -214,5 +214,225 @@ public void InjectFault_With_Context_Should_not_execute_user_delegate_async_with
executed.Should().BeFalse();
}
#endregion

#region Cancellable scenarios

[Fact]
public void InjectFault_With_Context_Should_not_execute_user_delegate_if_user_cancelationtoken_cancelled_before_to_start_execution()
{
string failureMessage = "Failure Message";
Boolean executed = false;
Context context = new Context();
context["ShouldFail"] = true;
context["Message"] = failureMessage;
context["InjectionRate"] = 0.6;
Func<Context, CancellationToken, Task> actionAsync = (ctx, ct) =>
{
executed = true;
return TaskHelper.EmptyTask;
};

Func<Context, CancellationToken, Task<Exception>> fault = (ctx, cts) =>
{
if (ctx["Message"] != null)
{
Exception ex = new InvalidOperationException(ctx["Message"].ToString());
return Task.FromResult(ex);
}

return Task.FromResult(new Exception());
};

Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) =>
{
double rate = 0;
if (ctx["InjectionRate"] != null)
{
rate = (double)ctx["InjectionRate"];
}

return Task.FromResult(rate);
};

Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) =>
{
return Task.FromResult((bool)ctx["ShouldFail"]);
};

var policy = MonkeyPolicy.InjectFaultAsync(fault, injectionRate, enabled);
using (CancellationTokenSource cts = new CancellationTokenSource())
{
cts.Cancel();

policy.Awaiting(async x => await x.ExecuteAsync(actionAsync, context, cts.Token))
.ShouldThrow<OperationCanceledException>();
}

executed.Should().BeFalse();
}

[Fact]
public void InjectFault_With_Context_Should_not_execute_user_delegate_if_user_cancelationtoken_cancelled_on_enabled_config_delegate()
{
string failureMessage = "Failure Message";
Boolean executed = false;
Context context = new Context();
context["ShouldFail"] = true;
context["Message"] = failureMessage;
context["InjectionRate"] = 0.6;
Func<Context, CancellationToken, Task> actionAsync = (ctx, ct) =>
{
executed = true;
return TaskHelper.EmptyTask;
};

Func<Context, CancellationToken, Task<Exception>> fault = (ctx, cts) =>
{
if (ctx["Message"] != null)
{
Exception ex = new InvalidOperationException(ctx["Message"].ToString());
return Task.FromResult(ex);
}

return Task.FromResult(new Exception());
};

Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) =>
{
double rate = 0;
if (ctx["InjectionRate"] != null)
{
rate = (double)ctx["InjectionRate"];
}

return Task.FromResult(rate);
};

using (CancellationTokenSource cts = new CancellationTokenSource())
{
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) =>
{
cts.Cancel();
return Task.FromResult((bool)ctx["ShouldFail"]);
};

var policy = MonkeyPolicy.InjectFaultAsync(fault, injectionRate, enabled);

policy.Awaiting(async x => await x.ExecuteAsync(actionAsync, context, cts.Token))
.ShouldThrow<OperationCanceledException>();
}

executed.Should().BeFalse();
}

[Fact]
public void InjectFault_With_Context_Should_not_execute_user_delegate_if_user_cancelationtoken_cancelled_on_injectionrate_config_delegate()
{
string failureMessage = "Failure Message";
Boolean executed = false;
Context context = new Context();
context["ShouldFail"] = true;
context["Message"] = failureMessage;
context["InjectionRate"] = 0.6;
Func<Context, CancellationToken, Task> actionAsync = (ctx, ct) =>
{
executed = true;
return TaskHelper.EmptyTask;
};

Func<Context, CancellationToken, Task<Exception>> fault = (ctx, cts) =>
{
if (ctx["Message"] != null)
{
Exception ex = new InvalidOperationException(ctx["Message"].ToString());
return Task.FromResult(ex);
}

return Task.FromResult(new Exception());
};

using (CancellationTokenSource cts = new CancellationTokenSource())
{
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) =>
{
return Task.FromResult((bool)ctx["ShouldFail"]);
};

Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) =>
{
double rate = 0;
if (ctx["InjectionRate"] != null)
{
rate = (double)ctx["InjectionRate"];
}

cts.Cancel();
return Task.FromResult(rate);
};

var policy = MonkeyPolicy.InjectFaultAsync(fault, injectionRate, enabled);

policy.Awaiting(async x => await x.ExecuteAsync(actionAsync, context, cts.Token))
.ShouldThrow<OperationCanceledException>();
}

executed.Should().BeFalse();
}

[Fact]
public void InjectFault_With_Context_Should_not_execute_user_delegate_if_user_cancelationtoken_cancelled_on_fault_config_delegate()
{
string failureMessage = "Failure Message";
Boolean executed = false;
Context context = new Context();
context["ShouldFail"] = true;
context["Message"] = failureMessage;
context["InjectionRate"] = 0.6;
Func<Context, CancellationToken, Task> actionAsync = (ctx, ct) =>
{
executed = true;
return TaskHelper.EmptyTask;
};

using (CancellationTokenSource cts = new CancellationTokenSource())
{
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) =>
{
return Task.FromResult((bool)ctx["ShouldFail"]);
};

Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) =>
{
double rate = 0;
if (ctx["InjectionRate"] != null)
{
rate = (double)ctx["InjectionRate"];
}

return Task.FromResult(rate);
};

Func<Context, CancellationToken, Task<Exception>> fault = (ctx, ct) =>
{
cts.Cancel();
if (ctx["Message"] != null)
{
Exception ex = new InvalidOperationException(ctx["Message"].ToString());
return Task.FromResult(ex);
}

return Task.FromResult(new Exception());
};

var policy = MonkeyPolicy.InjectFaultAsync(fault, injectionRate, enabled);

policy.Awaiting(async x => await x.ExecuteAsync(actionAsync, context, cts.Token))
.ShouldThrow<OperationCanceledException>();
}

executed.Should().BeFalse();
}

#endregion
}
}
Loading

0 comments on commit 2ade7ef

Please sign in to comment.