Skip to content

Commit 2ade7ef

Browse files
authored
Merge pull request #45 from Polly-Contrib/v0_2
V0.2
2 parents 1ec059c + 30c82ac commit 2ade7ef

30 files changed

+2342
-348
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
1+
## 0.2.0
2+
- Makes InjectLatency policies cancellable (both sync and async)
3+
- Add support for cancellation on async configuration-providing delegates
4+
15
## 0.1.0
2-
- Initial launch
6+
- Initial launch

GitVersionConfig.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
next-version: 0.1.0
1+
next-version: 0.2.0

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,27 +43,27 @@ Simmy offers the following chaos-injection policies:
4343
## Inject fault
4444
```csharp
4545
var chaosPolicy = MonkeyPolicy.InjectFault(
46-
Exception | Func<Context, Exception> fault,
47-
double | Func<Context, double> injectionRate,
48-
Func<bool> | Func<Context, bool> enabled
46+
Exception | Func<Context, CancellationToken, Exception> fault,
47+
double | Func<Context, CancellationToken, double> injectionRate,
48+
Func<bool> | Func<Context, CancellationToken, bool> enabled
4949
);
5050
```
5151

5252
## Inject latency
5353
```csharp
5454
var chaosPolicy = MonkeyPolicy.InjectLatency(
55-
TimeSpan | Func<Context, Timespan> latency,
56-
double | Func<Context, double> injectionRate,
57-
Func<bool> | Func<Context, bool> enabled
55+
TimeSpan | Func<Context, CancellationToken, Timespan> latency,
56+
double | Func<Context, CancellationToken, double> injectionRate,
57+
Func<bool> | Func<Context, CancellationToken, bool> enabled
5858
);
5959
```
6060

6161
## Inject behavior
6262
```csharp
6363
var chaosPolicy = MonkeyPolicy.InjectBehaviour(
64-
Action | Action<Context> behaviour,
65-
double | Func<Context, double> injectionRate,
66-
Func<bool> | Func<Context, bool> enabled
64+
Action | Action<Context, CancellationToken> behaviour,
65+
double | Func<Context, CancellationToken, double> injectionRate,
66+
Func<bool> | Func<Context, CancellationToken, bool> enabled
6767
);
6868
```
6969

