Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for Seq #6032

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ jobs:
name: Hosting.Redis
- project: tests/Aspire.Hosting.Sdk.Tests/Aspire.Hosting.Sdk.Tests.csproj
name: Hosting.Sdk
- project: tests/Aspire.Hosting.Seq.Tests/Aspire.Hosting.Seq.Tests.csproj
name: Hosting.Seq
- project: tests/Aspire.Hosting.SqlServer.Tests/Aspire.Hosting.SqlServer.Tests.csproj
name: Hosting.SqlServer
- project: tests/Aspire.Hosting.Testing.Tests/Aspire.Hosting.Testing.Tests.csproj
Expand Down
7 changes: 7 additions & 0 deletions Aspire.sln
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.MongoDB.Driver.v3.Te
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stress.Empty", "playground\Stress\Stress.Empty\Stress.Empty.csproj", "{6C4B55AD-5D98-452D-B71D-CAF628E822B0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspire.Hosting.Seq.Tests", "tests\Aspire.Hosting.Seq.Tests\Aspire.Hosting.Seq.Tests.csproj", "{CA86754E-3AED-4937-BE7B-14EF9929E245}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1671,6 +1673,10 @@ Global
{6C4B55AD-5D98-452D-B71D-CAF628E822B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C4B55AD-5D98-452D-B71D-CAF628E822B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C4B55AD-5D98-452D-B71D-CAF628E822B0}.Release|Any CPU.Build.0 = Release|Any CPU
{CA86754E-3AED-4937-BE7B-14EF9929E245}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA86754E-3AED-4937-BE7B-14EF9929E245}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA86754E-3AED-4937-BE7B-14EF9929E245}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA86754E-3AED-4937-BE7B-14EF9929E245}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1977,6 +1983,7 @@ Global
{FD53B608-138D-8FB1-AA57-9B8CD42CF13E} = {27381127-6C45-4B4C-8F18-41FF48DFE4B2}
{223AF8EB-3A4E-E778-4EBD-6E4876C308B6} = {C424395C-1235-41A4-BF55-07880A04368C}
{6C4B55AD-5D98-452D-B71D-CAF628E822B0} = {CFDA7AC5-251C-43C7-B334-71AE8040A147}
{CA86754E-3AED-4937-BE7B-14EF9929E245} = {830A89EC-4029-4753-B25A-068BAE37DEC7}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {47DCFECF-5631-4BDE-A1EC-BE41E90F60C4}
Expand Down
18 changes: 14 additions & 4 deletions src/Aspire.Hosting.Seq/SeqBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ public static class SeqBuilderExtensions
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name to give the resource.</param>
/// <param name="port">The host port for the Seq server.</param>
#pragma warning disable RS0016 // Add public types and members to the declared API
public static IResourceBuilder<SeqResource> AddSeq(
#pragma warning restore RS0016 // Add public types and members to the declared API
this IDistributedApplicationBuilder builder,
string name,
int? port = null)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(name);

var seqResource = new SeqResource(name);
var resourceBuilder = builder.AddResource(seqResource)
.WithHttpEndpoint(port: port, targetPort: 80, name: SeqResource.PrimaryEndpointName)
Expand All @@ -48,7 +49,11 @@ public static IResourceBuilder<SeqResource> AddSeq(
/// <param name="isReadOnly">A flag that indicates if this is a read-only volume.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<SeqResource> WithDataVolume(this IResourceBuilder<SeqResource> builder, string? name = null, bool isReadOnly = false)
=> builder.WithVolume(name ?? VolumeNameGenerator.Generate(builder, "data"), SeqContainerDataDirectory, isReadOnly);
{
ArgumentNullException.ThrowIfNull(builder);

return builder.WithVolume(name ?? VolumeNameGenerator.Generate(builder, "data"), SeqContainerDataDirectory, isReadOnly);
}

/// <summary>
/// Adds a bind mount for the data folder to a Seq container resource.
Expand All @@ -58,5 +63,10 @@ public static IResourceBuilder<SeqResource> WithDataVolume(this IResourceBuilder
/// <param name="isReadOnly">A flag that indicates if this is a read-only mount.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<SeqResource> WithDataBindMount(this IResourceBuilder<SeqResource> builder, string source, bool isReadOnly = false)
=> builder.WithBindMount(source, SeqContainerDataDirectory, isReadOnly);
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(source);

return builder.WithBindMount(source, SeqContainerDataDirectory, isReadOnly);
}
}
165 changes: 165 additions & 0 deletions tests/Aspire.Hosting.Seq.Tests/AddSeqTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// 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.Sockets;
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Utils;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

namespace Aspire.Hosting.Seq.Tests;

