Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Aaronontheweb/77cd8736c7b1739bcf8086a3a3fe70c8 to your computer and use it in GitHub Desktop.
Save Aaronontheweb/77cd8736c7b1739bcf8086a3a3fe70c8 to your computer and use it in GitHub Desktop.
Akka.NET Integration Testing with WebApplicationFactory
// -----------------------------------------------------------------------
// <copyright file="AspDotNetClusteredRouterIntegrationSpec.cs" company="Petabridge, LLC">
// Copyright (C) 2021 - 2021 Petabridge, LLC <https://petabridge.com>
// </copyright>
// -----------------------------------------------------------------------
using System.Threading.Tasks;
using Phobos.Actor.Cluster.Integration.Tests.Services;
using Xunit;
using Xunit.Abstractions;
namespace Phobos.Actor.Cluster.Integration.Tests
{
[Collection("AspNet")]
public class AspDotNetClusteredRouterIntegrationSpec : IClassFixture<CustomWebApplicationFactory<ClusterStartup>>
{
private readonly CustomWebApplicationFactory<ClusterStartup> _factory;
private readonly ITestOutputHelper _output;
public AspDotNetClusteredRouterIntegrationSpec(CustomWebApplicationFactory<ClusterStartup> factory,
ITestOutputHelper output)
{
_factory = factory;
_output = output;
}
/// <summary>
/// Bug reproduction for https://github.com/petabridge/phobos/issues/619
/// </summary>
[Fact]
public async Task ShouldTraceFromControllerToChr()
{
// Arrange
using var client = _factory.CreateClient();
// Act
var response = await client.GetAsync("test/cluster-router");
// Assert
response.EnsureSuccessStatusCode(); // Status Code 200-299
var sp = _factory.Services;
await TestHelpers.AwaitSingleTrace(sp, 3, _output);
}
}
}
// -----------------------------------------------------------------------
// <copyright file="ClusterStartup.cs" company="Petabridge, LLC">
// Copyright (C) 2021 - 2021 Petabridge, LLC <https://petabridge.com>
// </copyright>
// -----------------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry;
using OpenTelemetry.Exporter;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using Phobos.Tracing;
namespace Phobos.Actor.Cluster.Integration.Tests.Services
{
public class ClusterStartup
{
public ClusterStartup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
Env = env;
}
public IConfiguration Configuration { get; }
public IWebHostEnvironment Env { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<List<Activity>>();
services.AddSingleton<List<Metric>>();
services.AddOpenTelemetry()
.WithTracing(builder =>
{
builder
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddPhobosInstrumentation();
})
.WithMetrics(builder =>
{
builder.AddPhobosInstrumentation();
});
services.ConfigureOpenTelemetryTracerProvider((provider, providerBuilder) =>
{
var traces = provider.GetRequiredService<List<Activity>>();
providerBuilder.AddInMemoryExporter(traces);
});
services.ConfigureOpenTelemetryMeterProvider((provider, providerBuilder) =>
{
var metrics = provider.GetRequiredService<List<Metric>>();
providerBuilder.AddReader(new BaseExportingMetricReader(new InMemoryExporter<Metric>(metrics))
{
TemporalityPreference = MetricReaderTemporalityPreference.Cumulative
});
});
services.AddSingleton(serviceProvider =>
{
var traces = serviceProvider.GetRequiredService<List<Activity>>();
var providerBuilder = serviceProvider.GetRequiredService<TracerProvider>();
var tracer = providerBuilder.GetTracer(ActorTracing.PhobosActivitySourceName);
return new TracerPayload(traces, providerBuilder, tracer);
});
services.AddSingleton<IClusterTestService, AkkaClusterService>();
services.AddHostedService(sp => (AkkaClusterService)sp.GetRequiredService<IClusterTestService>());
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(c => c.MapControllers());
// workaround for https://github.com/open-telemetry/opentelemetry-dotnet/issues/2806
using (var scope = app.ApplicationServices.CreateScope())
{
var services = scope.ServiceProvider;
// BUGFIX
var context = services.GetRequiredService<TracerPayload>();
using (var trace = context.Tracer.StartRootSpan("TEST"))
{
}
context.Provider.ForceFlush();
context.Reset();
}
}
}
}
// -----------------------------------------------------------------------
// <copyright file="CustomWebApplicationFactory.cs" company="Petabridge, LLC">
// Copyright (C) 2021 - 2021 Petabridge, LLC <https://petabridge.com>
// </copyright>
// -----------------------------------------------------------------------
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Hosting;
namespace Phobos.Actor.Cluster.Integration.Tests
{
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
protected override IHostBuilder CreateHostBuilder()
{
var builder = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(x => { x.UseTestServer(); })
.UseContentRoot(Path.Combine(Directory.GetCurrentDirectory(), "src", "core",
"Phobos.Actor.Cluster.Integration.Tests"));
return builder;
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseStartup<TStartup>().UseSolutionRelativeContentRoot("");
}
}
}
@Aaronontheweb
Copy link
Author

Worth noting: this code pre-dates the creation of Akka.Hosting, which is a better way to try and do this. This is still part of our active test suite for Phobos using ASP.NET Core 8.0 at the time of writing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment