| File: SeqEndpointCanBeConfigured.cs | Web Access |
| Project: src\tests\Aspire.Seq.Tests\Aspire.Seq.Tests.csproj (Aspire.Seq.Tests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Net; using System.Net.Sockets; using System.Text; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Hosting; using OpenTelemetry.Exporter; using Xunit; namespace Aspire.Seq.Tests; public class SeqTests { [Fact] public void SeqEndpointCanBeConfigured() { var builder = Host.CreateEmptyApplicationBuilder(null); builder.AddSeqEndpoint("seq", s => { s.DisableHealthChecks = true; s.Logs.TimeoutMilliseconds = 1000; s.Traces.Protocol = OtlpExportProtocol.Grpc; }); using var host = builder.Build(); } [Fact] public void ServerUrlSettingOverridesExporterEndpoints() { var builder = Host.CreateEmptyApplicationBuilder(null); var serverUrl = "http://localhost:9876"; SeqSettings settings = new SeqSettings(); builder.AddSeqEndpoint("seq", s => { settings = s; s.ServerUrl = serverUrl; s.ApiKey = "TestKey123!"; s.Logs.Endpoint = new Uri("http://localhost:1234/ingest/otlp/v1/logs"); s.Traces.Endpoint = new Uri("http://localhost:1234/ingest/otlp/v1/traces"); }); Assert.Equal(settings.Logs.Endpoint, new Uri("http://localhost:9876/ingest/otlp/v1/logs")); Assert.Equal(settings.Traces.Endpoint, new Uri("http://localhost:9876/ingest/otlp/v1/traces")); } [Fact] public void ApiKeySettingIsMergedWithConfiguredHeaders() { var builder = Host.CreateEmptyApplicationBuilder(null); SeqSettings settings = new SeqSettings(); builder.AddSeqEndpoint("seq", s => { settings = s; s.DisableHealthChecks = true; s.ApiKey = "TestKey123!"; s.Logs.Headers = "speed=fast,quality=good"; s.Traces.Headers = "quality=good,speed=fast"; }); Assert.Equal("speed=fast,quality=good,X-Seq-ApiKey=TestKey123!", settings.Logs.Headers); Assert.Equal("quality=good,speed=fast,X-Seq-ApiKey=TestKey123!", settings.Traces.Headers); } [Fact] public async Task HealthCheckDescriptionDoesNotExposeCredentialsFromServerUrl() { using var listener = new TcpListener(IPAddress.Loopback, 0); listener.Start(); var port = ((IPEndPoint)listener.LocalEndpoint).Port; var endpoint = new Uri($"http://127.0.0.1:{port}"); using var serverCts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var serverTask = WriteResponseAsync(listener, HttpStatusCode.ServiceUnavailable, serverCts.Token); var serverUrl = $"http://seq-user:secret-pass@{endpoint.Host}:{endpoint.Port}"; var builder = Host.CreateEmptyApplicationBuilder(null); builder.Configuration.AddInMemoryCollection([ new KeyValuePair<string, string?>("ConnectionStrings:seq", serverUrl) ]); builder.AddSeqEndpoint("seq"); using var host = builder.Build(); var healthCheckService = host.Services.GetRequiredService<HealthCheckService>(); using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var healthCheckReport = await healthCheckService.CheckHealthAsync(cts.Token); Assert.True(healthCheckReport.Entries.TryGetValue("Seq", out var entry)); Assert.Equal(HealthStatus.Unhealthy, entry.Status); Assert.NotNull(entry.Description); Assert.Contains($"http://{endpoint.Host}:{endpoint.Port}/health", entry.Description); Assert.DoesNotContain("seq-user", entry.Description); Assert.DoesNotContain("secret-pass", entry.Description); await serverTask; } private static async Task WriteResponseAsync(TcpListener listener, HttpStatusCode statusCode, CancellationToken cancellationToken) { using var client = await listener.AcceptTcpClientAsync(cancellationToken); await using var stream = client.GetStream(); var response = Encoding.ASCII.GetBytes( $"HTTP/1.1 {(int)statusCode} {statusCode}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n"); await stream.WriteAsync(response, cancellationToken); } }