public class AddSeqTests
{
[Fact]
public void AddSeqContainerWithDefaultsAddsAnnotationMetadata()
{
var appBuilder = DistributedApplication.CreateBuilder();
appBuilder.AddSeq("mySeq").PublishAsContainer();

using var app = appBuilder.Build();

var appModel = app.Services.GetRequiredService<DistributedApplicationModel>();

var containerResource = Assert.Single(appModel.Resources.OfType<SeqResource>());
Assert.Equal("mySeq", containerResource.Name);

var endpoint = Assert.Single(containerResource.Annotations.OfType<EndpointAnnotation>());
Assert.Equal(80, endpoint.TargetPort);
Assert.False(endpoint.IsExternal);
Assert.Equal("http", endpoint.Name);
Assert.Null(endpoint.Port);
Assert.Equal(ProtocolType.Tcp, endpoint.Protocol);
Assert.Equal("http", endpoint.Transport);
Assert.Equal("http", endpoint.UriScheme);

var containerAnnotation = Assert.Single(containerResource.Annotations.OfType<ContainerImageAnnotation>());
Assert.Equal(SeqContainerImageTags.Tag, containerAnnotation.Tag);
Assert.Equal(SeqContainerImageTags.Image, containerAnnotation.Image);
Assert.Equal(SeqContainerImageTags.Registry, containerAnnotation.Registry);
}

[Fact]
public void AddSeqContainerAddsAnnotationMetadata()
{
var appBuilder = DistributedApplication.CreateBuilder();
appBuilder.AddSeq("mySeq", port: 9813);

using var app = appBuilder.Build();

var appModel = app.Services.GetRequiredService<DistributedApplicationModel>();

var containerResource = Assert.Single(appModel.Resources.OfType<SeqResource>());
Assert.Equal("mySeq", containerResource.Name);

var endpoint = Assert.Single(containerResource.Annotations.OfType<EndpointAnnotation>());
Assert.Equal(80, endpoint.TargetPort);
Assert.False(endpoint.IsExternal);
Assert.Equal("http", endpoint.Name);
Assert.Equal(9813, endpoint.Port);
Assert.Equal(ProtocolType.Tcp, endpoint.Protocol);
Assert.Equal("http", endpoint.Transport);
Assert.Equal("http", endpoint.UriScheme);

var containerAnnotation = Assert.Single(containerResource.Annotations.OfType<ContainerImageAnnotation>());
Assert.Equal(SeqContainerImageTags.Tag, containerAnnotation.Tag);
Assert.Equal(SeqContainerImageTags.Image, containerAnnotation.Image);
Assert.Equal(SeqContainerImageTags.Registry, containerAnnotation.Registry);
}

[Fact]
public async Task SeqCreatesConnectionString()
{
var appBuilder = DistributedApplication.CreateBuilder();
appBuilder.AddSeq("mySeq")
.WithEndpoint("http", e => e.AllocatedEndpoint = new AllocatedEndpoint(e, "localhost", 2000));

using var app = appBuilder.Build();

var appModel = app.Services.GetRequiredService<DistributedApplicationModel>();

var connectionStringResource = Assert.Single(appModel.Resources.OfType<IResourceWithConnectionString>());
var connectionString = await connectionStringResource.GetConnectionStringAsync(default);
Assert.Equal("{mySeq.bindings.http.url}", connectionStringResource.ConnectionStringExpression.ValueExpression);
Assert.StartsWith("http://localhost:2000", connectionString);
}

[Fact]
public async Task VerifyManifest()
{
using var builder = TestDistributedApplicationBuilder.Create();
var seq = builder.AddSeq("seq");

var manifest = await ManifestUtils.GetManifest(seq.Resource);

var expectedManifest = $$"""
{
"type": "container.v0",
"connectionString": "{seq.bindings.http.url}",
"image": "{{SeqContainerImageTags.Registry}}/{{SeqContainerImageTags.Image}}:{{SeqContainerImageTags.Tag}}",
"env": {
"ACCEPT_EULA": "Y"
},
"bindings": {
"http": {
"scheme": "http",
"protocol": "tcp",
"transport": "http",
"targetPort": 80
}
}
}
""";
Assert.Equal(expectedManifest, manifest.ToString());
}

[Theory]
[InlineData(null)]
[InlineData(true)]
[InlineData(false)]
public void WithDataVolumeAddsVolumeAnnotation(bool? isReadOnly)
{
using var builder = TestDistributedApplicationBuilder.Create();
var seq = builder.AddSeq("mySeq");
if (isReadOnly.HasValue)
{
seq.WithDataVolume(isReadOnly: isReadOnly.Value);
}
else
{
seq.WithDataVolume();
}

var volumeAnnotation = seq.Resource.Annotations.OfType<ContainerMountAnnotation>().Single();

Assert.Equal($"{builder.GetVolumePrefix()}-mySeq-data", volumeAnnotation.Source);
Assert.Equal("/data", volumeAnnotation.Target);
Assert.Equal(ContainerMountType.Volume, volumeAnnotation.Type);
Assert.Equal(isReadOnly ?? false, volumeAnnotation.IsReadOnly);
}

[Theory]
[InlineData(null)]
[InlineData(true)]
[InlineData(false)]
public void WithDataBindMountAddsMountAnnotation(bool? isReadOnly)
{
using var builder = TestDistributedApplicationBuilder.Create();
var seq = builder.AddSeq("mySeq");
if (isReadOnly.HasValue)
{
seq.WithDataBindMount("mydata", isReadOnly: isReadOnly.Value);
}
else
{
seq.WithDataBindMount("mydata");
}

var volumeAnnotation = seq.Resource.Annotations.OfType<ContainerMountAnnotation>().Single();

Assert.Equal(Path.Combine(builder.AppHostDirectory, "mydata"), volumeAnnotation.Source);
Assert.Equal("/data", volumeAnnotation.Target);
Assert.Equal(ContainerMountType.BindMount, volumeAnnotation.Type);
Assert.Equal(isReadOnly ?? false, volumeAnnotation.IsReadOnly);
}
}
19 changes: 19 additions & 0 deletions tests/Aspire.Hosting.Seq.Tests/Aspire.Hosting.Seq.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(DefaultTargetFramework)</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Aspire.Hosting.AppHost\Aspire.Hosting.AppHost.csproj" />
<ProjectReference Include="..\..\src\Aspire.Hosting.Seq\Aspire.Hosting.Seq.csproj" />
<ProjectReference Include="..\Aspire.Hosting.Tests\Aspire.Hosting.Tests.csproj" />

<PackageReference Include="Microsoft.Extensions.Http.Resilience" />
</ItemGroup>

<ItemGroup>
<Compile Include="$(RepoRoot)src\Aspire.Hosting.Seq\SeqContainerImageTags.cs" />
</ItemGroup>

</Project>
Loading