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 11 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,328 @@
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);

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
},
ExitTime = DateTime.Now.AddSeconds(5)
};
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));
}
}

[Test]
[TestCase(PlatformID.Unix, "40000", "20")]
[TestCase(PlatformID.Unix, "25000", "5")]
public async Task ApacheBenchExecutorExecutesWorkloadForDifferentInputsAndGenerateMetricsForLinux(PlatformID platform, string noOfRequests, string noOfConcurrentRequests)
{

this.SetupDefaultBehaviors(platform);

this.fixture.Parameters = new Dictionary<string, IConvertible>
{
{ "PackageName", "apachehttpserver" },
{ "Scenario", "ExecuteApacheBenchBenchmark" },
{ "NoOfRequests", noOfRequests },
{ "NoOfConcurrentRequests", noOfConcurrentRequests },
};

bool allowPortCommandExecuted = false;
bool startServerCommandExecuted = false;
bool benchmarkCommandExecuted = false;

this.fixture.ProcessManager.OnCreateProcess = (command, arguments, workingDir) =>
{
if (arguments.Equals("ufw allow 'Apache'"))
{
allowPortCommandExecuted = true;
}
else if (arguments.Equals("systemctl start apache2"))
{
startServerCommandExecuted = true;
}
else if (arguments.Equals($"/usr/bin/ab -k -n {noOfRequests} -c {noOfConcurrentRequests} http://localhost:80/"))
{
benchmarkCommandExecuted = true;
}

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
},
ExitTime = DateTime.Now.AddSeconds(5)
};
process.StandardOutput.Append(results);
return process;
};
using (var executor = new TestApacheBenchExecutor(this.fixture))
{
await executor.ExecuteAsync(CancellationToken.None)
.ConfigureAwait(false);

Assert.IsTrue(allowPortCommandExecuted);
Assert.IsTrue(startServerCommandExecuted);
Assert.IsTrue(benchmarkCommandExecuted);
}
}

[Test]
[TestCase(PlatformID.Win32NT, "40000", "20")]
[TestCase(PlatformID.Win32NT, "25000", "5")]
public async Task ApacheBenchExecutorExecutesWorkloadForDifferentInputsAndGenerateMetricsForWindows(PlatformID platform, string noOfRequests, string noOfConcurrentRequests)
{

this.SetupDefaultBehaviors(platform);

this.fixture.Parameters = new Dictionary<string, IConvertible>
{
{ "PackageName", "apachehttpserver" },
{ "Scenario", "ExecuteApacheBenchBenchmark" },
{ "NoOfRequests", noOfRequests },
{ "NoOfConcurrentRequests", noOfConcurrentRequests },
};

bool startServerCommandExecuted = false;
bool benchmarkCommandExecuted = false;

this.fixture.ProcessManager.OnCreateProcess = (command, arguments, workingDir) =>
{
if (arguments.Equals("-k install"))
{
startServerCommandExecuted = true;
}
else if (arguments.Equals($"-k -n {noOfRequests} -c {noOfConcurrentRequests} http://localhost:80/"))
{
benchmarkCommandExecuted = true;
}

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
},
ExitTime = DateTime.Now.AddSeconds(5)
};
process.StandardOutput.Append(results);
return process;
};
using (var executor = new TestApacheBenchExecutor(this.fixture))
{
await executor.ExecuteAsync(CancellationToken.None)
.ConfigureAwait(false);

Assert.IsTrue(startServerCommandExecuted);
Assert.IsTrue(benchmarkCommandExecuted);
}
}

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>()))
.Returns(Task.CompletedTask);

// Profile parameters.
this.fixture.Parameters = new Dictionary<string, IConvertible>
{
{ "PackageName", "apachehttpserver" },
{ "Scenario", "ExecuteApacheBenchBenchmark" },
};
}
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());
}
}
}
Loading