Skip to content

Commit 3ea4868

Browse files
authored
New Syntax (#49)
* new syntax initial commit. * Implements IDisposable on unit tests * Possible method-chaining fluent syntax for monkey policy options * implements the new syntax for behavior monkeys * implements new syntax for InjectFault monkey. * implements new syntax for latency monkey. * PR feedback * updates readme just to force the build * Move Options into <PolicyType> namespaces * Rename some internal properties XInternal * Change Fault to Outcome in class and file names
1 parent d51aa4c commit 3ea4868

File tree

67 files changed

+6757
-30
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+6757
-30
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,4 @@ Simmy was [the brainchild of](https://github.com/App-vNext/Polly/issues/499) [@m
187187
* [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.
188188

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

src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourAsyncSpecs.cs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace Polly.Contrib.Simmy.Specs.Behavior
88
{
99
[Collection(Helpers.Constants.AmbientContextDependentTestCollection)]
10+
[Obsolete]
1011
public class InjectBehaviourAsyncSpecs : IDisposable
1112
{
1213
public InjectBehaviourAsyncSpecs()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
using FluentAssertions;
2+
using Polly.Contrib.Simmy.Utilities;
3+
using System;
4+
using System.Threading.Tasks;
5+
using Polly.Contrib.Simmy.Behavior;
6+
using Xunit;
7+
8+
namespace Polly.Contrib.Simmy.Specs.Behavior
9+
{
10+
[Collection(Helpers.Constants.AmbientContextDependentTestCollection)]
11+
public class InjectBehaviourAsyncWithOptionsSpecs : IDisposable
12+
{
13+
public InjectBehaviourAsyncWithOptionsSpecs()
14+
{
15+
ThreadSafeRandom_LockOncePerThread.NextDouble = () => 0.5;
16+
}
17+
18+
public void Dispose()
19+
{
20+
ThreadSafeRandom_LockOncePerThread.Reset();
21+
}
22+
23+
[Fact]
24+
public void Given_not_enabled_should_not_inject_behaviour()
25+
{
26+
Boolean userDelegateExecuted = false;
27+
Boolean injectedBehaviourExecuted = false;
28+
29+
var policy = MonkeyPolicy.InjectBehaviourAsync(with =>
30+
with.Behaviour(() =>
31+
{
32+
injectedBehaviourExecuted = true;
33+
return Task.CompletedTask;
34+
})
35+
.InjectionRate(0.6)
36+
.Enabled(false)
37+
);
38+
39+
policy.ExecuteAsync(() => { userDelegateExecuted = true; return Task.CompletedTask; });
40+
41+
userDelegateExecuted.Should().BeTrue();
42+
injectedBehaviourExecuted.Should().BeFalse();
43+
}
44+
45+
[Fact]
46+
public void Given_enabled_and_randomly_within_threshold_should_inject_behaviour()
47+
{
48+
Boolean userDelegateExecuted = false;
49+
Boolean injectedBehaviourExecuted = false;
50+
51+
var policy = MonkeyPolicy.InjectBehaviourAsync(with =>
52+
with.Behaviour(() =>
53+
{
54+
injectedBehaviourExecuted = true;
55+
return Task.CompletedTask;
56+
})
57+
.InjectionRate(0.6)
58+
.Enabled()
59+
);
60+
61+
policy.ExecuteAsync(() => { userDelegateExecuted = true; return Task.CompletedTask; });
62+
63+
userDelegateExecuted.Should().BeTrue();
64+
injectedBehaviourExecuted.Should().BeTrue();
65+
}
66+
67+
[Fact]
68+
public void Given_enabled_and_randomly_not_within_threshold_should_not_inject_behaviour()
69+
{
70+
Boolean userDelegateExecuted = false;
71+
Boolean injectedBehaviourExecuted = false;
72+
73+
var policy = MonkeyPolicy.InjectBehaviourAsync(with =>
74+
with.Behaviour(() =>
75+
{
76+
injectedBehaviourExecuted = true;
77+
return Task.CompletedTask;
78+
})
79+
.InjectionRate(0.4)
80+
.Enabled(false)
81+
);
82+
83+
policy.ExecuteAsync(() => { userDelegateExecuted = true; return Task.CompletedTask; });
84+
85+
userDelegateExecuted.Should().BeTrue();
86+
injectedBehaviourExecuted.Should().BeFalse();
87+
}
88+
89+
[Fact]
90+
public void Should_inject_behaviour_before_executing_user_delegate()
91+
{
92+
Boolean userDelegateExecuted = false;
93+
Boolean injectedBehaviourExecuted = false;
94+
95+
var policy = MonkeyPolicy.InjectBehaviourAsync(with =>
96+
with.Behaviour(() =>
97+
{
98+
userDelegateExecuted.Should().BeFalse(); // Not yet executed at the time the injected behaviour runs.
99+
injectedBehaviourExecuted = true;
100+
return Task.CompletedTask;
101+
})
102+
.InjectionRate(0.6)
103+
.Enabled()
104+
);
105+
106+
policy.ExecuteAsync(() => { userDelegateExecuted = true; return Task.CompletedTask; });
107+
108+
userDelegateExecuted.Should().BeTrue();
109+
injectedBehaviourExecuted.Should().BeTrue();
110+
}
111+
112+
#region invalid threshold on configuration and execution time
113+
114+
[Fact]
115+
public void Should_throw_error_on_configuration_time_when_threshold_is_negative()
116+
{
117+
Action act = () => MonkeyPolicy.InjectBehaviourAsync(with =>
118+
with.Behaviour(() => Task.CompletedTask)
119+
.Enabled()
120+
.InjectionRate(-1)
121+
);
122+
123+
act.ShouldThrow<ArgumentOutOfRangeException>()
124+
.WithMessage("Injection rate/threshold in Monkey policies should always be a double between [0, 1]; never a negative number.\r\nParameter name: injectionThreshold");
125+
}
126+
127+
[Fact]
128+
public void Should_throw_error_on_configuration_time_when_threshold_is_greater_than_one()
129+
{
130+
Action act = () => MonkeyPolicy.InjectBehaviourAsync(with =>
131+
with.Behaviour(() => Task.CompletedTask)
132+
.Enabled()
133+
.InjectionRate(1.1)
134+
);
135+
136+
act.ShouldThrow<ArgumentOutOfRangeException>()
137+
.WithMessage("Injection rate/threshold in Monkey policies should always be a double between [0, 1]; never a number greater than 1.\r\nParameter name: injectionThreshold");
138+
}
139+
140+
[Fact]
141+
public void Should_throw_error_on_execution_time_when_threshold_is_is_negative()
142+
{
143+
var policy = MonkeyPolicy.InjectBehaviourAsync(with =>
144+
with.Behaviour(() => Task.CompletedTask)
145+
.Enabled()
146+
.InjectionRate((_, __) => Task.FromResult(-1d))
147+
);
148+
149+
policy.Awaiting(async x => await x.ExecuteAsync(() => Task.CompletedTask))
150+
.ShouldThrow<ArgumentOutOfRangeException>()
151+
.WithMessage("Injection rate/threshold in Monkey policies should always be a double between [0, 1]; never a negative number.\r\nParameter name: injectionThreshold");
152+
}
153+
154+
[Fact]
155+
public void Should_throw_error_on_execution_time_when_threshold_is_greater_than_one()
156+
{
157+
var policy = MonkeyPolicy.InjectBehaviourAsync(with =>
158+
with.Behaviour(() => Task.CompletedTask)
159+
.Enabled()
160+
.InjectionRate((_, __) => Task.FromResult(1.1))
161+
);
162+
163+
policy.Awaiting(async x => await x.ExecuteAsync(() => Task.CompletedTask))
164+
.ShouldThrow<ArgumentOutOfRangeException>()
165+
.WithMessage("Injection rate/threshold in Monkey policies should always be a double between [0, 1]; never a number greater than 1.\r\nParameter name: injectionThreshold");
166+
}
167+
168+
#endregion
169+
}
170+
}

src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourSpecs.cs

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Polly.Contrib.Simmy.Specs.Behavior
77
{
88
[Collection(Helpers.Constants.AmbientContextDependentTestCollection)]
9+
[Obsolete]
910
public class InjectBehaviourSpecs : IDisposable
1011
{
1112
public InjectBehaviourSpecs()

src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourTResultAsyncSpecs.cs

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Polly.Contrib.Simmy.Specs.Behavior
99
{
1010
[Collection(Constants.AmbientContextDependentTestCollection)]
11+
[Obsolete]
1112
public class InjectBehaviourTResultAsyncSpecs : IDisposable
1213
{
1314
public InjectBehaviourTResultAsyncSpecs()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Polly.Contrib.Simmy.Behavior;
4+
using Polly.Contrib.Simmy.Specs.Helpers;
5+
using Polly.Contrib.Simmy.Utilities;
6+
using Xunit;
7+
using FluentAssertions;
8+
9+
namespace Polly.Contrib.Simmy.Specs.Behavior
10+
{
11+
[Collection(Helpers.Constants.AmbientContextDependentTestCollection)]
12+
public class InjectBehaviourTResultAsyncWithOptionsSpecs : IDisposable
13+
{
14+
public InjectBehaviourTResultAsyncWithOptionsSpecs()
15+
{
16+
ThreadSafeRandom_LockOncePerThread.NextDouble = () => 0.5;
17+
}
18+
19+
public void Dispose()
20+
{
21+
ThreadSafeRandom_LockOncePerThread.Reset();
22+
}
23+
24+
[Fact]
25+
public void Given_not_enabled_should_not_inject_behaviour()
26+
{
27+
Boolean userDelegateExecuted = false;
28+
Boolean injectedBehaviourExecuted = false;
29+
30+
var policy = MonkeyPolicy.InjectBehaviourAsync<ResultPrimitive>(with =>
31+
with.Behaviour(() =>
32+
{
33+
injectedBehaviourExecuted = true;
34+
return Task.CompletedTask;
35+
})
36+
.InjectionRate(0.6)
37+
.Enabled(false)
38+
);
39+
40+
policy.ExecuteAsync(() => { userDelegateExecuted = true; return Task.FromResult(ResultPrimitive.Good); });
41+
42+
userDelegateExecuted.Should().BeTrue();
43+
injectedBehaviourExecuted.Should().BeFalse();
44+
}
45+
46+
[Fact]
47+
public void Given_enabled_and_randomly_within_threshold_should_inject_behaviour()
48+
{
49+
Boolean userDelegateExecuted = false;
50+
Boolean injectedBehaviourExecuted = false;
51+
52+
var policy = MonkeyPolicy.InjectBehaviourAsync<ResultPrimitive>(with =>
53+
with.Behaviour(() =>
54+
{
55+
injectedBehaviourExecuted = true;
56+
return Task.CompletedTask;
57+
})
58+
.InjectionRate(0.6)
59+
.Enabled()
60+
);
61+
62+
policy.ExecuteAsync(() => { userDelegateExecuted = true; return Task.FromResult(ResultPrimitive.Good); });
63+
64+
userDelegateExecuted.Should().BeTrue();
65+
injectedBehaviourExecuted.Should().BeTrue();
66+
}
67+
68+
[Fact]
69+
public void Given_enabled_and_randomly_not_within_threshold_should_not_inject_behaviour()
70+
{
71+
Boolean userDelegateExecuted = false;
72+
Boolean injectedBehaviourExecuted = false;
73+
74+
var policy = MonkeyPolicy.InjectBehaviourAsync<ResultPrimitive>(with =>
75+
with.Behaviour(() =>
76+
{
77+
injectedBehaviourExecuted = true;
78+
return Task.CompletedTask;
79+
})
80+
.InjectionRate(0.4)
81+
.Enabled(false)
82+
);
83+
84+
policy.ExecuteAsync(() => { userDelegateExecuted = true; return Task.FromResult(ResultPrimitive.Good); });
85+
86+
userDelegateExecuted.Should().BeTrue();
87+
injectedBehaviourExecuted.Should().BeFalse();
88+
}
89+
90+
[Fact]
91+
public void Should_inject_behaviour_before_executing_user_delegate()
92+
{
93+
Boolean userDelegateExecuted = false;
94+
Boolean injectedBehaviourExecuted = false;
95+
96+
var policy = MonkeyPolicy.InjectBehaviourAsync<ResultPrimitive>(with =>
97+
with.Behaviour(() =>
98+
{
99+
userDelegateExecuted.Should().BeFalse(); // Not yet executed at the time the injected behaviour runs.
100+
injectedBehaviourExecuted = true;
101+
return Task.CompletedTask;
102+
})
103+
.InjectionRate(0.6)
104+
.Enabled()
105+
);
106+
107+
policy.ExecuteAsync(() => { userDelegateExecuted = true; return Task.FromResult(ResultPrimitive.Good); });
108+
109+
userDelegateExecuted.Should().BeTrue();
110+
injectedBehaviourExecuted.Should().BeTrue();
111+
}
112+
113+
#region invalid threshold on configuration and execution time
114+
115+
[Fact]
116+
public void Should_throw_error_on_configuration_time_when_threshold_is_negative()
117+
{
118+
Action act = () => MonkeyPolicy.InjectBehaviourAsync<ResultPrimitive>(with =>
119+
with.Behaviour(() => Task.CompletedTask)
120+
.Enabled()
121+
.InjectionRate(-1)
122+
);
123+
124+
act.ShouldThrow<ArgumentOutOfRangeException>()
125+
.WithMessage("Injection rate/threshold in Monkey policies should always be a double between [0, 1]; never a negative number.\r\nParameter name: injectionThreshold");
126+
}
127+
128+
[Fact]
129+
public void Should_throw_error_on_configuration_time_when_threshold_is_greater_than_one()
130+
{
131+
Action act = () => MonkeyPolicy.InjectBehaviourAsync<ResultPrimitive>(with =>
132+
with.Behaviour(() => Task.CompletedTask)
133+
.Enabled()
134+
.InjectionRate(1.1)
135+
);
136+
137+
act.ShouldThrow<ArgumentOutOfRangeException>()
138+
.WithMessage("Injection rate/threshold in Monkey policies should always be a double between [0, 1]; never a number greater than 1.\r\nParameter name: injectionThreshold");
139+
}
140+
141+
[Fact]
142+
public void Should_throw_error_on_execution_time_when_threshold_is_is_negative()
143+
{
144+
var policy = MonkeyPolicy.InjectBehaviourAsync<ResultPrimitive>(with =>
145+
with.Behaviour(() => Task.CompletedTask)
146+
.Enabled()
147+
.InjectionRate((_, __) => Task.FromResult(-1d))
148+
);
149+
150+
policy.Awaiting(async x => await x.ExecuteAsync(() => Task.FromResult(ResultPrimitive.Good)))
151+
.ShouldThrow<ArgumentOutOfRangeException>()
152+
.WithMessage("Injection rate/threshold in Monkey policies should always be a double between [0, 1]; never a negative number.\r\nParameter name: injectionThreshold");
153+
}
154+
155+
[Fact]
156+
public void Should_throw_error_on_execution_time_when_threshold_is_greater_than_one()
157+
{
158+
var policy = MonkeyPolicy.InjectBehaviourAsync<ResultPrimitive>(with =>
159+
with.Behaviour(() => Task.CompletedTask)
160+
.Enabled()
161+
.InjectionRate((_, __) => Task.FromResult(1.1))
162+
);
163+
164+
policy.Awaiting(async x => await x.ExecuteAsync(() => Task.FromResult(ResultPrimitive.Good)))
165+
.ShouldThrow<ArgumentOutOfRangeException>()
166+
.WithMessage("Injection rate/threshold in Monkey policies should always be a double between [0, 1]; never a number greater than 1.\r\nParameter name: injectionThreshold");
167+
}
168+
169+
#endregion
170+
}
171+
}

src/Polly.Contrib.Simmy.Specs/Behavior/InjectBehaviourTResultSpecs.cs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
namespace Polly.Contrib.Simmy.Specs.Behavior
88
{
99
[Collection(Constants.AmbientContextDependentTestCollection)]
10+
[Obsolete]
1011
public class InjectBehaviourTResultSpecs : IDisposable
1112
{
1213
public InjectBehaviourTResultSpecs()

0 commit comments

Comments
 (0)