opentelemetry-dotnet-instru.../test/integration-tests/IntegrationTests.Helpers/TestHelper.cs

154 lines
6.9 KiB
C#

using System;
using System.Diagnostics;
using System.IO;
using DotNet.Testcontainers.Containers.Builders;
using DotNet.Testcontainers.Containers.Modules;
using DotNet.Testcontainers.Containers.OutputConsumers;
using DotNet.Testcontainers.Containers.WaitStrategies;
using FluentAssertions;
using IntegrationTests.Helpers.Models;
using Xunit.Abstractions;
namespace IntegrationTests.Helpers
{
public abstract class TestHelper
{
// Warning: Long timeouts can cause integer overflow!
private static readonly TimeSpan DefaultProcessTimeout = TimeSpan.FromMinutes(5);
protected TestHelper(string sampleAppName, ITestOutputHelper output)
: this(new EnvironmentHelper(sampleAppName, typeof(TestHelper), output), output)
{
}
protected TestHelper(EnvironmentHelper environmentHelper, ITestOutputHelper output)
{
EnvironmentHelper = environmentHelper;
Output = output;
Output.WriteLine($"Platform: {EnvironmentTools.GetPlatform()}");
Output.WriteLine($"Configuration: {EnvironmentTools.GetBuildConfiguration()}");
Output.WriteLine($"TargetFramework: {EnvironmentHelper.GetTargetFramework()}");
Output.WriteLine($".NET Core: {EnvironmentHelper.IsCoreClr()}");
Output.WriteLine($"Profiler DLL: {EnvironmentHelper.GetProfilerPath()}");
}
protected EnvironmentHelper EnvironmentHelper { get; }
protected ITestOutputHelper Output { get; }
public Container StartContainer(int traceAgentPort, int webPort)
{
// get path to sample app that the profiler will attach to
string sampleName = $"samples-{EnvironmentHelper.SampleName.ToLowerInvariant()}";
var waitOS = EnvironmentTools.IsWindows()
? Wait.ForWindowsContainer()
: Wait.ForUnixContainer();
string agentBaseUrl = $"http://{DockerNetworkHelper.IntegrationTestsGateway}:{traceAgentPort}";
string healthCheckEndpoint = $"{agentBaseUrl}/health-check";
string zipkinEndpoint = $"{agentBaseUrl}/api/v2/spans";
string networkName = DockerNetworkHelper.IntegrationTestsNetworkName;
string networkId = DockerNetworkHelper.SetupIntegrationTestsNetwork();
Output.WriteLine($"Zipkin Endpoint: {zipkinEndpoint}");
string logPath = EnvironmentHelper.IsRunningOnCI()
? Path.Combine(Environment.GetEnvironmentVariable("GITHUB_WORKSPACE"), "build_data", "profiler-logs")
: Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), @"OpenTelemetry .NET AutoInstrumentation", "logs");
Directory.CreateDirectory(logPath);
Output.WriteLine("Collecting docker logs to: " + logPath);
var builder = new TestcontainersBuilder<TestcontainersContainer>()
.WithImage(sampleName)
.WithCleanUp(cleanUp: true)
.WithOutputConsumer(Consume.RedirectStdoutAndStderrToConsole())
.WithName($"{sampleName}-{traceAgentPort}-{webPort}")
.WithNetwork(networkId, networkName)
.WithPortBinding(webPort, 80)
.WithEnvironment("OTEL_EXPORTER_ZIPKIN_ENDPOINT", zipkinEndpoint)
.WithMount(logPath, "c:/inetpub/wwwroot/logs")
.WithMount(EnvironmentHelper.GetNukeBuildOutput(), "c:/opentelemetry");
var container = builder.Build();
var wasStarted = container.StartAsync().Wait(TimeSpan.FromMinutes(5));
wasStarted.Should().BeTrue($"Container based on {sampleName} has to be operational for the test.");
Output.WriteLine($"Container was started successfully.");
PowershellHelper.RunCommand($"docker exec {container.Name} curl -v {healthCheckEndpoint}", Output);
var (standardOutput, _) = PowershellHelper.RunCommand($"Write-Host (Test-NetConnection -ComputerName 'localhost' -Port {webPort}).TcpTestSucceeded", Output);
standardOutput.Should().Contain("True", $"Test connection to the port number {webPort} failed. On this port container service should be available.");
return new Container(container);
}
public Process StartSample(int traceAgentPort, string arguments, string packageVersion, int aspNetCorePort, string framework = "", bool enableStartupHook = true)
{
// get path to sample app that the profiler will attach to
string sampleAppPath = EnvironmentHelper.GetSampleApplicationPath(packageVersion, framework);
if (!File.Exists(sampleAppPath))
{
throw new Exception($"application not found: {sampleAppPath}");
}
Output.WriteLine($"Starting Application: {sampleAppPath}");
var executable = EnvironmentHelper.IsCoreClr() ? EnvironmentHelper.GetSampleExecutionSource() : sampleAppPath;
var args = EnvironmentHelper.IsCoreClr() ? $"{sampleAppPath} {arguments ?? string.Empty}" : arguments;
return InstrumentedProcessHelper.StartInstrumentedProcess(
executable,
EnvironmentHelper,
args,
traceAgentPort: traceAgentPort,
aspNetCorePort: aspNetCorePort,
processToProfile: executable,
enableStartupHook: enableStartupHook);
}
public ProcessResult RunSampleAndWaitForExit(int traceAgentPort, string arguments = null, string packageVersion = "", string framework = "", int aspNetCorePort = 5000, bool enableStartupHook = true)
{
var process = StartSample(traceAgentPort, arguments, packageVersion, aspNetCorePort: aspNetCorePort, framework: framework, enableStartupHook: enableStartupHook);
var name = process.ProcessName;
using var helper = new ProcessHelper(process);
bool processTimeout = !process.WaitForExit((int)DefaultProcessTimeout.TotalMilliseconds);
if (processTimeout)
{
process.Kill();
}
var exitCode = process.ExitCode;
Output.WriteLine($"ProcessName: " + name);
Output.WriteLine($"ProcessId: " + process.Id);
Output.WriteLine($"Exit Code: " + exitCode);
Output.WriteResult(helper);
if (processTimeout)
{
throw new TimeoutException($"{name} ({process.Id}) did not exit within {DefaultProcessTimeout.TotalSeconds} sec");
}
return new ProcessResult(process, helper.StandardOutput, helper.ErrorOutput, exitCode);
}
protected void EnableDebugMode()
{
EnvironmentHelper.DebugModeEnabled = true;
}
protected void SetEnvironmentVariable(string key, string value)
{
EnvironmentHelper.CustomEnvironmentVariables.Add(key, value);
}
}
}