Skip to content

Commit 2eccb17

Browse files
Centralizes --failure-rate option. Closes #194 (#245)
1 parent 948c7d3 commit 2eccb17

File tree

11 files changed

+81
-42
lines changed

11 files changed

+81
-42
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
using System.Runtime.Serialization;
5+
6+
namespace Microsoft.Graph.DeveloperProxy.Abstractions;
7+
8+
public enum LabelMode {
9+
[EnumMember(Value = "text")]
10+
Text,
11+
[EnumMember(Value = "icon")]
12+
Icon,
13+
[EnumMember(Value = "nerdFont")]
14+
NerdFont
15+
}
16+
17+
public interface IProxyConfiguration {
18+
int Port { get; }
19+
LabelMode LabelMode { get; }
20+
bool Record { get; }
21+
LogLevel LogLevel { get; }
22+
IEnumerable<int> WatchPids { get; }
23+
IEnumerable<string> WatchProcessNames { get; }
24+
int Rate { get; }
25+
}

msgraph-developer-proxy-abstractions/PluginEvents.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
namespace Microsoft.Graph.DeveloperProxy.Abstractions;
99

1010
public interface IProxyContext {
11-
public ILogger Logger { get; }
11+
IProxyConfiguration Configuration { get; }
12+
ILogger Logger { get; }
1213
}
1314

