12
12
using DevProxy . Plugins . Behavior ;
13
13
using Microsoft . Extensions . Logging ;
14
14
using System . Text . RegularExpressions ;
15
+ using System . CommandLine . Invocation ;
16
+ using System . CommandLine ;
15
17
16
18
namespace DevProxy . Plugins . RandomErrors ;
17
19
internal enum GenericRandomErrorFailMode
@@ -24,12 +26,15 @@ internal enum GenericRandomErrorFailMode
24
26
public class GenericRandomErrorConfiguration
25
27
{
26
28
public string ? ErrorsFile { get ; set ; }
29
+ public int Rate { get ; set ; } = 50 ;
27
30
public int RetryAfterInSeconds { get ; set ; } = 5 ;
28
31
public IEnumerable < GenericErrorResponse > Errors { get ; set ; } = [ ] ;
29
32
}
30
33
31
34
public class GenericRandomErrorPlugin ( IPluginEvents pluginEvents , IProxyContext context , ILogger logger , ISet < UrlToWatch > urlsToWatch , IConfigurationSection ? configSection = null ) : BaseProxyPlugin ( pluginEvents , context , logger , urlsToWatch , configSection )
32
35
{
36
+ private static readonly string _rateOptionName = "--failure-rate" ;
37
+
33
38
private readonly GenericRandomErrorConfiguration _configuration = new ( ) ;
34
39
private GenericErrorResponsesLoader ? _loader = null ;
35
40
@@ -38,7 +43,7 @@ public class GenericRandomErrorPlugin(IPluginEvents pluginEvents, IProxyContext
38
43
private readonly Random _random = new ( ) ;
39
44
40
45
// uses config to determine if a request should be failed
41
- private GenericRandomErrorFailMode ShouldFail ( ) => _random . Next ( 1 , 100 ) <= Context . Configuration . Rate ? GenericRandomErrorFailMode . Random : GenericRandomErrorFailMode . PassThru ;
46
+ private GenericRandomErrorFailMode ShouldFail ( ) => _random . Next ( 1 , 100 ) <= _configuration . Rate ? GenericRandomErrorFailMode . Random : GenericRandomErrorFailMode . PassThru ;
42
47
43
48
private void FailResponse ( ProxyRequestArgs e )
44
49
{
@@ -192,9 +197,43 @@ public override async Task RegisterAsync()
192
197
_loader = new GenericErrorResponsesLoader ( Logger , _configuration ) ;
193
198
194
199
PluginEvents . Init += OnInit ;
200
+ PluginEvents . OptionsLoaded += OnOptionsLoaded ;
195
201
PluginEvents . BeforeRequest += OnRequestAsync ;
196
202
}
197
203
204
+ public override Option [ ] GetOptions ( )
205
+ {
206
+ var _rateOption = new Option < int ? > ( _rateOptionName , "The percentage of chance that a request will fail" ) ;
207
+ _rateOption . AddAlias ( "-f" ) ;
208
+ _rateOption . ArgumentHelpName = "failure rate" ;
209
+ _rateOption . AddValidator ( ( input ) =>
210
+ {
211
+ try
212
+ {
213
+ int ? value = input . GetValueForOption ( _rateOption ) ;
214
+ if ( value . HasValue && ( value < 0 || value > 100 ) )
215
+ {
216
+ input . ErrorMessage = $ "{ value } is not a valid failure rate. Specify a number between 0 and 100";
217
+ }
218
+ }
219
+ catch ( InvalidOperationException ex )
220
+ {
221
+ input . ErrorMessage = ex . Message ;
222
+ }
223
+ } ) ;
224
+
225
+ return [ _rateOption ] ;
226
+ }
227
+
228
+ private void OnOptionsLoaded ( object ? sender , OptionsLoadedArgs e )
229
+ {
230
+ InvocationContext context = e . Context ;
231
+
232
+ var rate = context . ParseResult . GetValueForOption < int ? > ( _rateOptionName , e . Options ) ;
233
+ if ( rate is not null )
234
+ _configuration . Rate = rate . Value ;
235
+ }
236
+
198
237
private void OnInit ( object ? sender , InitArgs e )
199
238
{
200
239
_loader ? . InitResponsesWatcher ( ) ;
@@ -216,7 +255,7 @@ private Task OnRequestAsync(object? sender, ProxyRequestArgs e)
216
255
217
256
var failMode = ShouldFail ( ) ;
218
257
219
- if ( failMode == GenericRandomErrorFailMode . PassThru && Context . Configuration ? . Rate != 100 )
258
+ if ( failMode == GenericRandomErrorFailMode . PassThru && _configuration . Rate != 100 )
220
259
{
221
260
Logger . LogRequest ( "Pass through" , MessageType . Skipped , new LoggingContext ( e . Session ) ) ;
222
261
return Task . CompletedTask ;
0 commit comments