1212using DevProxy . Plugins . Behavior ;
1313using Microsoft . Extensions . Logging ;
1414using System . Text . RegularExpressions ;
15+ using System . CommandLine . Invocation ;
16+ using System . CommandLine ;
1517
1618namespace DevProxy . Plugins . RandomErrors ;
1719internal enum GenericRandomErrorFailMode
@@ -24,12 +26,15 @@ internal enum GenericRandomErrorFailMode
2426public class GenericRandomErrorConfiguration
2527{
2628 public string ? ErrorsFile { get ; set ; }
29+ public int Rate { get ; set ; } = 50 ;
2730 public int RetryAfterInSeconds { get ; set ; } = 5 ;
2831 public IEnumerable < GenericErrorResponse > Errors { get ; set ; } = [ ] ;
2932}
3033
3134public class GenericRandomErrorPlugin ( IPluginEvents pluginEvents , IProxyContext context , ILogger logger , ISet < UrlToWatch > urlsToWatch , IConfigurationSection ? configSection = null ) : BaseProxyPlugin ( pluginEvents , context , logger , urlsToWatch , configSection )
3235{
36+ private static readonly string _rateOptionName = "--failure-rate" ;
37+
3338 private readonly GenericRandomErrorConfiguration _configuration = new ( ) ;
3439 private GenericErrorResponsesLoader ? _loader = null ;
3540
@@ -38,7 +43,7 @@ public class GenericRandomErrorPlugin(IPluginEvents pluginEvents, IProxyContext
3843 private readonly Random _random = new ( ) ;
3944
4045 // 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 ;
4247
4348 private void FailResponse ( ProxyRequestArgs e )
4449 {
@@ -192,9 +197,43 @@ public override async Task RegisterAsync()
192197 _loader = new GenericErrorResponsesLoader ( Logger , _configuration ) ;
193198
194199 PluginEvents . Init += OnInit ;
200+ PluginEvents . OptionsLoaded += OnOptionsLoaded ;
195201 PluginEvents . BeforeRequest += OnRequestAsync ;
196202 }
197203
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+
198237 private void OnInit ( object ? sender , InitArgs e )
199238 {
200239 _loader ? . InitResponsesWatcher ( ) ;
@@ -216,7 +255,7 @@ private Task OnRequestAsync(object? sender, ProxyRequestArgs e)
216255
217256 var failMode = ShouldFail ( ) ;
218257
219- if ( failMode == GenericRandomErrorFailMode . PassThru && Context . Configuration ? . Rate != 100 )
258+ if ( failMode == GenericRandomErrorFailMode . PassThru && _configuration . Rate != 100 )
220259 {
221260 Logger . LogRequest ( "Pass through" , MessageType . Skipped , new LoggingContext ( e . Session ) ) ;
222261 return Task . CompletedTask ;
0 commit comments