Add integration tests for the API clients

This commit is contained in:
Peter 2021-02-28 12:40:40 +01:00
parent 2fb3546b76
commit 3a3b6f840e
Signed by: prskr
GPG key ID: C1DB5D2E8DB512F9
10 changed files with 188 additions and 4 deletions

View file

@ -4,9 +4,20 @@ stages:
- test - test
- release - release
variables:
DOCKER_TLS_CERTDIR: "/certs"
DOCKER_CERT_PATH: "/certs/client"
DOCKER_TLS_VERIFY: 0
DOCKER_HOST: 'tcp://docker:2375'
test: test:
stage: test stage: test
services:
- docker:dind
variables:
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/docker
script: script:
- curl https://download.docker.com/linux/static/stable/x86_64/docker-20.10.4.tgz | tar -xzv -C /usr/local/
- dotnet tool restore - dotnet tool restore
- dotnet nuke Test - dotnet nuke Test

View file

@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "INetMock.Client.Test", "tes
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{37738E95-E68E-4242-B7D7-9591605D8E33}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{37738E95-E68E-4242-B7D7-9591605D8E33}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "INetMock.Client.IntegrationTest", "tests\INetMock.Client.IntegrationTest\INetMock.Client.IntegrationTest.csproj", "{D12E0C79-2E27-4FDB-94E7-402EBA267F72}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -39,9 +41,14 @@ Global
{66DAC329-57DE-4218-9880-84E65E91E623}.Debug|Any CPU.Build.0 = Debug|Any CPU {66DAC329-57DE-4218-9880-84E65E91E623}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66DAC329-57DE-4218-9880-84E65E91E623}.Release|Any CPU.ActiveCfg = Release|Any CPU {66DAC329-57DE-4218-9880-84E65E91E623}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66DAC329-57DE-4218-9880-84E65E91E623}.Release|Any CPU.Build.0 = Release|Any CPU {66DAC329-57DE-4218-9880-84E65E91E623}.Release|Any CPU.Build.0 = Release|Any CPU
{D12E0C79-2E27-4FDB-94E7-402EBA267F72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D12E0C79-2E27-4FDB-94E7-402EBA267F72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D12E0C79-2E27-4FDB-94E7-402EBA267F72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D12E0C79-2E27-4FDB-94E7-402EBA267F72}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(NestedProjects) = preSolution GlobalSection(NestedProjects) = preSolution
{4B1CFFB0-23B5-4238-BFCC-4155F459FF8E} = {07100561-E3C0-4B95-92E1-D2D3BA12C3A6} {4B1CFFB0-23B5-4238-BFCC-4155F459FF8E} = {07100561-E3C0-4B95-92E1-D2D3BA12C3A6}
{66DAC329-57DE-4218-9880-84E65E91E623} = {4FF6267B-A7EC-4277-98EA-39155A82C886} {66DAC329-57DE-4218-9880-84E65E91E623} = {4FF6267B-A7EC-4277-98EA-39155A82C886}
{D12E0C79-2E27-4FDB-94E7-402EBA267F72} = {4FF6267B-A7EC-4277-98EA-39155A82C886}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View file

@ -0,0 +1,3 @@
FROM registry.gitlab.com/inetmock/inetmock:latest
USER root

View file