1415
public class ProxyHttpEventArgsBase {

msgraph-developer-proxy-plugins/RandomErrors/GenericRandomErrorPlugin.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ internal enum GenericRandomErrorFailMode {
1919
}
2020

2121
public class GenericRandomErrorConfiguration {
22-
public int Rate { get; set; } = 0;
2322
public string? ErrorsFile { get; set; }
2423
[JsonPropertyName("responses")]
2524
public IEnumerable<GenericErrorResponse> Responses { get; set; } = Array.Empty<GenericErrorResponse>();
@@ -28,6 +27,7 @@ public class GenericRandomErrorConfiguration {
2827
public class GenericRandomErrorPlugin : BaseProxyPlugin {
2928
private readonly GenericRandomErrorConfiguration _configuration = new();
3029
private GenericErrorResponsesLoader? _loader = null;
30+
private IProxyConfiguration? _proxyConfiguration;
3131

3232
public override string Name => nameof(GenericRandomErrorPlugin);
3333

@@ -56,7 +56,7 @@ private GenericRandomErrorFailMode ShouldFail(ProxyRequestArgs e) {
5656
_throttledRequests.Remove(key);
5757
}
5858
}
59-
return _random.Next(1, 100) <= _configuration.Rate ? GenericRandomErrorFailMode.Random : GenericRandomErrorFailMode.PassThru;
59+
return _random.Next(1, 100) <= _proxyConfiguration?.Rate ? GenericRandomErrorFailMode.Random : GenericRandomErrorFailMode.PassThru;
6060
}
6161

6262
private void FailResponse(ProxyRequestArgs e, GenericRandomErrorFailMode failMode) {
@@ -127,6 +127,12 @@ public override void Register(IPluginEvents pluginEvents,
127127

128128
pluginEvents.Init += OnInit;
129129
pluginEvents.BeforeRequest += OnRequest;
130+
131+
// needed to get the failure rate configuration
132+
// must keep reference of the whole config rather than just rate
133+
// because rate is an int and can be set through command line args
134+
// which is done after plugins have been registered
135+
_proxyConfiguration = context.Configuration;
130136
}
131137

132138
private void OnInit(object? sender, InitArgs e) {
@@ -141,7 +147,7 @@ private async Task OnRequest(object? sender, ProxyRequestArgs e) {
141147
&& e.ShouldExecute(_urlsToWatch)) {
142148
var failMode = ShouldFail(e);
143149

144-
if (failMode == GenericRandomErrorFailMode.PassThru && _configuration.Rate != 100) {
150+
if (failMode == GenericRandomErrorFailMode.PassThru && _proxyConfiguration?.Rate != 100) {
145151
_logger?.LogRequest(new[] { "Passed through" }, MessageType.PassedThrough, new LoggingContext(e.Session));
146152
return;
147153
}

msgraph-developer-proxy-plugins/RandomErrors/GraphRandomErrorPlugin.cs

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@ internal enum GraphRandomErrorFailMode {
2121
}
2222

2323
public class GraphRandomErrorConfiguration {
24-
public int Rate { get; set; } = 0;
2524
public List<int> AllowedErrors { get; set; } = new();
2625
}
2726

2827
public class GraphRandomErrorPlugin : BaseProxyPlugin {
29-
private readonly Option<int?> _rate;
3028
private readonly Option<IEnumerable<int>> _allowedErrors;
3129
private readonly GraphRandomErrorConfiguration _configuration = new();
30+
private IProxyConfiguration? _proxyConfiguration;
3231

3332
public override string Name => nameof(GraphRandomErrorPlugin);
3433

@@ -89,15 +88,6 @@ public class GraphRandomErrorPlugin : BaseProxyPlugin {
8988
private readonly Random _random;
9089

9190
public GraphRandomErrorPlugin() {
92-
_rate = new Option<int?>("--failure-rate", "The percentage of requests to graph to respond with failures");
93-
_rate.AddAlias("-f");
94-
_rate.ArgumentHelpName = "failure rate";
95-
_rate.AddValidator((input) => {
96-
int? value = input.GetValueForOption(_rate);
97-
if (value.HasValue && (value < 0 || value > 100)) {
98-
input.ErrorMessage = $"{value} is not a valid failure rate. Specify a number between 0 and 100";
99-
}
100-
});
10191
_allowedErrors = new Option<IEnumerable<int>>("--allowed-errors", "List of errors that the developer proxy may produce");
10292
_allowedErrors.AddAlias("-a");
10393
_allowedErrors.ArgumentHelpName = "allowed errors";
@@ -123,7 +113,7 @@ private GraphRandomErrorFailMode ShouldFail(ProxyRequestArgs e) {
123113
_throttledRequests.Remove(key);
124114
}
125115
}
126-
return _random.Next(1, 100) <= _configuration.Rate ? GraphRandomErrorFailMode.Random : GraphRandomErrorFailMode.PassThru;
116+
return _random.Next(1, 100) <= _proxyConfiguration?.Rate ? GraphRandomErrorFailMode.Random : GraphRandomErrorFailMode.PassThru;
127117
}
128118

129119
private void FailResponse(ProxyRequestArgs e, GraphRandomErrorFailMode failMode) {
@@ -178,19 +168,20 @@ public override void Register(IPluginEvents pluginEvents,
178168
pluginEvents.Init += OnInit;
179169
pluginEvents.OptionsLoaded += OnOptionsLoaded;
180170
pluginEvents.BeforeRequest += OnRequest;
171+
172+
// needed to get the failure rate configuration
173+
// must keep reference of the whole config rather than just rate
174+
// because rate is an int and can be set through command line args
175+
// which is done after plugins have been registered
176+
_proxyConfiguration = context.Configuration;
181177
}
182178

183179
private void OnInit(object? sender, InitArgs e) {
184-
e.RootCommand.AddOption(_rate);
185180
e.RootCommand.AddOption(_allowedErrors);
186181
}
187182

188183
private void OnOptionsLoaded(object? sender, OptionsLoadedArgs e) {
189184
InvocationContext context = e.Context;
190-
// configure probability of failure
191-
int? rate = context.ParseResult.GetValueForOption(_rate);
192-
if (rate.HasValue)
193-
_configuration.Rate = rate.Value;
194185

195186
// Configure the allowed errors
196187
IEnumerable<int>? allowedErrors = context.ParseResult.GetValueForOption(_allowedErrors);
@@ -212,7 +203,7 @@ private async Task OnRequest(object? sender, ProxyRequestArgs e) {
212203
&& e.ShouldExecute(_urlsToWatch)) {
213204
var failMode = ShouldFail(e);
214205

215-
if (failMode == GraphRandomErrorFailMode.PassThru && _configuration.Rate != 100) {
206+
if (failMode == GraphRandomErrorFailMode.PassThru && _proxyConfiguration?.Rate != 100) {
216207
return;
217208
}
218209
FailResponse(e, failMode);

msgraph-developer-proxy/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
PluginEvents pluginEvents = new PluginEvents();
99
ILogger logger = new ConsoleLogger(ProxyCommandHandler.Configuration, pluginEvents);
10-
IProxyContext context = new ProxyContext(logger);
10+
IProxyContext context = new ProxyContext(logger, ProxyCommandHandler.Configuration);
1111
ProxyHost proxyHost = new();
1212
RootCommand rootCommand = proxyHost.GetRootCommand();
1313
PluginLoaderResult loaderResults = new PluginLoader(logger).LoadPlugins(pluginEvents, context);

msgraph-developer-proxy/ProxyCommandHandler.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class ProxyCommandHandler : ICommandHandler {
1414
public Option<bool?> Record { get; set; }
1515
public Option<IEnumerable<int>?> WatchPids { get; set; }
1616
public Option<IEnumerable<string>?> WatchProcessNames { get; set; }
17+
public Option<int?> Rate { get; set; }
1718

1819
private readonly PluginEvents _pluginEvents;
1920
private readonly ISet<UrlToWatch> _urlsToWatch;
@@ -24,6 +25,7 @@ public ProxyCommandHandler(Option<int?> port,
2425
Option<bool?> record,
2526
Option<IEnumerable<int>?> watchPids,
2627
Option<IEnumerable<string>?> watchProcessNames,
28+
Option<int?> rate,
2729
PluginEvents pluginEvents,
2830
ISet<UrlToWatch> urlsToWatch,
2931
ILogger logger) {
@@ -32,6 +34,7 @@ public ProxyCommandHandler(Option<int?> port,
3234
Record = record ?? throw new ArgumentNullException(nameof(record));
3335
WatchPids = watchPids ?? throw new ArgumentNullException(nameof(watchPids));
3436
WatchProcessNames = watchProcessNames ?? throw new ArgumentNullException(nameof(watchProcessNames));
37+
Rate = rate ?? throw new ArgumentNullException(nameof(rate));
3538
_pluginEvents = pluginEvents ?? throw new ArgumentNullException(nameof(pluginEvents));
3639
_urlsToWatch = urlsToWatch ?? throw new ArgumentNullException(nameof(urlsToWatch));
3740
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
@@ -62,6 +65,10 @@ public async Task<int> InvokeAsync(InvocationContext context) {
6265
if (watchProcessNames is not null) {
6366
Configuration.WatchProcessNames = watchProcessNames;
6467
}
68+
var rate = context.ParseResult.GetValueForOption(Rate);
69+
if (rate is not null) {
70+
Configuration.Rate = rate.Value;
71+
}
6572

6673
CancellationToken? cancellationToken = (CancellationToken?)context.BindingContext.GetService(typeof(CancellationToken?));
6774

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
using System.Runtime.Serialization;
54
using System.Text.Json.Serialization;
65
using Microsoft.Graph.DeveloperProxy.Abstractions;
76

87
namespace Microsoft.Graph.DeveloperProxy;
98

10-
public enum LabelMode {
11-
[EnumMember(Value = "text")]
12-
Text,
13-
[EnumMember(Value = "icon")]
14-
Icon,
15-
[EnumMember(Value = "nerdFont")]
16-
NerdFont
17-
}
18-
19-
public class ProxyConfiguration {
9+
public class ProxyConfiguration: IProxyConfiguration {
2010
[JsonPropertyName("port")]
2111
public int Port { get; set; } = 8000;
2212
[JsonPropertyName("labelMode")]
@@ -29,5 +19,7 @@ public class ProxyConfiguration {
2919
public LogLevel LogLevel { get; set; } = LogLevel.Info;
3020
public IEnumerable<int> WatchPids { get; set; } = new List<int>();
3121
public IEnumerable<string> WatchProcessNames { get; set; } = new List<string>();
22+
[JsonPropertyName("rate")]
23+
public int Rate { get; set; } = 50;
3224
}
3325

msgraph-developer-proxy/ProxyContext.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@
55

66
namespace Microsoft.Graph.DeveloperProxy;
77

8-
internal class ProxyContext : IProxyContext {
9-
public ILogger Logger { get; }
8+
internal class ProxyContext : IProxyContext
9+
{
10+
public ILogger Logger { get; }
1011

11-
public ProxyContext(ILogger logger) {
12-
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
13-
}
12+
public IProxyConfiguration Configuration { get; }
13+
14+
public ProxyContext(ILogger logger, IProxyConfiguration configuration)
15+
{
16+
Logger = logger ?? throw new ArgumentNullException(nameof(logger));
17+
Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
18+
}
1419
}

msgraph-developer-proxy/ProxyHost.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ internal class ProxyHost {
1414
private Option<IEnumerable<int>?> _watchPidsOption;
1515
private Option<IEnumerable<string>?> _watchProcessNamesOption;
1616
private static Option<string?>? _configFileOption;
17+
private Option<int?> _rateOption;
1718

1819
private static bool _configFileResolved = false;
1920
private static string _configFile = "appsettings.json";
@@ -73,6 +74,16 @@ public ProxyHost() {
7374
_watchProcessNamesOption = new Option<IEnumerable<string>?>("--watch-process-names", "The names of processes to watch for requests");
7475
_watchProcessNamesOption.ArgumentHelpName = "processNames";
7576
_watchProcessNamesOption.AllowMultipleArgumentsPerToken = true;
77+
78+
_rateOption = new Option<int?>("--failure-rate", "The percentage of chance that a request will fail");
79+
_rateOption.AddAlias("-f");
80+
_rateOption.ArgumentHelpName = "failure rate";
81+
_rateOption.AddValidator((input) => {
82+
int? value = input.GetValueForOption(_rateOption);
83+
if (value.HasValue && (value < 0 || value > 100)) {
84+
input.ErrorMessage = $"{value} is not a valid failure rate. Specify a number between 0 and 100";
85+
}
86+
});
7687
}
7788

7889
public RootCommand GetRootCommand() {
@@ -82,6 +93,7 @@ public RootCommand GetRootCommand() {
8293
_recordOption,
8394
_watchPidsOption,
8495
_watchProcessNamesOption,
96+
_rateOption,
8597
// _configFileOption is set during the call to load
8698
// `ProxyCommandHandler.Configuration`. As such, it's always set here
8799
_configFileOption!
@@ -91,6 +103,6 @@ public RootCommand GetRootCommand() {
91103
return command;
92104
}
93105

94-
public ProxyCommandHandler GetCommandHandler(PluginEvents pluginEvents, ISet<UrlToWatch> urlsToWatch, ILogger logger) => new ProxyCommandHandler(_portOption, _logLevelOption, _recordOption, _watchPidsOption, _watchProcessNamesOption, pluginEvents, urlsToWatch, logger);
106+
public ProxyCommandHandler GetCommandHandler(PluginEvents pluginEvents, ISet<UrlToWatch> urlsToWatch, ILogger logger) => new ProxyCommandHandler(_portOption, _logLevelOption, _recordOption, _watchPidsOption, _watchProcessNamesOption, _rateOption, pluginEvents, urlsToWatch, logger);
95107
}
96108

msgraph-developer-proxy/appsettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,12 @@
104104
"mocksFile": "responses.json"
105105
},
106106
"graphRandomErrorsPlugin": {
107-
"rate": 50,
108107
"allowedErrors": [ 429, 500, 502, 503, 504, 507 ]
109108
},
110109
"executionSummaryPlugin": {
111110
"groupBy": "url"
112111
},
112+
"rate": 50,
113113
"labelMode": "text",
114114
"logLevel": "info"
115115
}

0 commit comments

Comments
 (0)