diff --git a/.editorconfig b/.editorconfig index a121307e..1203020c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -231,7 +231,7 @@ dotnet_diagnostic.SA1000.severity = suggestion # Need to configure formatting in # Parameter '*' should begin with lower-case letter dotnet_diagnostic.SA1313.severity = suggestion # Rider disagrees? -[**/*.{Tests,E2ETests,ArchTests}*/**.cs] +[**/*.{Tests,E2ETests.*,ArchTests}*/**.cs] dotnet_diagnostic.CA1852.severity = warning dotnet_diagnostic.CA1816.severity = warning dotnet_diagnostic.CA2007.severity = none diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f8db662e..71c95975 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -20,8 +20,8 @@ on: - 'diagnostic' jobs: - test: - name: Test + test-linux: + name: 🐧 Test runs-on: ubuntu-latest timeout-minutes: 5 env: @@ -41,15 +41,46 @@ jobs: --target Test --commit ${{ github.sha }} --msbuildverbosity ${{ github.event.inputs.verbosity }} + --platform linux_x64 - name: Display test results continue-on-error: true if: always() run: dotnet trx --verbosity normal - # TODO fix publish warnings and re-enable check - name: Check for warnings run: > dotnet run --project ./build/_build.csproj --target CheckBuildWarnings + + test-windows: + name: 🪟 Test + runs-on: windows-latest + timeout-minutes: 10 + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Set up runner + uses: ./.github/actions/setup-runner + + - name: Run tests + run: | + dotnet run ` + --project ./build/_build.csproj ` + --target Test ` + --commit ${{ github.sha }} ` + --msbuildverbosity ${{ github.event.inputs.verbosity }} ` + --platform win_x64 + + - name: Display test results + continue-on-error: true + if: always() + run: dotnet trx --verbosity normal + + - name: Check for warnings + run: | + dotnet run ` + --project ./build/_build.csproj ` + --target CheckBuildWarnings diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index 40e55bc6..ec3f6f74 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -41,6 +41,9 @@ "Restore", "Test", "TestE2E", + "TestE2E_Binary", + "TestE2E_Container", + "TestE2E_General", "TestLocal", "TestSelf", "TestUnit" @@ -147,6 +150,45 @@ "type": "string", "description": "MsBuildVerbosity - Console output verbosity - Default is 'normal'" }, + "Platform": { + "type": "string", + "description": "Platform - A .NET RID but with underscores instead of dashes e.g. linux_x64 or win_x64", + "enum": [ + "linux_arm", + "linux_arm64", + "linux_musl_x64", + "linux_x64", + "osx_10_10_x64", + "osx_10_11_x64", + "osx_10_12_x64", + "osx_10_13_x64", + "osx_10_14_x64", + "osx_10_15_x64", + "osx_11_0_arm64", + "osx_11_0_x64", + "osx_12_arm64", + "osx_12_x64", + "osx_x64", + "rhel_6_x64", + "rhel_x64", + "tizen", + "tizen_4_0_0", + "tizen_5_0_0", + "win_arm", + "win_arm64", + "win_x64", + "win_x86", + "win10_arm", + "win10_arm64", + "win10_x64", + "win10_x86", + "win7_x64", + "win7_x86", + "win81_arm", + "win81_x64", + "win81_x86" + ] + }, "Solution": { "type": "string", "description": "Path to a solution file that is automatically loaded" diff --git a/Drift.sln b/Drift.sln index 59537d88..5b758dea 100644 --- a/Drift.sln +++ b/Drift.sln @@ -38,7 +38,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "src\Common\Common EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Tests", "src\Common.Tests\Common.Tests.csproj", "{004FE90A-E749-4C17-B7B7-B529AA0F5F34}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cli.E2ETests", "src\Cli.E2ETests\Cli.E2ETests.csproj", "{11F44BDE-0563-4C64-BE3C-9E7B69F89E12}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cli.E2ETests.Binary", "src\Cli.E2ETests.Binary\Cli.E2ETests.Binary.csproj", "{B1A2C3D4-E5F6-7890-ABCD-EF1234567890}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cli.E2ETests.Container", "src\Cli.E2ETests.Container\Cli.E2ETests.Container.csproj", "{C2B3D4E5-F6A7-8901-BCDE-F12345678901}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cli.E2ETests.General", "src\Cli.E2ETests.General\Cli.E2ETests.General.csproj", "{D3C4E5F6-A7B8-9012-CDEF-123456789012}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cli.Abstractions", "src\Cli.Abstractions\Cli.Abstractions.csproj", "{42ECC801-ADCB-43E4-86C0-E0E4B017D7B6}" EndProject @@ -76,6 +80,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cli.Settings.SchemaGenerato EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.Schemas", "src\Common.Schemas\Common.Schemas.csproj", "{BAC0F9AF-CAE2-43FB-AF47-B9AC7B62544B}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "E2E", "E2E", "{D1DBBF0F-1A0D-486C-A893-ACEB667F2A63}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -132,10 +138,18 @@ Global {004FE90A-E749-4C17-B7B7-B529AA0F5F34}.Release|Any CPU.Build.0 = Release|Any CPU {8523E9E0-F412-41B7-B361-ADE639FFAF24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8523E9E0-F412-41B7-B361-ADE639FFAF24}.Release|Any CPU.ActiveCfg = Release|Any CPU - {11F44BDE-0563-4C64-BE3C-9E7B69F89E12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {11F44BDE-0563-4C64-BE3C-9E7B69F89E12}.Debug|Any CPU.Build.0 = Debug|Any CPU - {11F44BDE-0563-4C64-BE3C-9E7B69F89E12}.Release|Any CPU.ActiveCfg = Release|Any CPU - {11F44BDE-0563-4C64-BE3C-9E7B69F89E12}.Release|Any CPU.Build.0 = Release|Any CPU + {B1A2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1A2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1A2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1A2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU + {C2B3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2B3D4E5-F6A7-8901-BCDE-F12345678901}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2B3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2B3D4E5-F6A7-8901-BCDE-F12345678901}.Release|Any CPU.Build.0 = Release|Any CPU + {D3C4E5F6-A7B8-9012-CDEF-123456789012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D3C4E5F6-A7B8-9012-CDEF-123456789012}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3C4E5F6-A7B8-9012-CDEF-123456789012}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D3C4E5F6-A7B8-9012-CDEF-123456789012}.Release|Any CPU.Build.0 = Release|Any CPU {42ECC801-ADCB-43E4-86C0-E0E4B017D7B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {42ECC801-ADCB-43E4-86C0-E0E4B017D7B6}.Debug|Any CPU.Build.0 = Debug|Any CPU {42ECC801-ADCB-43E4-86C0-E0E4B017D7B6}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/README.md b/README.md index da1ef958..232c055f 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,8 @@ state, Drift can detect issues like unknown devices or unexpected subnet access, You can install Drift by either: -- Downloading the latest release from the [Releases page](https://github.com/hojmark/drift/releases?q=prerelease%3Afalse), or +- Downloading the latest release from + the [Releases page](https://github.com/hojmark/drift/releases?q=prerelease%3Afalse), or - Running the installation script: ```bash @@ -43,6 +44,23 @@ drift init drift scan -i ``` +### Windows x64 + +#### Install + +Download the `.zip` archive from the [Releases page](https://github.com/hojmark/drift/releases?q=prerelease%3Afalse), +extract `drift.exe`, and place it somewhere on your `PATH`. + +#### Run + +```powershell +# Create a network spec using auto-discovery +drift init + +# Scan and detect drift +drift scan -i +``` + ### Container #### Run @@ -106,7 +124,8 @@ JSON Schemas are available to enable editor auto-completion and validation: } ``` -There’s no official documentation site yet — if you run into trouble, feel free to [open a discussion](https://github.com/hojmark/drift/discussions/categories/q-a). +There’s no official documentation site yet — if you run into trouble, feel free +to [open a discussion](https://github.com/hojmark/drift/discussions/categories/q-a). ### ▸ What can be automatically discovered? diff --git a/build/NukeBuild.Binaries.cs b/build/NukeBuild.Binaries.cs index 5198e595..a4725325 100644 --- a/build/NukeBuild.Binaries.cs +++ b/build/NukeBuild.Binaries.cs @@ -14,33 +14,33 @@ // ReSharper disable UnusedMember.Local sealed partial class NukeBuild { - private static readonly string[] FilesToDistribute = ["drift", "drift.dbg"]; + private static readonly string[] FilesToDistributeLinux = ["drift", "drift.dbg"]; + private static readonly string[] FilesToDistributeWindows = ["drift.exe"]; Target PublishBinaries => _ => _ .DependsOn( Build, CleanArtifacts ) + .Requires( () => Platform ) + .Requires( () => SupportedRuntimes.Contains( Platform ) ) .Executes( async () => { using var _ = new OperationTimer( nameof(PublishBinaries) ); - // TODO https://nuke.build/docs/common/cli-tools/#combinatorial-modifications - foreach ( var runtime in SupportedRuntimes ) { - var publishDir = Paths.PublishDirectoryForRuntime( runtime ); - var version = await Versioning.Value.GetVersionAsync(); + var publishDir = Paths.PublishDirectoryForRuntime( Platform ); + var version = await Versioning.Value.GetVersionAsync(); - Log.Information( "Publishing {Runtime} build to {PublishDir}", runtime, publishDir ); - DotNetPublish( s => s - .SetProject( Solution.Cli ) - .SetConfiguration( Configuration ) - .SetOutput( publishDir ) - .SetSelfContained( true ) - .SetVersionProperties( version ) - // TODO if not specifying a RID, apparently only x64 gets built on x64 host - .SetRuntime( runtime ) - .SetProcessAdditionalArguments( $"-bl:{BinaryPublishLogName}" ) - .EnableNoLogo() - .EnableNoRestore() - .EnableNoBuild() - ); - } + Log.Information( "Publishing {Runtime} build to {PublishDir}", Platform, publishDir ); + Log.Debug( "Supported runtimes are {SupportedRuntimes}", string.Join( ", ", SupportedRuntimes ) ); + DotNetPublish( s => s + .SetProject( Solution.Cli ) + .SetConfiguration( Configuration ) + .SetOutput( publishDir ) + .SetSelfContained( true ) + .SetVersionProperties( version ) + .SetRuntime( Platform ) + .SetProcessAdditionalArguments( $"-bl:{BinaryPublishLogName}" ) + .EnableNoLogo() + .EnableNoRestore() + .EnableNoBuild() + ); } ); @@ -50,15 +50,23 @@ sealed partial class NukeBuild { using var _ = new OperationTimer( nameof(PackBinaries) ); var version = await Versioning.Value.GetVersionAsync(); + var publishDir = Paths.PublishDirectoryForRuntime( Platform ); - foreach ( var runtime in SupportedRuntimes ) { - var publishDir = Paths.PublishDirectoryForRuntime( runtime ); - var artifactFile = Paths.ArtifactsDirectory / $"drift_{version.WithoutMetadata()}_{runtime}.tar.gz"; + var isWindows = Platform == DotNetRuntimeIdentifier.win_x64; + var extension = isWindows ? "zip" : "tar.gz"; + var filesToDistribute = isWindows ? FilesToDistributeWindows : FilesToDistributeLinux; + var artifactFile = Paths.ArtifactsDirectory / $"drift_{version.WithoutMetadata()}_{Platform}.{extension}"; - Log.Information( "Creating {ArtifactFile}", artifactFile ); + Log.Information( "Creating {ArtifactFile}", artifactFile ); + + if ( isWindows ) { + Log.Debug( "Including files matching: {Files}", string.Join( ", ", filesToDistribute ) ); + publishDir.ZipTo( artifactFile, f => filesToDistribute.Contains( f.Name ), fileMode: FileMode.CreateNew ); + } + else { var files = publishDir .GetFiles() - .Where( file => FilesToDistribute.Contains( file.Name ) ) + .Where( file => filesToDistribute.Contains( file.Name ) ) .ToList(); Log.Debug( "Including files: {Files}", string.Join( ", ", files.Select( f => f.Name ) ) ); publishDir.TarGZipTo( artifactFile, files, fileMode: FileMode.CreateNew ); diff --git a/build/NukeBuild.Container.cs b/build/NukeBuild.Container.cs index 75c155b6..dca6872c 100644 --- a/build/NukeBuild.Container.cs +++ b/build/NukeBuild.Container.cs @@ -6,6 +6,7 @@ using JetBrains.Annotations; using Nuke.Common; using Nuke.Common.Tools.Docker; +using Nuke.Common.Tools.DotNet; using Serilog; using Versioning; @@ -33,6 +34,7 @@ partial class NukeBuild { Target PublishContainer => _ => _ .DependsOn( PublishBinaries, CleanArtifacts ) + .OnlyWhenDynamic( () => Platform != DotNetRuntimeIdentifier.win_x64 ) .Requires( () => Commit ) .Executes( async () => { using var _ = new OperationTimer( nameof(PublishContainer) ); diff --git a/build/NukeBuild.Test.cs b/build/NukeBuild.Test.cs index dfdbc08c..f8ae8cb7 100644 --- a/build/NukeBuild.Test.cs +++ b/build/NukeBuild.Test.cs @@ -16,6 +16,11 @@ // ReSharper disable UnusedMember.Local sealed partial class NukeBuild { + private string DriftBinaryName => + Platform == DotNetRuntimeIdentifier.linux_x64 ? "drift" : + Platform == DotNetRuntimeIdentifier.win_x64 ? "drift.exe" : + throw new PlatformNotSupportedException(); + Target Test => _ => _ .DependsOn( TestSelf, TestUnit, TestE2E ); @@ -65,44 +70,89 @@ sealed partial class NukeBuild { ); Target TestE2E => _ => _ + .DependsOn( TestE2E_General, TestE2E_Binary, TestE2E_Container ); + + Target TestE2E_General => _ => _ + .After( TestUnit ) + .Executes( () => { + using var _ = new OperationTimer( nameof(TestE2E_General) ); + + Log.Information( "Running general E2E tests" ); + + DotNetTest( settings => settings + .SetProjectFile( Solution.Cli_E2ETests_General ) + .SetConfiguration( Configuration ) + .ConfigureLoggers( MsBuildVerbosityParsed ) + .SetBlameHangTimeout( "60s" ) + .EnableNoLogo() + .EnableNoRestore() + .EnableNoBuild() + ); + } + ); + + Target TestE2E_Binary => _ => _ + .DependsOn( PublishBinaries ) + .After( TestUnit ) + .Executes( () => { + using var _ = new OperationTimer( nameof(TestE2E_Binary) ); + + var driftBinary = Paths.PublishDirectoryForRuntime( Platform ) / DriftBinaryName; + + Log.Information( "Running binary E2E tests on {Runtime} using binary {Binary}", Platform, driftBinary ); + + var envVars = new Dictionary { { "DRIFT_BINARY_PATH", driftBinary }, }; + + DotNetTest( settings => settings + .SetProjectFile( Solution.Cli_E2ETests_Binary ) + .SetConfiguration( Configuration ) + .ConfigureLoggers( MsBuildVerbosityParsed ) + .SetBlameHangTimeout( "60s" ) + .EnableNoLogo() + .EnableNoRestore() + .EnableNoBuild() + .AddProcessEnvironmentVariables( envVars ) + ); + } + ); + + Target TestE2E_Container => _ => _ .DependsOn( PublishBinaries, PublishContainer ) .After( TestUnit ) + .OnlyWhenDynamic( () => Platform != DotNetRuntimeIdentifier.win_x64 ) .Executes( async () => { - using var _ = new OperationTimer( nameof(TestE2E) ); + using var _ = new OperationTimer( nameof(TestE2E_Container) ); var imageRef = _driftImageRef ?? throw new ArgumentNullException( nameof(_driftImageRef) ); Log.Information( "Using image {ImageRef}", imageRef ); - foreach ( var runtime in SupportedRuntimes ) { - var driftBinary = Paths.PublishDirectoryForRuntime( runtime ) / "drift"; - - var envVars = new Dictionary { - // { nameof(EnvVar.DRIFT_BINARY_PATH), driftBinary }, - { "DRIFT_BINARY_PATH", driftBinary }, // - { "DRIFT_CONTAINER_IMAGE_REF", imageRef.ToString() } - }; - - var alternateDockerHost = await FindAlternateDockerHostAsync(); - - DotNetTest( settings => { - if ( alternateDockerHost != null ) { - Log.Information( "Using alternate Docker host: {Host}", alternateDockerHost ); - settings.SetProcessEnvironmentVariable( "DOCKER_HOST", alternateDockerHost ); - } - - return settings - .SetProjectFile( Solution.Cli_E2ETests ) - .SetConfiguration( Configuration ) - .ConfigureLoggers( MsBuildVerbosityParsed ) - .SetBlameHangTimeout( "60s" ) - .EnableNoLogo() - .EnableNoRestore() - .EnableNoBuild() - .AddProcessEnvironmentVariables( envVars ); - } ); - - Log.Information( "Running E2E test on {Runtime} using binary {Binary}", runtime, driftBinary ); - } + var driftBinary = Paths.PublishDirectoryForRuntime( Platform ) / DriftBinaryName; + + Log.Information( "Running container E2E tests on {Runtime} using binary {Binary}", Platform, driftBinary ); + Log.Debug( "Supported runtimes are {SupportedRuntimes}", string.Join( ", ", SupportedRuntimes ) ); + + var envVars = new Dictionary { + { "DRIFT_BINARY_PATH", driftBinary }, { "DRIFT_CONTAINER_IMAGE_REF", imageRef.ToString() } + }; + + var alternateDockerHost = await FindAlternateDockerHostAsync(); + + DotNetTest( settings => { + if ( alternateDockerHost != null ) { + Log.Information( "Using alternate Docker host: {Host}", alternateDockerHost ); + settings.SetProcessEnvironmentVariable( "DOCKER_HOST", alternateDockerHost ); + } + + return settings + .SetProjectFile( Solution.Cli_E2ETests_Container ) + .SetConfiguration( Configuration ) + .ConfigureLoggers( MsBuildVerbosityParsed ) + .SetBlameHangTimeout( "60s" ) + .EnableNoLogo() + .EnableNoRestore() + .EnableNoBuild() + .AddProcessEnvironmentVariables( envVars ); + } ); } ); diff --git a/build/NukeBuild.cs b/build/NukeBuild.cs index 9b2ea201..42876c5d 100644 --- a/build/NukeBuild.cs +++ b/build/NukeBuild.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Drift.Build.Utilities; @@ -64,8 +65,18 @@ public NukeBuild() { [Secret, Parameter( $"{nameof(GitHubToken)} - GitHub token used to create releases" )] public string GitHubToken; + [Parameter( $"{nameof(Platform)} - A .NET RID but with underscores instead of dashes e.g. linux_x64 or win_x64" )] + public DotNetRuntimeIdentifier Platform = IsLocalBuild + ? RuntimeInformation.IsOSPlatform( OSPlatform.Linux ) + ? DotNetRuntimeIdentifier.linux_x64 + : RuntimeInformation.IsOSPlatform( OSPlatform.Windows ) + ? DotNetRuntimeIdentifier.win_x64 + : throw new PlatformNotSupportedException() + : null; + private static readonly DotNetRuntimeIdentifier[] SupportedRuntimes = [ DotNetRuntimeIdentifier.linux_x64, + DotNetRuntimeIdentifier.win_x64 // TODO support more architectures /* , DotNetRuntimeIdentifier.linux_musl_x64 diff --git a/src/ArchTests/SanityTests.cs b/src/ArchTests/SanityTests.cs index 3bac161e..8639eace 100644 --- a/src/ArchTests/SanityTests.cs +++ b/src/ArchTests/SanityTests.cs @@ -3,8 +3,8 @@ namespace Drift.ArchTests; internal sealed class SanityTests : DriftArchitectureFixture { - private const uint ExpectedAssemblyCount = 20; - private const uint ExpectedAssemblyCountTolerance = 3; + private const uint ExpectedAssemblyCount = 25; + private const uint ExpectedAssemblyCountTolerance = 5; [Test] public void FindManyAssemblies() { diff --git a/src/Cli.E2ETests/AssemblyInfo.cs b/src/Cli.E2ETests.Binary/AssemblyInfo.cs similarity index 100% rename from src/Cli.E2ETests/AssemblyInfo.cs rename to src/Cli.E2ETests.Binary/AssemblyInfo.cs diff --git a/src/Cli.E2ETests.Binary/Cli.E2ETests.Binary.csproj b/src/Cli.E2ETests.Binary/Cli.E2ETests.Binary.csproj new file mode 100644 index 00000000..a2fb527d --- /dev/null +++ b/src/Cli.E2ETests.Binary/Cli.E2ETests.Binary.csproj @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Cli.E2ETests/Commands/GlobalOptionsTests.cs b/src/Cli.E2ETests.Binary/Commands/GlobalOptionsTests.cs similarity index 96% rename from src/Cli.E2ETests/Commands/GlobalOptionsTests.cs rename to src/Cli.E2ETests.Binary/Commands/GlobalOptionsTests.cs index 6e40ca78..0896fe7a 100644 --- a/src/Cli.E2ETests/Commands/GlobalOptionsTests.cs +++ b/src/Cli.E2ETests.Binary/Commands/GlobalOptionsTests.cs @@ -1,6 +1,6 @@ using Drift.Cli.Abstractions; -namespace Drift.Cli.E2ETests.Commands; +namespace Drift.Cli.E2ETests.Binary.Commands; internal sealed class GlobalOptionsTests : DriftBinaryFixture { [Test] diff --git a/src/Cli.E2ETests/Commands/LintTests.InitThenLintTest.verified.txt b/src/Cli.E2ETests.Binary/Commands/LintTests.InitThenLintTest.verified.txt similarity index 84% rename from src/Cli.E2ETests/Commands/LintTests.InitThenLintTest.verified.txt rename to src/Cli.E2ETests.Binary/Commands/LintTests.InitThenLintTest.verified.txt index e3668b27..01fd0170 100644 --- a/src/Cli.E2ETests/Commands/LintTests.InitThenLintTest.verified.txt +++ b/src/Cli.E2ETests.Binary/Commands/LintTests.InitThenLintTest.verified.txt @@ -1,2 +1,2 @@ Validating {CurrentDirectory}unittest.spec.yaml -✔ Valid +✓ Valid diff --git a/src/Cli.E2ETests/Commands/LintTests.cs b/src/Cli.E2ETests.Binary/Commands/LintTests.cs similarity index 60% rename from src/Cli.E2ETests/Commands/LintTests.cs rename to src/Cli.E2ETests.Binary/Commands/LintTests.cs index 071a440b..b17b14c6 100644 --- a/src/Cli.E2ETests/Commands/LintTests.cs +++ b/src/Cli.E2ETests.Binary/Commands/LintTests.cs @@ -1,25 +1,31 @@ -using Drift.Cli.Abstractions; +using Drift.Cli.Abstractions; -namespace Drift.Cli.E2ETests.Commands; +namespace Drift.Cli.E2ETests.Binary.Commands; internal sealed class LintTests : DriftBinaryFixture { + private const string SpecName = "unittest"; + private const string SpecFileName = $"{SpecName}.spec.yaml"; + [Test] public async Task InitThenLintTest() { try { + // Clean up any leftover spec file from a previous run + File.Delete( SpecFileName ); + // Arrange - var initResult = await DriftBinary.ExecuteAsync( "init unittest" ); + var initResult = await DriftBinary.ExecuteAsync( $"init {SpecName}" ); TestContext.Out.WriteLine( "STD OUT:\n" + initResult.StdOut ); TestContext.Out.WriteLine( "ERR OUT:\n" + initResult.ErrOut ); using ( Assert.EnterMultipleScope() ) { Assert.That( initResult.ExitCode, Is.EqualTo( ExitCodes.Success ) ); - Assert.That( initResult.StdOut, Contains.Substring( "✔ Spec created" ) ); + Assert.That( initResult.StdOut, Contains.Substring( " Spec created" ) ); Assert.That( initResult.ErrOut, Is.Empty ); } // Act - var lintResult = await DriftBinary.ExecuteAsync( "lint unittest" ); + var lintResult = await DriftBinary.ExecuteAsync( $"lint {SpecName}" ); TestContext.Out.WriteLine( "STD OUT:\n" + initResult.StdOut ); TestContext.Out.WriteLine( "ERR OUT:\n" + initResult.ErrOut ); @@ -31,8 +37,8 @@ public async Task InitThenLintTest() { Assert.That( lintResult.ErrOut, Is.Empty ); } } - catch ( Exception ex ) { - Assert.Fail( ex.Message ); + finally { + File.Delete( SpecFileName ); } } } \ No newline at end of file diff --git a/src/Cli.E2ETests/Commands/ReadmeWorkflowTests.cs b/src/Cli.E2ETests.Binary/Commands/ReadmeWorkflowTests.cs similarity index 91% rename from src/Cli.E2ETests/Commands/ReadmeWorkflowTests.cs rename to src/Cli.E2ETests.Binary/Commands/ReadmeWorkflowTests.cs index d3d5fb26..2198615a 100644 --- a/src/Cli.E2ETests/Commands/ReadmeWorkflowTests.cs +++ b/src/Cli.E2ETests.Binary/Commands/ReadmeWorkflowTests.cs @@ -1,7 +1,7 @@ -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using Drift.Cli.Abstractions; -namespace Drift.Cli.E2ETests.Commands; +namespace Drift.Cli.E2ETests.Binary.Commands; internal sealed class ReadmeWorkflowTests : DriftBinaryFixture { // TODO implement @@ -18,7 +18,7 @@ public async Task InitThenScanTest() { using ( Assert.EnterMultipleScope() ) { Assert.That( initResult.ExitCode, Is.EqualTo( ExitCodes.Success ) ); - Assert.That( initResult.StdOut, Contains.Substring( "✔ Spec created /" ) ); + Assert.That( initResult.StdOut, Contains.Substring( "✓ Spec created /" ) ); } await Verify( initResult.StdOut ) diff --git a/src/Cli.E2ETests/DriftBinaryFixture.cs b/src/Cli.E2ETests.Binary/DriftBinaryFixture.cs similarity index 94% rename from src/Cli.E2ETests/DriftBinaryFixture.cs rename to src/Cli.E2ETests.Binary/DriftBinaryFixture.cs index 6698b2bc..594190b2 100644 --- a/src/Cli.E2ETests/DriftBinaryFixture.cs +++ b/src/Cli.E2ETests.Binary/DriftBinaryFixture.cs @@ -1,7 +1,7 @@ using Drift.Cli.E2ETests.Abstractions; using Drift.Common; -namespace Drift.Cli.E2ETests; +namespace Drift.Cli.E2ETests.Binary; internal abstract class DriftBinaryFixture { protected static ToolWrapper DriftBinary { diff --git a/src/Cli.E2ETests.Container/AssemblyInfo.cs b/src/Cli.E2ETests.Container/AssemblyInfo.cs new file mode 100644 index 00000000..a35c07e1 --- /dev/null +++ b/src/Cli.E2ETests.Container/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly: Category( "E2E" )] \ No newline at end of file diff --git a/src/Cli.E2ETests/Cli.E2ETests.csproj b/src/Cli.E2ETests.Container/Cli.E2ETests.Container.csproj similarity index 77% rename from src/Cli.E2ETests/Cli.E2ETests.csproj rename to src/Cli.E2ETests.Container/Cli.E2ETests.Container.csproj index edd8554e..7eaec3e1 100644 --- a/src/Cli.E2ETests/Cli.E2ETests.csproj +++ b/src/Cli.E2ETests.Container/Cli.E2ETests.Container.csproj @@ -1,4 +1,4 @@ - + @@ -7,13 +7,12 @@ - - + @@ -22,7 +21,6 @@ - diff --git a/src/Cli.E2ETests/Container/CommandTests.ValidCommand_ReturnsSuccessExitCode.verified.txt b/src/Cli.E2ETests.Container/CommandTests.ValidCommand_ReturnsSuccessExitCode.verified.txt similarity index 100% rename from src/Cli.E2ETests/Container/CommandTests.ValidCommand_ReturnsSuccessExitCode.verified.txt rename to src/Cli.E2ETests.Container/CommandTests.ValidCommand_ReturnsSuccessExitCode.verified.txt diff --git a/src/Cli.E2ETests/Container/CommandTests.cs b/src/Cli.E2ETests.Container/CommandTests.cs similarity index 96% rename from src/Cli.E2ETests/Container/CommandTests.cs rename to src/Cli.E2ETests.Container/CommandTests.cs index b2256dc3..aca4c932 100644 --- a/src/Cli.E2ETests/Container/CommandTests.cs +++ b/src/Cli.E2ETests.Container/CommandTests.cs @@ -1,10 +1,11 @@ -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; using DotNet.Testcontainers.Builders; using Drift.Cli.Abstractions; using Microsoft.Extensions.Logging.Abstractions; namespace Drift.Cli.E2ETests.Container; +[Platform( "Linux" )] internal sealed class CommandTests : DriftImageFixture { [Test] public async Task ValidCommand_ReturnsSuccessExitCode() { diff --git a/src/Cli.E2ETests/DriftImageFixture.cs b/src/Cli.E2ETests.Container/DriftImageFixture.cs similarity index 96% rename from src/Cli.E2ETests/DriftImageFixture.cs rename to src/Cli.E2ETests.Container/DriftImageFixture.cs index 1821460f..7c5b35bc 100644 --- a/src/Cli.E2ETests/DriftImageFixture.cs +++ b/src/Cli.E2ETests.Container/DriftImageFixture.cs @@ -3,7 +3,7 @@ using HLabs.ImageReferences; using Nuke.Common.Tools.Docker; -namespace Drift.Cli.E2ETests; +namespace Drift.Cli.E2ETests.Container; internal abstract class DriftImageFixture { protected static QualifiedImageRef DriftImage { diff --git a/src/Cli.E2ETests/Container/LabelsTest.cs b/src/Cli.E2ETests.Container/LabelsTest.cs similarity index 99% rename from src/Cli.E2ETests/Container/LabelsTest.cs rename to src/Cli.E2ETests.Container/LabelsTest.cs index 24ad8e7b..37de4821 100644 --- a/src/Cli.E2ETests/Container/LabelsTest.cs +++ b/src/Cli.E2ETests.Container/LabelsTest.cs @@ -3,6 +3,7 @@ namespace Drift.Cli.E2ETests.Container; +[Platform( "Linux" )] internal sealed class LabelsTest : DriftImageFixture { private readonly List _ociAnnotationsV1_1_1 = [ "org.opencontainers.image.created", diff --git a/src/Cli.E2ETests/Container/PortTest.cs b/src/Cli.E2ETests.Container/PortTest.cs similarity index 95% rename from src/Cli.E2ETests/Container/PortTest.cs rename to src/Cli.E2ETests.Container/PortTest.cs index 4472c4c8..669b1e54 100644 --- a/src/Cli.E2ETests/Container/PortTest.cs +++ b/src/Cli.E2ETests.Container/PortTest.cs @@ -1,5 +1,6 @@ namespace Drift.Cli.E2ETests.Container; +[Platform( "Linux" )] internal sealed class PortTest : DriftImageFixture { [Explicit( "Not implemented yet" )] [Test] diff --git a/src/Cli.E2ETests/Container/oci-annotations.LabelsUseOciAnnotationsTest.verified.txt b/src/Cli.E2ETests.Container/oci-annotations.LabelsUseOciAnnotationsTest.verified.txt similarity index 100% rename from src/Cli.E2ETests/Container/oci-annotations.LabelsUseOciAnnotationsTest.verified.txt rename to src/Cli.E2ETests.Container/oci-annotations.LabelsUseOciAnnotationsTest.verified.txt diff --git a/src/Cli.E2ETests/Container/remaining.LabelsUseOciAnnotationsTest.verified.txt b/src/Cli.E2ETests.Container/remaining.LabelsUseOciAnnotationsTest.verified.txt similarity index 100% rename from src/Cli.E2ETests/Container/remaining.LabelsUseOciAnnotationsTest.verified.txt rename to src/Cli.E2ETests.Container/remaining.LabelsUseOciAnnotationsTest.verified.txt diff --git a/src/Cli.E2ETests.General/AssemblyInfo.cs b/src/Cli.E2ETests.General/AssemblyInfo.cs new file mode 100644 index 00000000..a35c07e1 --- /dev/null +++ b/src/Cli.E2ETests.General/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly: Category( "E2E" )] \ No newline at end of file diff --git a/src/Cli.E2ETests.General/Cli.E2ETests.General.csproj b/src/Cli.E2ETests.General/Cli.E2ETests.General.csproj new file mode 100644 index 00000000..0cc19a30 --- /dev/null +++ b/src/Cli.E2ETests.General/Cli.E2ETests.General.csproj @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Cli.E2ETests/Installation/InstallTests.InstallLatestVersion_INSTALL_OUTPUT.verified.txt b/src/Cli.E2ETests.General/Installation/InstallTests.InstallLatestVersion_INSTALL_OUTPUT.verified.txt similarity index 100% rename from src/Cli.E2ETests/Installation/InstallTests.InstallLatestVersion_INSTALL_OUTPUT.verified.txt rename to src/Cli.E2ETests.General/Installation/InstallTests.InstallLatestVersion_INSTALL_OUTPUT.verified.txt diff --git a/src/Cli.E2ETests/Installation/InstallTests.cs b/src/Cli.E2ETests.General/Installation/InstallTests.cs similarity index 96% rename from src/Cli.E2ETests/Installation/InstallTests.cs rename to src/Cli.E2ETests.General/Installation/InstallTests.cs index eec1bd9d..e21b859a 100644 --- a/src/Cli.E2ETests/Installation/InstallTests.cs +++ b/src/Cli.E2ETests.General/Installation/InstallTests.cs @@ -3,13 +3,14 @@ using Drift.Cli.Abstractions; using Drift.Common; -namespace Drift.Cli.E2ETests.Installation; +namespace Drift.Cli.E2ETests.General.Installation; [SuppressMessage( "Minor Code Smell", - "S2325:Methods and properties that don\'t access instance data should be static", + "S2325:Methods and properties that don't access instance data should be static", Justification = "Unimplemented test methods should not be static" )] +[Platform( "Linux" )] internal sealed class InstallTests { // TODO split test into at least two parts [Test] diff --git a/src/Cli.E2ETests/Schemas/SchemasAvailabilityTests.cs b/src/Cli.E2ETests.General/Schemas/SchemasAvailabilityTests.cs similarity index 83% rename from src/Cli.E2ETests/Schemas/SchemasAvailabilityTests.cs rename to src/Cli.E2ETests.General/Schemas/SchemasAvailabilityTests.cs index 74427949..ed208e86 100644 --- a/src/Cli.E2ETests/Schemas/SchemasAvailabilityTests.cs +++ b/src/Cli.E2ETests.General/Schemas/SchemasAvailabilityTests.cs @@ -1,4 +1,6 @@ -namespace Drift.Cli.E2ETests.Schemas; +using System.Text.RegularExpressions; + +namespace Drift.Cli.E2ETests.General.Schemas; internal sealed class SchemasAvailabilityTests { [Explicit( "For now, use schema directly from GitHub repo" )] @@ -44,6 +46,10 @@ public async Task SchemaIsAvailableAtDocumentedUrl( string documentedUrl, string // Assert Assert.DoesNotThrow( () => response.EnsureSuccessStatusCode() ); var content = await response.Content.ReadAsStringAsync(); - Assert.That( content, Contains.Substring( expectedPartialContent ) ); + + var normalizedContent = Regex.Replace( content, @"\s", string.Empty ); + var normalizedExpected = Regex.Replace( expectedPartialContent, @"\s", string.Empty ); + + Assert.That( normalizedContent, Contains.Substring( normalizedExpected ) ); } } \ No newline at end of file diff --git a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=-v.verified.txt b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=-v.verified.txt index 8fc6f176..48b741f2 100644 --- a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=-v.verified.txt +++ b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=-v.verified.txt @@ -2,4 +2,4 @@ Found interfaces: [lo, up, 127.0.0.0/8], [enp0xxxxx, down, -], [enp8xxxxx, up, 192.168.0.0/24], [wlp, up, 192.168.0.0/24], [tun0, up, 100.100.1.9/32] Discovered subnet(s): 192.168.0.0/24 (RFC1918 addresses only) Found subnets: 192.168.0.0/24 (254 addresses, 00:00:05.0800000 estimated scan time) -✔ Spec created {CurrentDirectory}myNetworkWithDiscovery.spec.yaml +✓ Spec created {CurrentDirectory}myNetworkWithDiscovery.spec.yaml diff --git a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=.verified.txt b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=.verified.txt index 2b5daee4..cb225e0c 100644 --- a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=.verified.txt +++ b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithDiscoverySuccess_outputFormat=_verbose=.verified.txt @@ -1 +1 @@ -✔ Spec created {CurrentDirectory}myNetworkWithDiscovery.spec.yaml +✓ Spec created {CurrentDirectory}myNetworkWithDiscovery.spec.yaml diff --git a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithoutDiscoverySuccess.verified.txt b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithoutDiscoverySuccess.verified.txt index 4f144e23..11301189 100644 --- a/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithoutDiscoverySuccess.verified.txt +++ b/src/Cli.Tests/Commands/InitCommandTests.GenerateSpecWithoutDiscoverySuccess.verified.txt @@ -1 +1 @@ -✔ Spec created {CurrentDirectory}myNetworkWithoutDiscovery.spec.yaml +✓ Spec created {CurrentDirectory}myNetworkWithoutDiscovery.spec.yaml diff --git a/src/Cli.Tests/Commands/InitCommandTests.MissingNameOption.verified.txt b/src/Cli.Tests/Commands/InitCommandTests.MissingNameOption.verified.txt index 70e0e2ef..109a2439 100644 --- a/src/Cli.Tests/Commands/InitCommandTests.MissingNameOption.verified.txt +++ b/src/Cli.Tests/Commands/InitCommandTests.MissingNameOption.verified.txt @@ -1 +1 @@ -✗ Name is required \ No newline at end of file +✕ Name is required \ No newline at end of file diff --git a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=.verified.txt b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=.verified.txt similarity index 90% rename from src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=.verified.txt rename to src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=.verified.txt index 8c5733ee..810c1d7e 100644 --- a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=.verified.txt +++ b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=.verified.txt @@ -1,4 +1,4 @@ Validating {SolutionDirectory}src/Spec.Tests/resources/network_single_device_host.yaml -✗ Validation failed +✕ Validation failed • /: Required properties ["version"] are not present • /network/subnets/0: Required properties ["address"] are not present diff --git a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=log.verified.txt b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=log.verified.txt similarity index 100% rename from src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=log.verified.txt rename to src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=log.verified.txt diff --git a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=normal.verified.txt b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=normal.verified.txt similarity index 90% rename from src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=normal.verified.txt rename to src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=normal.verified.txt index 8c5733ee..810c1d7e 100644 --- a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_specName=network_single_device_host_outputFormat=normal.verified.txt +++ b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Linux_specName=network_single_device_host_outputFormat=normal.verified.txt @@ -1,4 +1,4 @@ Validating {SolutionDirectory}src/Spec.Tests/resources/network_single_device_host.yaml -✗ Validation failed +✕ Validation failed • /: Required properties ["version"] are not present • /network/subnets/0: Required properties ["address"] are not present diff --git a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=.verified.txt b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=.verified.txt new file mode 100644 index 00000000..a03c53de --- /dev/null +++ b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=.verified.txt @@ -0,0 +1,4 @@ +Validating {SolutionDirectory}src\Spec.Tests\resources\network_single_device_host.yaml +✕ Validation failed +• /: Required properties ["version"] are not present +• /network/subnets/0: Required properties ["address"] are not present diff --git a/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=log.verified.txt b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=log.verified.txt new file mode 100644 index 00000000..b7807cca --- /dev/null +++ b/src/Cli.Tests/Commands/LintCommandTests.LintInvalidSpec_platform=Windows_specName=network_single_device_host_outputFormat=log.verified.txt @@ -0,0 +1,4 @@ +[