@ -1,3 +1,4 @@
using System.IO;
using JetBrains.Annotations; using JetBrains.Annotations;
using Nuke.Common; using Nuke.Common;
using Nuke.Common.CI; using Nuke.Common.CI;
@ -7,6 +8,7 @@ using Nuke.Common.Git;
using Nuke.Common.IO; using Nuke.Common.IO;
using Nuke.Common.ProjectModel; using Nuke.Common.ProjectModel;
using Nuke.Common.Tooling; using Nuke.Common.Tooling;
using Nuke.Common.Tools.Docker;
using Nuke.Common.Tools.DotNet; using Nuke.Common.Tools.DotNet;
using Nuke.Common.Tools.GitVersion; using Nuke.Common.Tools.GitVersion;
using Nuke.Common.Utilities.Collections; using Nuke.Common.Utilities.Collections;
@ -79,8 +81,14 @@ class Build : NukeBuild
.EnableNoRestore()); .EnableNoRestore());
}); });
Target IntegrationTestImage => _ => _
.Executes(() => DockerTasks.DockerBuild(s => s
.SetFile(Path.Join("assets", "integration-tests.dockerfile"))
.SetTag("inetmock-root")
.SetPath(".")));
Target Test => _ => _ Target Test => _ => _
.DependsOn(Compile) .DependsOn(Compile, IntegrationTestImage)
.Executes(() => DotNetTest(s => s .Executes(() => DotNetTest(s => s
.SetProjectFile(Solution) .SetProjectFile(Solution)
.SetConfiguration(Configuration) .SetConfiguration(Configuration)

View file

@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Grpc.Core; using Grpc.Core;
using Grpc.Net.Client; using Grpc.Net.Client;
using INetMock.Client.Audit.Serialization; using INetMock.Client.Audit.Serialization;
using INetMock.Client.Grpc;
using INetMock.Client.Rpc; using INetMock.Client.Rpc;
namespace INetMock.Client.Audit.Client namespace INetMock.Client.Audit.Client
@ -18,7 +19,7 @@ namespace INetMock.Client.Audit.Client
} }
public AuditApiClient(Uri address, GrpcChannelOptions? options = null) : this( public AuditApiClient(Uri address, GrpcChannelOptions? options = null) : this(
GrpcChannel.ForAddress(address, options ?? new GrpcChannelOptions())) ChannelFactory.ForAddress(address, options ?? new GrpcChannelOptions()))
{ {
} }

View file

@ -0,0 +1,40 @@
using System;
using System.Net.Http;
using System.Net.Sockets;
using Grpc.Net.Client;
namespace INetMock.Client.Grpc
{
internal static class ChannelFactory
{
internal static GrpcChannel ForAddress(Uri uri, GrpcChannelOptions options) =>
uri.Scheme.ToLowerInvariant() switch
{
"unix" => ForUnixSocket(uri.AbsolutePath, options),
_ => GrpcChannel.ForAddress(uri, options)
};
private static GrpcChannel ForUnixSocket(string path, GrpcChannelOptions options)
{
var endpoint = new UnixDomainSocketEndPoint(path);
options.HttpHandler = new SocketsHttpHandler
{
ConnectCallback = async (_, cancellationToken) =>
{
var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
try
{
await socket.ConnectAsync(endpoint, cancellationToken).ConfigureAwait(false);
return new NetworkStream(socket, true);
}
catch
{
socket.Dispose();
throw;
}
}
};
return GrpcChannel.ForAddress("http://localhost", options);
}
}
}

View file

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Google.Protobuf.WellKnownTypes; using Google.Protobuf.WellKnownTypes;
using Grpc.Core; using Grpc.Core;
using Grpc.Net.Client; using Grpc.Net.Client;
using INetMock.Client.Grpc;
using INetMock.Client.Rpc; using INetMock.Client.Rpc;
namespace INetMock.Client.PCAP.Client namespace INetMock.Client.PCAP.Client
@ -21,7 +22,7 @@ namespace INetMock.Client.PCAP.Client
} }
public PcapApiClient(Uri address, GrpcChannelOptions? options = null) public PcapApiClient(Uri address, GrpcChannelOptions? options = null)
: this(GrpcChannel.ForAddress(address, options ?? new GrpcChannelOptions())) : this(ChannelFactory.ForAddress(address, options ?? new GrpcChannelOptions()))
{ {
} }
@ -90,7 +91,7 @@ namespace INetMock.Client.PCAP.Client
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
return new Subscription(key.Substring(0, splitIndex), key.Substring(splitIndex), key); return new Subscription(key.Substring(splitIndex+1), key.Substring(0, splitIndex), key);
} }
} }
} }

View file

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DotNet.Testcontainers" Version="1.4.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\INetMock.Client\INetMock.Client.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,41 @@
using System;
using System.IO;
using System.Threading.Tasks;
using DotNet.Testcontainers.Containers.Builders;
using DotNet.Testcontainers.Containers.Modules;
using DotNet.Testcontainers.Containers.WaitStrategies;
using Xunit;
namespace INetMock.Client.IntegrationTest
{
public class INetMockServerFixture : IAsyncLifetime
{
private readonly TestcontainersContainer _inetmockContainer;
public INetMockServerFixture()
{
_inetmockContainer = new TestcontainersBuilder<TestcontainersContainer>()
.WithImage("inetmock-root:latest")
.WithCommand("serve")
.WithPortBinding(80, true)
.WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(80))
.WithDockerEndpoint(Environment.GetEnvironmentVariable("DOCKER_HOST") ?? "unix:///var/run/docker.sock")
.WithMount(Path.GetTempPath(), "/var/run/inetmock")
.WithCleanUp(true)
.Build();
}
public Uri SocketPath => new ($"unix://{Path.Join(Path.GetTempPath(), "inetmock.sock")}", UriKind.Absolute);
public async Task InitializeAsync()
{
await _inetmockContainer.StartAsync();
}
public async Task DisposeAsync()
{
await _inetmockContainer.StopAsync();
await _inetmockContainer.DisposeAsync();
}
}
}

View file

@ -0,0 +1,45 @@
using INetMock.Client.PCAP;
using INetMock.Client.PCAP.Client;
using Xunit;
using Xunit.Abstractions;
namespace INetMock.Client.IntegrationTest.PCAP.Client
{
public class PcapApiClientTests : IClassFixture<INetMockServerFixture>
{
private readonly ITestOutputHelper _outputHelper;
private readonly IPcapApiClient _apiClient;
public PcapApiClientTests(ITestOutputHelper testOutputHelper, INetMockServerFixture inetmockFixture)
{
_outputHelper = testOutputHelper;
_apiClient = new PcapApiClient(inetmockFixture.SocketPath);
}
[Fact]
public async void ListAvailableDevicesAsync_RunningContainer_AtLeastLoopbackDevice()
{
var devs = await _apiClient.ListAvailableDevicesAsync();
Assert.Contains(devs, device => device.Name.Equals("lo"));
}
[Fact]
public async void ListActiveRecordingsAsync_NoRecordingsRunning_EmptyResult()
{
var recordings = await _apiClient.ListActiveRecordingsAsync();
Assert.Empty(recordings);
}
[Fact]
public async void StartPcapFileRecordingAsync_RecordLoopbackInterface_RunningRecording()
{
const string targetPath = "/tmp/lo_record.pcap";
await _apiClient.StartPcapFileRecordingAsync(new("lo", targetPath));
var subscriptions = await _apiClient.ListActiveRecordingsAsync();
Assert.Contains(subscriptions, subscription => subscription.Device.Equals("lo") && subscription.ConsumerName.Equals(targetPath));
}
}
}