From e71b22263a64ec041ae70265ff0cbf9514eff89e Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 15 Jan 2024 12:28:39 +0100 Subject: [PATCH 01/24] stage --- Elastic.OpenTelemetry.sln | 7 +++ .../Worker.cs | 49 +++++++++---------- tests/Directory.Build.props | 2 +- ...stic.OpenTelemetry.IntegrationTests.csproj | 15 ++++++ .../GlobalUsings.cs | 12 +++++ 5 files changed, 59 insertions(+), 26 deletions(-) create mode 100644 tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj create mode 100644 tests/Elastic.OpenTelemetry.IntegrationTests/GlobalUsings.cs diff --git a/Elastic.OpenTelemetry.sln b/Elastic.OpenTelemetry.sln index 18fbb65..cc8688e 100644 --- a/Elastic.OpenTelemetry.sln +++ b/Elastic.OpenTelemetry.sln @@ -32,6 +32,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.Elastic.OpenTelemet EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Elastic.OpenTelemetry.Worker", "examples\Example.Elastic.OpenTelemetry.Worker\Example.Elastic.OpenTelemetry.Worker.csproj", "{4377A059-16E0-4D5D-AC03-44C09BCE5BC4}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.OpenTelemetry.IntegrationTests", "tests\Elastic.OpenTelemetry.IntegrationTests\Elastic.OpenTelemetry.IntegrationTests.csproj", "{B970DBE1-6A04-4014-A285-6A9F36421025}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -70,6 +72,10 @@ Global {4377A059-16E0-4D5D-AC03-44C09BCE5BC4}.Debug|Any CPU.Build.0 = Debug|Any CPU {4377A059-16E0-4D5D-AC03-44C09BCE5BC4}.Release|Any CPU.ActiveCfg = Release|Any CPU {4377A059-16E0-4D5D-AC03-44C09BCE5BC4}.Release|Any CPU.Build.0 = Release|Any CPU + {B970DBE1-6A04-4014-A285-6A9F36421025}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B970DBE1-6A04-4014-A285-6A9F36421025}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B970DBE1-6A04-4014-A285-6A9F36421025}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B970DBE1-6A04-4014-A285-6A9F36421025}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -80,6 +86,7 @@ Global {22BF9223-3A6D-4197-8527-3E4E43A98A81} = {AAD39891-0B70-47FA-A212-43E1AAE5DF56} {EC81FA30-C765-4F04-8679-86F16DA3CC65} = {4E95C87B-655B-4BC3-8F2A-DF06B7AAB7E9} {4377A059-16E0-4D5D-AC03-44C09BCE5BC4} = {4E95C87B-655B-4BC3-8F2A-DF06B7AAB7E9} + {B970DBE1-6A04-4014-A285-6A9F36421025} = {AAD39891-0B70-47FA-A212-43E1AAE5DF56} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {573B2B5F-8CBB-4D52-A55A-4E65E282AAFB} diff --git a/examples/Example.Elastic.OpenTelemetry.Worker/Worker.cs b/examples/Example.Elastic.OpenTelemetry.Worker/Worker.cs index 9eee4f2..d36f378 100644 --- a/examples/Example.Elastic.OpenTelemetry.Worker/Worker.cs +++ b/examples/Example.Elastic.OpenTelemetry.Worker/Worker.cs @@ -3,40 +3,39 @@ // See the LICENSE file in the project root for more information using System.Diagnostics; -namespace Example.Elastic.OpenTelemetry.Worker +namespace Example.Elastic.OpenTelemetry.Worker; + +public class Worker : BackgroundService { - public class Worker : BackgroundService - { - private readonly ILogger _logger; + private readonly ILogger _logger; - private static readonly HttpClient HttpClient = new(); - private const string ActivitySourceName = "CustomActivitySource"; - private static readonly ActivitySource ActivitySource = new(ActivitySourceName, "1.0.0"); + private static readonly HttpClient HttpClient = new(); + private const string ActivitySourceName = "CustomActivitySource"; + private static readonly ActivitySource ActivitySource = new(ActivitySourceName, "1.0.0"); - public Worker(ILogger logger) => _logger = logger; + public Worker(ILogger logger) => _logger = logger; - protected override async Task ExecuteAsync(CancellationToken stoppingToken) + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) { - while (!stoppingToken.IsCancellationRequested) - { - _logger.LogInformation("Sending request... "); + _logger.LogInformation("Sending request... "); - using (var activity = ActivitySource.StartActivity("DoingStuff", ActivityKind.Internal)) - { - activity?.SetTag("CustomTag", "TagValue"); - - await Task.Delay(100, stoppingToken); - var response = await HttpClient.GetAsync("http://elastic.co", stoppingToken); - await Task.Delay(50, stoppingToken); + using (var activity = ActivitySource.StartActivity("DoingStuff", ActivityKind.Internal)) + { + activity?.SetTag("CustomTag", "TagValue"); - if (response.StatusCode == System.Net.HttpStatusCode.OK) - activity?.SetStatus(ActivityStatusCode.Ok); - else - activity?.SetStatus(ActivityStatusCode.Error); - } + await Task.Delay(100, stoppingToken); + var response = await HttpClient.GetAsync("http://elastic.co", stoppingToken); + await Task.Delay(50, stoppingToken); - await Task.Delay(5000, stoppingToken); + if (response.StatusCode == System.Net.HttpStatusCode.OK) + activity?.SetStatus(ActivityStatusCode.Ok); + else + activity?.SetStatus(ActivityStatusCode.Error); } + + await Task.Delay(5000, stoppingToken); } } } diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 9bf0584..e207e28 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -28,7 +28,7 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj b/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj new file mode 100644 index 0000000..0403db2 --- /dev/null +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj @@ -0,0 +1,15 @@ + + + + net8.0 + enable + enable + false + true + + + + + + + diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalUsings.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalUsings.cs new file mode 100644 index 0000000..5faef26 --- /dev/null +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalUsings.cs @@ -0,0 +1,12 @@ +// Licensed to Elasticsearch B.V under +// one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +global using Xunit; +global using System.Diagnostics; +global using FluentAssertions; + +using Xunit.Extensions.AssemblyFixture; + +[assembly: TestFramework(AssemblyFixtureFramework.TypeName, AssemblyFixtureFramework.AssemblyName)] From 0fa2a71bada0ff1eaecee8692f9a4e4a7c91111a Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Thu, 18 Jan 2024 12:16:38 +0100 Subject: [PATCH 02/24] stage --- build/build.fsproj | 54 ++++++++------- .../Program.cs | 10 ++- .../Properties/launchSettings.json | 4 +- .../DistributedApplicationFixture.cs | 68 +++++++++++++++++++ ...stic.OpenTelemetry.IntegrationTests.csproj | 4 +- .../EndToEndTests.cs | 15 ++++ 6 files changed, 123 insertions(+), 32 deletions(-) create mode 100644 tests/Elastic.OpenTelemetry.IntegrationTests/DistributedApplicationFixture.cs create mode 100644 tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs diff --git a/build/build.fsproj b/build/build.fsproj index 6a4e88d..c4d18d0 100644 --- a/build/build.fsproj +++ b/build/build.fsproj @@ -1,31 +1,33 @@ - - net8.0 - Exe - $(NoWarn);NU1701 - false - - - - - - - + + net8.0 + Exe + $(NoWarn);NU1701 + false + + + + + + + + + - - - + + + - - - - - - - - - - - + + + + + + + + + + + diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Program.cs b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Program.cs index 8120641..8d13536 100644 --- a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Program.cs +++ b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Program.cs @@ -1,6 +1,8 @@ -// Licensed to Elasticsearch B.V under one or more agreements. +// Licensed to Elasticsearch B.V under +// one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information + using Example.Elastic.OpenTelemetry.AspNetCore.Controllers; using OpenTelemetry.Trace; @@ -15,6 +17,8 @@ var app = builder.Build(); +app.Logger.LogInformation("Process Id {ProcesId}", Environment.ProcessId); + // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { @@ -31,7 +35,7 @@ app.UseAuthorization(); app.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); + "default", + "{controller=Home}/{action=Index}/{id?}"); app.Run(); diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json index dfcd958..96dfc62 100644 --- a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json +++ b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json @@ -13,7 +13,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "http://localhost:5245", + "applicationUrl": "http://localhost:5247", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } @@ -22,7 +22,7 @@ "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "https://localhost:7295;http://localhost:5245", + "applicationUrl": "https://localhost:7295;http://localhost:5247", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development", "OTEL_RESOURCE_ATTRIBUTES": "service.name=AspNetCoreApp,service.version=1.0.0,deployment.environment=development" diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedApplicationFixture.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedApplicationFixture.cs new file mode 100644 index 0000000..ec6de8e --- /dev/null +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedApplicationFixture.cs @@ -0,0 +1,68 @@ +// Licensed to Elasticsearch B.V under +// one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +using System.Reflection; +using System.Text.RegularExpressions; +using ProcNet; + +namespace Elastic.OpenTelemetry.IntegrationTests; + +public class DistributedApplicationFixture : IDisposable +{ + private readonly AspNetCoreExampleApplication _aspNetApplication; + + public DistributedApplicationFixture() => _aspNetApplication = new AspNetCoreExampleApplication(); + + public bool Started => _aspNetApplication.ProcessId.HasValue; + + public void Dispose() => _aspNetApplication.Dispose(); +} + +public class AspNetCoreExampleApplication : IDisposable +{ + private static readonly Regex ProcessIdMatch = new(@"^\s*Process Id (?\d+)"); + private readonly LongRunningApplicationSubscription _app; + + public AspNetCoreExampleApplication() + { + var args = CreateStartArgs(); + _app = Proc.StartLongRunning(args, TimeSpan.FromSeconds(10)); + } + + public int? ProcessId { get; private set; } + + private LongRunningArguments CreateStartArgs() + { + var start = new FileInfo(Assembly.GetExecutingAssembly().Location); + var root = start.Directory; + while (root != null && root.GetFiles("*.sln").Length == 0) + root = root.Parent; + + if (root == null) + throw new Exception($"Could not locate root starting from {start}"); + + var project = Path.Combine(root.FullName, "examples", "Example.Elastic.OpenTelemetry.AspNetCore"); + + return new("dotnet", "run", "--project", project) + { + StartedConfirmationHandler = (l) => + { + var processIdMatch = ProcessIdMatch.Match(l.Line); + if (processIdMatch.Success) + ProcessId = int.Parse(processIdMatch.Groups["processid"].Value); + + return l.Line.StartsWith(" Application started."); + } + }; + } + + public void Dispose() + { + var pid = _app.Process.ProcessId; + if (ProcessId.HasValue) + _app.SendControlC(ProcessId.Value); + _app.Dispose(); + } +} diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj b/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj index 0403db2..e1c8a99 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj @@ -6,10 +6,12 @@ enable false true + xUnit1041 - + + diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs new file mode 100644 index 0000000..e4acd18 --- /dev/null +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs @@ -0,0 +1,15 @@ +// Licensed to Elasticsearch B.V under +// one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +using Xunit.Extensions.AssemblyFixture; + +namespace Elastic.OpenTelemetry.IntegrationTests; + +public class EndToEndTests(DistributedApplicationFixture fixture) + : IAssemblyFixture +{ + [Fact] + public void Test() => fixture.Started.Should().BeTrue(); +} From ea4f577ce3ac944cc45cfa48166a862a07d6da75 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 23 Jan 2024 14:16:40 +0100 Subject: [PATCH 03/24] E2E controlled startup and traffic simulators --- .../Controllers/E2EController.cs | 43 +++++++++ ...le.Elastic.OpenTelemetry.AspNetCore.csproj | 6 +- .../Properties/launchSettings.json | 10 -- .../Views/E2E/Index.cshtml | 8 ++ .../appsettings.Development.json | 8 -- .../appsettings.json | 2 +- .../DistributedApplicationFixture.cs | 68 ------------- .../DistributedApplicationFixture.cs | 89 +++++++++++++++++ .../DotNetRunApplication.cs | 95 +++++++++++++++++++ ...stic.OpenTelemetry.IntegrationTests.csproj | 4 + .../EndToEndTests.cs | 14 ++- 11 files changed, 256 insertions(+), 91 deletions(-) create mode 100644 examples/Example.Elastic.OpenTelemetry.AspNetCore/Controllers/E2EController.cs create mode 100644 examples/Example.Elastic.OpenTelemetry.AspNetCore/Views/E2E/Index.cshtml delete mode 100644 examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.Development.json delete mode 100644 tests/Elastic.OpenTelemetry.IntegrationTests/DistributedApplicationFixture.cs create mode 100644 tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs create mode 100644 tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Controllers/E2EController.cs b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Controllers/E2EController.cs new file mode 100644 index 0000000..4816374 --- /dev/null +++ b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Controllers/E2EController.cs @@ -0,0 +1,43 @@ +// Licensed to Elasticsearch B.V under +// one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +using System.Diagnostics; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Mvc; + +namespace Example.Elastic.OpenTelemetry.AspNetCore.Controllers; + +public class E2EController : Controller +{ + public async Task Index() + { + var activityFeature = HttpContext.Features.Get(); + var activity = activityFeature?.Activity; + activity?.AddBaggage("operation.success", true.ToString()); + activity?.SetTag("CustomTag", "TagValue"); + + await Task.Delay(100); + + using var childActivity = activity?.Source.StartActivity("childActivity", ActivityKind.Internal); + await Task.Delay(200); + + return View(); + } + + public async Task Fail() + { + var activityFeature = HttpContext.Features.Get(); + var activity = activityFeature?.Activity; + activity?.AddBaggage("operation.success", false.ToString()); + activity?.SetTag("CustomTag", "TagValue"); + + await Task.Delay(100); + + using var childActivity = activity?.Source.StartActivity("childActivity", ActivityKind.Internal); + await Task.Delay(200); + + throw new Exception("Random failure"); + } +} diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Example.Elastic.OpenTelemetry.AspNetCore.csproj b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Example.Elastic.OpenTelemetry.AspNetCore.csproj index e8d42a1..d9cba6c 100644 --- a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Example.Elastic.OpenTelemetry.AspNetCore.csproj +++ b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Example.Elastic.OpenTelemetry.AspNetCore.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -7,11 +7,11 @@ - + - + diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json index 96dfc62..3cf6fca 100644 --- a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json +++ b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json @@ -18,16 +18,6 @@ "ASPNETCORE_ENVIRONMENT": "Development" } }, - "https": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "applicationUrl": "https://localhost:7295;http://localhost:5247", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development", - "OTEL_RESOURCE_ATTRIBUTES": "service.name=AspNetCoreApp,service.version=1.0.0,deployment.environment=development" - } - }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Views/E2E/Index.cshtml b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Views/E2E/Index.cshtml new file mode 100644 index 0000000..bcfd79a --- /dev/null +++ b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Views/E2E/Index.cshtml @@ -0,0 +1,8 @@ +@{ + ViewData["Title"] = "Home Page"; +} + +
+

