Skip to content

Commit

Permalink
[tests] Use existing container for tests executed with RemoteExecutor (
Browse files Browse the repository at this point in the history
…#3444)

The tracing tests in `ConformanceTests` for some components are run with

`RemoteExecutor.Invoke(() => RunWithFixtureAsync(obj => obj.ActivitySourceTest(key: null))).Dispose()`

.. where `RunWithFixtureAsync` starts up a `testcontainer` in the remote
process, and then runs the test. But unlike other instances of the
tracing tests, here starting up the container can take ~1min causing the `RemoteExecutor`
to fail after the default 1 min timeout.

Instead pass the connection string from the fixture to the
`RemoteExecutor`, so a new container doesn't need to be spun up.

Example log from the remote execution:

```
[testcontainers.org 00:00:02.97] Execute "/opt/mssql-tools/bin/sqlcmd -Q SELECT 1;" at Docker container d69a9831c425
[testcontainers.org 00:00:12.09] Execute "/opt/mssql-tools/bin/sqlcmd -Q SELECT 1;" at Docker container d69a9831c425
[testcontainers.org 00:00:21.15] Execute "/opt/mssql-tools/bin/sqlcmd -Q SELECT 1;" at Docker container d69a9831c425
[testcontainers.org 00:00:30.22] Execute "/opt/mssql-tools/bin/sqlcmd -Q SELECT 1;" at Docker container d69a9831c425
[testcontainers.org 00:00:39.29] Execute "/opt/mssql-tools/bin/sqlcmd -Q SELECT 1;" at Docker container d69a9831c425
[testcontainers.org 00:00:48.35] Execute "/opt/mssql-tools/bin/sqlcmd -Q SELECT 1;" at Docker container d69a9831c425
[testcontainers.org 00:00:57.42] Execute "/opt/mssql-tools/bin/sqlcmd -Q SELECT 1;" at Docker container d69a9831c425
[testcontainers.org 00:00:58.52] Execute "/opt/mssql-tools/bin/sqlcmd -Q SELECT 1;" at Docker container d69a9831c425
[testcontainers.org 00:00:59.60] Execute "/opt/mssql-tools/bin/sqlcmd -Q SELECT 1;" at Docker container d69a9831c425
[xUnit.net 00:02:38.60]     Aspire.Microsoft.EntityFrameworkCore.SqlServer.Tests.ConformanceTests_TypeSpecificConfig.TracingEnablesTheRightActivitySource [FAIL]
[xUnit.net 00:02:38.60]       Microsoft.DotNet.RemoteExecutor.RemoteExecutionException : Half-way through waiting for remote process.
[xUnit.net 00:02:38.60]       Timed out at 3/27/2024 5:35:56 PM after 60000ms waiting for remote process.
[xUnit.net 00:02:38.60]         Process ID: 36471
[xUnit.net 00:02:38.60]         Handle: 5036
[xUnit.net 00:02:38.60]         Name: dotnet
[xUnit.net 00:02:38.60]         MainModule: /datadisks/disk1/work/B5B5097E/p/dotnet-cli/dotnet
[xUnit.net 00:02:38.60]         StartTime: 3/27/2024 5:34:56 PM
[xUnit.net 00:02:38.60]         TotalProcessorTime: 00:00:02.1500000
[xUnit.net 00:02:38.60]
[xUnit.net 00:02:38.60]       Stack Trace:
[xUnit.net 00:02:38.60]         /_/src/Microsoft.DotNet.RemoteExecutor/src/RemoteInvokeHandle.cs(225,0): at Microsoft.DotNet.RemoteExecutor.RemoteInvokeHandle.Dispose(Boolean disposing)
[xUnit.net 00:02:38.60]         /_/src/Microsoft.DotNet.RemoteExecutor/src/RemoteInvokeHandle.cs(55,0): at Microsoft.DotNet.RemoteExecutor.RemoteInvokeHandle.Dispose()
[xUnit.net 00:02:38.60]         /_/tests/Aspire.Microsoft.EntityFrameworkCore.SqlServer.Tests/ConformanceTests.cs(116,0): at Aspire.Microsoft.EntityFrameworkCore.SqlServer.Tests.ConformanceTests.TracingEnabl>
[xUnit.net 00:02:38.60]            at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
[xUnit.net 00:02:38.60]            at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
```

Fixes #3221
  • Loading branch information
radical committed Apr 9, 2024
1 parent 37e795d commit bdc5ea4
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 82 deletions.
29 changes: 15 additions & 14 deletions tests/Aspire.Microsoft.Data.SqlClient.Tests/ConformanceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@ namespace Aspire.Microsoft.Data.SqlClient.Tests;

public class ConformanceTests : ConformanceTests<SqlConnection, MicrosoftDataSqlClientSettings>, IClassFixture<SqlServerContainerFixture>
{
private readonly SqlServerContainerFixture _containerFixture;
private readonly SqlServerContainerFixture? _containerFixture;
private string ConnectionString { get; set; }
protected override bool CanConnectToServer => RequiresDockerTheoryAttribute.IsSupported;
private string ConnectionString => RequiresDockerTheoryAttribute.IsSupported
? _containerFixture.GetConnectionString()
: "Data Source=fake;Database=master";
protected override ServiceLifetime ServiceLifetime => ServiceLifetime.Scoped;

// https://github.com/open-telemetry/opentelemetry-dotnet/blob/031ed48714e16ba4a5b099b6e14647994a0b9c1b/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlActivitySourceHelper.cs#L31
Expand Down Expand Up @@ -49,8 +47,13 @@ protected override (string json, string error)[] InvalidJsonToErrorMessage => ne
("""{"Aspire": { "Microsoft": { "Data" : { "SqlClient":{ "ConnectionString": "Con", "HealthChecks": "false"}}}}}""", "Value is \"string\" but should be \"boolean\"")
};

public ConformanceTests(SqlServerContainerFixture containerFixture)
=> _containerFixture = containerFixture;
public ConformanceTests(SqlServerContainerFixture? containerFixture)
{
_containerFixture = containerFixture;
ConnectionString = (_containerFixture is not null && RequiresDockerTheoryAttribute.IsSupported)
? _containerFixture.GetConnectionString()
: "Server=localhost;User ID=root;Password=password;Database=test_aspire_mysql";
}

protected override void PopulateConfiguration(ConfigurationManager configuration, string? key = null)
=> configuration.AddInMemoryCollection(new KeyValuePair<string, string?>[1]
Expand Down Expand Up @@ -90,17 +93,15 @@ protected override void TriggerActivity(SqlConnection service)

[RequiresDockerFact]
public void TracingEnablesTheRightActivitySource()
=> RemoteExecutor.Invoke(() => RunWithFixtureAsync(obj => obj.ActivitySourceTest(key: null))).Dispose();
=> RemoteExecutor.Invoke(static connectionStringToUse => RunWithConnectionString(connectionStringToUse, obj => obj.ActivitySourceTest(key: null)),
ConnectionString).Dispose();

[RequiresDockerFact]
public void TracingEnablesTheRightActivitySource_Keyed()
=> RemoteExecutor.Invoke(() => RunWithFixtureAsync(obj => obj.ActivitySourceTest(key: "key"))).Dispose();
=> RemoteExecutor.Invoke(static connectionStringToUse => RunWithConnectionString(connectionStringToUse, obj => obj.ActivitySourceTest(key: "key")),
ConnectionString).Dispose();

private static async Task RunWithFixtureAsync(Action<ConformanceTests> test)
{
await using var fixture = new SqlServerContainerFixture();
await fixture.InitializeAsync();
test(new ConformanceTests(fixture));
}
private static void RunWithConnectionString(string connectionString, Action<ConformanceTests> test)
=> test(new ConformanceTests(null) { ConnectionString = connectionString });

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ namespace Aspire.Microsoft.EntityFrameworkCore.SqlServer.Tests;

public class ConformanceTests : ConformanceTests<TestDbContext, MicrosoftEntityFrameworkCoreSqlServerSettings>, IClassFixture<SqlServerContainerFixture>
{
private readonly SqlServerContainerFixture _containerFixture;
protected string ConnectionString => RequiresDockerTheoryAttribute.IsSupported
? _containerFixture.GetConnectionString()
: "Host=fake;Database=catalog";
private readonly SqlServerContainerFixture? _containerFixture;
protected string ConnectionString { get; private set; }

protected override bool CanConnectToServer => RequiresDockerTheoryAttribute.IsSupported;
protected override ServiceLifetime ServiceLifetime => ServiceLifetime.Singleton;
Expand Down Expand Up @@ -64,8 +62,13 @@ protected override (string json, string error)[] InvalidJsonToErrorMessage => ne
("""{"Aspire": { "Microsoft": { "EntityFrameworkCore":{ "SqlServer": { "Tracing": "false"}}}}}""", "Value is \"string\" but should be \"boolean\""),
};

public ConformanceTests(SqlServerContainerFixture fixture)
=> _containerFixture = fixture;
public ConformanceTests(SqlServerContainerFixture? fixture)
{
_containerFixture = fixture;
ConnectionString = (_containerFixture is not null && RequiresDockerTheoryAttribute.IsSupported)
? _containerFixture.GetConnectionString()
: "Server=localhost;User ID=root;Password=password;Database=test_aspire_mysql";
}

protected override void PopulateConfiguration(ConfigurationManager configuration, string? key = null)
=> configuration.AddInMemoryCollection(new KeyValuePair<string, string?>[1]
Expand Down Expand Up @@ -113,12 +116,9 @@ public void DbContextCanBeAlwaysResolved()

[RequiresDockerFact]
public void TracingEnablesTheRightActivitySource()
=> RemoteExecutor.Invoke(() => RunWithFixtureAsync(obj => obj.ActivitySourceTest(key: null))).Dispose();
=> RemoteExecutor.Invoke(static connectionStringToUse => RunWithConnectionString(connectionStringToUse, obj => obj.ActivitySourceTest(key: null)),
ConnectionString).Dispose();

private static async Task RunWithFixtureAsync(Action<ConformanceTests> test)
{
await using var fixture = new SqlServerContainerFixture();
await fixture.InitializeAsync();
test(new ConformanceTests(fixture));
}
private static void RunWithConnectionString(string connectionString, Action<ConformanceTests> test)
=> test(new ConformanceTests(null) { ConnectionString = connectionString });
}
29 changes: 15 additions & 14 deletions tests/Aspire.MySqlConnector.Tests/ConformanceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ namespace Aspire.MySqlConnector.Tests;

public class ConformanceTests : ConformanceTests<MySqlDataSource, MySqlConnectorSettings>, IClassFixture<MySqlContainerFixture>
{
private readonly MySqlContainerFixture _containerFixture;
private string ConnectionString => RequiresDockerTheoryAttribute.IsSupported
? _containerFixture.GetConnectionString()
: "Server=localhost;User ID=root;Password=password;Database=test_aspire_mysql";
private readonly MySqlContainerFixture? _containerFixture;
private string ConnectionString { get; set; }
protected override ServiceLifetime ServiceLifetime => ServiceLifetime.Singleton;

// https://github.com/mysql-net/MySqlConnector/blob/d895afc013a5849d33a123a7061442e2cbb9ce76/src/MySqlConnector/Utilities/ActivitySourceHelper.cs#L61
Expand Down Expand Up @@ -55,8 +53,13 @@ protected override (string json, string error)[] InvalidJsonToErrorMessage => ne
("""{"Aspire": { "MySqlConnector":{ "ConnectionString": "Con", "HealthChecks": "false"}}}""", "Value is \"string\" but should be \"boolean\"")
};

public ConformanceTests(MySqlContainerFixture containerFixture)
=> _containerFixture = containerFixture;
public ConformanceTests(MySqlContainerFixture? containerFixture)
{
_containerFixture = containerFixture;
ConnectionString = (_containerFixture is not null && RequiresDockerTheoryAttribute.IsSupported)
? _containerFixture.GetConnectionString()
: "Server=localhost;User ID=root;Password=password;Database=test_aspire_mysql";
}

protected override void PopulateConfiguration(ConfigurationManager configuration, string? key = null)
=> configuration.AddInMemoryCollection(new KeyValuePair<string, string?>[1]
Expand Down Expand Up @@ -120,16 +123,14 @@ public void BothDataSourceAndConnectionCanBeResolved(string? key)

[RequiresDockerFact]
public void TracingEnablesTheRightActivitySource()
=> RemoteExecutor.Invoke(() => RunWithFixtureAsync(obj => obj.ActivitySourceTest(key: null))).Dispose();
=> RemoteExecutor.Invoke(static connectionStringToUse => RunWithConnectionString(connectionStringToUse, obj => obj.ActivitySourceTest(key: null)),
ConnectionString).Dispose();

[RequiresDockerFact]
public void TracingEnablesTheRightActivitySource_Keyed()
=> RemoteExecutor.Invoke(() => RunWithFixtureAsync(obj => obj.ActivitySourceTest(key: "key"))).Dispose();
=> RemoteExecutor.Invoke(static connectionStringToUse => RunWithConnectionString(connectionStringToUse, obj => obj.ActivitySourceTest(key: "key")),
ConnectionString).Dispose();

private static async Task RunWithFixtureAsync(Action<ConformanceTests> test)
{
await using var fixture = new MySqlContainerFixture();
await fixture.InitializeAsync();
test(new ConformanceTests(fixture));
}
private static void RunWithConnectionString(string connectionString, Action<ConformanceTests> test)
=> test(new ConformanceTests(null) { ConnectionString = connectionString });
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,8 @@ namespace Aspire.Npgsql.EntityFrameworkCore.PostgreSQL.Tests;
public class ConformanceTests : ConformanceTests<TestDbContext, NpgsqlEntityFrameworkCorePostgreSQLSettings>, IClassFixture<PostgreSQLContainerFixture>
{
// in the future it can become a static property that reads the value from Env Var
private readonly PostgreSQLContainerFixture _containerFixture;
protected string ConnectionString => RequiresDockerTheoryAttribute.IsSupported
? _containerFixture.GetConnectionString()
: "Host=localhost;Database=test;Username=postgres;Password=postgres";

private readonly PostgreSQLContainerFixture? _containerFixture;
protected string ConnectionString { get; private set; }
protected override ServiceLifetime ServiceLifetime => ServiceLifetime.Singleton;

// https://github.com/npgsql/npgsql/blob/ef9db1ffe9e432c1562d855b46dfac3514726b1b/src/Npgsql.OpenTelemetry/TracerProviderBuilderExtensions.cs#L18
Expand Down Expand Up @@ -79,8 +76,13 @@ protected override (string json, string error)[] InvalidJsonToErrorMessage => ne
("""{"Aspire": { "Npgsql": { "EntityFrameworkCore":{ "PostgreSQL": { "Metrics": "false"}}}}}""", "Value is \"string\" but should be \"boolean\""),
};

public ConformanceTests(PostgreSQLContainerFixture containerFixture)
=> _containerFixture = containerFixture;
public ConformanceTests(PostgreSQLContainerFixture? containerFixture)
{
_containerFixture = containerFixture;
ConnectionString = (_containerFixture is not null && RequiresDockerTheoryAttribute.IsSupported)
? _containerFixture.GetConnectionString()
: "Server=localhost;User ID=root;Password=password;Database=test_aspire_mysql";
}

protected override void PopulateConfiguration(ConfigurationManager configuration, string? key = null)
=> configuration.AddInMemoryCollection(new KeyValuePair<string, string?>[1]
Expand Down Expand Up @@ -131,12 +133,9 @@ public void DbContextCanBeAlwaysResolved()

[RequiresDockerFact]
public void TracingEnablesTheRightActivitySource()
=> RemoteExecutor.Invoke(() => RunWithFixtureAsync(obj => obj.ActivitySourceTest(key: null))).Dispose();
=> RemoteExecutor.Invoke(static connectionStringToUse => RunWithConnectionString(connectionStringToUse, obj => obj.ActivitySourceTest(key: null)),
ConnectionString).Dispose();

private static async Task RunWithFixtureAsync(Action<ConformanceTests> test)
{
await using var fixture = new PostgreSQLContainerFixture();
await fixture.InitializeAsync();
test(new ConformanceTests(fixture));
}
private static void RunWithConnectionString(string connectionString, Action<ConformanceTests> test)
=> test(new ConformanceTests(null) { ConnectionString = connectionString });
}
29 changes: 15 additions & 14 deletions tests/Aspire.Npgsql.Tests/ConformanceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ namespace Aspire.Npgsql.Tests;

public class ConformanceTests : ConformanceTests<NpgsqlDataSource, NpgsqlSettings>, IClassFixture<PostgreSQLContainerFixture>
{
private readonly PostgreSQLContainerFixture _containerFixture;
private string ConnectionString => RequiresDockerTheoryAttribute.IsSupported
? _containerFixture.GetConnectionString()
: "Host=localhost;Database=test_aspire_npgsql;Username=postgres;Password=postgres";
private readonly PostgreSQLContainerFixture? _containerFixture;
protected string ConnectionString { get; private set; }
protected override ServiceLifetime ServiceLifetime => ServiceLifetime.Singleton;

// https://github.com/npgsql/npgsql/blob/ef9db1ffe9e432c1562d855b46dfac3514726b1b/src/Npgsql.OpenTelemetry/TracerProviderBuilderExtensions.cs#L18
Expand Down Expand Up @@ -57,8 +55,13 @@ protected override (string json, string error)[] InvalidJsonToErrorMessage => ne
("""{"Aspire": { "Npgsql":{ "ConnectionString": "Con", "HealthChecks": "false"}}}""", "Value is \"string\" but should be \"boolean\"")
};

public ConformanceTests(PostgreSQLContainerFixture containerFixture)
=> _containerFixture = containerFixture;
public ConformanceTests(PostgreSQLContainerFixture? containerFixture)
{
_containerFixture = containerFixture;
ConnectionString = (_containerFixture is not null && RequiresDockerTheoryAttribute.IsSupported)
? _containerFixture.GetConnectionString()
: "Server=localhost;User ID=root;Password=password;Database=test_aspire_mysql";
}

protected override void PopulateConfiguration(ConfigurationManager configuration, string? key = null)
=> configuration.AddInMemoryCollection(new KeyValuePair<string, string?>[1]
Expand Down Expand Up @@ -122,16 +125,14 @@ public void BothDataSourceAndConnectionCanBeResolved(string? key)

[RequiresDockerFact]
public void TracingEnablesTheRightActivitySource()
=> RemoteExecutor.Invoke(() => RunWithFixtureAsync(obj => obj.ActivitySourceTest(key: null))).Dispose();
=> RemoteExecutor.Invoke(static connectionStringToUse => RunWithConnectionString(connectionStringToUse, obj => obj.ActivitySourceTest(key: null)),
ConnectionString).Dispose();

[RequiresDockerFact]
public void TracingEnablesTheRightActivitySource_Keyed()
=> RemoteExecutor.Invoke(() => RunWithFixtureAsync(obj => obj.ActivitySourceTest(key: "key"))).Dispose();
=> RemoteExecutor.Invoke(static connectionStringToUse => RunWithConnectionString(connectionStringToUse, obj => obj.ActivitySourceTest(key: "key")),
ConnectionString).Dispose();

private static async Task RunWithFixtureAsync(Action<ConformanceTests> test)
{
await using var fixture = new PostgreSQLContainerFixture();
await fixture.InitializeAsync();
test(new ConformanceTests(fixture));
}
private static void RunWithConnectionString(string connectionString, Action<ConformanceTests> test)
=> test(new ConformanceTests(null) { ConnectionString = connectionString });
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ namespace Aspire.Pomelo.EntityFrameworkCore.MySql.Tests;

public class ConformanceTests : ConformanceTests<TestDbContext, PomeloEntityFrameworkCoreMySqlSettings>, IClassFixture<MySqlContainerFixture>
{
private readonly MySqlContainerFixture _containerFixture;
protected string ConnectionString => RequiresDockerTheoryAttribute.IsSupported
? _containerFixture.GetConnectionString()
: "Server=localhost;User ID=root;Password=pass;Database=test";
private readonly MySqlContainerFixture? _containerFixture;
protected string ConnectionString { get; private set; }
protected readonly string ServerVersion = $"{MySqlContainerImageTags.Tag}-mysql";

protected override ServiceLifetime ServiceLifetime => ServiceLifetime.Singleton;
Expand Down Expand Up @@ -74,8 +72,13 @@ protected override (string json, string error)[] InvalidJsonToErrorMessage => ne
("""{"Aspire": { "Pomelo": { "EntityFrameworkCore":{ "MySql": { "Metrics": "false"}}}}}""", "Value is \"string\" but should be \"boolean\""),
};

public ConformanceTests(MySqlContainerFixture containerFixture)
=> _containerFixture = containerFixture;
public ConformanceTests(MySqlContainerFixture? containerFixture)
{
_containerFixture = containerFixture;
ConnectionString = (_containerFixture is not null && RequiresDockerTheoryAttribute.IsSupported)
? _containerFixture.GetConnectionString()
: "Server=localhost;User ID=root;Password=password;Database=test_aspire_mysql";
}

protected override void PopulateConfiguration(ConfigurationManager configuration, string? key = null)
=> configuration.AddInMemoryCollection(new KeyValuePair<string, string?>[2]
Expand Down Expand Up @@ -126,12 +129,9 @@ public void DbContextCanBeAlwaysResolved()

[RequiresDockerFact]
public void TracingEnablesTheRightActivitySource()
=> RemoteExecutor.Invoke(() => RunWithFixtureAsync(obj => obj.ActivitySourceTest(key: null))).Dispose();
=> RemoteExecutor.Invoke(static connectionStringToUse => RunWithConnectionString(connectionStringToUse, obj => obj.ActivitySourceTest(key: null)),
ConnectionString).Dispose();

private static async Task RunWithFixtureAsync(Action<ConformanceTests> test)
{
await using var fixture = new MySqlContainerFixture();
await fixture.InitializeAsync();
test(new ConformanceTests(fixture));
}
private static void RunWithConnectionString(string connectionString, Action<ConformanceTests> test)
=> test(new ConformanceTests(null) { ConnectionString = connectionString });
}

0 comments on commit bdc5ea4

Please sign in to comment.