Skip to content

Commit 873edf5

Browse files
committed
initial version, new icon
1 parent f2bff8c commit 873edf5

File tree

12 files changed

+438
-9
lines changed

12 files changed

+438
-9
lines changed

bombardier/linux/bombardier

11.2 MB
Binary file not shown.

bombardier/win/bombardier.exe

10.9 MB
Binary file not shown.

qatoolkit-64x64.png

-225 Bytes
Loading
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using QAToolKit.Core.Models;
2+
3+
namespace QAToolKit.Engine.Bombardier
4+
{
5+
public class BombardierOptions
6+
{
7+
internal string CustomerAccessToken { get; set; }
8+
internal string AdministratorAccessToken { get; private set; }
9+
internal string ApiKey { get; private set; }
10+
internal ReplacementValue[] ReplacementValues { get; private set; }
11+
public int BombardierConcurrentUsers { get; set; }
12+
public int BombardierTimeout { get; set; }
13+
public int BombardierDuration { get; set; }
14+
public int BombardierRateLimit { get; set; }
15+
public bool BombardierUseHttp2 { get; set; }
16+
17+
public BombardierOptions AddReplacementValues(ReplacementValue[] replacementValues)
18+
{
19+
ReplacementValues = replacementValues;
20+
return this;
21+
}
22+
23+
public BombardierOptions AddTokensAndApiKeys(string customerToken, string adminToken, string apiKey)
24+
{
25+
CustomerAccessToken = customerToken;
26+
AdministratorAccessToken = adminToken;
27+
ApiKey = apiKey;
28+
return this;
29+
}
30+
}
31+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using QAToolKit.Core.Interfaces;
2+
3+
namespace QAToolKit.Engine.Bombardier
4+
{
5+
public class BombardierResult : ILoadTestResult
6+
{
7+
public string Command { get; set; }
8+
public int Counter1xx { get; set; }
9+
public int Counter2xx { get; set; }
10+
public int Counter3xx { get; set; }
11+
public int Counter4xx { get; set; }
12+
public int Counter5xx { get; set; }
13+
public decimal AverageLatency { get; set; }
14+
public decimal AverageRequestsPerSecond { get; set; }
15+
public decimal MaxLatency { get; set; }
16+
public decimal MaxRequestsPerSecond { get; set; }
17+
public decimal StdevLatency { get; set; }
18+
public decimal StdevRequestsPerSecond { get; set; }
19+
20+
public override string ToString()
21+
{
22+
return $"1xx - {Counter1xx}, 2xx - {Counter2xx}, 3xx - {Counter3xx}, 4xx - {Counter4xx}, 5xx - {Counter5xx}, avg lat {AverageLatency}ms, std lat {StdevLatency}ms, max lat {MaxLatency}ms, avg rps {AverageRequestsPerSecond}, std rps {StdevRequestsPerSecond}, max rps {MaxRequestsPerSecond}";
23+
}
24+
}
25+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace QAToolKit.Engine.Bombardier
2+
{
3+
public class BombardierTest
4+
{
5+
public string Method { get; set; }
6+
public string Url { get; set; }
7+
public string Command { get; set; }
8+
}
9+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using QAToolKit.Core.Interfaces;
2+
using QAToolKit.Core.Models;
3+
using QAToolKit.Engine.Bombardier.Helpers;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IO;
7+
using System.Runtime.InteropServices;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
11+
namespace QAToolKit.Engine.Bombardier
12+
{
13+
public class BombardierTestsGenerator : IGenerator<IList<HttpTestRequest>, IEnumerable<BombardierTest>>
14+
{
15+
private readonly BombardierOptions _bombardierOptions;
16+
17+
public BombardierTestsGenerator(Action<BombardierOptions> options)
18+
{
19+
_bombardierOptions = new BombardierOptions();
20+
options?.Invoke(_bombardierOptions);
21+
}
22+
23+
/// <summary>
24+
/// Generate a Bombardier script
25+
/// </summary>
26+
/// <returns></returns>
27+
public async Task<IEnumerable<BombardierTest>> Generate(IList<HttpTestRequest> restRequests)
28+
{
29+
var bombardierTests = new List<BombardierTest>();
30+
var scriptBuilder = new StringBuilder();
31+
32+
var bombardierFullPath = String.Empty;
33+
34+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
35+
{
36+
bombardierFullPath = Path.Combine(Environment.CurrentDirectory, "bombardier", "win", "bombardier.exe");
37+
}
38+
else
39+
{
40+
bombardierFullPath = Path.Combine("./bombardier", "linux", "bombardier");
41+
}
42+
43+
foreach (var request in restRequests)
44+
{
45+
string authHeader = GeneratorHelper.GenerateAuthHeader(request, _bombardierOptions.CustomerAccessToken,
46+
_bombardierOptions.AdministratorAccessToken, _bombardierOptions.ApiKey);
47+
48+
scriptBuilder.AppendLine($"{bombardierFullPath} " +
49+
$"-m {request.Method.ToString().ToUpper()} {GeneratorHelper.GenerateUrlParameters(request, _bombardierOptions.ReplacementValues)} " +
50+
$"-c {_bombardierOptions.BombardierConcurrentUsers} " +
51+
$"{authHeader}" +
52+
$"{GeneratorHelper.GenerateContentTypeHeader(request)}" +
53+
$"{GeneratorHelper.GenerateJsonBody(request, _bombardierOptions.ReplacementValues)}" +
54+
$"--{(Convert.ToBoolean(_bombardierOptions.BombardierUseHttp2) ? "http2" : "http1")} " +
55+
$"--timeout={_bombardierOptions.BombardierTimeout}s " +
56+
$"--duration={_bombardierOptions.BombardierDuration}s " +
57+
$"{GeneratorHelper.GenerateRateLimit(_bombardierOptions.BombardierRateLimit)}");
58+
59+
bombardierTests.Add(new BombardierTest()
60+
{
61+
Url = request.Path,
62+
Method = request.Method.ToString(),
63+
Command = scriptBuilder.ToString()
64+
});
65+
}
66+
67+
return bombardierTests;
68+
}
69+
}
70+
}
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
using QAToolKit.Core.Helpers;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Diagnostics;
5+
using System.Globalization;
6+
using System.IO;
7+
using System.Text;
8+
using System.Text.RegularExpressions;
9+
using System.Threading.Tasks;
10+
11+
namespace QAToolKit.Engine.Bombardier
12+
{
13+
public class BombardierTestsRunner
14+
{
15+
private readonly IList<BombardierTest> _bombardierTests;
16+
17+
public BombardierTestsRunner(IList<BombardierTest> bombardierTests)
18+
{
19+
_bombardierTests = bombardierTests;
20+
}
21+
22+
public async Task<IList<BombardierResult>> Run()
23+
{
24+
var bombardierResult = new List<BombardierResult>();
25+
26+
foreach (var test in _bombardierTests)
27+
{
28+
bombardierResult.Add(await Run(test.Command));
29+
}
30+
31+
return bombardierResult;
32+
}
33+
34+
private async Task<BombardierResult> Run(string testCommand)
35+
{
36+
var indexOfDelimiter = testCommand.IndexOf("-m");
37+
var bombardierExecutable = testCommand
38+
.Substring(0, indexOfDelimiter - 1);
39+
var bombardierArguments = testCommand
40+
.Substring(indexOfDelimiter, testCommand.Length - indexOfDelimiter)
41+
.Replace(Environment.NewLine, "")
42+
.Trim();
43+
44+
var bombardrierOutput = new StringBuilder();
45+
46+
using (var process = new Process())
47+
{
48+
process.StartInfo = new ProcessStartInfo
49+
{
50+
FileName = bombardierExecutable,
51+
RedirectStandardOutput = true,
52+
CreateNoWindow = true,
53+
Arguments = bombardierArguments
54+
};
55+
56+
process.Start();
57+
58+
while (!process.StandardOutput.EndOfStream)
59+
{
60+
bombardrierOutput.AppendLine(await process.StandardOutput.ReadLineAsync());
61+
}
62+
63+
process.WaitForExit();
64+
}
65+
66+
//Delete temp files
67+
DeleteBodyFile(bombardierArguments);
68+
69+
var parsedBombardierOutput = ParseOutput(bombardrierOutput, bombardierArguments);
70+
71+
return parsedBombardierOutput;
72+
}
73+
74+
private void DeleteBodyFile(string arguments)
75+
{
76+
try
77+
{
78+
var file = StringHelper.Between(arguments, "-f \"", "\"");
79+
80+
if (string.IsNullOrEmpty(file) && File.Exists(file))
81+
{
82+
File.Delete(file);
83+
}
84+
}
85+
catch { }
86+
}
87+
88+
private BombardierResult ParseOutput(StringBuilder sb, string command)
89+
{
90+
try
91+
{
92+
var results = new BombardierResult();
93+
94+
var str = sb.ToString();
95+
96+
results.Command = command;
97+
results.Counter1xx = Convert.ToInt32(StringHelper.RemoveAllNonNumericChars(StringHelper.Between(str, "1xx - ", ",")));
98+
results.Counter2xx = Convert.ToInt32(StringHelper.RemoveAllNonNumericChars(StringHelper.Between(str, "2xx - ", ",")));
99+
results.Counter3xx = Convert.ToInt32(StringHelper.RemoveAllNonNumericChars(StringHelper.Between(str, "3xx - ", ",")));
100+
results.Counter4xx = Convert.ToInt32(StringHelper.RemoveAllNonNumericChars(StringHelper.Between(str, "4xx - ", ",")));
101+
results.Counter5xx = Convert.ToInt32(StringHelper.RemoveAllNonNumericChars(StringHelper.Between(str, "5xx - ", " ")));
102+
103+
var reqsPerSec = StringHelper.ReplaceMultipleSpacesWithOne(StringHelper.Between(str, "Reqs/sec", Environment.NewLine).TrimStart().TrimEnd()).Split(' ');
104+
105+
CultureInfo cultures = new CultureInfo("en-US");
106+
results.AverageRequestsPerSecond = Convert.ToDecimal(reqsPerSec[0], cultures);
107+
results.StdevRequestsPerSecond = Convert.ToDecimal(reqsPerSec[1], cultures);
108+
results.MaxRequestsPerSecond = Convert.ToDecimal(reqsPerSec[2], cultures);
109+
110+
var latencies = StringHelper.ReplaceMultipleSpacesWithOne(StringHelper.Between(str, "Latency ", Environment.NewLine).TrimStart().TrimEnd()).Split(' ');
111+
112+
results.AverageLatency = GetLatencyMiliseconds(latencies[0]);
113+
results.StdevLatency = GetLatencyMiliseconds(latencies[1]);
114+
results.MaxLatency = GetLatencyMiliseconds(latencies[2]);
115+
116+
return results;
117+
}
118+
catch
119+
{
120+
throw;
121+
}
122+
}
123+
124+
private decimal GetLatencyMiliseconds(string latency)
125+
{
126+
CultureInfo cultures = new CultureInfo("en-US");
127+
var digitString = Regex.Match(latency, @"\d+.\d+");
128+
var unitString = Regex.Replace(latency, @"\d+.\d+", "");
129+
decimal digit;
130+
131+
switch (unitString)
132+
{
133+
case "s":
134+
digit = Convert.ToDecimal(digitString.Value, cultures) * 1000;
135+
break;
136+
case "ms":
137+
digit = Convert.ToDecimal(digitString.Value, cultures);
138+
break;
139+
case "us":
140+
digit = Convert.ToDecimal(digitString.Value, cultures) / 1000;
141+
break;
142+
default:
143+
digit = Convert.ToDecimal(digitString.Value, cultures);
144+
break;
145+
}
146+
147+
return digit;
148+
}
149+
}
150+
}

src/QAToolKit.Engine.Bombardier/Class1.cs

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)