@@ -183,4 +183,4 @@ Simmy was [the brainchild of](https://github.com/App-vNext/Polly/issues/499) [@m
183183
### Samples
184184
* [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.
185185

186-
* [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.
186+
* [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.

src/Polly.Contrib.Simmy.Specs/Fault/InjectFaultAsyncSpecs.cs

Lines changed: 231 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public void InjectFault_With_Context_Should_not_execute_user_delegate_async()
6969
var policy = MonkeyPolicy.InjectFaultAsync(
7070
new Exception("test"),
7171
0.6,
72-
async (ctx) =>
72+
async (ctx, ct) =>
7373
{
7474
return await Task.FromResult((bool)ctx["ShouldFail"]);
7575
});
@@ -89,7 +89,7 @@ public void InjectFault_With_Context_Should_execute_user_delegate_async()
8989
var policy = MonkeyPolicy.InjectFaultAsync(
9090
new Exception("test"),
9191
0.4,
92-
async (ctx) =>
92+
async (ctx, ct) =>
9393
{
9494
return await Task.FromResult((bool)ctx["ShouldFail"]);
9595
});
@@ -108,7 +108,7 @@ public void InjectFault_With_Context_Should_execute_user_delegate_async_with_ena
108108
var policy = MonkeyPolicy.InjectFaultAsync(
109109
new Exception("test"),
110110
0.6,
111-
async (ctx) =>
111+
async (ctx, ct) =>
112112
{
113113
return await Task.FromResult((bool)ctx["ShouldFail"]);
114114
});
@@ -128,8 +128,8 @@ public void InjectFault_should_throw_if_injection_rate_is_out_of_range_too_low()
128128
Context context = new Context();
129129

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

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

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

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

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

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

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

204-
Func<Context, Task<bool>> enabled = (ctx) =>
204+
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) =>
205205
{
206206
return Task.FromResult((bool)ctx["ShouldFail"]);
207207
};
@@ -214,5 +214,225 @@ public void InjectFault_With_Context_Should_not_execute_user_delegate_async_with
214214
executed.Should().BeFalse();
215215
}
216216
#endregion
217+
218+
#region Cancellable scenarios
219+
220+
[Fact]
221+
public void InjectFault_With_Context_Should_not_execute_user_delegate_if_user_cancelationtoken_cancelled_before_to_start_execution()
222+
{
223+
string failureMessage = "Failure Message";
224+
Boolean executed = false;
225+
Context context = new Context();
226+
context["ShouldFail"] = true;
227+
context["Message"] = failureMessage;
228+
context["InjectionRate"] = 0.6;
229+
Func<Context, CancellationToken, Task> actionAsync = (ctx, ct) =>
230+
{
231+
executed = true;
232+
return TaskHelper.EmptyTask;
233+
};
234+
235+
Func<Context, CancellationToken, Task<Exception>> fault = (ctx, cts) =>
236+
{
237+
if (ctx["Message"] != null)
238+
{
239+
Exception ex = new InvalidOperationException(ctx["Message"].ToString());
240+
return Task.FromResult(ex);
241+
}
242+
243+
return Task.FromResult(new Exception());
244+
};
245+
246+
Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) =>
247+
{
248+
double rate = 0;
249+
if (ctx["InjectionRate"] != null)
250+
{
251+
rate = (double)ctx["InjectionRate"];
252+
}
253+
254+
return Task.FromResult(rate);
255+
};
256+
257+
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) =>
258+
{
259+
return Task.FromResult((bool)ctx["ShouldFail"]);
260+
};
261+
262+
var policy = MonkeyPolicy.InjectFaultAsync(fault, injectionRate, enabled);
263+
using (CancellationTokenSource cts = new CancellationTokenSource())
264+
{
265+
cts.Cancel();
266+
267+
policy.Awaiting(async x => await x.ExecuteAsync(actionAsync, context, cts.Token))
268+
.ShouldThrow<OperationCanceledException>();
269+
}
270+
271+
executed.Should().BeFalse();
272+
}
273+
274+
[Fact]
275+
public void InjectFault_With_Context_Should_not_execute_user_delegate_if_user_cancelationtoken_cancelled_on_enabled_config_delegate()
276+
{
277+
string failureMessage = "Failure Message";
278+
Boolean executed = false;
279+
Context context = new Context();
280+
context["ShouldFail"] = true;
281+
context["Message"] = failureMessage;
282+
context["InjectionRate"] = 0.6;
283+
Func<Context, CancellationToken, Task> actionAsync = (ctx, ct) =>
284+
{
285+
executed = true;
286+
return TaskHelper.EmptyTask;
287+
};
288+
289+
Func<Context, CancellationToken, Task<Exception>> fault = (ctx, cts) =>
290+
{
291+
if (ctx["Message"] != null)
292+
{
293+
Exception ex = new InvalidOperationException(ctx["Message"].ToString());
294+
return Task.FromResult(ex);
295+
}
296+
297+
return Task.FromResult(new Exception());
298+
};
299+
300+
Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) =>
301+
{
302+
double rate = 0;
303+
if (ctx["InjectionRate"] != null)
304+
{
305+
rate = (double)ctx["InjectionRate"];
306+
}
307+
308+
return Task.FromResult(rate);
309+
};
310+
311+
using (CancellationTokenSource cts = new CancellationTokenSource())
312+
{
313+
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) =>
314+
{
315+
cts.Cancel();
316+
return Task.FromResult((bool)ctx["ShouldFail"]);
317+
};
318+
319+
var policy = MonkeyPolicy.InjectFaultAsync(fault, injectionRate, enabled);
320+
321+
policy.Awaiting(async x => await x.ExecuteAsync(actionAsync, context, cts.Token))
322+
.ShouldThrow<OperationCanceledException>();
323+
}
324+
325+
executed.Should().BeFalse();
326+
}
327+
328+
[Fact]
329+
public void InjectFault_With_Context_Should_not_execute_user_delegate_if_user_cancelationtoken_cancelled_on_injectionrate_config_delegate()
330+
{
331+
string failureMessage = "Failure Message";
332+
Boolean executed = false;
333+
Context context = new Context();
334+
context["ShouldFail"] = true;
335+
context["Message"] = failureMessage;
336+
context["InjectionRate"] = 0.6;
337+
Func<Context, CancellationToken, Task> actionAsync = (ctx, ct) =>
338+
{
339+
executed = true;
340+
return TaskHelper.EmptyTask;
341+
};
342+
343+
Func<Context, CancellationToken, Task<Exception>> fault = (ctx, cts) =>
344+
{
345+
if (ctx["Message"] != null)
346+
{
347+
Exception ex = new InvalidOperationException(ctx["Message"].ToString());
348+
return Task.FromResult(ex);
349+
}
350+
351+
return Task.FromResult(new Exception());
352+
};
353+
354+
using (CancellationTokenSource cts = new CancellationTokenSource())
355+
{
356+
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) =>
357+
{
358+
return Task.FromResult((bool)ctx["ShouldFail"]);
359+
};
360+
361+
Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) =>
362+
{
363+
double rate = 0;
364+
if (ctx["InjectionRate"] != null)
365+
{
366+
rate = (double)ctx["InjectionRate"];
367+
}
368+
369+
cts.Cancel();
370+
return Task.FromResult(rate);
371+
};
372+
373+
var policy = MonkeyPolicy.InjectFaultAsync(fault, injectionRate, enabled);
374+
375+
policy.Awaiting(async x => await x.ExecuteAsync(actionAsync, context, cts.Token))
376+
.ShouldThrow<OperationCanceledException>();
377+
}
378+
379+
executed.Should().BeFalse();
380+
}
381+
382+
[Fact]
383+
public void InjectFault_With_Context_Should_not_execute_user_delegate_if_user_cancelationtoken_cancelled_on_fault_config_delegate()
384+
{
385+
string failureMessage = "Failure Message";
386+
Boolean executed = false;
387+
Context context = new Context();
388+
context["ShouldFail"] = true;
389+
context["Message"] = failureMessage;
390+
context["InjectionRate"] = 0.6;
391+
Func<Context, CancellationToken, Task> actionAsync = (ctx, ct) =>
392+
{
393+
executed = true;
394+
return TaskHelper.EmptyTask;
395+
};
396+
397+
using (CancellationTokenSource cts = new CancellationTokenSource())
398+
{
399+
Func<Context, CancellationToken, Task<bool>> enabled = (ctx, ct) =>
400+
{
401+
return Task.FromResult((bool)ctx["ShouldFail"]);
402+
};
403+
404+
Func<Context, CancellationToken, Task<Double>> injectionRate = (ctx, ct) =>
405+
{
406+
double rate = 0;
407+
if (ctx["InjectionRate"] != null)
408+
{
409+
rate = (double)ctx["InjectionRate"];
410+
}
411+
412+
return Task.FromResult(rate);
413+
};
414+
415+
Func<Context, CancellationToken, Task<Exception>> fault = (ctx, ct) =>
416+
{
417+
cts.Cancel();
418+
if (ctx["Message"] != null)
419+
{
420+
Exception ex = new InvalidOperationException(ctx["Message"].ToString());
421+
return Task.FromResult(ex);
422+
}
423+
424+
return Task.FromResult(new Exception());
425+
};
426+
427+
var policy = MonkeyPolicy.InjectFaultAsync(fault, injectionRate, enabled);
428+
429+
policy.Awaiting(async x => await x.ExecuteAsync(actionAsync, context, cts.Token))
430+
.ShouldThrow<OperationCanceledException>();
431+
}
432+
433+
executed.Should().BeFalse();
434+
}
435+
436+
#endregion
217437
}
218438
}

0 commit comments

Comments
 (0)