Beta.cs
15.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
/************************************************************************************************
* All code in this file is under the MS-RL License (https://opensource.org/licenses/MS-RL) *
* By using the code in this file in any way, you agree to the above license terms. *
* Copyright (C) LIGHTS IN LINE AB (https://www.lightsinline.se) *
* Repository, Wiki, Issue tracker and more at https://git.lightsinline.se/products/VSTT-Plugins *
* *
* Contributors *
* LIGHTS IN LINE AB *
* SWEDBANK AB *
* SKATTEVERKET *
************************************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.WebTesting;
using System.ComponentModel;
using Microsoft.VisualStudio.TestTools.WebTesting.Rules;
using System.Text.RegularExpressions;
using System.IO;
using Microsoft.VisualStudio.TestTools.LoadTesting;
namespace LIL_VSTT_Plugins
{
[DisplayName("Set Request Think Time"), Description("Changes the thinktime on requests with a set thinktime over 0 to the value of the ThinkTime context parameter")]
public class SetRequestThinkTime : WebTestPlugin
{
[DisplayName("Debug"), DefaultValue(false), Description("Debug logging when thinktime is set on requests")]
public bool DebugMode { get; set; }
public override void PreRequest(object sender, PreRequestEventArgs e)
{
WebTestContext ctx = e.WebTest.Context;
if (ctx.ContainsKey("ThinkTime"))
{
int tt = Int32.Parse(ctx["ThinkTime"].ToString());
if (e.Request.ThinkTime > 0)
{
if (DebugMode) e.WebTest.AddCommentToResult("Setting Think Time to " + tt);
e.Request.ThinkTime = tt;
}
}
}
}
[DisplayName("Clear Cookies"), Description("Clears all cookies from previous iterations of this webtest")]
public class ClearCookies : WebTestPlugin
{
public override void PreWebTest(object sender, PreWebTestEventArgs e)
{
e.WebTest.Context.CookieContainer = new System.Net.CookieContainer();
}
}
[DisplayName("Think Time Emulator 10/190"), Description("Sets a context parameter named ThinkTime in each starting test to a random value between 10%-190% of the specified value.")]
public class ThinkTimeEmulator10190 : ILoadTestPlugin
{
[DisplayName("Think Time"), DefaultValue(0), Description("The Think Time to be used seconds. Default is 0.")]
public int ThinkTime { get; set; }
//store the load test object.
LoadTest mLoadTest;
Random rnd = new Random();
public void Initialize(LoadTest loadTest)
{
mLoadTest = loadTest;
//connect to the TestStarting event.
mLoadTest.TestStarting += new EventHandler<TestStartingEventArgs>(mLoadTest_TestStarting);
}
void mLoadTest_TestStarting(object sender, TestStartingEventArgs e)
{
// Set the think time parameter in the tests context to a new value
int min = ThinkTime/10;
int max = ThinkTime*2 - min;
e.TestContextProperties.Add("ThinkTime", rnd.Next(min, max));
}
}
[DisplayName("Set Cookie from Query String"), Description("Sets a cookie with given name from the value of a given Query String parameter if found in the current request")]
public class SetCookieFromQueryString : WebTestPlugin
{
[DisplayName("Cookie name"), Description("Name of the cookie to set")]
public String CookieName { get; set; }
[DisplayName("Query String parameter name"), Description("Name of the query string parameter to look for")]
public String ParamName { get; set; }
public override void PreRequest(object sender, PreRequestEventArgs e)
{
base.PreRequest(sender, e);
QueryStringParameterCollection col = e.Request.QueryStringParameters;
for(int x=0; x < col.Count; x++)
{
if (col[x].Name == ParamName)
{
e.Request.Cookies.Add(new System.Net.Cookie(CookieName, col[x].Value));
return;
}
}
}
public override void PostRequest(object sender, PostRequestEventArgs e)
{
base.PostRequest(sender, e);
if (e.Request.HasDependentRequests)
{
foreach (WebTestRequest item in e.Request.DependentRequests)
{
QueryStringParameterCollection col = item.QueryStringParameters;
for (int x = 0; x < col.Count; x++)
{
if (col[x].Name == ParamName)
{
item.Cookies.Add(new System.Net.Cookie(CookieName, col[x].Value));
}
}
}
}
}
}
[DisplayName("Add Header"), Description("Adds the specified header to all requests matching a given URL regex")]
public class AddHeader : WebTestPlugin
{
[DisplayName("Header Name"), Description("Name of the header to set")]
public String HeaderName { get; set; }
[DisplayName("Header Value"), Description("Value of the header to set")]
public String HeaderValue { get; set; }
[DisplayName("URL RegEx"), Description("Regular Expression to match on the URL. Empty matches all requests.")]
public String RegEx { get; set; }
public override void PreRequest(object sender, PreRequestEventArgs e)
{
base.PreRequest(sender, e);
if (Regex.Match(e.Request.Url, RegEx).Success || RegEx.Length == 0)
{
e.Request.Headers.Add(HeaderName, HeaderValue);
}
}
public override void PostRequest(object sender, PostRequestEventArgs e)
{
base.PostRequest(sender, e);
if (e.Request.HasDependentRequests)
{
foreach (WebTestRequest item in e.Request.DependentRequests)
{
if (Regex.Match(item.Url, RegEx).Success || RegEx.Length == 0)
{
item.Headers.Add(HeaderName, HeaderValue);
}
}
}
}
}
[DisplayName("Log Context Arrays to File"), Description("Logs the specified context parameter arrays to file after each test iteration, one row for each array value")]
public class LogContextArrayToFile : WebTestPlugin
{
[DisplayName("Parameter arrays"), Description("Comma separated list of array parameters to log")]
public String Params { get; set; }
[DisplayName("File Name"), Description("The file name to use for logging")]
public String Filename { get; set; }
private bool header = true;
private string[] paramlist = null;
public override void PostWebTest(object sender, PostWebTestEventArgs e)
{
if (Params.Length == 0 || Filename.Length == 0) return;
if (paramlist == null) paramlist = Params.Split(',');
if (header)
{
File.AppendAllText(Filename, Params + "\r\n");
header = false;
}
// Check that the first param array has a count
int count = 0;
WebTestContext ctx = e.WebTest.Context;
if (ctx.ContainsKey(paramlist[0] + "_count")) count = Int32.Parse(ctx[paramlist[0] + "_count"].ToString());
for (int i = 1; i <= count; i++)
{
string row = "";
foreach (string param in paramlist)
{
if (row.Length > 0) row += ",";
if (ctx.ContainsKey(param + "_" + i)) row += ctx[param + "_" + i].ToString();
}
File.AppendAllText(Filename, row + "\r\n");
}
base.PostWebTest(sender, e);
}
}
[DisplayName("Log Context to File"), Description("Logs the specified context parameters to file after each test iteration")]
public class LogContextToFile : WebTestPlugin
{
[DisplayName("Regular Expression"), Description("The RegEx to use to match context parameter names")]
public String myRegex { get; set; }
[DisplayName("File Name"), Description("The file name to use for logging")]
public String Filename { get; set; }
[DisplayName("Write header"), DefaultValue(false), Description("Writes the parameter names as a header. Will write a new header for each user (dont use in loadtest)")]
public bool useHeader { get; set; }
[DisplayName("Log if passed"), DefaultValue(true), Description("Logs the parameters if the webtest passed")]
public bool logPassed { get; set; }
[DisplayName("Log if failed"), DefaultValue(true), Description("Logs the parameters if the webtest failed")]
public bool logFailed { get; set; }
private bool header = true;
public override void PostWebTest(object sender, PostWebTestEventArgs e)
{
if ((e.WebTest.Outcome == Outcome.Pass && logPassed) || (e.WebTest.Outcome == Outcome.Fail && logFailed)) {
string row = "";
string hrow = "";
foreach (KeyValuePair<string, object> pair in e.WebTest.Context)
{
if (Regex.Match(pair.Key, myRegex).Success)
{
if (header && useHeader)
{
if (hrow.Length == 0) hrow = pair.Key.ToString();
else hrow += "," + pair.Key.ToString();
}
if (row.Length == 0) row = pair.Value.ToString();
else row += "," + pair.Value.ToString();
}
}
if (header && useHeader)
{
File.AppendAllText(Filename + e.WebTest.Context.WebTestUserId + ".log", hrow + "\r\n");
header = false;
}
File.AppendAllText(Filename + e.WebTest.Context.WebTestUserId + ".log", row + "\r\n");
base.PostWebTest(sender, e);
}
}
}
[DisplayName("Multi Regular Expression"), Description("Saves all matches for a regular expression including a count")]
public class MultiRegExExtract : ExtractionRule
{
[DisplayName("Regular Expression"), Description("The RegEx to use, supports grouping, for example (.+?)")]
public String Regex { get; set; }
[DisplayName("Group Name"), DefaultValue("1"), Description("The group to use as the value for the parameter, default is 1")]
public String GroupName { get; set; }
[DisplayName("Pass if not found"), DefaultValue(false), Description("Wherever this extration rule should pass even if no matches are found. Default false.")]
public bool PassIfNotFound { get; set; }
public override void Extract(object sender, ExtractionEventArgs e)
{
MatchCollection matches = System.Text.RegularExpressions.Regex.Matches(
e.Response.BodyString,
Regex,
RegexOptions.IgnoreCase);
int index = 0;
foreach (Match match in matches)
{
index++;
e.WebTest.Context[ContextParameterName + "_" + index] = match.Groups[GroupName].Value;
}
if (index > 0)
{
e.WebTest.Context[ContextParameterName + "_count"] = index.ToString();
e.Success = true;
e.Message = "Found " + index + " matches";
}
else
{
e.WebTest.Context[ContextParameterName + "_count"] = index.ToString();
e.Success = PassIfNotFound;
e.Message = "No matches found. Body size is " + e.Response.BodyString.Length;
}
}
}
[DisplayName("Extract Count"), Description("Counts all matches for a given RegEx and saves the count to the specified parameter")]
public class ExtractCount : ExtractionRule
{
[DisplayName("Regular Expression"), Description("The RegEx to use")]
public String Regex { get; set; }
[DisplayName("Fail on zero count"), DefaultValue(false), Description("Wherever this extration rule should fail if no matches are found")]
public bool FailOnZero { get; set; }
public override void Extract(object sender, ExtractionEventArgs e)
{
MatchCollection matches = System.Text.RegularExpressions.Regex.Matches(
e.Response.BodyString,
Regex,
RegexOptions.IgnoreCase);
e.WebTest.Context[ContextParameterName] = matches.Count.ToString();
e.Message = "Found " + matches.Count + " matches";
if (FailOnZero && matches.Count == 0)
{
e.Success = false;
}
}
}
[DisplayName("Regular Expression Loop"), Description("Loop Condition that matches once on each regexp in previous response body")]
public class RegExpLoop : ConditionalRule
{
private Int32 CurrentMatch { get; set; }
private String LastUrl { get; set; }
private MatchCollection Matches { get; set; }
[DisplayName("Context parameter"), IsContextParameterName(true),
Description("Name of context parameter where the current value should be set in each loop")]
public string ContextParameterName { get; set; }
[DisplayName("Regex"), Description("The RegEx to use, supports grouping, for example (.+?)")]
public String Regex { get; set; }
[DisplayName("GroupName"), Description("The group to use as the value for the parameter if several are specified, default is 1")]
public String GroupName { get; set; }
// Methods
public override void CheckCondition(object sender, ConditionalEventArgs e)
{
if (CurrentMatch < Matches.Count)
{
e.WebTest.Context[ContextParameterName] =
Matches[CurrentMatch].Groups[GroupName].Value;
e.IsMet = true;
CurrentMatch++;
return;
}
e.IsMet = false;
}
public override void Initialize(object sender, ConditionalEventArgs e)
{
CurrentMatch = 0;
Matches = System.Text.RegularExpressions.Regex.Matches(
e.WebTest.LastResponse.BodyString,
Regex,
RegexOptions.IgnoreCase);
}
public override string StringRepresentation()
{
return "Regex condition " + Regex;
}
}
}