Skip to content

Commit

Permalink
feat: Enable SuccessfulCommandTest by leveraging Testcontainers (#4198)
Browse files Browse the repository at this point in the history
Co-authored-by: Alan West <[email protected]>
  • Loading branch information
HofmeisterAn and alanwest authored Mar 29, 2023
1 parent 63de729 commit 533513f
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 146 deletions.
12 changes: 0 additions & 12 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,6 @@ on:
- '**.md'

jobs:
sql-test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
version: [net6.0,net7.0]
steps:
- uses: actions/checkout@v3

- name: Run sql docker-compose.integration
run: docker-compose --file=test/OpenTelemetry.Instrumentation.SqlClient.Tests/docker-compose.yml --file=build/docker-compose.${{ matrix.version }}.yml --project-directory=. up --exit-code-from=tests --build

w3c-trace-context-test:
runs-on: ubuntu-latest
strategy:
Expand Down
1 change: 1 addition & 0 deletions build/Common.nonprod.props
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
<MicrosoftExtensionsLoggingAbstractionsPkgVer>[6.0.0,)</MicrosoftExtensionsLoggingAbstractionsPkgVer>
<MicrosoftNETTestSdkPkgVer>[17.4.1]</MicrosoftNETTestSdkPkgVer>
<MoqPkgVer>[4.18.3,5.0)</MoqPkgVer>
<TestcontainersPkgVer>3.0.0</TestcontainersPkgVer>
<RabbitMQClientPkgVer>[6.4.0,7.0)</RabbitMQClientPkgVer>
<RuntimeInstrumentationPkgVer>[1.0.0,2.0)</RuntimeInstrumentationPkgVer>
<SwashbuckleAspNetCorePkgVer>[6.4.0]</SwashbuckleAspNetCorePkgVer>
Expand Down
22 changes: 0 additions & 22 deletions test/OpenTelemetry.Instrumentation.SqlClient.Tests/Dockerfile

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
</PropertyGroup>

<ItemGroup>
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\EnabledOnDockerPlatformTheoryAttribute.cs" Link="EnabledOnDockerPlatformTheoryAttribute.cs" />
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\SkipUnlessEnvVarFoundTheoryAttribute.cs" Link="SkipUnlessEnvVarFoundTheoryAttribute.cs" />
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\EventSourceTestHelper.cs" Link="EventSourceTestHelper.cs" />
<Compile Include="$(RepoRoot)\test\OpenTelemetry.Tests\Shared\TestEventListener.cs" Link="TestEventListener.cs" />
Expand All @@ -21,6 +22,8 @@
<PackageReference Include="Microsoft.Data.SqlClient" Version="2.1.2" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPkgVer)" />
<PackageReference Include="Moq" Version="$(MoqPkgVer)" />
<PackageReference Include="Testcontainers.MsSql" Version="$(TestcontainersPkgVer)" />
<PackageReference Include="Testcontainers.SqlEdge" Version="$(TestcontainersPkgVer)" />
<PackageReference Include="xunit" Version="$(XUnitPkgVer)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XUnitRunnerVisualStudioPkgVer)">
<PrivateAssets>all</PrivateAssets>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// <copyright file="SqlClientIntegrationTests.cs" company="OpenTelemetry Authors">
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

using System.Data;
using System.Diagnostics;
using System.Runtime.InteropServices;
using DotNet.Testcontainers.Containers;
using Microsoft.Data.SqlClient;
using OpenTelemetry.Tests;
using OpenTelemetry.Trace;
using Testcontainers.MsSql;
using Testcontainers.SqlEdge;
using Xunit;