Welcome

+

Learn about building Web apps with ASP.NET Core.

+
diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.Development.json b/examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.Development.json deleted file mode 100644 index 0c208ae..0000000 --- a/examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.Development.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - } -} diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.json b/examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.json index f3af4af..6314868 100644 --- a/examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.json +++ b/examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.json @@ -12,5 +12,5 @@ } }, "AllowedHosts": "*", - "ServiceName": "elastic-otel-test-aspnetcore" + "ServiceName": "elastic-otel-example-aspnetcore" } diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedApplicationFixture.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedApplicationFixture.cs deleted file mode 100644 index ec6de8e..0000000 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedApplicationFixture.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Licensed to Elasticsearch B.V under -// one or more agreements. -// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. -// See the LICENSE file in the project root for more information - -using System.Reflection; -using System.Text.RegularExpressions; -using ProcNet; - -namespace Elastic.OpenTelemetry.IntegrationTests; - -public class DistributedApplicationFixture : IDisposable -{ - private readonly AspNetCoreExampleApplication _aspNetApplication; - - public DistributedApplicationFixture() => _aspNetApplication = new AspNetCoreExampleApplication(); - - public bool Started => _aspNetApplication.ProcessId.HasValue; - - public void Dispose() => _aspNetApplication.Dispose(); -} - -public class AspNetCoreExampleApplication : IDisposable -{ - private static readonly Regex ProcessIdMatch = new(@"^\s*Process Id (?\d+)"); - private readonly LongRunningApplicationSubscription _app; - - public AspNetCoreExampleApplication() - { - var args = CreateStartArgs(); - _app = Proc.StartLongRunning(args, TimeSpan.FromSeconds(10)); - } - - public int? ProcessId { get; private set; } - - private LongRunningArguments CreateStartArgs() - { - var start = new FileInfo(Assembly.GetExecutingAssembly().Location); - var root = start.Directory; - while (root != null && root.GetFiles("*.sln").Length == 0) - root = root.Parent; - - if (root == null) - throw new Exception($"Could not locate root starting from {start}"); - - var project = Path.Combine(root.FullName, "examples", "Example.Elastic.OpenTelemetry.AspNetCore"); - - return new("dotnet", "run", "--project", project) - { - StartedConfirmationHandler = (l) => - { - var processIdMatch = ProcessIdMatch.Match(l.Line); - if (processIdMatch.Success) - ProcessId = int.Parse(processIdMatch.Groups["processid"].Value); - - return l.Line.StartsWith(" Application started."); - } - }; - } - - public void Dispose() - { - var pid = _app.Process.ProcessId; - if (ProcessId.HasValue) - _app.SendControlC(ProcessId.Value); - _app.Dispose(); - } -} diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs new file mode 100644 index 0000000..d2cb277 --- /dev/null +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs @@ -0,0 +1,89 @@ +// Licensed to Elasticsearch B.V under +// one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +using System.Globalization; +using System.Net; +using System.Security.Cryptography; +using System.Text; + +namespace Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; + +public class DistributedApplicationFixture : IDisposable, IAsyncLifetime +{ + private readonly AspNetCoreExampleApplication _aspNetApplication; + private readonly ITrafficSimulator[] _trafficSimulators; + + public DistributedApplicationFixture() + { + ServiceName = $"dotnet-e2e-{ShaForCurrentTicks()}"; + HttpClient = new HttpClient { BaseAddress = new Uri("http://localhost:5247") }; + _aspNetApplication = new AspNetCoreExampleApplication(ServiceName); + _trafficSimulators = + [ + new DefaultTrafficSimulator() + ]; + } + + public HttpClient HttpClient { get; } + + public string ServiceName { get; } + + public bool Started => _aspNetApplication.ProcessId.HasValue; + + private static string ShaForCurrentTicks() + { + var buffer = Encoding.UTF8.GetBytes(DateTime.UtcNow.Ticks.ToString(DateTimeFormatInfo.InvariantInfo)); + + return BitConverter.ToString(SHA1.Create().ComputeHash(buffer)) + .Replace("-", "") + .ToLowerInvariant() + .Substring(0, 12); + } + + public void Dispose() + { + _aspNetApplication.Dispose(); + HttpClient.Dispose(); + } + + public async Task InitializeAsync() + { + foreach (var trafficSimulator in _trafficSimulators) + await trafficSimulator.Start(ServiceName, HttpClient); + + // TODO query OTEL_BSP_SCHEDULE_DELAY? + await Task.Delay(5000); + + // Stateless refresh + await Task.Delay(TimeSpan.FromSeconds(10)); + } + + public Task DisposeAsync() + { + Dispose(); + return Task.CompletedTask; + } +} + +public class AspNetCoreExampleApplication(string serviceName) + : DotNetRunApplication(serviceName, "Example.Elastic.OpenTelemetry.AspNetCore"); + +public interface ITrafficSimulator +{ + Task Start(string serviceName, HttpClient client); +} + +public class DefaultTrafficSimulator : ITrafficSimulator +{ + public async Task Start(string serviceName, HttpClient client) + { + for (var i = 0; i < 10; i++) + { + var get = await client.GetAsync("e2e"); + get.StatusCode.Should().Be(HttpStatusCode.OK); + var response = await get.Content.ReadAsStringAsync(); + } + } +} diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs new file mode 100644 index 0000000..61503fb --- /dev/null +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs @@ -0,0 +1,95 @@ +// Licensed to Elasticsearch B.V under +// one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +using System.Reflection; +using System.Text.RegularExpressions; +using Microsoft.Extensions.Configuration; +using ProcNet; + +namespace Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; + +public abstract class DotNetRunApplication +{ + private static readonly DirectoryInfo CurrentDirectory = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory!; + private static readonly Regex ProcessIdMatch = new(@"^\s*Process Id (?\d+)"); + private readonly LongRunningApplicationSubscription _app; + private readonly string _applicationName; + private readonly string _authorization; + private readonly string _endpoint; + private readonly string _serviceName; + + public DotNetRunApplication(string serviceName, string applicationName) + { + _serviceName = serviceName; + _applicationName = applicationName; + var args = CreateStartArgs(); + var configuration = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddUserSecrets() + .Build(); + _endpoint = configuration["E2E:Endpoint"]?.Trim() ?? string.Empty; + _authorization = configuration["E2E:Authorization"]?.Trim() ?? string.Empty; + + _app = Proc.StartLongRunning(args, TimeSpan.FromSeconds(10)); + } + + public int? ProcessId { get; private set; } + + protected virtual string[] GetArguments() => Array.Empty(); + + private DirectoryInfo GetSolutionRoot() + { + var root = CurrentDirectory; + while (root != null && root.GetFiles("*.sln").Length == 0) + root = root.Parent; + + if (root == null) + throw new Exception($"Could not locate root starting from {CurrentDirectory}"); + + return root; + } + + private LongRunningArguments CreateStartArgs() + { + var root = GetSolutionRoot(); + var project = Path.Combine(root.FullName, "examples", _applicationName); + + var arguments = new[] { "run", "--project", project }; + var applicationArguments = GetArguments(); + if (applicationArguments.Length > 0) + arguments = [..arguments, "--", ..applicationArguments]; + + return new("dotnet", arguments) + { + Environment = new Dictionary + { + { "OTEL_EXPORTER_OTLP_ENDPOINT", _endpoint }, + { "OTEL_EXPORTER_OTLP_HEADERS", _authorization }, + { "OTEL_METRICS_EXPORTER", "otlp" }, + { "OTEL_LOGS_EXPORTER", "otlp" }, + { "OTEL_BSP_SCHEDULE_DELAY", "1000" }, + { "OTEL_BSP_MAX_EXPORT_BATCH_SIZE", "10" }, + { "OTEL_RESOURCE_ATTRIBUTES", $"service.name={_serviceName},service.version=1.0,1,deployment.environment=e2e" }, + }, + StartedConfirmationHandler = (l) => + { + //Grab actual process id to send SIGINT to. + var processIdMatch = ProcessIdMatch.Match(l.Line); + if (processIdMatch.Success) + ProcessId = int.Parse(processIdMatch.Groups["processid"].Value); + + return l.Line.StartsWith(" Application started."); + } + }; + } + + public void Dispose() + { + var pid = _app.Process.ProcessId; + if (ProcessId.HasValue) + _app.SendControlC(ProcessId.Value); + _app.Dispose(); + } +} diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj b/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj index e1c8a99..a564a01 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj @@ -7,11 +7,15 @@ false true xUnit1041 + 588f828e-db42-4b45-9783-023f03243753 + + +
diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs index e4acd18..fa478e7 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs @@ -3,6 +3,8 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information +using System.Net; +using Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; using Xunit.Extensions.AssemblyFixture; namespace Elastic.OpenTelemetry.IntegrationTests; @@ -11,5 +13,15 @@ public class EndToEndTests(DistributedApplicationFixture fixture) : IAssemblyFixture { [Fact] - public void Test() => fixture.Started.Should().BeTrue(); + public async Task Test() + { + fixture.Started.Should().BeTrue(); + var http = new HttpClient(); + + var get = await http.GetAsync("http://localhost:5247/e2e"); + + get.StatusCode.Should().BeOneOf(HttpStatusCode.OK, HttpStatusCode.InternalServerError); + + var response = await get.Content.ReadAsStringAsync(); + } } From 83fa33c2138c0e663b2c7941d05de78eea06f11f Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 23 Jan 2024 16:33:16 +0100 Subject: [PATCH 04/24] setup to bootstrap UI tests to services overview page with current service listed --- .../DistributedApplicationFixture.cs | 63 +++++++++++++------ .../DotNetRunApplication.cs | 14 +++-- .../DistributedFixture/ITrafficSimulator.cs | 26 ++++++++ ...stic.OpenTelemetry.IntegrationTests.csproj | 2 + .../EndToEndTests.cs | 43 ++++++++++--- 5 files changed, 117 insertions(+), 31 deletions(-) create mode 100644 tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs index d2cb277..28e82bd 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs @@ -7,6 +7,8 @@ using System.Net; using System.Security.Cryptography; using System.Text; +using Microsoft.Extensions.Configuration; +using Microsoft.Playwright; namespace Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; @@ -19,13 +21,24 @@ public DistributedApplicationFixture() { ServiceName = $"dotnet-e2e-{ShaForCurrentTicks()}"; HttpClient = new HttpClient { BaseAddress = new Uri("http://localhost:5247") }; - _aspNetApplication = new AspNetCoreExampleApplication(ServiceName); + + var configuration = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddUserSecrets() + .Build(); + + _aspNetApplication = new AspNetCoreExampleApplication(ServiceName, configuration); _trafficSimulators = [ new DefaultTrafficSimulator() ]; + ApmUIContext = new ApmUIBrowserContext(configuration, ApmKibanaUrl); } + public ApmUIBrowserContext ApmUIContext { get; } + + public Uri ApmKibanaUrl => _aspNetApplication.ApmKibanaUrl; + public HttpClient HttpClient { get; } public string ServiceName { get; } @@ -57,33 +70,47 @@ public async Task InitializeAsync() await Task.Delay(5000); // Stateless refresh - await Task.Delay(TimeSpan.FromSeconds(10)); + //https://github.com/elastic/elasticsearch/blob/main/server/src/main/java/org/elasticsearch/index/IndexSettings.java#L286 + await Task.Delay(TimeSpan.FromSeconds(15)); + await ApmUIContext.InitializeAsync(); } - public Task DisposeAsync() + public async Task DisposeAsync() { Dispose(); - return Task.CompletedTask; + await ApmUIContext.DisposeAsync(); } } -public class AspNetCoreExampleApplication(string serviceName) - : DotNetRunApplication(serviceName, "Example.Elastic.OpenTelemetry.AspNetCore"); +public class AspNetCoreExampleApplication(string serviceName, IConfiguration configuration) + : DotNetRunApplication(serviceName, configuration, "Example.Elastic.OpenTelemetry.AspNetCore"); -public interface ITrafficSimulator -{ - Task Start(string serviceName, HttpClient client); -} -public class DefaultTrafficSimulator : ITrafficSimulator +public class ApmUIBrowserContext(IConfigurationRoot configuration, Uri kibanaUrl) : IAsyncLifetime { - public async Task Start(string serviceName, HttpClient client) + + public IPage Page { get; private set; } = null!; + public IBrowser Browser { get; private set; } = null!; + public IPlaywright HeadlessTester { get; private set; } = null!; + + public async Task InitializeAsync() + { + var username = configuration["E2E:BrowserEmail"]?.Trim() ?? string.Empty; + var password = configuration["E2E:BrowserPassword"]?.Trim() ?? string.Empty; + Program.Main(["install", "chromium"]); + HeadlessTester = await Playwright.CreateAsync(); + Browser = await HeadlessTester.Chromium.LaunchAsync(); + Page = await Browser.NewPageAsync(); + await Page.GotoAsync(kibanaUrl.ToString()); + + await Page.GetByRole(AriaRole.Textbox, new () { Name = "email" }).FillAsync(username); + await Page.GetByRole(AriaRole.Textbox, new () { Name = "password" }).FillAsync(password); + await Page.GetByRole(AriaRole.Button, new() { Name = "Log in" }).ClickAsync(); + } + + public async Task DisposeAsync() { - for (var i = 0; i < 10; i++) - { - var get = await client.GetAsync("e2e"); - get.StatusCode.Should().Be(HttpStatusCode.OK); - var response = await get.Content.ReadAsStringAsync(); - } + await Browser.DisposeAsync(); + HeadlessTester.Dispose(); } } diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs index 61503fb..0b22c77 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs @@ -20,21 +20,23 @@ public abstract class DotNetRunApplication private readonly string _endpoint; private readonly string _serviceName; - public DotNetRunApplication(string serviceName, string applicationName) + public DotNetRunApplication(string serviceName, IConfiguration configuration, string applicationName) { _serviceName = serviceName; _applicationName = applicationName; - var args = CreateStartArgs(); - var configuration = new ConfigurationBuilder() - .AddEnvironmentVariables() - .AddUserSecrets() - .Build(); _endpoint = configuration["E2E:Endpoint"]?.Trim() ?? string.Empty; _authorization = configuration["E2E:Authorization"]?.Trim() ?? string.Empty; + var args = CreateStartArgs(); + + var newBase = _endpoint.Replace(".apm.", ".kb."); + ApmKibanaUrl = new Uri(new Uri(newBase), "app/apm"); + _app = Proc.StartLongRunning(args, TimeSpan.FromSeconds(10)); } + public Uri ApmKibanaUrl { get; } + public int? ProcessId { get; private set; } protected virtual string[] GetArguments() => Array.Empty(); diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs new file mode 100644 index 0000000..4bdf2fd --- /dev/null +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs @@ -0,0 +1,26 @@ +// Licensed to Elasticsearch B.V under +// one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +using System.Net; + +namespace Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; + +public interface ITrafficSimulator +{ + Task Start(string serviceName, HttpClient client); +} + +public class DefaultTrafficSimulator : ITrafficSimulator +{ + public async Task Start(string serviceName, HttpClient client) + { + for (var i = 0; i < 10; i++) + { + var get = await client.GetAsync("e2e"); + get.StatusCode.Should().Be(HttpStatusCode.OK); + var response = await get.Content.ReadAsStringAsync(); + } + } +} diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj b/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj index a564a01..953fa48 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj @@ -11,7 +11,9 @@ + + diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs index fa478e7..5ff5f0f 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs @@ -3,25 +3,54 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information -using System.Net; using Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; +using Microsoft.Playwright; using Xunit.Extensions.AssemblyFixture; +using static Microsoft.Playwright.Assertions; namespace Elastic.OpenTelemetry.IntegrationTests; -public class EndToEndTests(DistributedApplicationFixture fixture) - : IAssemblyFixture +public class EndToEndTests(ITestOutputHelper output, DistributedApplicationFixture fixture) + : XunitContextBase(output), IAssemblyFixture, IAsyncLifetime { + public IPage Page => fixture.ApmUIContext.Page; + private string _testName = string.Empty; + [Fact] public async Task Test() { fixture.Started.Should().BeTrue(); - var http = new HttpClient(); - var get = await http.GetAsync("http://localhost:5247/e2e"); + Page.SetDefaultTimeout((float)TimeSpan.FromSeconds(20).TotalMilliseconds); + var servicesHeader = Page.GetByRole(AriaRole.Heading, new() { Name = "Services" }); + await servicesHeader.WaitForAsync(new () { State = WaitForSelectorState.Visible }); - get.StatusCode.Should().BeOneOf(HttpStatusCode.OK, HttpStatusCode.InternalServerError); + var serviceLink = Page.GetByRole(AriaRole.Link, new() { Name = fixture.ServiceName }); + await serviceLink.WaitForAsync(new () { State = WaitForSelectorState.Visible }); + Page.SetDefaultTimeout((float)TimeSpan.FromSeconds(5).TotalMilliseconds); - var response = await get.Content.ReadAsStringAsync(); + await Expect(Page.GetByRole(AriaRole.Link, new() { Name = "Get started" })).ToBeVisibleAsync(); } + + public async Task InitializeAsync() + { + _testName = XunitContext.Context.ClassName + "." + XunitContext.Context.Test.DisplayName; + await Page.Context.Tracing.StartAsync(new() + { + Title = _testName, + Screenshots = true, + Snapshots = true, + Sources = true + }); + } + + public async Task DisposeAsync() => + await Page.Context.Tracing.StopAsync(new() + { + Path = Path.Combine( + Path.Combine(XunitContext.Context.SolutionDirectory, ".artifacts"), + "playwright-traces", + $"{_testName}.zip" + ) + }); } From dc7da56a5b02cc6d482214288475eb042e087a80 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Thu, 25 Jan 2024 14:06:38 +0100 Subject: [PATCH 05/24] minimal tests --- Elastic.OpenTelemetry.sln.DotSettings | 1 + .../DistributedFixture/ApmUIBrowserContext.cs | 136 ++++++++++++++++++ .../DistributedApplicationFixture.cs | 70 +++------ .../DotNetRunApplication.cs | 12 +- .../DistributedFixture/ITrafficSimulator.cs | 6 +- .../EndToEndTests.cs | 52 +++---- .../{GlobalUsings.cs => GlobalSetup.cs} | 11 +- 7 files changed, 196 insertions(+), 92 deletions(-) create mode 100644 tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs rename tests/Elastic.OpenTelemetry.IntegrationTests/{GlobalUsings.cs => GlobalSetup.cs} (66%) diff --git a/Elastic.OpenTelemetry.sln.DotSettings b/Elastic.OpenTelemetry.sln.DotSettings index 14fff26..c196257 100644 --- a/Elastic.OpenTelemetry.sln.DotSettings +++ b/Elastic.OpenTelemetry.sln.DotSettings @@ -564,6 +564,7 @@ See the LICENSE file in the project root for more information True False KM + UI False True True diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs new file mode 100644 index 0000000..ad77d47 --- /dev/null +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs @@ -0,0 +1,136 @@ +// Licensed to Elasticsearch B.V under +// one or more agreements. +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information + +using Microsoft.Extensions.Configuration; +using Microsoft.Playwright; + +namespace Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; + +public class ApmUIBrowserContext : IAsyncLifetime +{ + private readonly IConfigurationRoot _configuration; + private readonly string _serviceName; + + public ApmUIBrowserContext(IConfigurationRoot configuration, string serviceName) + { + _configuration = configuration; + _serviceName = serviceName; + //"https://{instance}.apm.us-east-1.aws.elastic.cloud:443" + // https://{instance}.kb.us-east-1.aws.elastic.cloud/app/apm/services?comparisonEnabled=true&environment=ENVIRONMENT_ALL&rangeFrom=now-15m&rangeTo=now&offset=1d + var endpoint = configuration["E2E:Endpoint"]?.Trim() ?? string.Empty; + var newBase = endpoint.Replace(".apm.", ".kb."); + KibanaAppUri = new Uri(new Uri(newBase), "app/apm"); + } + + public Uri KibanaAppUri { get; } + + public IBrowser Browser { get; private set; } = null!; + public IPlaywright HeadlessTester { get; private set; } = null!; + + public async Task InitializeAsync() + { + var username = _configuration["E2E:BrowserEmail"]?.Trim() ?? string.Empty; + var password = _configuration["E2E:BrowserPassword"]?.Trim() ?? string.Empty; + Program.Main(["install", "chromium"]); + HeadlessTester = await Playwright.CreateAsync(); + Browser = await HeadlessTester.Chromium.LaunchAsync(); + var page = await OpenApmLandingPage("test_bootstrap"); + try + { + await page.GetByRole(AriaRole.Textbox, new () { Name = "email" }).FillAsync(username); + await page.GetByRole(AriaRole.Textbox, new () { Name = "password" }).FillAsync(password); + await page.GetByRole(AriaRole.Button, new() { Name = "Log in" }).ClickAsync(); + + await WaitForServiceOnOverview(page); + + StorageState = await page.Context.StorageStateAsync(); + + await StopTrace(page); + } + catch (Exception e) + { + await StopTrace(page, "test_bootstrap"); + Console.WriteLine(e); + throw; + } + } + + public string? StorageState { get; set; } + + public async Task OpenApmLandingPage(string testName) + { + var page = await Browser.NewPageAsync(new () { StorageState = StorageState }); + await page.Context.Tracing.StartAsync(new() + { + Title = testName, + Screenshots = true, + Snapshots = true, + Sources = true + }); + await page.GotoAsync(KibanaAppUri.ToString()); + return page; + } + + public async Task WaitForServiceOnOverview(IPage page) + { + page.SetDefaultTimeout((float)TimeSpan.FromSeconds(30).TotalMilliseconds); + + var servicesHeader = page.GetByRole(AriaRole.Heading, new() { Name = "Services" }); + await servicesHeader.WaitForAsync(new () { State = WaitForSelectorState.Visible }); + + page.SetDefaultTimeout((float)TimeSpan.FromSeconds(10).TotalMilliseconds); + + Exception? observed = null; + for (var i = 0; i < 10;i++) + { + try + { + var serviceLink = page.GetByRole(AriaRole.Link, new() { Name = _serviceName }); + await serviceLink.WaitForAsync(new() { State = WaitForSelectorState.Visible }); + observed = null; + break; + } + catch (Exception e) + { + observed ??= e; + await page.ReloadAsync(); + } + finally + { + page.SetDefaultTimeout((float)TimeSpan.FromSeconds(5).TotalMilliseconds); + } + } + if (observed != null) + throw observed; //TODO proper rethrow with stack + + } + + public async Task StopTrace(IPage page, string? testName = null) + { + + if (string.IsNullOrWhiteSpace(testName)) + await page.Context.Tracing.StopAsync(new ()); + else + { + var root = DotNetRunApplication.GetSolutionRoot(); + await page.Context.Tracing.StopAsync(new() + { + Path = Path.Combine( + Path.Combine(root.FullName, ".artifacts"), + "playwright-traces", + $"{testName}.zip" + ) + }); + } + await page.CloseAsync(); + } + + + public async Task DisposeAsync() + { + await Browser.DisposeAsync(); + HeadlessTester.Dispose(); + } +} diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs index 28e82bd..957fcba 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs @@ -8,42 +8,34 @@ using System.Security.Cryptography; using System.Text; using Microsoft.Extensions.Configuration; -using Microsoft.Playwright; namespace Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; public class DistributedApplicationFixture : IDisposable, IAsyncLifetime { - private readonly AspNetCoreExampleApplication _aspNetApplication; + public AspNetCoreExampleApplication AspNetApplication { get; } + private readonly ITrafficSimulator[] _trafficSimulators; public DistributedApplicationFixture() { ServiceName = $"dotnet-e2e-{ShaForCurrentTicks()}"; - HttpClient = new HttpClient { BaseAddress = new Uri("http://localhost:5247") }; var configuration = new ConfigurationBuilder() .AddEnvironmentVariables() .AddUserSecrets() .Build(); + _trafficSimulators = [ new DefaultTrafficSimulator() ]; - _aspNetApplication = new AspNetCoreExampleApplication(ServiceName, configuration); - _trafficSimulators = - [ - new DefaultTrafficSimulator() - ]; - ApmUIContext = new ApmUIBrowserContext(configuration, ApmKibanaUrl); + AspNetApplication = new AspNetCoreExampleApplication(ServiceName, configuration); + ApmUI = new ApmUIBrowserContext(configuration, ServiceName); } - public ApmUIBrowserContext ApmUIContext { get; } - - public Uri ApmKibanaUrl => _aspNetApplication.ApmKibanaUrl; - - public HttpClient HttpClient { get; } + public ApmUIBrowserContext ApmUI { get; } public string ServiceName { get; } - public bool Started => _aspNetApplication.ProcessId.HasValue; + public bool Started => AspNetApplication.ProcessId.HasValue; private static string ShaForCurrentTicks() { @@ -55,16 +47,12 @@ private static string ShaForCurrentTicks() .Substring(0, 12); } - public void Dispose() - { - _aspNetApplication.Dispose(); - HttpClient.Dispose(); - } + public void Dispose() => AspNetApplication.Dispose(); public async Task InitializeAsync() { foreach (var trafficSimulator in _trafficSimulators) - await trafficSimulator.Start(ServiceName, HttpClient); + await trafficSimulator.Start(this); // TODO query OTEL_BSP_SCHEDULE_DELAY? await Task.Delay(5000); @@ -72,45 +60,27 @@ public async Task InitializeAsync() // Stateless refresh //https://github.com/elastic/elasticsearch/blob/main/server/src/main/java/org/elasticsearch/index/IndexSettings.java#L286 await Task.Delay(TimeSpan.FromSeconds(15)); - await ApmUIContext.InitializeAsync(); + await ApmUI.InitializeAsync(); } public async Task DisposeAsync() { Dispose(); - await ApmUIContext.DisposeAsync(); + await ApmUI.DisposeAsync(); } } -public class AspNetCoreExampleApplication(string serviceName, IConfiguration configuration) - : DotNetRunApplication(serviceName, configuration, "Example.Elastic.OpenTelemetry.AspNetCore"); - - -public class ApmUIBrowserContext(IConfigurationRoot configuration, Uri kibanaUrl) : IAsyncLifetime +public class AspNetCoreExampleApplication : DotNetRunApplication { + public AspNetCoreExampleApplication(string serviceName, IConfiguration configuration) + : base(serviceName, configuration, "Example.Elastic.OpenTelemetry.AspNetCore") => + HttpClient = new HttpClient { BaseAddress = new Uri("http://localhost:5247") }; - public IPage Page { get; private set; } = null!; - public IBrowser Browser { get; private set; } = null!; - public IPlaywright HeadlessTester { get; private set; } = null!; - - public async Task InitializeAsync() - { - var username = configuration["E2E:BrowserEmail"]?.Trim() ?? string.Empty; - var password = configuration["E2E:BrowserPassword"]?.Trim() ?? string.Empty; - Program.Main(["install", "chromium"]); - HeadlessTester = await Playwright.CreateAsync(); - Browser = await HeadlessTester.Chromium.LaunchAsync(); - Page = await Browser.NewPageAsync(); - await Page.GotoAsync(kibanaUrl.ToString()); - - await Page.GetByRole(AriaRole.Textbox, new () { Name = "email" }).FillAsync(username); - await Page.GetByRole(AriaRole.Textbox, new () { Name = "password" }).FillAsync(password); - await Page.GetByRole(AriaRole.Button, new() { Name = "Log in" }).ClickAsync(); - } + public HttpClient HttpClient { get; } - public async Task DisposeAsync() + public override void Dispose() { - await Browser.DisposeAsync(); - HeadlessTester.Dispose(); + base.Dispose(); + HttpClient.Dispose(); } -} +}; diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs index 0b22c77..13a9096 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs @@ -28,20 +28,14 @@ public DotNetRunApplication(string serviceName, IConfiguration configuration, st _authorization = configuration["E2E:Authorization"]?.Trim() ?? string.Empty; var args = CreateStartArgs(); - - var newBase = _endpoint.Replace(".apm.", ".kb."); - ApmKibanaUrl = new Uri(new Uri(newBase), "app/apm"); - _app = Proc.StartLongRunning(args, TimeSpan.FromSeconds(10)); } - public Uri ApmKibanaUrl { get; } - public int? ProcessId { get; private set; } protected virtual string[] GetArguments() => Array.Empty(); - private DirectoryInfo GetSolutionRoot() + public static DirectoryInfo GetSolutionRoot() { var root = CurrentDirectory; while (root != null && root.GetFiles("*.sln").Length == 0) @@ -72,7 +66,7 @@ private LongRunningArguments CreateStartArgs() { "OTEL_METRICS_EXPORTER", "otlp" }, { "OTEL_LOGS_EXPORTER", "otlp" }, { "OTEL_BSP_SCHEDULE_DELAY", "1000" }, - { "OTEL_BSP_MAX_EXPORT_BATCH_SIZE", "10" }, + { "OTEL_BSP_MAX_EXPORT_BATCH_SIZE", "5" }, { "OTEL_RESOURCE_ATTRIBUTES", $"service.name={_serviceName},service.version=1.0,1,deployment.environment=e2e" }, }, StartedConfirmationHandler = (l) => @@ -87,7 +81,7 @@ private LongRunningArguments CreateStartArgs() }; } - public void Dispose() + public virtual void Dispose() { var pid = _app.Process.ProcessId; if (ProcessId.HasValue) diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs index 4bdf2fd..c68ac06 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs @@ -9,16 +9,16 @@ namespace Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; public interface ITrafficSimulator { - Task Start(string serviceName, HttpClient client); + Task Start(DistributedApplicationFixture distributedInfra); } public class DefaultTrafficSimulator : ITrafficSimulator { - public async Task Start(string serviceName, HttpClient client) + public async Task Start(DistributedApplicationFixture distributedInfra) { for (var i = 0; i < 10; i++) { - var get = await client.GetAsync("e2e"); + var get = await distributedInfra.AspNetApplication.HttpClient.GetAsync("e2e"); get.StatusCode.Should().Be(HttpStatusCode.OK); var response = await get.Content.ReadAsStringAsync(); } diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs index 5ff5f0f..556df71 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs @@ -13,44 +13,38 @@ namespace Elastic.OpenTelemetry.IntegrationTests; public class EndToEndTests(ITestOutputHelper output, DistributedApplicationFixture fixture) : XunitContextBase(output), IAssemblyFixture, IAsyncLifetime { - public IPage Page => fixture.ApmUIContext.Page; private string _testName = string.Empty; + private IPage _page = null!; [Fact] - public async Task Test() - { - fixture.Started.Should().BeTrue(); - - Page.SetDefaultTimeout((float)TimeSpan.FromSeconds(20).TotalMilliseconds); - var servicesHeader = Page.GetByRole(AriaRole.Heading, new() { Name = "Services" }); - await servicesHeader.WaitForAsync(new () { State = WaitForSelectorState.Visible }); - - var serviceLink = Page.GetByRole(AriaRole.Link, new() { Name = fixture.ServiceName }); - await serviceLink.WaitForAsync(new () { State = WaitForSelectorState.Visible }); - Page.SetDefaultTimeout((float)TimeSpan.FromSeconds(5).TotalMilliseconds); + public void EnsureApplicationWasStarted() => fixture.Started.Should().BeTrue(); - await Expect(Page.GetByRole(AriaRole.Link, new() { Name = "Get started" })).ToBeVisibleAsync(); + [Fact] + public async Task LatencyShowsAGraph() + { + // click on service in service overview page. + _page.SetDefaultTimeout((float)TimeSpan.FromSeconds(30).TotalMilliseconds); + var uri = new Uri(fixture.ApmUI.KibanaAppUri, $"/app/apm/services/{fixture.ServiceName}/overview").ToString(); + await _page.GotoAsync(uri); + await Expect(_page.GetByRole(AriaRole.Heading, new() { Name = "Latency", Exact = true })).ToBeVisibleAsync(); } + public async Task InitializeAsync() { - _testName = XunitContext.Context.ClassName + "." + XunitContext.Context.Test.DisplayName; - await Page.Context.Tracing.StartAsync(new() + _testName = XunitContext.Context.UniqueTestName; + _page = await fixture.ApmUI.OpenApmLandingPage(_testName); + try + { + await fixture.ApmUI.WaitForServiceOnOverview(_page); + } + catch { - Title = _testName, - Screenshots = true, - Snapshots = true, - Sources = true - }); + await fixture.ApmUI.StopTrace(_page, _testName); + throw; + } + } - public async Task DisposeAsync() => - await Page.Context.Tracing.StopAsync(new() - { - Path = Path.Combine( - Path.Combine(XunitContext.Context.SolutionDirectory, ".artifacts"), - "playwright-traces", - $"{_testName}.zip" - ) - }); + public async Task DisposeAsync() => await fixture.ApmUI.StopTrace(_page, XunitContext.Context.TestException == null ? null : _testName); } diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalUsings.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalSetup.cs similarity index 66% rename from tests/Elastic.OpenTelemetry.IntegrationTests/GlobalUsings.cs rename to tests/Elastic.OpenTelemetry.IntegrationTests/GlobalSetup.cs index 5faef26..352cb0f 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalUsings.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalSetup.cs @@ -6,7 +6,16 @@ global using Xunit; global using System.Diagnostics; global using FluentAssertions; - +using System.Runtime.CompilerServices; using Xunit.Extensions.AssemblyFixture; [assembly: TestFramework(AssemblyFixtureFramework.TypeName, AssemblyFixtureFramework.AssemblyName)] + +namespace Elastic.OpenTelemetry.IntegrationTests; + +public static class GlobalSetup +{ + [ModuleInitializer] + public static void Setup() => + XunitContext.EnableExceptionCapture(); +} From 61fda6cb66241063b6b279987c94774323267dfe Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Thu, 25 Jan 2024 14:54:30 +0100 Subject: [PATCH 06/24] minimal documentation for running tests --- .../README.md | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 tests/Elastic.OpenTelemetry.IntegrationTests/README.md diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/README.md b/tests/Elastic.OpenTelemetry.IntegrationTests/README.md new file mode 100644 index 0000000..a29a992 --- /dev/null +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/README.md @@ -0,0 +1,45 @@ +# E2E Tests: Elastic's .NET OpenTelemetry Distribution + + +## Target Environment + +Requires an already running serverless observability project on cloud. + +The configuration can be provided either as asp.net secrets or environment variables. + +```bash +dotnet user-secrets set "E2E:Endpoint" "" --project tests/Elastic.OpenTelemetry.IntegrationTests +dotnet user-secrets set "E2E:Authorization" "
" --project tests/Elastic.OpenTelemetry.IntegrationTests +``` + +The equivalent environment variables are `E2E__ENDPOINT` and `E2E__AUTHORIZATION`. For local development setting +secrets is preferred. + +This ensures the instrumented applications will send OTLP data. + +## Browser authentication + +The tests require a headless browser to login. This requires a non OAuth login to be setup on your serverless +observability project. + +To do this is to invite an email address you own to your organization: + +https://cloud.elastic.co/account/members + +This user only needs instance access to the `Target Environment`. + +**NOTE:** since you can only be part of a single organization on cloud be sure that the organization you are part of is +not used for any production usecases and you have clearance from the organization owner. + +By default accounts on cloud are part of their own personal organization. + +Once invited and accepted the invited email can be used to login during the automated tests. + +These can be provided again as user secrets: + +```bash +dotnet user-secrets set "E2E:BrowserEmail" "" --project tests/Elastic.OpenTelemetry.IntegrationTests +dotnet user-secrets set "E2E:BrowserPassword" "" --project tests/Elastic.OpenTelemetry.IntegrationTests +``` + +or environment variables (`E2E__BROWSEREMAIL` and `E2E__BROWSERPASSWORD`). From feeaea49cf49039ddc969d530cc24a536bb3f4b9 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Thu, 25 Jan 2024 15:01:34 +0100 Subject: [PATCH 07/24] update license headers --- .../Controllers/E2EController.cs | 3 +-- examples/Example.Elastic.OpenTelemetry.AspNetCore/Program.cs | 3 +-- .../DistributedFixture/ApmUIBrowserContext.cs | 3 +-- .../DistributedFixture/DistributedApplicationFixture.cs | 3 +-- .../DistributedFixture/DotNetRunApplication.cs | 3 +-- .../DistributedFixture/ITrafficSimulator.cs | 3 +-- tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs | 3 +-- tests/Elastic.OpenTelemetry.IntegrationTests/GlobalSetup.cs | 3 +-- 8 files changed, 8 insertions(+), 16 deletions(-) diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Controllers/E2EController.cs b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Controllers/E2EController.cs index 4816374..07f5bb9 100644 --- a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Controllers/E2EController.cs +++ b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Controllers/E2EController.cs @@ -1,5 +1,4 @@ -// Licensed to Elasticsearch B.V under -// one or more agreements. +// Licensed to Elasticsearch B.V under one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Program.cs b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Program.cs index 96c26ae..406fa44 100644 --- a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Program.cs +++ b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Program.cs @@ -1,5 +1,4 @@ -// Licensed to Elasticsearch B.V under -// one or more agreements. +// Licensed to Elasticsearch B.V under one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs index ad77d47..65458c9 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs @@ -1,5 +1,4 @@ -// Licensed to Elasticsearch B.V under -// one or more agreements. +// Licensed to Elasticsearch B.V under one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs index 957fcba..53ad6fd 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs @@ -1,5 +1,4 @@ -// Licensed to Elasticsearch B.V under -// one or more agreements. +// Licensed to Elasticsearch B.V under one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs index 13a9096..4c5bb00 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs @@ -1,5 +1,4 @@ -// Licensed to Elasticsearch B.V under -// one or more agreements. +// Licensed to Elasticsearch B.V under one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs index c68ac06..01baf67 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs @@ -1,5 +1,4 @@ -// Licensed to Elasticsearch B.V under -// one or more agreements. +// Licensed to Elasticsearch B.V under one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs index 556df71..c64a068 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs @@ -1,5 +1,4 @@ -// Licensed to Elasticsearch B.V under -// one or more agreements. +// Licensed to Elasticsearch B.V under one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalSetup.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalSetup.cs index 352cb0f..8270058 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalSetup.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalSetup.cs @@ -1,5 +1,4 @@ -// Licensed to Elasticsearch B.V under -// one or more agreements. +// Licensed to Elasticsearch B.V under one or more agreements. // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information From 38808828c2c8615a542de772ea9600a5f14eaa87 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Thu, 25 Jan 2024 15:03:19 +0100 Subject: [PATCH 08/24] fix license header in DotSettings --- Elastic.OpenTelemetry.sln.DotSettings | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Elastic.OpenTelemetry.sln.DotSettings b/Elastic.OpenTelemetry.sln.DotSettings index c196257..ac2fd04 100644 --- a/Elastic.OpenTelemetry.sln.DotSettings +++ b/Elastic.OpenTelemetry.sln.DotSettings @@ -84,8 +84,7 @@ &lt;Reformat&gt;false&lt;/Reformat&gt; &lt;/Language&gt; &lt;/profile&gt;</RIDER_SETTINGS></Profile> - Licensed to Elasticsearch B.V under -one or more agreements. + Licensed to Elasticsearch B.V under one or more agreements. Elasticsearch B.V licenses this file to you under the Apache 2.0 License. See the LICENSE file in the project root for more information True From 2c35cf6fed07f13b6a3f32cfa326320dbb621bf2 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 30 Jan 2024 11:49:42 +0100 Subject: [PATCH 09/24] junit and github actions logger dont gel well together --- build/scripts/Targets.fs | 14 +++++++++++--- .../DistributedFixture/ApmUIBrowserContext.cs | 11 ++++++++++- .../EndToEndTests.cs | 16 +--------------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/build/scripts/Targets.fs b/build/scripts/Targets.fs index adaff74..52ffc32 100644 --- a/build/scripts/Targets.fs +++ b/build/scripts/Targets.fs @@ -45,15 +45,23 @@ let private test _ = let junitOutput = Path.Combine(testOutputPath.FullName, "junit-{assembly}-{framework}-test-results.xml") let loggerPathArgs = $"LogFilePath=%s{junitOutput}" let loggerArg = $"--logger:\"junit;%s{loggerPathArgs}\"" - let githubActionsLogger = $"--logger:\"GitHubActions;summary.includePassedTests=true\"" + let githubActionsLogger = $"--logger:\"GitHubActions;summary.includePassedTests=false\"" let tfmArgs = if OS.Current = OS.Windows then [] else ["-f"; "net8.0"] + //exec { run "dotnet" "test" "-c" "release" } exec { run "dotnet" ( - ["test"; "-c"; "release"; loggerArg; githubActionsLogger] + ["test"; "-c"; "release"; "--no-restore"; "--no-build"; githubActionsLogger] @ tfmArgs @ ["--"; "RunConfiguration.CollectSourceInformation=true"] ) - } + } + (*exec { + run "dotnet" ( + ["test"; "-c"; "release"; "-v"; "diag"; "--no-restore"; "--no-build"; loggerArg; githubActionsLogger] + @ tfmArgs + @ ["--"; "RunConfiguration.CollectSourceInformation=true"] + ) + } *) let private validateLicenses _ = let args = ["-u"; "-t"; "-i"; "Elastic.OpenTelemetry.sln"; "--use-project-assets-json" diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs index 65458c9..9a0b16e 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs @@ -58,7 +58,8 @@ public async Task InitializeAsync() public string? StorageState { get; set; } - public async Task OpenApmLandingPage(string testName) + + public async Task NewProfiledPage(string testName) { var page = await Browser.NewPageAsync(new () { StorageState = StorageState }); await page.Context.Tracing.StartAsync(new() @@ -68,6 +69,14 @@ await page.Context.Tracing.StartAsync(new() Snapshots = true, Sources = true }); + + return page; + } + + + public async Task OpenApmLandingPage(string testName) + { + var page = await NewProfiledPage(testName); await page.GotoAsync(KibanaAppUri.ToString()); return page; } diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs index c64a068..e1db29c 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs +++ b/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs @@ -29,21 +29,7 @@ public async Task LatencyShowsAGraph() } - public async Task InitializeAsync() - { - _testName = XunitContext.Context.UniqueTestName; - _page = await fixture.ApmUI.OpenApmLandingPage(_testName); - try - { - await fixture.ApmUI.WaitForServiceOnOverview(_page); - } - catch - { - await fixture.ApmUI.StopTrace(_page, _testName); - throw; - } - - } + public async Task InitializeAsync() => _page = await fixture.ApmUI.NewProfiledPage(_testName); public async Task DisposeAsync() => await fixture.ApmUI.StopTrace(_page, XunitContext.Context.TestException == null ? null : _testName); } From 20ce08fce06e145f0e645f427e55bb66293c7eef Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 6 Feb 2024 13:32:15 +0100 Subject: [PATCH 10/24] allow unit/integration/e2e test to be split and called in isolation --- build/scripts/CommandLine.fs | 11 ++++++++++- build/scripts/Targets.fs | 27 +++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/build/scripts/CommandLine.fs b/build/scripts/CommandLine.fs index 4998afa..944bbef 100644 --- a/build/scripts/CommandLine.fs +++ b/build/scripts/CommandLine.fs @@ -15,6 +15,10 @@ type Build = | [] Build | [] Test + | [] UnitTest + | [] Integrate + | [] EndToEnd + | [] PristineCheck | [] GeneratePackages | [] ValidateLicenses @@ -35,7 +39,12 @@ with | Clean -> "clean known output locations" | Version -> "print version information" | Build -> "Run build" - | Test -> "Runs build then tests" + + | UnitTest -> "build then run only the unit tests" + | Integrate -> "build then run only the integration tests" + | EndToEnd -> "build then run only the e2e tests" + | Test -> "build then run ALL the tests" + | Release -> "runs build, tests, and create and validates the packages shy of publishing them" // steps diff --git a/build/scripts/Targets.fs b/build/scripts/Targets.fs index cad9a91..5470511 100644 --- a/build/scripts/Targets.fs +++ b/build/scripts/Targets.fs @@ -40,7 +40,9 @@ let private pristineCheck (arguments:ParseResults) = | _, true -> printfn "The checkout folder does not have pending changes, proceeding" | _ -> failwithf "The checkout folder has pending changes, aborting. Specify -c to ./build.sh to skip this check" -let private runTests _ = +type TestSuite = | Unit | Integration | E2E | All + +let private runTests suite _ = let logger = // use junit xml logging locally, github actions logs using console out formats match BuildServer.isGitHubActionsBuild with @@ -50,20 +52,28 @@ let private runTests _ = let junitOutput = Path.Combine(testOutputPath.FullName, "junit-{assembly}-{framework}-test-results.xml") let loggerPathArgs = $"LogFilePath=%s{junitOutput}" $"--logger:\"junit;%s{loggerPathArgs}\"" - + let filterArgs = + match suite with + | All -> [] + | TestSuite.Unit -> [ "--filter"; "FullyQualifiedName~.Tests" ] + | TestSuite.Integration -> [ "--filter"; "FullyQualifiedName~.IntegrationTests" ] + | TestSuite.E2E -> [ "--filter"; "FullyQualifiedName~.EndToEndTests" ] + + let tfmArgs = if OS.Current = OS.Windows then [] else ["-f"; "net8.0"] exec { run "dotnet" ( ["test"; "-c"; "release"; "--no-restore"; "--no-build"; logger] + @ filterArgs @ tfmArgs @ ["--"; "RunConfiguration.CollectSourceInformation=true"] ) } -let private test (arguments:ParseResults) = +let private test suite (arguments:ParseResults) = match arguments.TryGetResult SkipTests with - | Some _ -> runTests arguments - | None -> printfn "Skipping tests because --skiptests was provided" + | None -> runTests suite arguments + | Some _ -> printfn "Skipping tests because --skiptests was provided" let private validateLicenses _ = let args = ["-u"; "-t"; "-i"; "Elastic.OpenTelemetry.sln"; "--use-project-assets-json" @@ -136,7 +146,12 @@ let Setup (parsed:ParseResults) = | Version -> Build.Step version | Clean -> Build.Cmd [Version] [] clean | Build -> Build.Cmd [Clean] [] build - | Test -> Build.Cmd [Build] [] test + + | UnitTest -> Build.Cmd [Build] [] <| test TestSuite.Unit + | Integrate -> Build.Cmd [Build] [] <| test TestSuite.Integration + | EndToEnd -> Build.Cmd [Build] [] <| test TestSuite.E2E + | Test -> Build.Cmd [UnitTest; Integrate; EndToEnd] [] ignore + | Release -> Build.Cmd [PristineCheck; Test] From 7f06162285f5c873907a1830982ee71cbd79e3e6 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 6 Feb 2024 13:33:54 +0100 Subject: [PATCH 11/24] Rename .IntegrationTests to EndToEndTests --- Elastic.OpenTelemetry.sln | 2 +- .../DistributedFixture/ApmUIBrowserContext.cs | 2 +- .../DistributedFixture/DistributedApplicationFixture.cs | 2 +- .../DistributedFixture/DotNetRunApplication.cs | 2 +- .../DistributedFixture/ITrafficSimulator.cs | 2 +- .../Elastic.OpenTelemetry.EndToEndTests.csproj} | 0 .../GlobalSetup.cs | 2 +- .../README.md | 0 .../ServiceTests.cs} | 5 +++-- 9 files changed, 9 insertions(+), 8 deletions(-) rename tests/{Elastic.OpenTelemetry.IntegrationTests => Elastic.OpenTelemetry.EndToEndTests}/DistributedFixture/ApmUIBrowserContext.cs (98%) rename tests/{Elastic.OpenTelemetry.IntegrationTests => Elastic.OpenTelemetry.EndToEndTests}/DistributedFixture/DistributedApplicationFixture.cs (97%) rename tests/{Elastic.OpenTelemetry.IntegrationTests => Elastic.OpenTelemetry.EndToEndTests}/DistributedFixture/DotNetRunApplication.cs (97%) rename tests/{Elastic.OpenTelemetry.IntegrationTests => Elastic.OpenTelemetry.EndToEndTests}/DistributedFixture/ITrafficSimulator.cs (90%) rename tests/{Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj => Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj} (100%) rename tests/{Elastic.OpenTelemetry.IntegrationTests => Elastic.OpenTelemetry.EndToEndTests}/GlobalSetup.cs (92%) rename tests/{Elastic.OpenTelemetry.IntegrationTests => Elastic.OpenTelemetry.EndToEndTests}/README.md (100%) rename tests/{Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs => Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs} (90%) diff --git a/Elastic.OpenTelemetry.sln b/Elastic.OpenTelemetry.sln index d08f8d2..f25e8aa 100644 --- a/Elastic.OpenTelemetry.sln +++ b/Elastic.OpenTelemetry.sln @@ -34,7 +34,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.Elastic.OpenTelemet EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elastic.OpenTelemetry.AspNetCore", "src\Elastic.OpenTelemetry.AspNetCore\Elastic.OpenTelemetry.AspNetCore.csproj", "{2139F902-B10D-475D-8A38-F78962CEBFD3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.OpenTelemetry.IntegrationTests", "tests\Elastic.OpenTelemetry.IntegrationTests\Elastic.OpenTelemetry.IntegrationTests.csproj", "{B970DBE1-6A04-4014-A285-6A9F36421025}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elastic.OpenTelemetry.EndToEndTests", "tests\Elastic.OpenTelemetry.EndToEndTests\Elastic.OpenTelemetry.EndToEndTests.csproj", "{B970DBE1-6A04-4014-A285-6A9F36421025}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ApmUIBrowserContext.cs similarity index 98% rename from tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs rename to tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ApmUIBrowserContext.cs index 9a0b16e..05f8328 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ApmUIBrowserContext.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ApmUIBrowserContext.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Playwright; -namespace Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; +namespace Elastic.OpenTelemetry.EndToEndTests.DistributedFixture; public class ApmUIBrowserContext : IAsyncLifetime { diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DistributedApplicationFixture.cs similarity index 97% rename from tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs rename to tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DistributedApplicationFixture.cs index 53ad6fd..2fc4ff7 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DistributedApplicationFixture.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DistributedApplicationFixture.cs @@ -8,7 +8,7 @@ using System.Text; using Microsoft.Extensions.Configuration; -namespace Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; +namespace Elastic.OpenTelemetry.EndToEndTests.DistributedFixture; public class DistributedApplicationFixture : IDisposable, IAsyncLifetime { diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DotNetRunApplication.cs similarity index 97% rename from tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs rename to tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DotNetRunApplication.cs index 4c5bb00..94c775e 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/DotNetRunApplication.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DotNetRunApplication.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Configuration; using ProcNet; -namespace Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; +namespace Elastic.OpenTelemetry.EndToEndTests.DistributedFixture; public abstract class DotNetRunApplication { diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ITrafficSimulator.cs similarity index 90% rename from tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs rename to tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ITrafficSimulator.cs index 01baf67..b2d4802 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/DistributedFixture/ITrafficSimulator.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ITrafficSimulator.cs @@ -4,7 +4,7 @@ using System.Net; -namespace Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; +namespace Elastic.OpenTelemetry.EndToEndTests.DistributedFixture; public interface ITrafficSimulator { diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj b/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj similarity index 100% rename from tests/Elastic.OpenTelemetry.IntegrationTests/Elastic.OpenTelemetry.IntegrationTests.csproj rename to tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalSetup.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs similarity index 92% rename from tests/Elastic.OpenTelemetry.IntegrationTests/GlobalSetup.cs rename to tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs index 8270058..02b16df 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/GlobalSetup.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs @@ -10,7 +10,7 @@ [assembly: TestFramework(AssemblyFixtureFramework.TypeName, AssemblyFixtureFramework.AssemblyName)] -namespace Elastic.OpenTelemetry.IntegrationTests; +namespace Elastic.OpenTelemetry.EndToEndTests; public static class GlobalSetup { diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/README.md b/tests/Elastic.OpenTelemetry.EndToEndTests/README.md similarity index 100% rename from tests/Elastic.OpenTelemetry.IntegrationTests/README.md rename to tests/Elastic.OpenTelemetry.EndToEndTests/README.md diff --git a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs similarity index 90% rename from tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs rename to tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs index e1db29c..bd45f3d 100644 --- a/tests/Elastic.OpenTelemetry.IntegrationTests/EndToEndTests.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs @@ -2,12 +2,13 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information -using Elastic.OpenTelemetry.IntegrationTests.DistributedFixture; +using Elastic.OpenTelemetry.EndToEndTests.DistributedFixture; using Microsoft.Playwright; +using Xunit.Abstractions; using Xunit.Extensions.AssemblyFixture; using static Microsoft.Playwright.Assertions; -namespace Elastic.OpenTelemetry.IntegrationTests; +namespace Elastic.OpenTelemetry.EndToEndTests; public class EndToEndTests(ITestOutputHelper output, DistributedApplicationFixture fixture) : XunitContextBase(output), IAssemblyFixture, IAsyncLifetime From cf980f619697c50efeb7768ce228a240d9745ea8 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Fri, 9 Feb 2024 16:11:43 +0100 Subject: [PATCH 12/24] Move to Nullean.Xunit.Partitions and simplify test logging --- .github/workflows/bootstrap/action.yml | 1 - Elastic.OpenTelemetry.sln | 1 + build/scripts/Targets.fs | 2 + tests/.runsettings | 8 +++ tests/Directory.Build.props | 2 +- .../DistributedApplicationFixture.cs | 49 +++++++++---------- ...Elastic.OpenTelemetry.EndToEndTests.csproj | 2 +- .../GlobalSetup.cs | 5 +- .../ServiceTests.cs | 5 +- 9 files changed, 40 insertions(+), 35 deletions(-) create mode 100644 tests/.runsettings diff --git a/.github/workflows/bootstrap/action.yml b/.github/workflows/bootstrap/action.yml index 1ee0518..de57e69 100644 --- a/.github/workflows/bootstrap/action.yml +++ b/.github/workflows/bootstrap/action.yml @@ -32,7 +32,6 @@ runs: dotnet-version: | 6.0.x 8.0.x - 6.0.x - id: dotnet shell: bash run: | diff --git a/Elastic.OpenTelemetry.sln b/Elastic.OpenTelemetry.sln index f25e8aa..d9a22f7 100644 --- a/Elastic.OpenTelemetry.sln +++ b/Elastic.OpenTelemetry.sln @@ -22,6 +22,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{AAD39891 ProjectSection(SolutionItems) = preProject tests\Directory.Build.props = tests\Directory.Build.props tests\xunit.runner.json = tests\xunit.runner.json + tests\.runsettings = tests\.runsettings EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elastic.OpenTelemetry.Tests", "tests\Elastic.OpenTelemetry.Tests\Elastic.OpenTelemetry.Tests.csproj", "{22BF9223-3A6D-4197-8527-3E4E43A98A81}" diff --git a/build/scripts/Targets.fs b/build/scripts/Targets.fs index 5470511..5d8e29a 100644 --- a/build/scripts/Targets.fs +++ b/build/scripts/Targets.fs @@ -60,10 +60,12 @@ let private runTests suite _ = | TestSuite.E2E -> [ "--filter"; "FullyQualifiedName~.EndToEndTests" ] + let settingsArg = ["-s"; "tests/.runsettings"] let tfmArgs = if OS.Current = OS.Windows then [] else ["-f"; "net8.0"] exec { run "dotnet" ( ["test"; "-c"; "release"; "--no-restore"; "--no-build"; logger] + @ settingsArg @ filterArgs @ tfmArgs @ ["--"; "RunConfiguration.CollectSourceInformation=true"] diff --git a/tests/.runsettings b/tests/.runsettings new file mode 100644 index 0000000..25f85e2 --- /dev/null +++ b/tests/.runsettings @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index e207e28..7bb3bac 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -23,7 +23,7 @@ - + diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DistributedApplicationFixture.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DistributedApplicationFixture.cs index 2fc4ff7..911a7fa 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DistributedApplicationFixture.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DistributedApplicationFixture.cs @@ -3,38 +3,26 @@ // See the LICENSE file in the project root for more information using System.Globalization; -using System.Net; using System.Security.Cryptography; using System.Text; using Microsoft.Extensions.Configuration; +using Nullean.Xunit.Partitions.Sdk; namespace Elastic.OpenTelemetry.EndToEndTests.DistributedFixture; -public class DistributedApplicationFixture : IDisposable, IAsyncLifetime +public class DistributedApplicationFixture : IPartitionLifetime { - public AspNetCoreExampleApplication AspNetApplication { get; } + private readonly ITrafficSimulator[] _trafficSimulators = [ new DefaultTrafficSimulator() ]; - private readonly ITrafficSimulator[] _trafficSimulators; + public string ServiceName { get; } = $"dotnet-e2e-{ShaForCurrentTicks()}"; - public DistributedApplicationFixture() - { - ServiceName = $"dotnet-e2e-{ShaForCurrentTicks()}"; - - var configuration = new ConfigurationBuilder() - .AddEnvironmentVariables() - .AddUserSecrets() - .Build(); - _trafficSimulators = [ new DefaultTrafficSimulator() ]; - - AspNetApplication = new AspNetCoreExampleApplication(ServiceName, configuration); - ApmUI = new ApmUIBrowserContext(configuration, ServiceName); - } + public bool Started => AspNetApplication.ProcessId.HasValue; - public ApmUIBrowserContext ApmUI { get; } + public int? MaxConcurrency => null; - public string ServiceName { get; } + public ApmUIBrowserContext ApmUI { get; private set; } = null!; - public bool Started => AspNetApplication.ProcessId.HasValue; + public AspNetCoreExampleApplication AspNetApplication { get; private set; } = null!; private static string ShaForCurrentTicks() { @@ -46,10 +34,24 @@ private static string ShaForCurrentTicks() .Substring(0, 12); } - public void Dispose() => AspNetApplication.Dispose(); + public async Task DisposeAsync() + { + AspNetApplication.Dispose(); + await ApmUI.DisposeAsync(); + } public async Task InitializeAsync() { + var configuration = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddUserSecrets() + .Build(); + + AspNetApplication = new AspNetCoreExampleApplication(ServiceName, configuration); + ApmUI = new ApmUIBrowserContext(configuration, ServiceName); + + Console.WriteLine("Initializing.......?"); + foreach (var trafficSimulator in _trafficSimulators) await trafficSimulator.Start(this); @@ -62,11 +64,6 @@ public async Task InitializeAsync() await ApmUI.InitializeAsync(); } - public async Task DisposeAsync() - { - Dispose(); - await ApmUI.DisposeAsync(); - } } public class AspNetCoreExampleApplication : DotNetRunApplication diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj b/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj index 953fa48..8d4f1a9 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj @@ -12,9 +12,9 @@ + - diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs index 02b16df..672d0c5 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs @@ -3,12 +3,11 @@ // See the LICENSE file in the project root for more information global using Xunit; -global using System.Diagnostics; global using FluentAssertions; using System.Runtime.CompilerServices; -using Xunit.Extensions.AssemblyFixture; +using Nullean.Xunit.Partitions; -[assembly: TestFramework(AssemblyFixtureFramework.TypeName, AssemblyFixtureFramework.AssemblyName)] +[assembly: TestFramework(Partition.TestFramework, Partition.Assembly)] namespace Elastic.OpenTelemetry.EndToEndTests; diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs index bd45f3d..473328a 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs @@ -4,14 +4,13 @@ using Elastic.OpenTelemetry.EndToEndTests.DistributedFixture; using Microsoft.Playwright; -using Xunit.Abstractions; -using Xunit.Extensions.AssemblyFixture; +using Nullean.Xunit.Partitions.Sdk; using static Microsoft.Playwright.Assertions; namespace Elastic.OpenTelemetry.EndToEndTests; public class EndToEndTests(ITestOutputHelper output, DistributedApplicationFixture fixture) - : XunitContextBase(output), IAssemblyFixture, IAsyncLifetime + : XunitContextBase(output), IPartitionFixture, IAsyncLifetime { private string _testName = string.Empty; private IPage _page = null!; From bcb00466c53a04d5c3169a0dfb038ad8e8c61d49 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 12 Feb 2024 15:29:08 +0100 Subject: [PATCH 13/24] introduce --test-suite to better control what tests need to run --- .github/workflows/ci.yml | 4 ++-- .github/workflows/e2e.yml | 10 ++++++--- .github/workflows/prerelease.yml | 2 +- .github/workflows/release.yml | 2 +- build/scripts/CommandLine.fs | 30 +++++++++++++------------- build/scripts/Targets.fs | 37 +++++++++++++++++--------------- 6 files changed, 46 insertions(+), 39 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d877e51..32513c7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,7 +33,7 @@ jobs: id: bootstrap uses: ./.github/workflows/bootstrap - - run: build.bat test + - run: build.bat test --test-suite=skip-e2e shell: cmd name: Test @@ -46,5 +46,5 @@ jobs: uses: ./.github/workflows/bootstrap # We still run the full release build on pull-requests this ensures packages are validated ahead of time - - run: ./build.sh release + - run: ./build.sh release --test-suite=skip-e2e name: Release diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index c1ee6f6..c15a26d 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -51,6 +51,10 @@ jobs: vault-role-id: ${{ secrets.VAULT_ROLE_ID }} vault-secret-id: ${{ secrets.VAULT_SECRET_ID }} - # TODO: run the e2e targeting the required endpoint. - # those values can be found in https://github.com/elastic/apm-pipeline-library/tree/main/.github/actions/oblt-cli-cluster-credentials#outputs - - run: curl -X GET "${ELASTICSEARCH_HOST}/_cat/indices?v" -u ${ELASTICSEARCH_USERNAME}:${ELASTICSEARCH_PASSWORD} + + - run: ./build.sh test --test-suite=e2e + env: + E2E__ENDPOINT: "${ELASTIC_APM_SERVER_URL}" + E2E__Authorization: "Authentication=ApiKey ${ELASTIC_APM_API_KEY}" + E2E__BROWSEREMAIL: "${KIBANA_USERNAME}" + E2E__BROWSERPASSWORD: "${KIBANA_PASSWORD}" diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index f73cc0e..5211a00 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -21,7 +21,7 @@ jobs: id: bootstrap uses: ./.github/workflows/bootstrap - - run: ./build.sh release + - run: ./build.sh release --test-suite=skip-e2e name: Release - name: publish canary packages github package repository diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fc6db8b..a81be4b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: id: bootstrap uses: ./.github/workflows/bootstrap - - run: ./build.sh release --skiptests + - run: ./build.sh release --test-suite=skip-all name: Release - name: Prepare Nuget diff --git a/build/scripts/CommandLine.fs b/build/scripts/CommandLine.fs index 944bbef..27133b0 100644 --- a/build/scripts/CommandLine.fs +++ b/build/scripts/CommandLine.fs @@ -9,15 +9,16 @@ open Microsoft.FSharp.Reflection open System open Bullseye +type TestSuite = All | Unit | Integration | E2E | Skip_All | Skip_E2E + type Build = | [] Clean | [] Version | [] Build | [] Test - | [] UnitTest - | [] Integrate - | [] EndToEnd + | [] Unit_Test + | [] End_To_End | [] PristineCheck | [] GeneratePackages @@ -27,10 +28,10 @@ type Build = | [] GenerateApiChanges | [] Release - | [] SingleTarget + | [] Single_Target | [] Token of string - | [] SkipDirtyCheck - | [] SkipTests + | [] Skip_Dirty_Check + | [] Test_Suite of TestSuite with interface IArgParserTemplate with member this.Usage = @@ -40,11 +41,9 @@ with | Version -> "print version information" | Build -> "Run build" - | UnitTest -> "build then run only the unit tests" - | Integrate -> "build then run only the integration tests" - | EndToEnd -> "build then run only the e2e tests" - | Test -> "build then run ALL the tests" - + | Unit_Test -> "alias to providing: test --test-suite=unit" + | End_To_End -> "alias to providing: test --test-suite=e2e" + | Test -> "runs a clean build and then runs all the tests unless --test-suite is provided" | Release -> "runs build, tests, and create and validates the packages shy of publishing them" // steps @@ -56,10 +55,11 @@ with | GenerateApiChanges -> "Undocumented, dependent target" // flags - | SingleTarget -> "Runs the provided sub command without running their dependencies" + | Single_Target -> "Runs the provided sub command without running their dependencies" | Token _ -> "Token to be used to authenticate with github" - | SkipDirtyCheck -> "Skip the clean checkout check that guards the release/publish targets" - | SkipTests -> "Skips running tests" + | Skip_Dirty_Check -> "Skip the clean checkout check that guards the release/publish targets" + | Test_Suite _ -> "Specify the test suite to run, defaults to all" + member this.StepName = match FSharpValue.GetUnionFields(this, typeof) with @@ -79,7 +79,7 @@ with Targets.Target(target.StepName, Action(fun _ -> action(parsed))) static member Cmd (dependsOn: Build list) (composedOf: Build list) action (target: Build) (parsed: ParseResults) = - let singleTarget = parsed.TryGetResult SingleTarget |> Option.isSome + let singleTarget = parsed.TryGetResult Single_Target |> Option.isSome let dependsOn = if singleTarget then [] else dependsOn let steps = dependsOn @ composedOf |> List.map (_.StepName) diff --git a/build/scripts/Targets.fs b/build/scripts/Targets.fs index 5d8e29a..b656435 100644 --- a/build/scripts/Targets.fs +++ b/build/scripts/Targets.fs @@ -34,14 +34,12 @@ let private version _ = let private generatePackages _ = exec { run "dotnet" "pack" } let private pristineCheck (arguments:ParseResults) = - let skipCheck = arguments.TryGetResult SkipDirtyCheck |> Option.isSome + let skipCheck = arguments.TryGetResult Skip_Dirty_Check |> Option.isSome match skipCheck, Information.isCleanWorkingCopy "." with | true, _ -> printfn "Checkout is dirty but -c was specified to ignore this" | _, true -> printfn "The checkout folder does not have pending changes, proceeding" | _ -> failwithf "The checkout folder has pending changes, aborting. Specify -c to ./build.sh to skip this check" -type TestSuite = | Unit | Integration | E2E | All - let private runTests suite _ = let logger = // use junit xml logging locally, github actions logs using console out formats @@ -55,9 +53,11 @@ let private runTests suite _ = let filterArgs = match suite with | All -> [] - | TestSuite.Unit -> [ "--filter"; "FullyQualifiedName~.Tests" ] - | TestSuite.Integration -> [ "--filter"; "FullyQualifiedName~.IntegrationTests" ] - | TestSuite.E2E -> [ "--filter"; "FullyQualifiedName~.EndToEndTests" ] + | Skip_All -> ["--filter"; "FullyQualifiedName~.SKIPPING.ALL.TESTS"] + | Unit -> [ "--filter"; "FullyQualifiedName~.Tests" ] + | Integration -> [ "--filter"; "FullyQualifiedName~.IntegrationTests" ] + | E2E -> [ "--filter"; "FullyQualifiedName~.EndToEndTests" ] + | Skip_E2E -> [ "--filter"; "FullyQualifiedName!~.EndToEndTests" ] let settingsArg = ["-s"; "tests/.runsettings"] @@ -72,10 +72,14 @@ let private runTests suite _ = ) } -let private test suite (arguments:ParseResults) = - match arguments.TryGetResult SkipTests with - | None -> runTests suite arguments - | Some _ -> printfn "Skipping tests because --skiptests was provided" +let private test (arguments:ParseResults) = + let arg = arguments.TryGetResult Test_Suite + match arg with + | None -> runTests TestSuite.All arguments + | Some suite -> + match suite with + | Skip_All -> printfn "Skipping tests because --test-suite skip was provided" + | _ -> runTests suite arguments let private validateLicenses _ = let args = ["-u"; "-t"; "-i"; "Elastic.OpenTelemetry.sln"; "--use-project-assets-json" @@ -149,10 +153,9 @@ let Setup (parsed:ParseResults) = | Clean -> Build.Cmd [Version] [] clean | Build -> Build.Cmd [Clean] [] build - | UnitTest -> Build.Cmd [Build] [] <| test TestSuite.Unit - | Integrate -> Build.Cmd [Build] [] <| test TestSuite.Integration - | EndToEnd -> Build.Cmd [Build] [] <| test TestSuite.E2E - | Test -> Build.Cmd [UnitTest; Integrate; EndToEnd] [] ignore + | End_To_End -> Build.Cmd [] [Build] <| runTests E2E + | Unit_Test -> Build.Cmd [] [Build] <| runTests Unit + | Test -> Build.Cmd [] [Build] test | Release -> Build.Cmd @@ -169,10 +172,10 @@ let Setup (parsed:ParseResults) = | GenerateApiChanges -> Build.Step generateApiChanges // flags - | SingleTarget - | SkipTests + | Single_Target + | Test_Suite _ | Token _ - | SkipDirtyCheck -> Build.Ignore + | Skip_Dirty_Check -> Build.Ignore for target in Build.Targets do let setup = wireCommandLine target From f7d9592930598c245249bb012034e567eca41d46 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 12 Feb 2024 15:32:45 +0100 Subject: [PATCH 14/24] allow equal assignment on flags --- build/scripts/CommandLine.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/scripts/CommandLine.fs b/build/scripts/CommandLine.fs index 27133b0..3ebfdcc 100644 --- a/build/scripts/CommandLine.fs +++ b/build/scripts/CommandLine.fs @@ -31,7 +31,7 @@ type Build = | [] Single_Target | [] Token of string | [] Skip_Dirty_Check - | [] Test_Suite of TestSuite + | [] Test_Suite of TestSuite with interface IArgParserTemplate with member this.Usage = From 132b6919ca7f06d83623fabd7afcc6852afb110a Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 12 Feb 2024 15:41:08 +0100 Subject: [PATCH 15/24] pass env's more explicitly --- .github/workflows/e2e.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index c15a26d..05b816c 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -54,7 +54,7 @@ jobs: - run: ./build.sh test --test-suite=e2e env: - E2E__ENDPOINT: "${ELASTIC_APM_SERVER_URL}" - E2E__Authorization: "Authentication=ApiKey ${ELASTIC_APM_API_KEY}" - E2E__BROWSEREMAIL: "${KIBANA_USERNAME}" - E2E__BROWSERPASSWORD: "${KIBANA_PASSWORD}" + E2E__ENDPOINT: "${{env.ELASTIC_APM_SERVER_URL}}" + E2E__Authorization: "Authentication=ApiKey ${{env.ELASTIC_APM_API_KEY}}" + E2E__BROWSEREMAIL: "${{env.KIBANA_USERNAME}}" + E2E__BROWSERPASSWORD: "${{env.KIBANA_PASSWORD}}" From 1b6e9dbd55129cdd49623be29a12d54d35aa89ae Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 12 Feb 2024 17:03:59 +0100 Subject: [PATCH 16/24] ensure we can write to console out early if e2e is not configured properly --- .github/workflows/e2e.yml | 2 +- .../DistributedFixture/ApmUIBrowserContext.cs | 1 + .../DistributedApplicationFixture.cs | 2 - .../DistributedFixture/ITrafficSimulator.cs | 1 + ...Elastic.OpenTelemetry.EndToEndTests.csproj | 2 +- .../GlobalSetup.cs | 41 +++++++++++++++---- .../ServiceTests.cs | 8 +++- 7 files changed, 44 insertions(+), 13 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 05b816c..83da3ab 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -55,6 +55,6 @@ jobs: - run: ./build.sh test --test-suite=e2e env: E2E__ENDPOINT: "${{env.ELASTIC_APM_SERVER_URL}}" - E2E__Authorization: "Authentication=ApiKey ${{env.ELASTIC_APM_API_KEY}}" + E2E__AUTHORIZATION: "Authentication=ApiKey ${{env.ELASTIC_APM_API_KEY}}" E2E__BROWSEREMAIL: "${{env.KIBANA_USERNAME}}" E2E__BROWSERPASSWORD: "${{env.KIBANA_PASSWORD}}" diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ApmUIBrowserContext.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ApmUIBrowserContext.cs index 05f8328..57c1ebb 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ApmUIBrowserContext.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ApmUIBrowserContext.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Playwright; +using Xunit; namespace Elastic.OpenTelemetry.EndToEndTests.DistributedFixture; diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DistributedApplicationFixture.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DistributedApplicationFixture.cs index 911a7fa..64297b3 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DistributedApplicationFixture.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DistributedApplicationFixture.cs @@ -50,8 +50,6 @@ public async Task InitializeAsync() AspNetApplication = new AspNetCoreExampleApplication(ServiceName, configuration); ApmUI = new ApmUIBrowserContext(configuration, ServiceName); - Console.WriteLine("Initializing.......?"); - foreach (var trafficSimulator in _trafficSimulators) await trafficSimulator.Start(this); diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ITrafficSimulator.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ITrafficSimulator.cs index b2d4802..118a0c4 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ITrafficSimulator.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/ITrafficSimulator.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information using System.Net; +using FluentAssertions; namespace Elastic.OpenTelemetry.EndToEndTests.DistributedFixture; diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj b/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj index 8d4f1a9..9c9289d 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj @@ -14,7 +14,7 @@ - + diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs index 672d0c5..1db63e3 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs @@ -2,18 +2,45 @@ // Elasticsearch B.V licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information -global using Xunit; -global using FluentAssertions; -using System.Runtime.CompilerServices; +using Elastic.OpenTelemetry.EndToEndTests; +using Elastic.OpenTelemetry.EndToEndTests.DistributedFixture; +using FluentAssertions; +using Microsoft.Extensions.Configuration; using Nullean.Xunit.Partitions; +using Xunit; [assembly: TestFramework(Partition.TestFramework, Partition.Assembly)] +[assembly: PartitionOptions(typeof(EndToEndOptions))] namespace Elastic.OpenTelemetry.EndToEndTests; -public static class GlobalSetup +public class EndToEndOptions : PartitionOptions { - [ModuleInitializer] - public static void Setup() => - XunitContext.EnableExceptionCapture(); + public EndToEndOptions() { } + + public override void OnBeforeTestsRun() + { + var configuration = new ConfigurationBuilder() + .AddEnvironmentVariables() + .AddUserSecrets() + .Build(); + try + { + configuration["E2E:Endpoint"].Should() + .NotBeNullOrWhiteSpace("Missing E2E:Endpoint configuration"); + configuration["E2E:Authorization"].Should() + .NotBeNullOrWhiteSpace("Missing E2E:Authorization configuration"); + configuration["E2E:BrowserEmail"].Should() + .NotBeNullOrWhiteSpace("Missing E2E:BrowserEmail configuration"); + configuration["E2E:BrowserPassword"].Should() + .NotBeNullOrWhiteSpace("Missing E2E:BrowserPassword configuration"); + } + catch (Exception e) + { + Console.WriteLine(); + Console.WriteLine(e.Message); + Console.WriteLine(); + throw; + } + } } diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs index 473328a..531d105 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs @@ -3,15 +3,19 @@ // See the LICENSE file in the project root for more information using Elastic.OpenTelemetry.EndToEndTests.DistributedFixture; +using FluentAssertions; using Microsoft.Playwright; using Nullean.Xunit.Partitions.Sdk; +using Xunit; +using Xunit.Abstractions; using static Microsoft.Playwright.Assertions; namespace Elastic.OpenTelemetry.EndToEndTests; public class EndToEndTests(ITestOutputHelper output, DistributedApplicationFixture fixture) - : XunitContextBase(output), IPartitionFixture, IAsyncLifetime + : IPartitionFixture, IAsyncLifetime { + public ITestOutputHelper Output { get; } = output; private string _testName = string.Empty; private IPage _page = null!; @@ -31,5 +35,5 @@ public async Task LatencyShowsAGraph() public async Task InitializeAsync() => _page = await fixture.ApmUI.NewProfiledPage(_testName); - public async Task DisposeAsync() => await fixture.ApmUI.StopTrace(_page, XunitContext.Context.TestException == null ? null : _testName); + public async Task DisposeAsync() => await fixture.ApmUI.StopTrace(_page, null == null ? null : _testName); } From 821cdc669604ee99dc1b11c8cf95f68adc868a71 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 12 Feb 2024 17:11:03 +0100 Subject: [PATCH 17/24] possible null handling in StartedConfirationHandler --- .../DistributedFixture/DotNetRunApplication.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DotNetRunApplication.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DotNetRunApplication.cs index 94c775e..5793840 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DotNetRunApplication.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/DistributedFixture/DotNetRunApplication.cs @@ -68,9 +68,10 @@ private LongRunningArguments CreateStartArgs() { "OTEL_BSP_MAX_EXPORT_BATCH_SIZE", "5" }, { "OTEL_RESOURCE_ATTRIBUTES", $"service.name={_serviceName},service.version=1.0,1,deployment.environment=e2e" }, }, - StartedConfirmationHandler = (l) => + StartedConfirmationHandler = l => { //Grab actual process id to send SIGINT to. + if (l.Line == null) return false; var processIdMatch = ProcessIdMatch.Match(l.Line); if (processIdMatch.Success) ProcessId = int.Parse(processIdMatch.Groups["processid"].Value); @@ -82,7 +83,6 @@ private LongRunningArguments CreateStartArgs() public virtual void Dispose() { - var pid = _app.Process.ProcessId; if (ProcessId.HasValue) _app.SendControlC(ProcessId.Value); _app.Dispose(); From f4689bf34e203b16187b7d29c104ca92c41df224 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 13 Feb 2024 10:09:46 +0100 Subject: [PATCH 18/24] ensure validation only happens if we run e2e tests --- build/scripts/CommandLine.fs | 6 +++++- build/scripts/Targets.fs | 1 + .../Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs | 10 ++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/build/scripts/CommandLine.fs b/build/scripts/CommandLine.fs index 3ebfdcc..4bf27b4 100644 --- a/build/scripts/CommandLine.fs +++ b/build/scripts/CommandLine.fs @@ -9,7 +9,11 @@ open Microsoft.FSharp.Reflection open System open Bullseye -type TestSuite = All | Unit | Integration | E2E | Skip_All | Skip_E2E +type TestSuite = All | Unit | Integration | E2E | Skip_All | Skip_E2E + with + member this.SuitName = + match FSharpValue.GetUnionFields(this, typeof) with + | case, _ -> case.Name.ToLowerInvariant() type Build = | [] Clean diff --git a/build/scripts/Targets.fs b/build/scripts/Targets.fs index b656435..cf6e665 100644 --- a/build/scripts/Targets.fs +++ b/build/scripts/Targets.fs @@ -63,6 +63,7 @@ let private runTests suite _ = let settingsArg = ["-s"; "tests/.runsettings"] let tfmArgs = if OS.Current = OS.Windows then [] else ["-f"; "net8.0"] exec { + env (Map ["TEST_SUITE", suite.SuitName]) run "dotnet" ( ["test"; "-c"; "release"; "--no-restore"; "--no-build"; logger] @ settingsArg diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs index 1db63e3..17c7766 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs @@ -24,6 +24,16 @@ public override void OnBeforeTestsRun() .AddEnvironmentVariables() .AddUserSecrets() .Build(); + + var testSuite = Environment.GetEnvironmentVariable("TEST_SUITE"); + + //only validate credentials if we are actually running the e2e suite + if (testSuite == null || ( + !testSuite.Equals("e2e", StringComparison.InvariantCultureIgnoreCase) + && !testSuite.Equals("all", StringComparison.InvariantCultureIgnoreCase)) + ) + return; + try { configuration["E2E:Endpoint"].Should() From 9e656b1398f25237a0d1b5e8233cd3d9e5f59141 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 13 Feb 2024 15:12:05 +0100 Subject: [PATCH 19/24] Update to latest partitions xunit that keeps track of the last test exception --- .../Elastic.OpenTelemetry.EndToEndTests.csproj | 3 +-- tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs | 2 -- tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj b/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj index 9c9289d..41dfa91 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/Elastic.OpenTelemetry.EndToEndTests.csproj @@ -12,9 +12,8 @@ - + - diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs index 17c7766..46113ca 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs @@ -16,8 +16,6 @@ namespace Elastic.OpenTelemetry.EndToEndTests; public class EndToEndOptions : PartitionOptions { - public EndToEndOptions() { } - public override void OnBeforeTestsRun() { var configuration = new ConfigurationBuilder() diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs index 531d105..2e0b432 100644 --- a/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs +++ b/tests/Elastic.OpenTelemetry.EndToEndTests/ServiceTests.cs @@ -35,5 +35,5 @@ public async Task LatencyShowsAGraph() public async Task InitializeAsync() => _page = await fixture.ApmUI.NewProfiledPage(_testName); - public async Task DisposeAsync() => await fixture.ApmUI.StopTrace(_page, null == null ? null : _testName); + public async Task DisposeAsync() => await fixture.ApmUI.StopTrace(_page, PartitionContext.TestException == null ? null : _testName); } From 51cb911b44a31c0ad572b3580e5a6acb8965053c Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 13 Feb 2024 15:20:24 +0100 Subject: [PATCH 20/24] fix vault lookup --- .github/workflows/e2e.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 96fd98d..05e410b 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -63,7 +63,7 @@ jobs: secretId: ${{ secrets.VAULT_SECRET_ID }} method: approle secrets: | - secret/observability-team/ci/elastic-cloud/observability-team-${{ env.VAULT_SECRET_SUFFIX }} username | E2E__BROWSEREMAIL + secret/observability-team/ci/elastic-cloud/observability-team-${{ env.VAULT_SECRET_SUFFIX }} username | E2E__BROWSEREMAIL ; secret/observability-team/ci/elastic-cloud/observability-team-${{ env.VAULT_SECRET_SUFFIX }} password | E2E__BROWSERPASSWORD - run: ./build.sh test --test-suite=e2e From 824782f7b08e34802798c6b9029372ec8a88e2a9 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Tue, 13 Feb 2024 15:30:12 +0100 Subject: [PATCH 21/24] ci: use pro secret --- .github/workflows/e2e.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 05e410b..cbc5e29 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -24,8 +24,8 @@ concurrency: env: # (keep_serverless-staging-oblt, keep_serverless-qa-oblt or serverless-production-oblt) SERVERLESS_PROJECT: serverless-production-oblt - # (staging, qa or production) - VAULT_SECRET_SUFFIX: production + # (staging, qa or pro) + VAULT_SECRET_SUFFIX: pro # NOTE: if you add a new job and it's a mandatory check then # update e2e-docs.yml From 5c2ece25ea66e352cd9522f4a44d892b1d0005ba Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Tue, 13 Feb 2024 15:40:14 +0100 Subject: [PATCH 22/24] temporarily disable e2e tests --- .github/workflows/e2e.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index cbc5e29..e4bc5f4 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -31,9 +31,10 @@ env: # update e2e-docs.yml jobs: test: - if: | - github.event_name != 'pull_request' || - (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false) + if: false() + #if: | + # github.event_name != 'pull_request' || + # (github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 From 0b2dc2ca1a2f73543ca6d3b18485914f5fc133f1 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 19 Feb 2024 10:47:27 +0100 Subject: [PATCH 23/24] restore deleted development files --- .../Properties/launchSettings.json | 10 ++++++++++ .../appsettings.Development.json | 8 ++++++++ 2 files changed, 18 insertions(+) create mode 100644 examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.Development.json diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json index 3cf6fca..96dfc62 100644 --- a/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json +++ b/examples/Example.Elastic.OpenTelemetry.AspNetCore/Properties/launchSettings.json @@ -18,6 +18,16 @@ "ASPNETCORE_ENVIRONMENT": "Development" } }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:7295;http://localhost:5247", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "OTEL_RESOURCE_ATTRIBUTES": "service.name=AspNetCoreApp,service.version=1.0.0,deployment.environment=development" + } + }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, diff --git a/examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.Development.json b/examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/examples/Example.Elastic.OpenTelemetry.AspNetCore/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} From 544be616b3145510f3ac3e6fbc873b37f1e593b3 Mon Sep 17 00:00:00 2001 From: Martijn Laarman Date: Mon, 19 Feb 2024 10:50:14 +0100 Subject: [PATCH 24/24] rename GlobalSetup to EndToEndOptions --- .../{GlobalSetup.cs => EndToEndOptions.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/Elastic.OpenTelemetry.EndToEndTests/{GlobalSetup.cs => EndToEndOptions.cs} (100%) diff --git a/tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs b/tests/Elastic.OpenTelemetry.EndToEndTests/EndToEndOptions.cs similarity index 100% rename from tests/Elastic.OpenTelemetry.EndToEndTests/GlobalSetup.cs rename to tests/Elastic.OpenTelemetry.EndToEndTests/EndToEndOptions.cs