Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Onboarding workload Apachebench for Apache Httpserver #251

Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
namespace VirtualClient.Actions.ApacheBench
iprashantp marked this conversation as resolved.
Show resolved Hide resolved
{
using Microsoft.Extensions.Logging;
using Moq;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using Polly;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.ServiceModel.Channels;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using VirtualClient.Actions.Properties;
using VirtualClient.Common;
using VirtualClient.Common.Extensions;
using VirtualClient.Common.Telemetry;
using VirtualClient.Contracts;
using static VirtualClient.Actions.ApacheBenchExecutor;

[TestFixture]
[Category("Unit")]
public class ApacheBenchExecutorTests
{
private MockFixture fixture;
private DependencyPath mockWorkloadPackage;

[Test]
public void ApacheBenchExecutorThrowsIfTheApacheHttpWorkloadPackageDoesNotExist()
{
this.SetupDefaultBehaviors(PlatformID.Win32NT, Architecture.X64);

using (var executor = new TestApacheBenchExecutor(this.fixture))
{
// The package does not exist on the system.
this.fixture.PackageManager.Reset();

DependencyException error = Assert.ThrowsAsync<DependencyException>(
() => executor.InitializeAsync(EventContext.None, CancellationToken.None));

Assert.AreEqual(ErrorReason.WorkloadDependencyMissing, error.Reason);
}
}

[Test]
public async Task ApacheBenchExecutorCreatesStateWhenStateDoesNotExist()
{
this.SetupDefaultBehaviors(PlatformID.Win32NT, Architecture.X64);
this.fixture.File.Setup(file => file.ReadAllTextAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(string.Empty);
this.fixture.File.Setup(file => file.WriteAllTextAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.Callback<string, string, CancellationToken>((path, content, token) =>
{
Assert.IsEmpty(content);
});

using (var executor = new TestApacheBenchExecutor(this.fixture))
{
this.SetupDefaultBehaviors(PlatformID.Win32NT);
await executor.InitializeAsync(EventContext.None, CancellationToken.None);
}
iprashantp marked this conversation as resolved.
Show resolved Hide resolved
}

[Test]
iprashantp marked this conversation as resolved.
Show resolved Hide resolved
public async Task ApacheBenchExecutorExecutesInstallCommandWhenStateNotInitialized()
{
this.SetupDefaultBehaviors(PlatformID.Win32NT, Architecture.X64);
bool isCommandExecuted = false;
this.fixture.StateManager.OnGetState()
iprashantp marked this conversation as resolved.
Show resolved Hide resolved
.ReturnsAsync(JObject.FromObject(new ApacheBenchExecutor.ApacheBenchState()
{
ApacheBenchStateInitialized = false,
}));
this.fixture.StateManager.OnSaveState()
.Callback<string, JObject, CancellationToken, IAsyncPolicy>((stateId, state, token, retryPolicy) =>
{
Assert.IsNotNull(state);
});
this.fixture.ProcessManager.OnCreateProcess = (command, arguments, workingDir) =>
{
isCommandExecuted = true;
IProcessProxy process = this.fixture.ProcessManager.CreateProcess(command, arguments, workingDir);
process.StandardOutput.Append('a', 5);
return process;
};

using (var executor = new TestApacheBenchExecutor(this.fixture))
{
this.SetupDefaultBehaviors(PlatformID.Win32NT);
await executor.InitializeAsync(EventContext.None, CancellationToken.None);
}

Assert.IsTrue(isCommandExecuted);
}

[Test]
public async Task ApacheBenchExecutorDoesNotExecuteInstallCommandWhenStateIsInitialized()
{
this.SetupDefaultBehaviors(PlatformID.Win32NT, Architecture.X64);
bool isCommandExecuted = false;
this.fixture.StateManager.OnGetState()
.ReturnsAsync(JObject.FromObject(new ApacheBenchExecutor.ApacheBenchState()
{
ApacheBenchStateInitialized = true,
}));
this.fixture.StateManager.OnSaveState()
.Callback<string, JObject, CancellationToken, IAsyncPolicy>((stateId, state, token, retryPolicy) =>
{
Assert.IsNotNull(state);
});
this.fixture.ProcessManager.OnCreateProcess = (command, arguments, workingDir) =>
{
isCommandExecuted = true;
IProcessProxy process = this.fixture.ProcessManager.CreateProcess(command, arguments, workingDir);
process.StandardOutput.Append('a', 5);
return process;
};

using (var executor = new TestApacheBenchExecutor(this.fixture))
{
this.SetupDefaultBehaviors(PlatformID.Win32NT);
await executor.InitializeAsync(EventContext.None, CancellationToken.None);
}

Assert.IsFalse(isCommandExecuted);
}

[Test]
[TestCase(PlatformID.Unix, "ufw allow 'Apache'")]
public async Task ApacheBenchExecutorExecutesTheExpectedApacheBenchCommand(PlatformID platform, string expectedCommand)
{

this.SetupDefaultBehaviors(platform);
this.fixture.ProcessManager.OnCreateProcess = (command, arguments, workingDir) =>
{
string currentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string resultsPath = Path.Combine(currentDirectory, "Examples", "ApacheBench", "ApacheBenchResultsExample.txt");
string results = File.ReadAllText(resultsPath);
IProcessProxy process = new InMemoryProcess
{
StartInfo = new ProcessStartInfo
{
FileName = command,
Arguments = arguments,
WorkingDirectory = workingDir
}
};
process.StandardOutput.Append(results);
return process;
};
using (var executor = new TestApacheBenchExecutor(this.fixture))
{
await executor.ExecuteAsync(CancellationToken.None)
.ConfigureAwait(false);

Assert.IsTrue(this.fixture.ProcessManager.CommandsExecuted(expectedCommand));
}
}
private void SetupDefaultBehaviors(PlatformID platform = PlatformID.Unix, Architecture architecture = Architecture.X64)
{
this.fixture = new MockFixture();
this.fixture.Setup(platform, architecture);

string workloadName = "apachehttpserver";
this.fixture.Parameters.AddRange(new Dictionary<string, IConvertible>
{
{ nameof(Example2WorkloadExecutor.PackageName), workloadName },
iprashantp marked this conversation as resolved.
Show resolved Hide resolved
{ nameof(Example2WorkloadExecutor.CommandLine), "Run" },
{ nameof(Example2WorkloadExecutor.TestName), "ExampleTest" }
});

this.mockWorkloadPackage = new DependencyPath(
workloadName,
this.fixture.PlatformSpecifics.GetPackagePath(workloadName));
this.fixture.PackageManager.OnGetPackage()
.Callback<string, CancellationToken>((packageName, token) => Assert.AreEqual(packageName, "apachehttpserver"))
.ReturnsAsync(this.mockWorkloadPackage);
this.fixture.File.Setup(file => file.Exists(It.IsAny<string>()))
.Returns(true);
this.fixture.File.Setup(file => file.ReadAllTextAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
.ReturnsAsync("text");
iprashantp marked this conversation as resolved.
Show resolved Hide resolved
this.fixture.File.Setup(file => file.WriteAllTextAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
.Callback<string, string, CancellationToken>((path, content, token) =>
{
Assert.AreEqual(content, "text");
});

// Profile parameters.
this.fixture.Parameters = new Dictionary<string, IConvertible>
{
{ "CommandArguments", "-k -n 100 -c 100 http://localhost:80/" },
{ "PackageName", "apachehttpserver" },
{ "CommandLine", "" },
{ "Scenario", "ApacheBench_N50000_C10" },
};
}
private class TestApacheBenchExecutor : ApacheBenchExecutor
{
public TestApacheBenchExecutor(MockFixture fixture)
: base(fixture.Dependencies, fixture.Parameters)
{
}

public new Task InitializeAsync(EventContext telemetryContext, CancellationToken cancellationToken)
{
return base.InitializeAsync(telemetryContext, cancellationToken);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
namespace VirtualClient.Actions.ApacheBench
{
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

public class ApacheBenchMetricsParserTests
{
private string rawText;
private ApacheBenchMetricsParser testParser;

[SetUp]
public void Setup()
{
string workingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string outputPath = Path.Combine(workingDirectory, @"Examples\ApacheBench\ApacheBenchResultsExample.txt");
this.rawText = File.ReadAllText(outputPath);
this.testParser = new ApacheBenchMetricsParser(this.rawText);
}

[Test]
public void ApacheBenchMetricsParserParsesAsExpected()
{
this.testParser.Parse();
Assert.IsNotNull(this.testParser.Sections["Metrics"]);
}

[Test]
public void ApacheBenchMetricsParserParsesInputAsExpected()
{
this.testParser.Parse();
string metricsInput = this.testParser.Sections["Metrics"];
Assert.IsNotNull(metricsInput);

Assert.IsTrue(metricsInput.Contains("Total requests"));
iprashantp marked this conversation as resolved.
Show resolved Hide resolved
Assert.IsTrue(metricsInput.Contains("Total time (seconds)"));
Assert.IsTrue(metricsInput.Contains("Total failed requests"));
Assert.IsTrue(metricsInput.Contains("Total requests (per second)"));
Assert.IsTrue(metricsInput.Contains("Total time (milliseconds) per request"));
Assert.IsTrue(metricsInput.Contains("Total data transferred (bytes)"));
Assert.IsTrue(metricsInput.Contains("Data transfer rate (kilo bytes per second)"));
}

[Test]
public void ApacheBenchResultsParserThrowsWhenInvalidResultsAreProvided()
{
string workingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string outputPath = Path.Combine(workingDirectory, @"Examples\ApacheBench\ApacheBenchResultsInvalidExample.txt");
this.rawText = File.ReadAllText(outputPath);
this.testParser = new ApacheBenchMetricsParser(this.rawText);
Assert.Throws<WorkloadException>(() => this.testParser.Parse());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://localhost:80/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking www.holisticseo.digital (be patient).....done


Server Software: cloudflare
Server Hostname: www.holisticseo.digital
Server Port: 80

Document Path: /
Document Length: 0 bytes

Concurrency Level: 100
Time taken for tests: 0.578 seconds
Complete requests: 100
Failed requests: 0
Non-2xx responses: 100
Keep-Alive requests: 0
Total transferred: 65006 bytes
HTML transferred: 0 bytes
Requests per second: 172.97 [#/sec] (mean)
Time per request: 578.124 [ms] (mean)
Time per request: 5.781 [ms] (mean, across all concurrent requests)
Transfer rate: 109.81 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 5 7.5 0 16
Processing: 16 268 155.8 266 547
Waiting: 0 263 155.6 266 531
Total: 16 274 156.0 281 562

Percentage of the requests served within a certain time (ms)
50% 281
66% 359
75% 406
80% 437
90% 484
95% 516
98% 531
99% 562
100% 562 (longest request)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
This is ApacheBench, Version 2.3 <$Revision: 1903618 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://localhost:80/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking www.holisticseo.digital (be patient).....done

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 5 7.5 0 16
Processing: 16 268 155.8 266 547
Waiting: 0 263 155.6 266 531
Total: 16 274 156.0 281 562

Percentage of the requests served within a certain time (ms)
50% 281
66% 359
75% 406
80% 437
90% 484
95% 516
98% 531
99% 562
100% 562 (longest request)

No fvModels present
No fvConstraints present

Starting time loop

Time = 1

smoothSolver: Solving for Ux, Initial residual = 1, Final residual = 0.0611362, No Iterations 2
iprashantp marked this conversation as resolved.
Show resolved Hide resolved
smoothSolver: Solving for Uy, Initial residual = 1, Final residual = 0.0585177, No Iterations 2
GAMG: Solving for p, Initial residual = 1, Final residual = 0.0796943, No Iterations 9
time step continuity errors : sum local = 0.00025243, global = -8.28823e-05, cumulative = -8.28823e-05
smoothSolver: Solving for nuTilda, Initial residual = 1, Final residual = 0.0447475, No Iterations 2
ExecutionTime = 0.23 s ClockTime = 0 s
Loading