namespace OpenTelemetry.Instrumentation.SqlClient.Tests
{
public sealed class SqlClientIntegrationTests : IAsyncLifetime
{
// The Microsoft SQL Server Docker image is not compatible with ARM devices, such as Macs with Apple Silicon.
private readonly IContainer databaseContainer = Architecture.Arm64.Equals(RuntimeInformation.ProcessArchitecture) ? new SqlEdgeBuilder().Build() : new MsSqlBuilder().Build();

public Task InitializeAsync()
{
return this.databaseContainer.StartAsync();
}

public Task DisposeAsync()
{
return this.databaseContainer.DisposeAsync().AsTask();
}

[Trait("CategoryName", "SqlIntegrationTests")]
[EnabledOnDockerPlatformTheory(EnabledOnDockerPlatformTheoryAttribute.DockerPlatform.Linux)]
[InlineData(CommandType.Text, "select 1/1", false)]
[InlineData(CommandType.Text, "select 1/1", false, true)]
[InlineData(CommandType.Text, "select 1/0", false, false, true)]
[InlineData(CommandType.Text, "select 1/0", false, false, true, false, false)]
[InlineData(CommandType.Text, "select 1/0", false, false, true, true, false)]
[InlineData(CommandType.StoredProcedure, "sp_who", false)]
[InlineData(CommandType.StoredProcedure, "sp_who", true)]
public void SuccessfulCommandTest(
CommandType commandType,
string commandText,
bool captureStoredProcedureCommandName,
bool captureTextCommandContent = false,
bool isFailure = false,
bool recordException = false,
bool shouldEnrich = true)
{
#if NETFRAMEWORK
// Disable things not available on netfx
recordException = false;
shouldEnrich = false;
#endif

var sampler = new TestSampler();
var activities = new List<Activity>();
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.SetSampler(sampler)
.AddInMemoryExporter(activities)
.AddSqlClientInstrumentation(options =>
{
#if !NETFRAMEWORK
options.SetDbStatementForStoredProcedure = captureStoredProcedureCommandName;
options.SetDbStatementForText = captureTextCommandContent;
#else
options.SetDbStatementForText = captureStoredProcedureCommandName || captureTextCommandContent;
#endif
options.RecordException = recordException;
if (shouldEnrich)
{
options.Enrich = SqlClientTests.ActivityEnrichment;
}
})
.Build();

using SqlConnection sqlConnection = new SqlConnection(this.GetConnectionString());

sqlConnection.Open();

string dataSource = sqlConnection.DataSource;

sqlConnection.ChangeDatabase("master");

using SqlCommand sqlCommand = new SqlCommand(commandText, sqlConnection)
{
CommandType = commandType,
};

try
{
sqlCommand.ExecuteNonQuery();
}
catch
{
}

Assert.Single(activities);
var activity = activities[0];

SqlClientTests.VerifyActivityData(commandType, commandText, captureStoredProcedureCommandName, captureTextCommandContent, isFailure, recordException, shouldEnrich, dataSource, activity);
SqlClientTests.VerifySamplingParameters(sampler.LatestSamplingParameters);
}

private string GetConnectionString()
{
switch (this.databaseContainer)
{
case SqlEdgeContainer container:
return container.GetConnectionString();
case MsSqlContainer container:
return container.GetConnectionString();
default:
throw new InvalidOperationException($"Container type ${this.databaseContainer.GetType().Name} not supported.");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,8 @@ namespace OpenTelemetry.Instrumentation.SqlClient.Tests
{
public class SqlClientTests : IDisposable
{
/*
To run the integration tests, set the OTEL_SQLCONNECTIONSTRING machine-level environment variable to a valid Sql Server connection string.
To use Docker...
1) Run: docker run -d --name sql2019 -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=Pass@word" -p 5433:1433 mcr.microsoft.com/mssql/server:2019-latest
2) Set OTEL_SQLCONNECTIONSTRING as: Data Source=127.0.0.1,5433; User ID=sa; Password=Pass@word
*/

private const string SqlConnectionStringEnvVarName = "OTEL_SQLCONNECTIONSTRING";
private const string TestConnectionString = "Data Source=(localdb)\\MSSQLLocalDB;Database=master";

private static readonly string SqlConnectionString = SkipUnlessEnvVarFoundTheoryAttribute.GetEnvironmentVariable(SqlConnectionStringEnvVarName);

private readonly FakeSqlClientDiagnosticSource fakeSqlClientDiagnosticSource;

public SqlClientTests()
Expand Down Expand Up @@ -81,79 +70,6 @@ public void SqlClient_NamedOptions()
Assert.Equal(1, namedExporterOptionsConfigureOptionsInvocations);
}

[Trait("CategoryName", "SqlIntegrationTests")]
[SkipUnlessEnvVarFoundTheory(SqlConnectionStringEnvVarName)]
[InlineData(CommandType.Text, "select 1/1", false)]
[InlineData(CommandType.Text, "select 1/1", false, true)]
[InlineData(CommandType.Text, "select 1/0", false, false, true)]
[InlineData(CommandType.Text, "select 1/0", false, false, true, false, false)]
[InlineData(CommandType.Text, "select 1/0", false, false, true, true, false)]
[InlineData(CommandType.StoredProcedure, "sp_who", false)]
[InlineData(CommandType.StoredProcedure, "sp_who", true)]
public void SuccessfulCommandTest(
CommandType commandType,
string commandText,
bool captureStoredProcedureCommandName,
bool captureTextCommandContent = false,
bool isFailure = false,
bool recordException = false,
bool shouldEnrich = true)
{
#if NETFRAMEWORK
// Disable things not available on netfx
recordException = false;
shouldEnrich = false;
#endif

var sampler = new TestSampler();
var activities = new List<Activity>();
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.SetSampler(sampler)
.AddInMemoryExporter(activities)
.AddSqlClientInstrumentation(options =>
{
#if !NETFRAMEWORK
options.SetDbStatementForStoredProcedure = captureStoredProcedureCommandName;
options.SetDbStatementForText = captureTextCommandContent;
#else
options.SetDbStatementForText = captureStoredProcedureCommandName || captureTextCommandContent;
#endif
options.RecordException = recordException;
if (shouldEnrich)
{
options.Enrich = ActivityEnrichment;
}
})
.Build();

using SqlConnection sqlConnection = new SqlConnection(SqlConnectionString);

sqlConnection.Open();

string dataSource = sqlConnection.DataSource;

sqlConnection.ChangeDatabase("master");

using SqlCommand sqlCommand = new SqlCommand(commandText, sqlConnection)
{
CommandType = commandType,
};

try
{
sqlCommand.ExecuteNonQuery();
}
catch
{
}

Assert.Single(activities);
var activity = activities[0];

VerifyActivityData(commandType, commandText, captureStoredProcedureCommandName, captureTextCommandContent, isFailure, recordException, shouldEnrich, dataSource, activity);
VerifySamplingParameters(sampler.LatestSamplingParameters);
}

// DiagnosticListener-based instrumentation is only available on .NET Core
#if !NETFRAMEWORK
[Theory]
Expand Down Expand Up @@ -384,7 +300,7 @@ public void ShouldNotCollectTelemetryAndShouldNotPropagateExceptionWhenFilterThr
}
#endif

private static void VerifyActivityData(
internal static void VerifyActivityData(
CommandType commandType,
string commandText,
bool captureStoredProcedureCommandName,
Expand Down Expand Up @@ -464,7 +380,7 @@ private static void VerifyActivityData(
Assert.Equal(dataSource, activity.GetTagValue(SemanticConventions.AttributePeerService));
}

private static void VerifySamplingParameters(SamplingParameters samplingParameters)
internal static void VerifySamplingParameters(SamplingParameters samplingParameters)
{
Assert.NotNull(samplingParameters.Tags);
Assert.Contains(
Expand All @@ -473,7 +389,7 @@ private static void VerifySamplingParameters(SamplingParameters samplingParamete
&& (string)kvp.Value == SqlActivitySourceHelper.MicrosoftSqlServerDatabaseSystemName);
}

private static void ActivityEnrichment(Activity activity, string method, object obj)
internal static void ActivityEnrichment(Activity activity, string method, object obj)
{
activity.SetTag("enriched", "yes");

Expand Down

This file was deleted.

Loading

0 comments on commit 533513f

Please sign in to comment.