From 56b77353f2e3a9fe198f23016957ee761fb80ac3 Mon Sep 17 00:00:00 2001 From: Peter Kurfer Date: Wed, 26 Jan 2022 15:19:04 +0100 Subject: [PATCH] Update to .NET 6 and latest InetMock API --- .config/dotnet-tools.json | 4 +- .editorconfig | 2 + .gitlab-ci.yml | 28 +++- .nuke | 1 - .nuke/build.schema.json | 127 +++++++++++++++ .nuke/parameters.json | 4 + .pre-commit-config.yaml | 13 ++ INetMock.sln | 1 + build.cmd | 2 +- build.ps1 | 6 +- build.sh | 2 +- build/Build.cs | 60 +++---- build/Configuration.cs | 6 +- build/_build.csproj | 8 +- global.json | 6 + .../Audit/Client/AuditApiClient.cs | 112 +++++++------- src/INetMock.Client/Audit/Details.cs | 121 +++++---------- src/INetMock.Client/Audit/Event.cs | 146 ++++++++---------- src/INetMock.Client/Audit/IAuditApiClient.cs | 15 +- src/INetMock.Client/Audit/IEventReader.cs | 44 ++++-- .../Audit/INetMockHttpHeaders.cs | 15 +- .../Audit/IProtoEventReader.cs | 10 +- .../Serialization/EventServerStreamReader.cs | 36 +++-- .../Audit/Serialization/GenericReader.cs | 60 ++++--- .../Audit/Serialization/ProtoReader.cs | 89 ++++++----- .../Audit/Serialization/TypedReader.cs | 141 ++++++++--------- src/INetMock.Client/Grpc/ChannelFactory.cs | 55 ++++--- src/INetMock.Client/INetMock.Client.csproj | 20 ++- .../PCAP/Client/PcapApiClient.cs | 128 ++++++++------- src/INetMock.Client/PCAP/IPcapApiClient.cs | 14 +- src/INetMock.Client/PCAP/Models.cs | 77 +++++---- .../Audit/Serialization/GenericReaderTest.cs | 26 ++++ .../Audit/Serialization/TypedReaderTest.cs | 71 +++++++++ .../DockerEndpoint.cs | 36 ----- .../DockerEndpointTests.cs | 22 --- .../INetMock.Client.IntegrationTest.csproj | 15 +- .../INetMockFixture.cs | 19 +++ .../INetMockServerFixture.cs | 42 ----- .../PCAP/Client/PcapApiClientTests.cs | 70 +++++---- .../testdata/test.ima | Bin 0 -> 3946 bytes .../Audit/Serialization/GenericReaderTest.cs | 83 +++++----- .../Audit/Serialization/TypedReaderTest.cs | 57 ++++--- tests/INetMock.Client.Test/Hex/Converter.cs | 16 +- .../INetMock.Client.Test.csproj | 6 +- .../PCAP/SubscriptionTests.cs | 19 ++- 45 files changed, 1000 insertions(+), 835 deletions(-) delete mode 100644 .nuke create mode 100644 .nuke/build.schema.json create mode 100644 .nuke/parameters.json create mode 100644 .pre-commit-config.yaml create mode 100644 global.json create mode 100644 tests/INetMock.Client.IntegrationTest/Audit/Serialization/GenericReaderTest.cs create mode 100644 tests/INetMock.Client.IntegrationTest/Audit/Serialization/TypedReaderTest.cs delete mode 100644 tests/INetMock.Client.IntegrationTest/DockerEndpoint.cs delete mode 100644 tests/INetMock.Client.IntegrationTest/DockerEndpointTests.cs create mode 100644 tests/INetMock.Client.IntegrationTest/INetMockFixture.cs delete mode 100644 tests/INetMock.Client.IntegrationTest/INetMockServerFixture.cs create mode 100644 tests/INetMock.Client.IntegrationTest/testdata/test.ima diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 8d59dce..4b91376 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,13 +3,13 @@ "isRoot": true, "tools": { "dotnet-grpc": { - "version": "2.40.0", + "version": "2.42.0", "commands": [ "dotnet-grpc" ] }, "nuke.globaltool": { - "version": "5.3.0", + "version": "6.0.1", "commands": [ "nuke" ] diff --git a/.editorconfig b/.editorconfig index 01e1042..2a559ae 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,6 +12,8 @@ indent_size = 4 [*.cs] indent_size = 4 +csharp_style_namespace_declarations = file_scoped:warning +csharp_prefer_braces = true:warning [*.json] indent_size = 2 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5fa61e8..d7a9992 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,13 +14,30 @@ test: stage: test services: - docker:dind + before_script: + - | + curl https://download.docker.com/linux/static/stable/x86_64/docker-20.10.9.tgz | tar -xzv -C /usr/local/ + + docker run --rm -d \ + --cap-add CAP_NET_RAW \ + --cap-add CAP_NET_ADMIN \ + --cap-add CAP_NET_BIND_SERVICE \ + -u root \ + -p 6767:6767 \ + -e INETMOCK_API_LISTEN=tcp://0.0.0.0:6767 \ + --name inetmock \ + registry.gitlab.com/inetmock/inetmock:latest + + for i in `seq 1 10` + do + docker exec -i inetmock /usr/lib/inetmock/bin/imctl health container 2>&1 > /dev/null || sleep 1; + done; + after_script: + - docker stop inetmock variables: PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/docker + INETMOCK_SOCKET: http://docker:6767 script: - - curl https://download.docker.com/linux/static/stable/x86_64/docker-20.10.4.tgz | tar -xzv -C /usr/local/ - - mkdir /usr/local/share/ca-certificates/docker-ca - - cp "${DOCKER_CERT_PATH}/ca.pem" /usr/local/share/ca-certificates/docker-ca/ - - update-ca-certificates --fresh - dotnet tool restore - dotnet nuke Test @@ -30,7 +47,7 @@ protobuf-lint: name: docker.io/bufbuild/buf:latest entrypoint: [""] script: - - cd api/ + - cd api/proto/ - buf ls-files - buf lint @@ -39,6 +56,7 @@ nuget-publish: only: refs: - tags + - main script: - dotnet tool restore - dotnet nuke NuGetPush diff --git a/.nuke b/.nuke deleted file mode 100644 index ae940c5..0000000 --- a/.nuke +++ /dev/null @@ -1 +0,0 @@ -INetMock.sln \ No newline at end of file diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json new file mode 100644 index 0000000..ed1030d --- /dev/null +++ b/.nuke/build.schema.json @@ -0,0 +1,127 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Build Schema", + "$ref": "#/definitions/build", + "definitions": { + "build": { + "type": "object", + "properties": { + "Configuration": { + "type": "string", + "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)", + "enum": [ + "Debug", + "Release" + ] + }, + "Continue": { + "type": "boolean", + "description": "Indicates to continue a previously failed build attempt" + }, + "Help": { + "type": "boolean", + "description": "Shows the help text for this build assembly" + }, + "Host": { + "type": "string", + "description": "Host for execution. Default is 'automatic'", + "enum": [ + "AppVeyor", + "AzurePipelines", + "Bamboo", + "Bitrise", + "GitHubActions", + "GitLab", + "Jenkins", + "Rider", + "SpaceAutomation", + "TeamCity", + "Terminal", + "TravisCI", + "VisualStudio", + "VSCode" + ] + }, + "NoLogo": { + "type": "boolean", + "description": "Disables displaying the NUKE logo" + }, + "nuget-password": { + "type": "string", + "description": "Password to use for publishing NuGet packages" + }, + "nuget-username": { + "type": "string", + "description": "Username to use for publishing NuGet packages" + }, + "Partition": { + "type": "string", + "description": "Partition to use on CI" + }, + "Plan": { + "type": "boolean", + "description": "Shows the execution plan (HTML)" + }, + "Profile": { + "type": "array", + "description": "Defines the profiles to load", + "items": { + "type": "string" + } + }, + "Root": { + "type": "string", + "description": "Root directory during build execution" + }, + "Skip": { + "type": "array", + "description": "List of targets to be skipped. Empty list skips all dependencies", + "items": { + "type": "string", + "enum": [ + "AddNugetSource", + "Clean", + "Compile", + "Format", + "NuGetPush", + "Pack", + "Restore", + "Test" + ] + } + }, + "Solution": { + "type": "string", + "description": "Path to a solution file that is automatically loaded" + }, + "Target": { + "type": "array", + "description": "List of targets to be invoked. Default is '{default_target}'", + "items": { + "type": "string", + "enum": [ + "AddNugetSource", + "Clean", + "Compile", + "Format", + "NuGetPush", + "Pack", + "Restore", + "Test" + ] + } + }, + "Verbosity": { + "type": "string", + "description": "Logging verbosity during build execution. Default is 'Normal'", + "enum": [ + "Minimal", + "Normal", + "Quiet", + "Verbose" + ] + } + } + } + } +} \ No newline at end of file diff --git a/.nuke/parameters.json b/.nuke/parameters.json new file mode 100644 index 0000000..a165392 --- /dev/null +++ b/.nuke/parameters.json @@ -0,0 +1,4 @@ +{ + "$schema": "./build.schema.json", + "Solution": "INetMock.sln" +} \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..9cbe814 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,13 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: + - repo: https://github.com/dotnet/format + rev: "v5.1.225507" # Specify a tag or sha here, or run "pre-commit autoupdate" + hooks: + - id: dotnet-format + args: + - "" + - --folder + - --check + - --verbosity=detailed + - --include diff --git a/INetMock.sln b/INetMock.sln index 2d86fc6..54084ae 100644 --- a/INetMock.sln +++ b/INetMock.sln @@ -8,6 +8,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt .editorconfig = .editorconfig .gitignore = .gitignore .gitlab-ci.yml = .gitlab-ci.yml + .pre-commit-config.yaml = .pre-commit-config.yaml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{07100561-E3C0-4B95-92E1-D2D3BA12C3A6}" diff --git a/build.cmd b/build.cmd index 8b8b89d..b08cc59 100755 --- a/build.cmd +++ b/build.cmd @@ -4,4 +4,4 @@ :; exit $? @ECHO OFF -powershell -ExecutionPolicy ByPass -NoProfile "%~dp0build.ps1" %* +powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %* diff --git a/build.ps1 b/build.ps1 index e5c8a44..1c774e5 100644 --- a/build.ps1 +++ b/build.ps1 @@ -14,7 +14,7 @@ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent ########################################################################### $BuildProjectFile = "$PSScriptRoot\build\_build.csproj" -$TempDirectory = "$PSScriptRoot\\.tmp" +$TempDirectory = "$PSScriptRoot\\.nuke\temp" $DotNetGlobalFile = "$PSScriptRoot\\global.json" $DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1" @@ -56,9 +56,9 @@ else { # Install by channel or version $DotNetDirectory = "$TempDirectory\dotnet-win" if (!(Test-Path variable:DotNetVersion)) { - ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath } + ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath } } else { - ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } + ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } } $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe" } diff --git a/build.sh b/build.sh index 3d52643..e8961f9 100755 --- a/build.sh +++ b/build.sh @@ -10,7 +10,7 @@ SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd) ########################################################################### BUILD_PROJECT_FILE="$SCRIPT_DIR/build/_build.csproj" -TEMP_DIRECTORY="$SCRIPT_DIR//.tmp" +TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp" DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json" DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh" diff --git a/build/Build.cs b/build/Build.cs index e513723..2d9d880 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -1,4 +1,4 @@ -using System.IO; +using System; using JetBrains.Annotations; using Nuke.Common; using Nuke.Common.CI; @@ -8,7 +8,6 @@ using Nuke.Common.Git; using Nuke.Common.IO; using Nuke.Common.ProjectModel; using Nuke.Common.Tooling; -using Nuke.Common.Tools.Docker; using Nuke.Common.Tools.DotNet; using Nuke.Common.Tools.GitVersion; using Nuke.Common.Utilities.Collections; @@ -20,38 +19,29 @@ using static Nuke.Common.Tools.DotNet.DotNetTasks; class Build : NukeBuild { private const string NuGetSourceName = "GitLab"; - public static int Main() => Execute(x => x.Compile); + public static int Main() => Execute(x => x.Test); [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")] readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release; + [Parameter("Username to use for publishing NuGet packages", Name = "nuget-username")] + string NuGetUsername { get; } = Environment.GetEnvironmentVariable("NUGET_USERNAME") ?? string.Empty; + + [Parameter("Password to use for publishing NuGet packages", Name = "nuget-password")] + string NuGetPassword { get; } = Environment.GetEnvironmentVariable("NUGET_PASSWORD") ?? string.Empty; + [Solution] readonly Solution Solution; [GitRepository] readonly GitRepository GitRepository; - [GitVersion(NoFetch = true, Framework = "net5.0")] readonly GitVersion GitVersion; + [GitVersion(NoFetch = true)] readonly GitVersion GitVersion; - [CanBeNull] GitLab CI => GitLab.Instance; + [CanBeNull] + GitLab CI => GitLab.Instance; AbsolutePath SourceDirectory => RootDirectory / "src"; AbsolutePath TestsDirectory => RootDirectory / "tests"; AbsolutePath ArtifactsDirectory => RootDirectory / "artifacts"; - Target PrintEnv => _ => _ - .Executes(() => - { - if (CI == null) - { - Logger.Info("Running in local environment"); - Logger.Info($"Git commit: {GitRepository.Commit}"); - } - else - { - Logger.Info("Running in GitLab CI"); - Logger.Info($"Git commit: {CI.CommitSha}"); - Logger.Info($"Pipeline ID: {CI.PipelineId}"); - } - }); - Target Clean => _ => _ .Before(Restore) .Executes(() => @@ -69,7 +59,7 @@ class Build : NukeBuild }); Target Compile => _ => _ - .DependsOn(Restore, PrintEnv) + .DependsOn(Restore) .Executes(() => { DotNetBuild(s => s @@ -81,14 +71,12 @@ class Build : NukeBuild .EnableNoRestore()); }); - Target IntegrationTestImage => _ => _ - .Executes(() => DockerTasks.DockerBuild(s => s - .SetFile(Path.Join("assets", "integration-tests.dockerfile")) - .SetTag("inetmock-root") - .SetPath("."))); + Target Format => _ => _ + .DependsOn(Restore) + .Executes(() => DotNet(CI == null ? "format --no-restore" : "format --no-restore --verify-no-changes")); Target Test => _ => _ - .DependsOn(Compile, IntegrationTestImage) + .DependsOn(Compile, Format) .Executes(() => DotNetTest(s => s .SetProjectFile(Solution) .SetConfiguration(Configuration) @@ -97,20 +85,20 @@ class Build : NukeBuild .EnableProcessLogOutput())); Target AddNugetSource => _ => _ - .OnlyWhenStatic(() => GitRepository.IsOnMasterBranch()) + .OnlyWhenStatic(() => GitRepository.IsOnMainBranch()) .OnlyWhenStatic(() => CI != null) + .OnlyWhenStatic(() => !string.IsNullOrEmpty(NuGetUsername) && !string.IsNullOrEmpty(NuGetPassword)) .ProceedAfterFailure() .Executes(() => DotNetNuGetAddSource(s => s .SetName(NuGetSourceName) - //.SetSource($"https://gitlab.com/api/v4/projects/{CI.ProjectId}/packages/nuget/index.json") - .SetSource($"https://gitlab.com/api/v4/projects/24385200/packages/nuget/index.json") - .SetUsername("baez90") - .SetPassword("RcMwfaXgvBxSWt4ZMB6z") + .SetSource($"https://gitlab.com/api/v4/projects/{CI.ProjectId}/packages/nuget/index.json") + .SetUsername(NuGetUsername) + .SetPassword(NuGetPassword) .EnableStorePasswordInClearText())); Target Pack => _ => _ - .DependsOn(Test) - .OnlyWhenStatic(() => GitRepository.IsOnMasterBranch()) + .DependsOn(Compile) + .OnlyWhenStatic(() => GitRepository.IsOnMainBranch()) .Executes(() => SourceDirectory .GlobFiles("**/*.csproj") .ForEach(csproj => DotNetPack(s => s @@ -127,7 +115,7 @@ class Build : NukeBuild Target NuGetPush => _ => _ .DependsOn(Pack, AddNugetSource) - .OnlyWhenStatic(() => GitRepository.IsOnMasterBranch()) + .OnlyWhenStatic(() => GitRepository.IsOnMainBranch()) .Executes(() => ArtifactsDirectory .GlobFiles("**/*.nupkg") .ForEach(nupkg => DotNetNuGetPush(s => s diff --git a/build/Configuration.cs b/build/Configuration.cs index 9c08b1a..78049f7 100644 --- a/build/Configuration.cs +++ b/build/Configuration.cs @@ -1,13 +1,11 @@ -using System; using System.ComponentModel; -using System.Linq; using Nuke.Common.Tooling; [TypeConverter(typeof(TypeConverter))] public class Configuration : Enumeration { - public static Configuration Debug = new Configuration { Value = nameof(Debug) }; - public static Configuration Release = new Configuration { Value = nameof(Release) }; + public static Configuration Debug = new() { Value = nameof(Debug) }; + public static Configuration Release = new() { Value = nameof(Release) }; public static implicit operator string(Configuration configuration) { diff --git a/build/_build.csproj b/build/_build.csproj index adfe94b..794a52b 100644 --- a/build/_build.csproj +++ b/build/_build.csproj @@ -6,12 +6,14 @@ CS0649;CS0169 .. .. - net5.0 + net6.0 + latest + 1 - - + + diff --git a/global.json b/global.json new file mode 100644 index 0000000..08fc58c --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "6.0.100", + "rollForward": "latestMinor" + } +} \ No newline at end of file diff --git a/src/INetMock.Client/Audit/Client/AuditApiClient.cs b/src/INetMock.Client/Audit/Client/AuditApiClient.cs index 3559e17..0d5113d 100644 --- a/src/INetMock.Client/Audit/Client/AuditApiClient.cs +++ b/src/INetMock.Client/Audit/Client/AuditApiClient.cs @@ -6,69 +6,67 @@ using Grpc.Core; using Grpc.Net.Client; using INetMock.Client.Audit.Serialization; using INetMock.Client.Grpc; -using INetMock.Client.Rpc; -namespace INetMock.Client.Audit.Client +namespace INetMock.Client.Audit.Client; + +public class AuditApiClient : IAuditApiClient { - public class AuditApiClient : IAuditApiClient + private readonly AuditService.AuditServiceClient _auditClient; + + public AuditApiClient(string address, GrpcChannelOptions? options = null) : this(new Uri(address), options) { - private readonly AuditService.AuditServiceClient _auditClient; + } - public AuditApiClient(string address, GrpcChannelOptions? options = null) : this(new Uri(address), options) + public AuditApiClient(Uri address, GrpcChannelOptions? options = null) : this( + ChannelFactory.ForAddress(address, options ?? new GrpcChannelOptions())) + { + } + + public AuditApiClient(ChannelBase channel) + { + _auditClient = new AuditService.AuditServiceClient(channel); + } + + public async Task> ListSinksAsync(CancellationToken token = default) + { + var sinks = await _auditClient.ListSinksAsync(new ListSinksRequest(), Metadata.Empty, null, token); + return sinks.Sinks; + } + + public async Task RegisterFileSinkAsync(string targetPath, CancellationToken token = default) + { + var resp = await _auditClient.RegisterFileSinkAsync( + new RegisterFileSinkRequest { TargetPath = targetPath }, + Metadata.Empty, + null, + token + ); + + return resp.ResolvedPath; + } + + public async Task RemoveFileSinkAsync(string targetPath, CancellationToken token = default) + { + var resp = await _auditClient.RemoveFileSinkAsync(new RemoveFileSinkRequest { - } + TargetPath = targetPath + }, + Metadata.Empty, + null, + token + ); - public AuditApiClient(Uri address, GrpcChannelOptions? options = null) : this( - ChannelFactory.ForAddress(address, options ?? new GrpcChannelOptions())) - { - } + return resp.SinkGotRemoved; + } - public AuditApiClient(ChannelBase channel) - { - _auditClient = new AuditService.AuditServiceClient(channel); - } - - public async Task> ListSinksAsync(CancellationToken token = default) - { - var sinks = await _auditClient.ListSinksAsync(new ListSinksRequest(), Metadata.Empty, null, token); - return sinks.Sinks; - } - - public async Task RegisterFileSinkAsync(string targetPath, CancellationToken token = default) - { - var resp = await _auditClient.RegisterFileSinkAsync( - new RegisterFileSinkRequest {TargetPath = targetPath}, - Metadata.Empty, - null, - token - ); - - return resp.ResolvedPath; - } - - public async Task RemoveFileSinkAsync(string targetPath, CancellationToken token = default) - { - var resp = await _auditClient.RemoveFileSinkAsync(new RemoveFileSinkRequest - { - TargetPath = targetPath - }, - Metadata.Empty, - null, - token - ); - - return resp.SinkGotRemoved; - } - - public IProtoEventReader EventStreamAsync(string watcherName, CancellationToken token = default) - { - var stream = _auditClient.WatchEvents( - new WatchEventsRequest {WatcherName = watcherName}, - Metadata.Empty, - null, - token - ); - return new EventServerStreamReader(stream); - } + public IProtoEventReader EventStreamAsync(string watcherName, CancellationToken token = default) + { + var stream = _auditClient.WatchEvents( + new WatchEventsRequest { WatcherName = watcherName }, + Metadata.Empty, + null, + token + ); + return new EventServerStreamReader(stream); } } diff --git a/src/INetMock.Client/Audit/Details.cs b/src/INetMock.Client/Audit/Details.cs index ccfba88..d5dea8c 100644 --- a/src/INetMock.Client/Audit/Details.cs +++ b/src/INetMock.Client/Audit/Details.cs @@ -3,88 +3,51 @@ using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; using Google.Protobuf.Collections; -using Google.Protobuf.WellKnownTypes; -namespace INetMock.Client.Audit +namespace INetMock.Client.Audit; + +public abstract record EventDetails; + +public record HttpDetails() : EventDetails { - public abstract record EventDetails; - - public record EmptyDetails : EventDetails; - - public record GenericDetails : EventDetails + public HttpDetails(HTTPDetailsEntity detailsEntity) : this() { - private readonly Any? _detailsAny; - - public GenericDetails() - { - _detailsAny = null; - } - - public GenericDetails(Any? any) - { - _detailsAny = any; - } - - public static implicit operator HttpDetails(GenericDetails gd) - { - if (gd._detailsAny == null || gd._detailsAny.Value == null) return new(); - if (!gd._detailsAny.TypeUrl.EndsWith(HTTPDetailsEntity.Descriptor.FullName)) - throw new InvalidOperationException(); - return new HttpDetails(gd._detailsAny); - } - - public static implicit operator DnsDetails(GenericDetails gd) - { - if (gd._detailsAny == null || gd._detailsAny.Value == null) return new(); - if (!gd._detailsAny.TypeUrl.EndsWith(HTTPDetailsEntity.Descriptor.FullName)) - throw new InvalidOperationException(); - return new DnsDetails(gd._detailsAny); - } + Method = new HttpMethod(detailsEntity.Method.ToString()); + Host = detailsEntity.Host; + Uri = detailsEntity.Uri; + Proto = detailsEntity.Proto; + Headers = new INetMockHttpHeaders(detailsEntity.Headers); } - public record HttpDetails : EventDetails - { - public HttpDetails() - { - } - - public HttpDetails(Any? any) - { - if (any == null || any.Value == null) return; - - var detailsEntity = HTTPDetailsEntity.Parser.ParseFrom(any.Value); - - Method = new HttpMethod(detailsEntity.Method.ToString()); - Host = detailsEntity.Host; - Uri = detailsEntity.Uri; - Proto = detailsEntity.Proto; - Headers = new INetMockHttpHeaders(detailsEntity.Headers); - } - - public HttpMethod Method { get; init; } = HttpMethod.Get; - public string Host { get; init; } = string.Empty; - public string Uri { get; init; } = string.Empty; - public string Proto { get; init; } = string.Empty; - public HttpHeaders Headers { get; init; } = new INetMockHttpHeaders(new MapField()); - } - - public record DnsDetails : EventDetails - { - public DnsDetails() - { - } - - public DNSOpCode OpCode { get; init; } = DNSOpCode.Query; - - public IReadOnlyList Questions { get; init; } = Array.Empty(); - - public DnsDetails(Any? any) - { - if (any == null || any.Value == null) return; - - var entity = DNSDetailsEntity.Parser.ParseFrom(any.Value); - OpCode = entity.Opcode; - Questions = entity.Questions; - } - } + public HttpMethod Method { get; init; } = HttpMethod.Get; + public string Host { get; init; } = string.Empty; + public string Uri { get; init; } = string.Empty; + public string Proto { get; init; } = string.Empty; + public HttpHeaders Headers { get; init; } = new INetMockHttpHeaders(new MapField()); +} + +public record DnsDetails() : EventDetails +{ + public DnsDetails(DNSDetailsEntity entity) : this() + { + OpCode = entity.Opcode; + Questions = entity.Questions; + } + + public DNSOpCode OpCode { get; init; } = DNSOpCode.Query; + public IReadOnlyList Questions { get; init; } = Array.Empty(); +} + +public record DhcpDetails() : EventDetails +{ + public DhcpDetails(DHCPDetailsEntity entity) : this() + { + HopCount = entity.HopCount; + OpCode = entity.Opcode; + HardwareType = entity.HwType; + } + + public int HopCount { get; init; } + public DHCPOpCode OpCode { get; init; } = DHCPOpCode.Unspecified; + public DHCPHwType HardwareType { get; init; } = DHCPHwType.Unspecified; } diff --git a/src/INetMock.Client/Audit/Event.cs b/src/INetMock.Client/Audit/Event.cs index c1b93ff..3eeb1ff 100644 --- a/src/INetMock.Client/Audit/Event.cs +++ b/src/INetMock.Client/Audit/Event.cs @@ -1,90 +1,76 @@ using System; using System.Net; -namespace INetMock.Client.Audit +namespace INetMock.Client.Audit; + +public abstract record EventBase { - public record Event where T : EventDetails, new() + protected EventBase(EventEntity entity) { - public Event() + if (entity == null) { + throw new ArgumentNullException(nameof(entity)); } - public Event(EventEntity entity) - { - if (entity == null) throw new ArgumentNullException(nameof(entity)); - - var details = (new T(), entity.Application) switch - { - (GenericDetails, _) => new GenericDetails(entity.ProtocolDetails) as T, - (_, AppProtocol.Dns) => new DnsDetails(entity.ProtocolDetails) as T, - (_, AppProtocol.Http or AppProtocol.HttpProxy) => new HttpDetails(entity.ProtocolDetails) as T, - (_, _) => new EmptyDetails() as T - }; - - Id = entity.Id; - Timestamp = entity.Timestamp.ToDateTimeOffset(); - Transport = entity.Transport; - SourceIp = new IPAddress(entity.SourceIp.Span); - SourcePort = Convert.ToUInt16(entity.SourcePort); - DestinationIp = new IPAddress(entity.DestinationIp.Span); - DestinationPort = Convert.ToUInt16(entity.DestinationPort); - TlsDetails = entity.Tls; - Application = entity.Application; - Details = details; - } - - public long Id { get; init; } - public DateTimeOffset Timestamp { get; init; } - public TransportProtocol Transport { get; init; } - public AppProtocol Application { get; init; } - public IPAddress SourceIp { get; init; } = IPAddress.Any; - public IPAddress DestinationIp { get; init; } = IPAddress.Any; - public ushort SourcePort { get; init; } - public ushort DestinationPort { get; init; } - public TLSDetailsEntity TlsDetails { get; init; } = new(); - public T? Details { get; init; } - - public bool CanConvert() where TTarget : EventDetails, new() - { - if (Details == null) return false; - - return (new TTarget(), Application) switch - { - (DnsDetails, AppProtocol.Dns) => true, - (HttpDetails, AppProtocol.Http or AppProtocol.HttpProxy) => true, - (_, _) => false - }; - } - - public static explicit operator Event?(Event ge) - { - T? details = null; - if (ge.Details != null) - { - details = ge.Application switch - { - AppProtocol.Dns => (DnsDetails) ge.Details as T, - AppProtocol.Http or AppProtocol.HttpProxy => (HttpDetails) ge.Details as T, - _ => new EmptyDetails() as T - }; - } - - - if (details == null) return null; - - return new() - { - Id = ge.Id, - Timestamp = ge.Timestamp, - Transport = ge.Transport, - SourceIp = ge.SourceIp, - SourcePort = ge.SourcePort, - DestinationIp = ge.DestinationIp, - DestinationPort = ge.DestinationPort, - TlsDetails = ge.TlsDetails, - Application = ge.Application, - Details = details - }; - } + Id = entity.Id; + Timestamp = entity.Timestamp.ToDateTimeOffset(); + Transport = entity.Transport; + SourceIp = new IPAddress(entity.SourceIp.Span); + SourcePort = Convert.ToUInt16(entity.SourcePort); + DestinationIp = new IPAddress(entity.DestinationIp.Span); + DestinationPort = Convert.ToUInt16(entity.DestinationPort); + TlsDetails = entity.Tls; + Application = entity.Application; } + + public long Id { get; init; } + public DateTimeOffset Timestamp { get; init; } + public TransportProtocol Transport { get; init; } + public AppProtocol Application { get; init; } + public IPAddress SourceIp { get; init; } = IPAddress.Any; + public IPAddress DestinationIp { get; init; } = IPAddress.Any; + public ushort SourcePort { get; init; } + public ushort DestinationPort { get; init; } + public TLSDetailsEntity TlsDetails { get; init; } = new(); +} + +public record Event : EventBase +{ + public Event(EventEntity entity) : base(entity) + { + Details = entity.ProtocolDetailsCase switch + { + EventEntity.ProtocolDetailsOneofCase.Http => new HttpDetails(entity.Http), + EventEntity.ProtocolDetailsOneofCase.Dns => new DnsDetails(entity.Dns), + EventEntity.ProtocolDetailsOneofCase.Dhcp => new DhcpDetails(entity.Dhcp), + _ => null + }; + } + + public object? Details { get; init; } + + public T? DetailsAs() where T : EventDetails => Details as T; +} + +public record Event : EventBase where T : EventDetails, new() +{ + public Event(EventEntity entity) : base(entity) + { + Details = entity.ProtocolDetailsCase switch + { + EventEntity.ProtocolDetailsOneofCase.Http => new HttpDetails(entity.Http) as T, + EventEntity.ProtocolDetailsOneofCase.Dns => new DnsDetails(entity.Dns) as T, + EventEntity.ProtocolDetailsOneofCase.Dhcp => new DhcpDetails(entity.Dhcp) as T, + _ => null + }; + } + + private Event(Event raw) : base(raw) + { + Details = raw.Details as T; + } + + public T? Details { get; init; } + + public static explicit operator Event(Event raw) => new(raw); } diff --git a/src/INetMock.Client/Audit/IAuditApiClient.cs b/src/INetMock.Client/Audit/IAuditApiClient.cs index 45baca9..9aa0f55 100644 --- a/src/INetMock.Client/Audit/IAuditApiClient.cs +++ b/src/INetMock.Client/Audit/IAuditApiClient.cs @@ -2,13 +2,12 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace INetMock.Client.Audit +namespace INetMock.Client.Audit; + +public interface IAuditApiClient { - public interface IAuditApiClient - { - IProtoEventReader EventStreamAsync(string watcherName, CancellationToken token = default); - Task> ListSinksAsync(CancellationToken token = default); - Task RegisterFileSinkAsync(string targetPath, CancellationToken token = default); - Task RemoveFileSinkAsync(string targetPath, CancellationToken token = default); - } + IProtoEventReader EventStreamAsync(string watcherName, CancellationToken token = default); + Task> ListSinksAsync(CancellationToken token = default); + Task RegisterFileSinkAsync(string targetPath, CancellationToken token = default); + Task RemoveFileSinkAsync(string targetPath, CancellationToken token = default); } diff --git a/src/INetMock.Client/Audit/IEventReader.cs b/src/INetMock.Client/Audit/IEventReader.cs index 9702237..1e347f3 100644 --- a/src/INetMock.Client/Audit/IEventReader.cs +++ b/src/INetMock.Client/Audit/IEventReader.cs @@ -3,20 +3,34 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace INetMock.Client.Audit -{ - public interface IEventReader : IDisposable, IAsyncDisposable where T : EventDetails, new() - { - IAsyncEnumerable> ReadAllAsync(CancellationToken token = default); +namespace INetMock.Client.Audit; - /// - /// - /// - /// - /// - /// An event as long as underlying stream has data. - /// When the end of the stream has been reached it will return null. - /// - Task?> ReadAsync(CancellationToken token = default); - } +public interface IEventReader : IDisposable, IAsyncDisposable +{ + IAsyncEnumerable ReadAllAsync(CancellationToken token = default); + + /// + /// + /// + /// + /// + /// An event as long as underlying stream has data. + /// When the end of the stream has been reached it will return null. + /// + Task ReadAsync(CancellationToken token = default); +} + +public interface IEventReader : IDisposable, IAsyncDisposable where T : EventDetails, new() +{ + IAsyncEnumerable> ReadAllAsync(CancellationToken token = default); + + /// + /// + /// + /// + /// + /// An event as long as underlying stream has data. + /// When the end of the stream has been reached it will return null. + /// + Task?> ReadAsync(CancellationToken token = default); } diff --git a/src/INetMock.Client/Audit/INetMockHttpHeaders.cs b/src/INetMock.Client/Audit/INetMockHttpHeaders.cs index 968723e..23fe9b4 100644 --- a/src/INetMock.Client/Audit/INetMockHttpHeaders.cs +++ b/src/INetMock.Client/Audit/INetMockHttpHeaders.cs @@ -1,17 +1,20 @@ using System.Net.Http.Headers; using Google.Protobuf.Collections; -namespace INetMock.Client.Audit +namespace INetMock.Client.Audit; + +internal class INetMockHttpHeaders : HttpHeaders { - internal class INetMockHttpHeaders : HttpHeaders + internal INetMockHttpHeaders(MapField headers) { - internal INetMockHttpHeaders(MapField headers) + foreach (var (key, values) in headers) { - foreach (var (key, values) in headers) + if (string.IsNullOrEmpty(key) || values == null) { - if (string.IsNullOrEmpty(key) || values == null) continue; - Add(key, values.Values); + continue; } + + Add(key, values.Values); } } } diff --git a/src/INetMock.Client/Audit/IProtoEventReader.cs b/src/INetMock.Client/Audit/IProtoEventReader.cs index 01e434e..93d0cd9 100644 --- a/src/INetMock.Client/Audit/IProtoEventReader.cs +++ b/src/INetMock.Client/Audit/IProtoEventReader.cs @@ -1,11 +1,11 @@ using System; using System.Threading; using System.Threading.Tasks; +using Inetmock.Audit.V1; -namespace INetMock.Client.Audit +namespace INetMock.Client.Audit; + +public interface IProtoEventReader : IDisposable, IAsyncDisposable { - public interface IProtoEventReader : IDisposable, IAsyncDisposable - { - Task ReadAsync(CancellationToken token = default); - } + Task ReadAsync(CancellationToken token = default); } diff --git a/src/INetMock.Client/Audit/Serialization/EventServerStreamReader.cs b/src/INetMock.Client/Audit/Serialization/EventServerStreamReader.cs index e549ed2..42ef109 100644 --- a/src/INetMock.Client/Audit/Serialization/EventServerStreamReader.cs +++ b/src/INetMock.Client/Audit/Serialization/EventServerStreamReader.cs @@ -1,31 +1,33 @@ using System.Threading; using System.Threading.Tasks; using Grpc.Core; -using INetMock.Client.Rpc; -namespace INetMock.Client.Audit.Serialization +namespace INetMock.Client.Audit.Serialization; + +public sealed class EventServerStreamReader : IProtoEventReader { - public sealed class EventServerStreamReader : IProtoEventReader + private readonly AsyncServerStreamingCall _asyncEventStream; + + public EventServerStreamReader(AsyncServerStreamingCall asyncEventStream) { - private readonly AsyncServerStreamingCall _asyncEventStream; + _asyncEventStream = asyncEventStream; + } - public EventServerStreamReader(AsyncServerStreamingCall asyncEventStream) + public async Task ReadAsync(CancellationToken token = default) + { + if (!await _asyncEventStream.ResponseStream.MoveNext(token)) { - _asyncEventStream = asyncEventStream; + return null; } - public async Task ReadAsync(CancellationToken token = default) - { - if (!await _asyncEventStream.ResponseStream.MoveNext(token)) return null; - return _asyncEventStream.ResponseStream.Current.Entity; - } + return _asyncEventStream.ResponseStream.Current.Entity; + } - public void Dispose() => _asyncEventStream.Dispose(); + public void Dispose() => _asyncEventStream.Dispose(); - public ValueTask DisposeAsync() - { - _asyncEventStream.Dispose(); - return ValueTask.CompletedTask; - } + public ValueTask DisposeAsync() + { + _asyncEventStream.Dispose(); + return ValueTask.CompletedTask; } } diff --git a/src/INetMock.Client/Audit/Serialization/GenericReader.cs b/src/INetMock.Client/Audit/Serialization/GenericReader.cs index b175aec..9682a61 100644 --- a/src/INetMock.Client/Audit/Serialization/GenericReader.cs +++ b/src/INetMock.Client/Audit/Serialization/GenericReader.cs @@ -3,44 +3,42 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; -namespace INetMock.Client.Audit.Serialization +namespace INetMock.Client.Audit.Serialization; + +public sealed class GenericReader : IEventReader { - public sealed class GenericReader : IEventReader + private readonly IProtoEventReader _reader; + + public GenericReader(IProtoEventReader reader) { - private readonly IProtoEventReader _reader; + _reader = reader; + } - public GenericReader(IProtoEventReader reader) + public async IAsyncEnumerable ReadAllAsync( + [EnumeratorCancellation] CancellationToken token = default) + { + while (true) { - _reader = reader; - } - - public async IAsyncEnumerable> ReadAllAsync( - [EnumeratorCancellation] CancellationToken token = default) - { - while (true) + var ev = await ReadAsync(token); + if (ev == null) { - var ev = await ReadAsync(token); - if (ev == null) - { - yield break; - } - - yield return ev; + yield break; } - } - public async Task?> ReadAsync(CancellationToken token = default) - { - var entity = await _reader.ReadAsync(token); - if (entity == null) return null; - return new Event(entity); - } - - public ValueTask DisposeAsync() => _reader.DisposeAsync(); - - public void Dispose() - { - _reader.Dispose(); + yield return ev; } } + + public async Task ReadAsync(CancellationToken token = default) + { + var entity = await _reader.ReadAsync(token); + return entity == null ? null : new Event(entity); + } + + public ValueTask DisposeAsync() => _reader.DisposeAsync(); + + public void Dispose() + { + _reader.Dispose(); + } } diff --git a/src/INetMock.Client/Audit/Serialization/ProtoReader.cs b/src/INetMock.Client/Audit/Serialization/ProtoReader.cs index bc0180c..c6728cf 100644 --- a/src/INetMock.Client/Audit/Serialization/ProtoReader.cs +++ b/src/INetMock.Client/Audit/Serialization/ProtoReader.cs @@ -5,64 +5,63 @@ using System.Threading; using System.Threading.Tasks; using Google.Protobuf; -namespace INetMock.Client.Audit.Serialization +namespace INetMock.Client.Audit.Serialization; + +public sealed class ProtoReader : IProtoEventReader { - public sealed class ProtoReader : IProtoEventReader + private readonly MemoryPool _memoryPool; + private readonly Stream _sourceStream; + private readonly bool _keepStreamOpen; + + public ProtoReader(Stream sourceStream, bool keepStreamOpen = false) { - private readonly MemoryPool _memoryPool; - private readonly Stream _sourceStream; - private readonly bool _keepStreamOpen; + _memoryPool = MemoryPool.Shared; + _sourceStream = sourceStream; + _keepStreamOpen = keepStreamOpen; + } - public ProtoReader(Stream sourceStream, bool keepStreamOpen = false) + public async Task ReadAsync(CancellationToken token = default) + { + using var rentedLengthMem = _memoryPool.Rent(4); + var lengthMem = rentedLengthMem.Memory.Slice(0, 4); + var read = await _sourceStream.ReadAsync(lengthMem, token); + if (read != 4) { - _memoryPool = MemoryPool.Shared; - _sourceStream = sourceStream; - _keepStreamOpen = keepStreamOpen; + return null; } - public async Task ReadAsync(CancellationToken token = default) + var messageLength = BinaryPrimitives.ReadInt32BigEndian(lengthMem.Span); + using var rentedMsgMem = _memoryPool.Rent(messageLength); + var msgMem = rentedMsgMem.Memory.Slice(0, messageLength); + read = await _sourceStream.ReadAsync(msgMem, token); + if (read != messageLength) { - using var rentedLengthMem = _memoryPool.Rent(4); - var lengthMem = rentedLengthMem.Memory.Slice(0, 4); - var read = await _sourceStream.ReadAsync(lengthMem, token); - if (read != 4) - { - return null; - } - - var messageLength = BinaryPrimitives.ReadInt32BigEndian(lengthMem.Span); - using var rentedMsgMem = _memoryPool.Rent(messageLength); - var msgMem = rentedMsgMem.Memory.Slice(0, messageLength); - read = await _sourceStream.ReadAsync(msgMem, token); - if (read != messageLength) - { - return null; - } - - var entity = new EventEntity(); - entity.MergeFrom(msgMem.ToArray()); - - return entity; + return null; } - public async ValueTask DisposeAsync() - { - if (!_keepStreamOpen) - { - await _sourceStream.DisposeAsync(); - } + var entity = new EventEntity(); + entity.MergeFrom(msgMem.ToArray()); - _memoryPool.Dispose(); + return entity; + } + + public async ValueTask DisposeAsync() + { + if (!_keepStreamOpen) + { + await _sourceStream.DisposeAsync(); } - public void Dispose() - { - if (!_keepStreamOpen) - { - _sourceStream?.Dispose(); - } + _memoryPool.Dispose(); + } - _memoryPool?.Dispose(); + public void Dispose() + { + if (!_keepStreamOpen) + { + _sourceStream?.Dispose(); } + + _memoryPool?.Dispose(); } } diff --git a/src/INetMock.Client/Audit/Serialization/TypedReader.cs b/src/INetMock.Client/Audit/Serialization/TypedReader.cs index 6ed486c..4c0127f 100644 --- a/src/INetMock.Client/Audit/Serialization/TypedReader.cs +++ b/src/INetMock.Client/Audit/Serialization/TypedReader.cs @@ -3,77 +3,80 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; -namespace INetMock.Client.Audit.Serialization +namespace INetMock.Client.Audit.Serialization; + +/// +/// Configures how the TypedReader proceeds with mismatching entities. +/// Given a TypedReader<HttpDetails> it can't guarantee that every Event<T> contains a HttpDetails entity. +/// Therefore different dropping strategies can be configured. +/// +public enum DropMode { /// - /// Configures how the TypedReader proceeds with mismatching entities. - /// Given a TypedReader<HttpDetails> it can't guarantee that every Event<T> contains a HttpDetails entity. - /// Therefore different dropping strategies can be configured. + /// Drops the whole entity. + /// This filters the actual stream for entities supporting the details in question. /// - public enum DropMode - { - /// - /// Drops the whole entity. - /// This filters the actual stream for entities supporting the details in question. - /// - DropEntity, + DropEntity, - /// - /// Drops only the mismatching details but keeps the event - /// e.g. a TypedReader<HttpDetails> would still contain DNS events but no details about them - /// - DropDetails - } - - public sealed class TypedReader : IEventReader where T : EventDetails, new() - { - private readonly IProtoEventReader _reader; - private readonly DropMode _dropMode; - - public TypedReader(IProtoEventReader reader, DropMode dropMode = DropMode.DropDetails) - { - _reader = reader; - _dropMode = dropMode; - } - - public async IAsyncEnumerable> ReadAllAsync([EnumeratorCancellation] CancellationToken token = default) - { - while (true) - { - var ev = await ReadAsync(token); - if (ev == null) - { - yield break; - } - - yield return ev; - } - } - - public async Task?> ReadAsync(CancellationToken token = default) - { - do - { - var entity = await _reader.ReadAsync(token); - if (entity == null) return null; - var parsed = new Event(entity); - - var canReturn = (_dropMode, parsed.Details) switch - { - (DropMode.DropDetails, null) => true, - (DropMode.DropEntity, null) => false, - (_, _) => true - }; - - if (canReturn) - { - return parsed; - } - } while (true); - } - - public void Dispose() => _reader.Dispose(); - - public ValueTask DisposeAsync() => _reader.DisposeAsync(); - } + /// + /// Drops only the mismatching details but keeps the event + /// e.g. a TypedReader<HttpDetails> would still contain DNS events but no details about them + /// + DropDetails +} + +public sealed class TypedReader : IEventReader where T : EventDetails, new() +{ + private readonly IProtoEventReader _reader; + private readonly DropMode _dropMode; + + public TypedReader(IProtoEventReader reader, DropMode dropMode = DropMode.DropDetails) + { + _reader = reader; + _dropMode = dropMode; + } + + public async IAsyncEnumerable> ReadAllAsync([EnumeratorCancellation] CancellationToken token = default) + { + while (true) + { + var ev = await ReadAsync(token); + if (ev == null) + { + yield break; + } + + yield return ev; + } + } + + public async Task?> ReadAsync(CancellationToken token = default) + { + do + { + var entity = await _reader.ReadAsync(token); + if (entity == null) + { + return null; + } + + var parsed = new Event(entity); + + var canReturn = (_dropMode, parsed.Details) switch + { + (DropMode.DropDetails, null) => true, + (DropMode.DropEntity, null) => false, + (_, _) => true + }; + + if (canReturn) + { + return parsed; + } + } while (true); + } + + public void Dispose() => _reader.Dispose(); + + public ValueTask DisposeAsync() => _reader.DisposeAsync(); } diff --git a/src/INetMock.Client/Grpc/ChannelFactory.cs b/src/INetMock.Client/Grpc/ChannelFactory.cs index c8cb588..b96bea2 100644 --- a/src/INetMock.Client/Grpc/ChannelFactory.cs +++ b/src/INetMock.Client/Grpc/ChannelFactory.cs @@ -3,38 +3,37 @@ using System.Net.Http; using System.Net.Sockets; using Grpc.Net.Client; -namespace INetMock.Client.Grpc +namespace INetMock.Client.Grpc; + +internal static class ChannelFactory { - 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) + internal static GrpcChannel ForAddress(Uri uri, GrpcChannelOptions options) => + uri.Scheme.ToLowerInvariant() switch { - var endpoint = new UnixDomainSocketEndPoint(path); - options.HttpHandler = new SocketsHttpHandler + "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) => { - ConnectCallback = async (_, cancellationToken) => + var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); + try { - 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; - } + await socket.ConnectAsync(endpoint, cancellationToken).ConfigureAwait(false); + return new NetworkStream(socket, true); } - }; - return GrpcChannel.ForAddress("http://localhost", options); - } + catch + { + socket.Dispose(); + throw; + } + } + }; + return GrpcChannel.ForAddress("http://localhost", options); } } diff --git a/src/INetMock.Client/INetMock.Client.csproj b/src/INetMock.Client/INetMock.Client.csproj index 3029a30..d90bc6d 100644 --- a/src/INetMock.Client/INetMock.Client.csproj +++ b/src/INetMock.Client/INetMock.Client.csproj @@ -1,24 +1,30 @@ - net5.0 + net6.0 enable latest - - - - + + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + - + + diff --git a/src/INetMock.Client/PCAP/Client/PcapApiClient.cs b/src/INetMock.Client/PCAP/Client/PcapApiClient.cs index 4e4a00d..38f7344 100644 --- a/src/INetMock.Client/PCAP/Client/PcapApiClient.cs +++ b/src/INetMock.Client/PCAP/Client/PcapApiClient.cs @@ -7,82 +7,80 @@ using System.Threading.Tasks; using Google.Protobuf.WellKnownTypes; using Grpc.Core; using Grpc.Net.Client; -using INetMock.Client.Grpc; -using INetMock.Client.Rpc; +using ChannelFactory = INetMock.Client.Grpc.ChannelFactory; -namespace INetMock.Client.PCAP.Client +namespace INetMock.Client.PCAP.Client; + +public class PcapApiClient : IPcapApiClient { - public class PcapApiClient : IPcapApiClient + private readonly PCAPService.PCAPServiceClient _pcapServiceClient; + + public PcapApiClient(string address, GrpcChannelOptions? options = null) + : this(new Uri(address), options) { - private readonly PCAPService.PCAPServiceClient _pcapServiceClient; + } - public PcapApiClient(string address, GrpcChannelOptions? options = null) - : this(new Uri(address), options) - { - } + public PcapApiClient(Uri address, GrpcChannelOptions? options = null) + : this(ChannelFactory.ForAddress(address, options ?? new GrpcChannelOptions())) + { + } - public PcapApiClient(Uri address, GrpcChannelOptions? options = null) - : this(ChannelFactory.ForAddress(address, options ?? new GrpcChannelOptions())) - { - } + public PcapApiClient(ChannelBase channel) + { + _pcapServiceClient = new PCAPService.PCAPServiceClient(channel); + } - public PcapApiClient(ChannelBase channel) - { - _pcapServiceClient = new PCAPService.PCAPServiceClient(channel); - } - - public async Task> ListAvailableDevicesAsync(CancellationToken token = default) - { - var devices = await _pcapServiceClient.ListAvailableDevicesAsync(new(), Metadata.Empty, null, token); - return devices.AvailableDevices - .Select(d => new RecordingDevice( - d.Name, - d.Addresses - .Select(addr => new IPAddress(addr.Span)) - .ToList() - ) + public async Task> ListAvailableDevicesAsync(CancellationToken token = default) + { + var devices = await _pcapServiceClient.ListAvailableDevicesAsync(new(), Metadata.Empty, null, token); + return devices.AvailableDevices + .Select(d => new RecordingDevice( + d.Name, + d.Addresses + .Select(addr => new IPAddress(addr.Span)) + .ToList() ) - .ToList(); - } + ) + .ToList(); + } - public async Task> ListActiveRecordingsAsync(CancellationToken token = default) + public async Task> ListActiveRecordingsAsync(CancellationToken token = default) + { + var recordings = await _pcapServiceClient.ListActiveRecordingsAsync(new(), Metadata.Empty, null, token); + return recordings.Subscriptions + .Select(consumerKey => new Subscription(consumerKey)) + .ToList(); + } + + public async Task StartPcapFileRecordingAsync(RecordingRequest request, + CancellationToken token = default) + { + var clientRequest = new StartPCAPFileRecordingRequest { - var recordings = await _pcapServiceClient.ListActiveRecordingsAsync(new(), Metadata.Empty, null, token); - return recordings.Subscriptions - .Select(consumerKey => new Subscription(consumerKey)) - .ToList(); - } + Device = request.Device, + Promiscuous = request.Promiscuous, + TargetPath = request.TargetPath, + ReadTimeout = Duration.FromTimeSpan(request.ReadTimeout) + }; - public async Task StartPcapFileRecordingAsync(RecordingRequest request, - CancellationToken token = default) - { - var clientRequest = new StartPCAPFileRecordingRequest - { - Device = request.Device, - Promiscuous = request.Promiscuous, - TargetPath = request.TargetPath, - ReadTimeout = Duration.FromTimeSpan(request.ReadTimeout) - }; + var result = await _pcapServiceClient.StartPCAPFileRecordingAsync( + clientRequest, + Metadata.Empty, + null, + token); - var result = await _pcapServiceClient.StartPCAPFileRecordingAsync( - clientRequest, - Metadata.Empty, - null, - token); + return result.ResolvedPath; + } - return result.ResolvedPath; - } - - public async Task StopPcapFileRecording(string consumerKey, CancellationToken token = default) - { - var clientRequest = new StopPCAPFileRecordingRequest {ConsumerKey = consumerKey}; - var result = await _pcapServiceClient.StopPCAPFileRecordingAsync( - clientRequest, - Metadata.Empty, - null, - token - ); - return result.Removed; - } + public async Task StopPcapFileRecordingAsync(string consumerKey, CancellationToken token = default) + { + var clientRequest = new StopPCAPFileRecordingRequest { ConsumerKey = consumerKey }; + var result = await _pcapServiceClient.StopPCAPFileRecordingAsync( + clientRequest, + Metadata.Empty, + null, + token + ); + return result.Removed; } } diff --git a/src/INetMock.Client/PCAP/IPcapApiClient.cs b/src/INetMock.Client/PCAP/IPcapApiClient.cs index c5d5b25..42a5cf7 100644 --- a/src/INetMock.Client/PCAP/IPcapApiClient.cs +++ b/src/INetMock.Client/PCAP/IPcapApiClient.cs @@ -2,12 +2,12 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace INetMock.Client.PCAP +namespace INetMock.Client.PCAP; + +public interface IPcapApiClient { - public interface IPcapApiClient - { - Task> ListAvailableDevicesAsync(CancellationToken token = default); - Task> ListActiveRecordingsAsync(CancellationToken token = default); - Task StartPcapFileRecordingAsync(RecordingRequest request, CancellationToken token = default); - } + Task> ListAvailableDevicesAsync(CancellationToken token = default); + Task> ListActiveRecordingsAsync(CancellationToken token = default); + Task StartPcapFileRecordingAsync(RecordingRequest request, CancellationToken token = default); + Task StopPcapFileRecordingAsync(string consumerKey, CancellationToken token = default); } diff --git a/src/INetMock.Client/PCAP/Models.cs b/src/INetMock.Client/PCAP/Models.cs index 2642158..2efed64 100644 --- a/src/INetMock.Client/PCAP/Models.cs +++ b/src/INetMock.Client/PCAP/Models.cs @@ -2,52 +2,51 @@ using System; using System.Collections.Generic; using System.Net; -namespace INetMock.Client.PCAP +namespace INetMock.Client.PCAP; + +public record RecordingDevice(string Name, IReadOnlyList Addresses); + +public record Subscription { - public record RecordingDevice(string Name, IReadOnlyList Addresses); - - public record Subscription + public Subscription(string consumerKey) { - public Subscription(string consumerKey) - { - ConsumerKey = consumerKey; - (ConsumerName, Device) = SplitConsumerKey(consumerKey); - } - - public Subscription(string consumerKey, string consumerName, string device) - { - ConsumerKey = consumerKey; - ConsumerName = consumerName; - Device = device; - } - - public string ConsumerKey { get; init; } - public string ConsumerName { get; init; } - public string Device { get; init; } - - private static (string name, string key) SplitConsumerKey(string consumerKey) - { - var splitIndex = consumerKey.IndexOf(':'); - if (splitIndex < 0) - { - throw new ArgumentOutOfRangeException( - nameof(consumerKey), - "The given consumer key could not be split into components" - ); - } - - return (consumerKey[(splitIndex + 1)..], consumerKey[..splitIndex]); - } + ConsumerKey = consumerKey; + (ConsumerName, Device) = SplitConsumerKey(consumerKey); } - public record RecordingRequest(string Device, string TargetPath, bool Promiscuous = false) + public Subscription(string consumerKey, string consumerName, string device) { - public RecordingRequest(string device, string targetPath, bool promiscuous, TimeSpan readTimeout) : this(device, - targetPath, promiscuous) + ConsumerKey = consumerKey; + ConsumerName = consumerName; + Device = device; + } + + public string ConsumerKey { get; init; } + public string ConsumerName { get; init; } + public string Device { get; init; } + + private static (string name, string key) SplitConsumerKey(string consumerKey) + { + var splitIndex = consumerKey.IndexOf(':'); + if (splitIndex < 0) { - ReadTimeout = readTimeout; + throw new ArgumentOutOfRangeException( + nameof(consumerKey), + "The given consumer key could not be split into components" + ); } - public TimeSpan ReadTimeout { get; } = TimeSpan.FromSeconds(30); + return (consumerKey[(splitIndex + 1)..], consumerKey[..splitIndex]); } } + +public record RecordingRequest(string Device, string TargetPath, bool Promiscuous = false) +{ + public RecordingRequest(string device, string targetPath, bool promiscuous, TimeSpan readTimeout) : this(device, + targetPath, promiscuous) + { + ReadTimeout = readTimeout; + } + + public TimeSpan ReadTimeout { get; } = TimeSpan.FromSeconds(30); +} diff --git a/tests/INetMock.Client.IntegrationTest/Audit/Serialization/GenericReaderTest.cs b/tests/INetMock.Client.IntegrationTest/Audit/Serialization/GenericReaderTest.cs new file mode 100644 index 0000000..1fc5cca --- /dev/null +++ b/tests/INetMock.Client.IntegrationTest/Audit/Serialization/GenericReaderTest.cs @@ -0,0 +1,26 @@ +using System.IO; +using System.Threading.Tasks; +using INetMock.Client.Audit; +using INetMock.Client.Audit.Serialization; +using Xunit; + +namespace INetMock.Client.IntegrationTest.Audit.Serialization; + +public class GenericReaderTest +{ + [Fact] + public async Task Test_ReadAllAsync_AuditFile() + { + await using var auditFileStream = File.OpenRead(Path.Join("testdata", "test.ima")); + await using IEventReader reader = new GenericReader(new ProtoReader(auditFileStream)); + + var count = 0; + await foreach (var ev in reader.ReadAllAsync()) + { + Assert.NotNull(ev); + count++; + } + + Assert.True(count > 0); + } +} diff --git a/tests/INetMock.Client.IntegrationTest/Audit/Serialization/TypedReaderTest.cs b/tests/INetMock.Client.IntegrationTest/Audit/Serialization/TypedReaderTest.cs new file mode 100644 index 0000000..274bbc9 --- /dev/null +++ b/tests/INetMock.Client.IntegrationTest/Audit/Serialization/TypedReaderTest.cs @@ -0,0 +1,71 @@ +using System.IO; +using System.Threading.Tasks; +using INetMock.Client.Audit; +using INetMock.Client.Audit.Serialization; +using Xunit; + +namespace INetMock.Client.IntegrationTest.Audit.Serialization; + +public class TypedReaderTest +{ + [Fact] + public async Task Test_ReadAllAsync_DropDetails_AuditFile_HTTPEvents() + { + await using var fileStream = File.OpenRead(Path.Join("testdata", "test.ima")); + await using IEventReader httpReader = new TypedReader(new ProtoReader(fileStream)); + + var count = 0; + await foreach (var ev in httpReader.ReadAllAsync()) + { + Assert.NotNull(ev); + count++; + } + Assert.True(count > 0); + } + + [Fact] + public async Task Test_ReadAllAsync_DropEntity_AuditFile_HTTPEvents() + { + await using var fileStream = File.OpenRead(Path.Join("testdata", "test.ima")); + await using IEventReader httpReader = new TypedReader(new ProtoReader(fileStream), DropMode.DropEntity); + + var count = 0; + await foreach (var ev in httpReader.ReadAllAsync()) + { + Assert.NotNull(ev); + Assert.NotNull(ev.Details); + count++; + } + Assert.True(count > 0); + } + + [Fact] + public async Task Test_ReadAllAsync_DropDetails_AuditFile_DNSEvents() + { + await using var fileStream = File.OpenRead(Path.Join("testdata", "test.ima")); + await using IEventReader httpReader = new TypedReader(new ProtoReader(fileStream)); + + var count = 0; + await foreach (var ev in httpReader.ReadAllAsync()) + { + Assert.NotNull(ev); + count++; + } + Assert.True(count > 0); + } + + [Fact] + public async Task Test_ReadAllAsync_DropEntity_AuditFile_DNSEvents() + { + await using var fileStream = File.OpenRead(Path.Join("testdata", "test.ima")); + await using IEventReader httpReader = new TypedReader(new ProtoReader(fileStream), DropMode.DropEntity); + + var count = 0; + await foreach (var ev in httpReader.ReadAllAsync()) + { + Assert.NotNull(ev); + count++; + } + Assert.True(count > 0); + } +} diff --git a/tests/INetMock.Client.IntegrationTest/DockerEndpoint.cs b/tests/INetMock.Client.IntegrationTest/DockerEndpoint.cs deleted file mode 100644 index 1649166..0000000 --- a/tests/INetMock.Client.IntegrationTest/DockerEndpoint.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Globalization; -using System.Runtime.InteropServices; - -namespace INetMock.Client.IntegrationTest -{ - internal static class DockerEndpoint - { - private const string DockerHostEnvName = "DOCKER_HOST"; - private const string DockerTlsVerifyEnvName = "DOCKER_TLS_VERIFY"; - - internal static string DetermineFromEnv() => DetermineEndpoint( - Environment.GetEnvironmentVariable(DockerHostEnvName), - Environment.GetEnvironmentVariable(DockerTlsVerifyEnvName) - ); - - internal static string DetermineEndpoint(string? dockerHost, string? tlsVerify) - { - dockerHost ??= ""; - var dockerTlsVerify = int.TryParse(tlsVerify, out var verify) && verify == 1; - var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - return (dockerHost, dockerTlsVerify, isWindows) switch - { - ("", _, true) => "npipe://./pipe/docker_engine", - ("", _, false) => "unix:/var/run/docker.sock", - (_, false, _) => dockerHost, - (var h, true, _) when h.StartsWith("tcp") => h.Replace( - "tcp", - "https", - true, - CultureInfo.InvariantCulture), - _ => "", - }; - } - } -} diff --git a/tests/INetMock.Client.IntegrationTest/DockerEndpointTests.cs b/tests/INetMock.Client.IntegrationTest/DockerEndpointTests.cs deleted file mode 100644 index b006fcc..0000000 --- a/tests/INetMock.Client.IntegrationTest/DockerEndpointTests.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Xunit; - -namespace INetMock.Client.IntegrationTest -{ - public class DockerEndpointTests - { - [Theory] - [InlineData(null, null, "unix:/var/run/docker.sock")] - [InlineData("tcp://docker:2375", null, "tcp://docker:2375")] - [InlineData("tcp://docker:2375", "0", "tcp://docker:2375")] - [InlineData("http://docker:2375", null, "http://docker:2375")] - [InlineData("http://docker:2375", "0", "http://docker:2375")] - [InlineData("tcp://docker:2376", "1", "https://docker:2376")] - [InlineData("https://docker:2376", "0", "https://docker:2376")] - public void DetermineDockerEndpoint_Input_ExpectedOutput(string? dockerHost, string? tlsVerify, string expected) - { - var actual = DockerEndpoint.DetermineEndpoint(dockerHost, tlsVerify); - - Assert.Equal(expected, actual); - } - } -} diff --git a/tests/INetMock.Client.IntegrationTest/INetMock.Client.IntegrationTest.csproj b/tests/INetMock.Client.IntegrationTest/INetMock.Client.IntegrationTest.csproj index 0961e02..99b230e 100644 --- a/tests/INetMock.Client.IntegrationTest/INetMock.Client.IntegrationTest.csproj +++ b/tests/INetMock.Client.IntegrationTest/INetMock.Client.IntegrationTest.csproj @@ -1,22 +1,23 @@ - net5.0 + net6.0 false enable + + 10 - - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -26,4 +27,10 @@ + + + PreserveNewest + + + diff --git a/tests/INetMock.Client.IntegrationTest/INetMockFixture.cs b/tests/INetMock.Client.IntegrationTest/INetMockFixture.cs new file mode 100644 index 0000000..f4c6120 --- /dev/null +++ b/tests/INetMock.Client.IntegrationTest/INetMockFixture.cs @@ -0,0 +1,19 @@ +using System; + +namespace INetMock.Client.IntegrationTest; + +public class INetMockFixture +{ + private const string DefaultINetMockSocketPath = "unix:///var/run/inetmock/inetmock.sock"; + + public INetMockFixture() + { + INetMockSocketPath = Environment.GetEnvironmentVariable("INETMOCK_SOCKET") ?? DefaultINetMockSocketPath; + if (INetMockSocketPath.StartsWith("http:")) + { + AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true); + } + } + + public string INetMockSocketPath { get; } +} diff --git a/tests/INetMock.Client.IntegrationTest/INetMockServerFixture.cs b/tests/INetMock.Client.IntegrationTest/INetMockServerFixture.cs deleted file mode 100644 index f8cb433..0000000 --- a/tests/INetMock.Client.IntegrationTest/INetMockServerFixture.cs +++ /dev/null @@ -1,42 +0,0 @@ -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() - .WithImage("inetmock-root:latest") - .WithCommand("serve") - .WithPortBinding(80, true) - .WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(80)) - .WithDockerEndpoint(DockerEndpoint.DetermineFromEnv()) - .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(); - } - } -} diff --git a/tests/INetMock.Client.IntegrationTest/PCAP/Client/PcapApiClientTests.cs b/tests/INetMock.Client.IntegrationTest/PCAP/Client/PcapApiClientTests.cs index 0d291dc..bf135d1 100644 --- a/tests/INetMock.Client.IntegrationTest/PCAP/Client/PcapApiClientTests.cs +++ b/tests/INetMock.Client.IntegrationTest/PCAP/Client/PcapApiClientTests.cs @@ -1,45 +1,63 @@ +using System.Linq; using INetMock.Client.PCAP; using INetMock.Client.PCAP.Client; using Xunit; using Xunit.Abstractions; -namespace INetMock.Client.IntegrationTest.PCAP.Client +namespace INetMock.Client.IntegrationTest.PCAP.Client; + +public class PcapApiClientTests : IClassFixture { - public class PcapApiClientTests : IClassFixture + private readonly ITestOutputHelper _outputHelper; + private readonly IPcapApiClient _apiClient; + + public PcapApiClientTests(ITestOutputHelper testOutputHelper, INetMockFixture inetMockFixture) { - private readonly ITestOutputHelper _outputHelper; - private readonly IPcapApiClient _apiClient; + _outputHelper = testOutputHelper; + _apiClient = new PcapApiClient(inetMockFixture.INetMockSocketPath); + } - public PcapApiClientTests(ITestOutputHelper testOutputHelper, INetMockServerFixture inetmockFixture) + [Fact] + public async void ListAvailableDevicesAsync_RunningContainer_AtLeastLoopbackDevice() + { + var devs = await _apiClient.ListAvailableDevicesAsync(); + + foreach (var (name, _) in devs) { - _outputHelper = testOutputHelper; - _apiClient = new PcapApiClient(inetmockFixture.SocketPath); + _outputHelper.WriteLine(name); } - [Fact] - public async void ListAvailableDevicesAsync_RunningContainer_AtLeastLoopbackDevice() + 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() + { + var recordingDevice = (await _apiClient.ListAvailableDevicesAsync()).FirstOrDefault(); + if (recordingDevice == null) { - var devs = await _apiClient.ListAvailableDevicesAsync(); - - Assert.Contains(devs, device => device.Name.Equals("lo")); + return; } - [Fact] - public async void ListActiveRecordingsAsync_NoRecordingsRunning_EmptyResult() - { - var recordings = await _apiClient.ListActiveRecordingsAsync(); - - Assert.Empty(recordings); - } + var targetPath = $"/tmp/{recordingDevice.Name}_record.pcap"; + await _apiClient.StartPcapFileRecordingAsync(new(recordingDevice.Name, targetPath)); - [Fact] - public async void StartPcapFileRecordingAsync_RecordLoopbackInterface_RunningRecording() + var subscriptions = await _apiClient.ListActiveRecordingsAsync(); + Assert.Contains(subscriptions, subscription => + subscription.Device.Equals(recordingDevice.Name) && + subscription.ConsumerName.Equals(targetPath) + ); + foreach (var subscription in subscriptions) { - 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)); + await _apiClient.StopPcapFileRecordingAsync(subscription.ConsumerKey); } } } diff --git a/tests/INetMock.Client.IntegrationTest/testdata/test.ima b/tests/INetMock.Client.IntegrationTest/testdata/test.ima new file mode 100644 index 0000000000000000000000000000000000000000..d1cb3f08e1e3572a34252dfba279add0d603d1d1 GIT binary patch literal 3946 zcmdT`ZAcSg9N%pw=ef!*HC-==-x}=ZZI*s?h-hLExV|>7yW4rW-L2c{vM>2ksFfKK zQDA)-Sr8Sn$|8FaNvIGEDM2VAFtP~!(uW|>p1V2QZt9-7g|z3>p1u6;_wxMyk4~p^ zp{*mWm+tp}opj;Z=t9?6Z)VPy(3=AV`Xa=fqg#G0E}qiq5L?tv_@naIKlByX(A!8p zo{J)Qj+f#+1Sg7|hb3syOMq`3LEGXWCSQJshv@7ws1SMhb^x(85C{+w%P_ngLEsb; zmt#o;uP?wOTsad)*n{r^2nCd%aZ>?SB504;#JD|_v`mIk$Y`K$^>x)k>lGXi>$MXv zM2&bJNrV?KSSW^(2uku%if9bl9*1*d<{~`KLMTjW3CBi+mj(whD$?C~sQPbQ^8do~ ztLKpdq-fLH0SHH;eB_a#V%Sh?LNoAuXI;I^QC06EZRM`&%7d=@8i#G){va}dpawjP zw3QJhV38)w$_ReT@g`PkDMo9Y&O=t9g1Hde>Y!=XCtIonT4Z>E!!xlA?j-Ls7h~9A zKPy=r94p9pE{0c&mIhh&S!fRrcGREeV_PakK?ZLvb*#Y24R{8ox7*BnF=J%k+2UjI zLTm@+^Lcohl6g^3pTx`h{S?On-Ded&?#1fS`C?AhLl33LAcP)m2vBP?<>LvS7MP<- zj!jwCV`3xgx7y31Bw0Ui(!4ufP7FhN1_;E-YZ1U3*w>Yw_j zW_2(&tDoljlOX#Pf-F>4ZA3|eyqQ-%o@7E}!C$M!f~;z|PEQ5X%oWa9g=`{Y*DnYd zvqmMw8nPcgkE&$hO8GH_v58ArApzf>t2k^=rPsset3?%x4f?>ZsU*w~LFfTfR1mg8 zBtx~hBhKQx!{ZxbaSC%c9SJEVRXxDm)mZ$j``w1AP?y zI;zU0bmg&SPo@`FKVOj|(CE=UJO6*_QA(yu51ktPC$YhwK0Ve8AN()); + Assert.Null(ev.DetailsAs()); + + var httpEvent = (Event)ev; + Assert.NotNull(httpEvent); + Assert.NotNull(httpEvent.Details); } + } - [Fact] - public async void TestRead_HttpEvent_Success() + [Fact] + public async void TestRead_DnsEvent_Success() + { + await using var memStream = new MemoryStream(_dnsEventPayloadBytes); + await using var protoReader = new ProtoReader(new MemoryStream(_dnsEventPayloadBytes)); + await using IEventReader reader = new GenericReader(protoReader); + await foreach (var ev in reader.ReadAllAsync()) { - await using var protoReader = new ProtoReader(new MemoryStream(_httpEventPayloadBytes)); - await using IEventReader reader = new GenericReader(protoReader); - await foreach (var ev in reader.ReadAllAsync()) - { - Assert.NotNull(ev); - - Assert.True(ev.CanConvert()); - Assert.False(ev.CanConvert()); - - var httpEvent = (Event?) ev; - var dnsEvent = (Event?) ev; + Assert.NotNull(ev); + Assert.NotNull(ev.Details); + Assert.NotNull(ev.DetailsAs()); - Assert.NotNull(httpEvent); - Assert.Null(dnsEvent); - } - } - - [Fact] - public async void TestRead_DnsEvent_Success() - { - await using var memStream = new MemoryStream(_dnsEventPayloadBytes); - await using var protoReader = new ProtoReader(new MemoryStream(_dnsEventPayloadBytes)); - await using IEventReader reader = new GenericReader(protoReader); - await foreach (var ev in reader.ReadAllAsync()) - { - Assert.NotNull(ev); - Assert.True(ev.CanConvert()); - var dnsEvent = (Event?) ev; - Assert.NotNull(dnsEvent); - } + var dnsEvent = (Event)ev; + Assert.NotNull(dnsEvent); + Assert.NotNull(dnsEvent.Details); } } } diff --git a/tests/INetMock.Client.Test/Audit/Serialization/TypedReaderTest.cs b/tests/INetMock.Client.Test/Audit/Serialization/TypedReaderTest.cs index 57b90f5..f638ff3 100644 --- a/tests/INetMock.Client.Test/Audit/Serialization/TypedReaderTest.cs +++ b/tests/INetMock.Client.Test/Audit/Serialization/TypedReaderTest.cs @@ -4,42 +4,41 @@ using INetMock.Client.Audit.Serialization; using INetMock.Client.Test.Hex; using Xunit; -namespace INetMock.Client.Test.Audit.Serialization +namespace INetMock.Client.Test.Audit.Serialization; + +public class TypedReaderTest { - public class TypedReaderTest + private const string HttpEventPayload = "000000e5120b088092b8c398feffffff01180120022a047f00000132047f00000138d8fc0140504a3308041224544c535f45434448455f45434453415f574954485f4145535f3235365f4342435f5348411a096c6f63616c686f7374528a010a3c747970652e676f6f676c65617069732e636f6d2f696e65746d6f636b2e61756469742e64657461696c732e4854545044657461696c73456e74697479124a12096c6f63616c686f73741a15687474703a2f2f6c6f63616c686f73742f6173646622084854545020312e312a1c0a0641636365707412120a106170706c69636174696f6e2f6a736f6e"; + private const string DnsEventPayload = "0000003b120b088092b8c398feffffff01180120012a100000000000000000000000000000000132100000000000000000000000000000000138d8fc014050"; + + private readonly byte[] _httpEventPayloadBytes; + private readonly byte[] _dnsEventPayloadBytes; + + public TypedReaderTest() { - private const string HttpEventPayload = "000000e5120b088092b8c398feffffff01180120022a047f00000132047f00000138d8fc0140504a3308041224544c535f45434448455f45434453415f574954485f4145535f3235365f4342435f5348411a096c6f63616c686f7374528a010a3c747970652e676f6f676c65617069732e636f6d2f696e65746d6f636b2e61756469742e64657461696c732e4854545044657461696c73456e74697479124a12096c6f63616c686f73741a15687474703a2f2f6c6f63616c686f73742f6173646622084854545020312e312a1c0a0641636365707412120a106170706c69636174696f6e2f6a736f6e"; - private const string DnsEventPayload = "0000003b120b088092b8c398feffffff01180120012a100000000000000000000000000000000132100000000000000000000000000000000138d8fc014050"; + _httpEventPayloadBytes = HttpEventPayload.HexToByteArray(); + _dnsEventPayloadBytes = DnsEventPayload.HexToByteArray(); + } - private readonly byte[] _httpEventPayloadBytes; - private readonly byte[] _dnsEventPayloadBytes; - - public TypedReaderTest() + [Fact] + public async void TestRead_HttpEvent_Success() + { + await using var protoReader = new ProtoReader(new MemoryStream(_httpEventPayloadBytes)); + await using IEventReader reader = new TypedReader(protoReader, DropMode.DropEntity); + await foreach (var ev in reader.ReadAllAsync()) { - _httpEventPayloadBytes = HttpEventPayload.HexToByteArray(); - _dnsEventPayloadBytes = DnsEventPayload.HexToByteArray(); + Assert.NotNull(ev); } + } - [Fact] - public async void TestRead_HttpEvent_Success() + [Fact] + public async void TestRead_DnsEvent_Success() + { + await using var protoReader = new ProtoReader(new MemoryStream(_dnsEventPayloadBytes)); + await using IEventReader reader = new TypedReader(protoReader, DropMode.DropEntity); + await foreach (var ev in reader.ReadAllAsync()) { - await using var protoReader = new ProtoReader(new MemoryStream(_httpEventPayloadBytes)); - await using IEventReader reader = new TypedReader(protoReader, DropMode.DropEntity); - await foreach (var ev in reader.ReadAllAsync()) - { - Assert.NotNull(ev); - } - } - - [Fact] - public async void TestRead_DnsEvent_Success() - { - await using var protoReader = new ProtoReader(new MemoryStream(_dnsEventPayloadBytes)); - await using IEventReader reader = new TypedReader(protoReader, DropMode.DropEntity); - await foreach (var ev in reader.ReadAllAsync()) - { - Assert.NotNull(ev); - } + Assert.NotNull(ev); } } } diff --git a/tests/INetMock.Client.Test/Hex/Converter.cs b/tests/INetMock.Client.Test/Hex/Converter.cs index 4d1abd5..d34abac 100644 --- a/tests/INetMock.Client.Test/Hex/Converter.cs +++ b/tests/INetMock.Client.Test/Hex/Converter.cs @@ -1,15 +1,15 @@ using System; using System.Linq; -namespace INetMock.Client.Test.Hex +namespace INetMock.Client.Test.Hex; + +public static class Converter { - public static class Converter + public static byte[] HexToByteArray(this string hex) { - public static byte[] HexToByteArray(this string hex) { - return Enumerable.Range(0, hex.Length) - .Where(x => x % 2 == 0) - .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) - .ToArray(); - } + return Enumerable.Range(0, hex.Length) + .Where(x => x % 2 == 0) + .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) + .ToArray(); } } diff --git a/tests/INetMock.Client.Test/INetMock.Client.Test.csproj b/tests/INetMock.Client.Test/INetMock.Client.Test.csproj index f81850c..138e18c 100644 --- a/tests/INetMock.Client.Test/INetMock.Client.Test.csproj +++ b/tests/INetMock.Client.Test/INetMock.Client.Test.csproj @@ -1,20 +1,20 @@ - net5.0 + net6.0 false latest enable - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/INetMock.Client.Test/PCAP/SubscriptionTests.cs b/tests/INetMock.Client.Test/PCAP/SubscriptionTests.cs index 7a4e776..66eecef 100644 --- a/tests/INetMock.Client.Test/PCAP/SubscriptionTests.cs +++ b/tests/INetMock.Client.Test/PCAP/SubscriptionTests.cs @@ -1,17 +1,16 @@ using INetMock.Client.PCAP; using Xunit; -namespace INetMock.Client.Test.PCAP +namespace INetMock.Client.Test.PCAP; + +public class SubscriptionTests { - public class SubscriptionTests + [Theory] + [InlineData("lo:test.pcap", "test.pcap", "lo")] + public void Constructor_ConsumerKey_SplitIntoComponents(string key, string expectedName, string expectedDevice) { - [Theory] - [InlineData("lo:test.pcap", "test.pcap", "lo")] - public void Constructor_ConsumerKey_SplitIntoComponents(string key, string expectedName, string expectedDevice) - { - var sub = new Subscription(key); - - Assert.Equal(sub, new Subscription(key, expectedName, expectedDevice)); - } + var sub = new Subscription(key); + + Assert.Equal(sub, new Subscription(key, expectedName, expectedDevice)); } }