diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 0763ef1c5b..24ea9f438e 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,6 +15,13 @@ "regitlint" ], "rollForward": false + }, + "dotnet-reportgenerator-globaltool": { + "version": "5.5.0", + "commands": [ + "reportgenerator" + ], + "rollForward": false } } } \ No newline at end of file diff --git a/.github/workflows/Steeltoe.All.yml b/.github/workflows/Steeltoe.All.yml index d4b5897ca1..a5b65e8c0c 100644 --- a/.github/workflows/Steeltoe.All.yml +++ b/.github/workflows/Steeltoe.All.yml @@ -17,12 +17,14 @@ permissions: pull-requests: write env: + STEELTOE_MACOS_DIAGNOSE_HOSTNAME_LOOKUP: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_NOLOGO: true SOLUTION_FILE: 'src/Steeltoe.All.sln' + TEST_OUTPUT_DIRECTORY: '${{ github.workspace }}/TestOutput' COMMON_TEST_ARGS: >- - --no-build --configuration Release --collect "XPlat Code Coverage" --logger trx --results-directory ${{ github.workspace }}/dumps - --settings coverlet.runsettings --blame-crash --blame-hang-timeout 3m + --no-build --no-progress --configuration Release --results-directory '${{ github.workspace }}/TestOutput' + --report-trx --coverage --coverage-settings coverage.config --crashdump --hangdump --hangdump-timeout 1m jobs: analyze: @@ -36,9 +38,9 @@ jobs: - os: ubuntu-latest runDockerContainers: true - os: windows-latest - skipFilter: Category!=Integration + skipIntegrationTests: true - os: macos-latest - skipFilter: Category!=Integration + skipIntegrationTests: true runs-on: ${{ matrix.os }} continue-on-error: true @@ -89,29 +91,11 @@ jobs: - name: Build solution run: dotnet build ${{ env.SOLUTION_FILE }} --no-restore --configuration Release --verbosity minimal - - name: Set skip filters for tests - shell: bash - run: | - echo SKIP_FILTER_NO_MEMORY_DUMPS="${{ matrix.skipFilter && format('{0}&Category!=MemoryDumps', matrix.skipFilter) || 'Category!=MemoryDumps' }}" >> $GITHUB_ENV - echo SKIP_FILTER_WITH_MEMORY_DUMPS="${{ matrix.skipFilter && format('{0}&Category=MemoryDumps', matrix.skipFilter) || 'Category=MemoryDumps' }}" >> $GITHUB_ENV - - - name: Test (net10.0) - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net10.0 --filter "${{ env.SKIP_FILTER_NO_MEMORY_DUMPS }}" ${{ env.COMMON_TEST_ARGS }} - - - name: Test (net10.0) (memory dumps) - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net10.0 --filter "${{ env.SKIP_FILTER_WITH_MEMORY_DUMPS }}" ${{ env.COMMON_TEST_ARGS }} - - - name: Test (net9.0) - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net9.0 --filter "${{ env.SKIP_FILTER_NO_MEMORY_DUMPS }}" ${{ env.COMMON_TEST_ARGS }} - - - name: Test (net9.0) (memory dumps) - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net9.0 --filter "${{ env.SKIP_FILTER_WITH_MEMORY_DUMPS }}" ${{ env.COMMON_TEST_ARGS }} - - - name: Test (net8.0) - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net8.0 --filter "${{ env.SKIP_FILTER_NO_MEMORY_DUMPS }}" ${{ env.COMMON_TEST_ARGS }} + - name: Test + run: dotnet test --solution ${{ env.SOLUTION_FILE }} --filter-query "${{ matrix.skipIntegrationTests == true && '/[(Category!=MemoryDumps)&(Category!=Integration)]' || '/[Category!=MemoryDumps]' }}" ${{ env.COMMON_TEST_ARGS }} - - name: Test (net8.0) (memory dumps) - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net8.0 --filter "${{ env.SKIP_FILTER_WITH_MEMORY_DUMPS }}" ${{ env.COMMON_TEST_ARGS }} + - name: Test (memory dumps) + run: dotnet test --project src/Management/test/Endpoint.Test/Steeltoe.Management.Endpoint.Test.csproj --filter-trait "Category=MemoryDumps" ${{ env.COMMON_TEST_ARGS }} - name: Upload crash/hang dumps (on failure) if: ${{ failure() }} @@ -119,8 +103,8 @@ jobs: with: name: FailedTestOutput-${{ matrix.os }} path: | - ${{ github.workspace }}/dumps/**/*.dmp - ${{ github.workspace }}/dumps/**/Sequence_*.xml + ${{ env.TEST_OUTPUT_DIRECTORY }}/*.dmp + ${{ env.TEST_OUTPUT_DIRECTORY }}/Sequence_*.xml if-no-files-found: ignore - name: Report test results @@ -129,14 +113,15 @@ jobs: with: name: ${{ matrix.os }} test results reporter: dotnet-trx - path: '**/*.trx' + path: '${{ env.TEST_OUTPUT_DIRECTORY }}/*.trx' + path-replace-backslashes: true fail-on-empty: 'true' fail-on-error: 'false' - name: Generate code coverage report uses: danielpalme/ReportGenerator-GitHub-Action@v5 with: - reports: '**/coverage.opencover.xml' + reports: '${{ env.TEST_OUTPUT_DIRECTORY }}/*cobertura.xml' targetdir: 'coveragereport' reporttypes: 'MarkdownAssembliesSummary;MarkdownSummaryGithub' filefilters: '-*.g.cs' diff --git a/.github/workflows/component-shared-workflow.yml b/.github/workflows/component-shared-workflow.yml index 229e2f5801..1df0267540 100644 --- a/.github/workflows/component-shared-workflow.yml +++ b/.github/workflows/component-shared-workflow.yml @@ -19,12 +19,14 @@ permissions: pull-requests: write env: + STEELTOE_MACOS_DIAGNOSE_HOSTNAME_LOOKUP: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_NOLOGO: true SOLUTION_FILE: 'src/Steeltoe.${{ inputs.component }}.slnf' + TEST_OUTPUT_DIRECTORY: '${{ github.workspace }}/TestOutput' COMMON_TEST_ARGS: >- - --no-build --configuration Release --collect "XPlat Code Coverage" --logger trx --results-directory ${{ github.workspace }}/dumps - --settings coverlet.runsettings --blame-crash --blame-hang-timeout 3m + --no-build --no-progress --configuration Release --results-directory '${{ github.workspace }}/TestOutput' + --report-trx --coverage --coverage-settings coverage.config --crashdump --hangdump --hangdump-timeout 1m jobs: build: @@ -79,26 +81,12 @@ jobs: - name: Build solution run: dotnet build ${{ env.SOLUTION_FILE }} --no-restore --configuration Release --verbosity minimal - - name: Test (net10.0) - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net10.0 --filter "Category!=MemoryDumps" ${{ env.COMMON_TEST_ARGS }} + - name: Test + run: dotnet test --solution ${{ env.SOLUTION_FILE }} --filter-not-trait "Category=MemoryDumps" ${{ env.COMMON_TEST_ARGS }} - - name: Test (net10.0) (memory dumps) + - name: Test (memory dumps) if: ${{ inputs.component == 'Management' }} - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net10.0 --filter "Category=MemoryDumps" ${{ env.COMMON_TEST_ARGS }} - - - name: Test (net9.0) - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net9.0 --filter "Category!=MemoryDumps" ${{ env.COMMON_TEST_ARGS }} - - - name: Test (net9.0) (memory dumps) - if: ${{ inputs.component == 'Management' }} - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net9.0 --filter "Category=MemoryDumps" ${{ env.COMMON_TEST_ARGS }} - - - name: Test (net8.0) - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net8.0 --filter "Category!=MemoryDumps" ${{ env.COMMON_TEST_ARGS }} - - - name: Test (net8.0) (memory dumps) - if: ${{ inputs.component == 'Management' }} - run: dotnet test ${{ env.SOLUTION_FILE }} --framework net8.0 --filter "Category=MemoryDumps" ${{ env.COMMON_TEST_ARGS }} + run: dotnet test --project src/Management/test/Endpoint.Test/Steeltoe.Management.Endpoint.Test.csproj --filter-trait "Category=MemoryDumps" ${{ env.COMMON_TEST_ARGS }} - name: Upload crash/hang dumps (on failure) if: ${{ failure() }} @@ -106,8 +94,8 @@ jobs: with: name: FailedTestOutput-${{ inputs.OS }}-latest path: | - ${{ github.workspace }}/dumps/**/*.dmp - ${{ github.workspace }}/dumps/**/Sequence_*.xml + ${{ env.TEST_OUTPUT_DIRECTORY }}/*.dmp + ${{ env.TEST_OUTPUT_DIRECTORY }}/Sequence_*.xml if-no-files-found: ignore - name: Report test results @@ -116,6 +104,7 @@ jobs: with: name: ${{ inputs.OS }}-latest test results reporter: dotnet-trx - path: '**/*.trx' + path: '${{ env.TEST_OUTPUT_DIRECTORY }}/*.trx' + path-replace-backslashes: true fail-on-empty: 'true' fail-on-error: 'false' diff --git a/.github/workflows/sonarcube.yml b/.github/workflows/sonarcube.yml index 2fcebd9f8a..bac19c61a1 100644 --- a/.github/workflows/sonarcube.yml +++ b/.github/workflows/sonarcube.yml @@ -18,12 +18,14 @@ permissions: pull-requests: write env: + STEELTOE_MACOS_DIAGNOSE_HOSTNAME_LOOKUP: true DOTNET_CLI_TELEMETRY_OPTOUT: 1 DOTNET_NOLOGO: true SOLUTION_FILE: 'src/Steeltoe.All.sln' + TEST_OUTPUT_DIRECTORY: '${{ github.workspace }}/TestOutput' SONAR_TEST_ARGS: >- - --no-build --configuration Release --collect "XPlat Code Coverage" --logger trx --results-directory ${{ github.workspace }} - --settings coverlet.runsettings -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.UseSourceLink=false + --no-build --no-progress --configuration Release --results-directory '${{ github.workspace }}/TestOutput' + --report-trx --coverage --coverage-settings coverage.config jobs: analyze: @@ -73,29 +75,33 @@ jobs: env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: >- + # TODO: Revert to OpenCover, see https://github.com/microsoft/testfx/issues/7104 + # /d:sonar.cs.opencover.reportsPaths=**/coverage.opencover.xml dotnet sonarscanner begin /k:"SteeltoeOSS_steeltoe" /o:"steeltoeoss" /d:sonar.token="${{ secrets.SONAR_TOKEN }}" - /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths=**/coverage.opencover.xml + /d:sonar.host.url="https://sonarcloud.io" /d:sonar.coverageReportPaths=TestOutput/SonarQube.xml - name: Build solution run: dotnet build ${{ env.SOLUTION_FILE }} --no-restore --configuration Release --verbosity minimal - - name: Test (net10.0) - run: dotnet test ${{ env.SOLUTION_FILE }} --filter "Category!=MemoryDumps" --framework net10.0 ${{ env.SONAR_TEST_ARGS }} + - name: Test + run: dotnet test --solution ${{ env.SOLUTION_FILE }} --filter-not-trait "Category=MemoryDumps" ${{ env.SONAR_TEST_ARGS }} - - name: Test (net10.0) (memory dumps) - run: dotnet test ${{ env.SOLUTION_FILE }} --filter "Category=MemoryDumps" --framework net10.0 ${{ env.SONAR_TEST_ARGS }} + - name: Test (memory dumps) + run: dotnet test --project src/Management/test/Endpoint.Test/Steeltoe.Management.Endpoint.Test.csproj --filter-trait "Category=MemoryDumps" ${{ env.SONAR_TEST_ARGS }} - - name: Test (net9.0) - run: dotnet test ${{ env.SOLUTION_FILE }} --filter "Category!=MemoryDumps" --framework net9.0 ${{ env.SONAR_TEST_ARGS }} + - name: 'TEMP: List files before coverage conversion' + run: find ${{ env.TEST_OUTPUT_DIRECTORY }} - - name: Test (net9.0) (memory dumps) - run: dotnet test ${{ env.SOLUTION_FILE }} --filter "Category=MemoryDumps" --framework net9.0 ${{ env.SONAR_TEST_ARGS }} - - - name: Test (net8.0) - run: dotnet test ${{ env.SOLUTION_FILE }} --filter "Category!=MemoryDumps" --framework net8.0 ${{ env.SONAR_TEST_ARGS }} + - name: Convert Cobertura to Sonar format using ReportGenerator + uses: danielpalme/ReportGenerator-GitHub-Action@5.5.1 + with: + reports: '${{ env.TEST_OUTPUT_DIRECTORY }}/*cobertura.xml' + targetdir: '${{ env.TEST_OUTPUT_DIRECTORY }}' + reporttypes: 'SonarQube' + filefilters: '-*.g.cs' - - name: Test (net8.0) (memory dumps) - run: dotnet test ${{ env.SOLUTION_FILE }} --filter "Category=MemoryDumps" --framework net8.0 ${{ env.SONAR_TEST_ARGS }} + - name: 'TEMP: List files after coverage conversion' + run: find ${{ env.TEST_OUTPUT_DIRECTORY }} - name: End Sonar .NET scanner if: ${{ !cancelled() && steps.sonar_begin.outcome == 'success' }} diff --git a/Directory.Build.targets b/Directory.Build.targets index b59583d8cd..65ab7c7c73 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,6 +1,12 @@ + + + + + @@ -101,7 +107,7 @@ - + @@ -123,7 +129,7 @@ + Text="ConfigurationSchema.json is out of date for $(MSBuildProjectFile). Run 'dotnet build --no-incremental /p:UpdateConfigurationSchema=true' to update it." /> diff --git a/coverage.config b/coverage.config new file mode 100644 index 0000000000..9210688ee0 --- /dev/null +++ b/coverage.config @@ -0,0 +1,29 @@ + + + + cobertura + true + + + + .*ConfigurationSchemaGenerator.* + + + + + ^System\.ObsoleteAttribute$ + ^System\.CodeDom\.Compiler\.GeneratedCodeAttribute$ + ^System\.Runtime\.CompilerServices\.CompilerGeneratedAttribute$ + ^System\.Diagnostics\.CodeAnalysis\.ExcludeFromCodeCoverageAttribute$ + + + + + .*\\test\\.* + + + + diff --git a/coverlet.runsettings b/coverlet.runsettings deleted file mode 100644 index fe0adb82b8..0000000000 --- a/coverlet.runsettings +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - opencover - [ConfigurationSchemaGenerator]* - **/test/**/*.* - ObsoleteAttribute,GeneratedCodeAttribute,CompilerGeneratedAttribute - true - - - - - diff --git a/global.json b/global.json new file mode 100644 index 0000000000..3140116df3 --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "test": { + "runner": "Microsoft.Testing.Platform" + } +} diff --git a/macos-dump-entitlements.plist b/macos-dump-entitlements.plist new file mode 100644 index 0000000000..41bb93a0c7 --- /dev/null +++ b/macos-dump-entitlements.plist @@ -0,0 +1,16 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.cs.disable-library-validation + + com.apple.security.cs.debugger + + com.apple.security.get-task-allow + + + \ No newline at end of file diff --git a/mtp-test-entitlements.plist b/mtp-test-entitlements.plist new file mode 100644 index 0000000000..41bb93a0c7 --- /dev/null +++ b/mtp-test-entitlements.plist @@ -0,0 +1,16 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-dyld-environment-variables + + com.apple.security.cs.disable-library-validation + + com.apple.security.cs.debugger + + com.apple.security.get-task-allow + + + \ No newline at end of file diff --git a/nuget.config b/nuget.config index 128d95e590..94d8574860 100644 --- a/nuget.config +++ b/nuget.config @@ -3,10 +3,6 @@ + - - - - - diff --git a/shared-test.props b/shared-test.props index 16dad857a8..58c1999cb1 100644 --- a/shared-test.props +++ b/shared-test.props @@ -1,13 +1,14 @@ Exe + false $(NoWarn);S2094;S3717;SA1602;CA1062;CA1707;NU5104 - - false - true + true + + $(NoWarn);NU3018;NU3027;NU3042 @@ -16,14 +17,15 @@ - - + + + + - - + diff --git a/src/Common/src/Common/Calculator.cs b/src/Common/src/Common/Calculator.cs new file mode 100644 index 0000000000..7ac7bba3dc --- /dev/null +++ b/src/Common/src/Common/Calculator.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +namespace Steeltoe.Common; + +public sealed class Calculator +{ + public int Add(int left, int right) + { + if (left < 0 || right < 0) + { + throw new ArgumentException("Only non-negative integers are allowed."); + } + + return left + right; + } + + public int Subtract(int left, int right) + { + return left - right; + } +} diff --git a/src/Common/src/Common/Net/DomainNameResolver.cs b/src/Common/src/Common/Net/DomainNameResolver.cs index 0b1da12ddd..30fd0e55bd 100644 --- a/src/Common/src/Common/Net/DomainNameResolver.cs +++ b/src/Common/src/Common/Net/DomainNameResolver.cs @@ -9,6 +9,8 @@ namespace Steeltoe.Common.Net; internal sealed class DomainNameResolver : IDomainNameResolver { + private static readonly bool IsInDiagnosticsMode = Environment.GetEnvironmentVariable("STEELTOE_MACOS_DIAGNOSE_HOSTNAME_LOOKUP") == "true"; + public static DomainNameResolver Instance { get; } = new(); private DomainNameResolver() @@ -42,22 +44,44 @@ private DomainNameResolver() public string? ResolveHostName(bool throwOnError = false) { + // Gather diagnostic information to investigate intermittent failures on macOS. + string? resultFromGetHostName = null; + string? resultFromGetHostEntry = null; + bool? workaroundApplied = null; + try { string hostName = Dns.GetHostName(); + resultFromGetHostName = hostName; if (string.IsNullOrEmpty(hostName)) { // Workaround for failure when running on macOS. // See https://github.com/actions/runner-images/issues/1335 and https://github.com/dotnet/runtime/issues/36849. + hostName = "localhost"; + workaroundApplied = true; } IPHostEntry hostEntry = Dns.GetHostEntry(hostName); - return hostEntry.HostName; + resultFromGetHostEntry = hostEntry.HostName; + + if (IsInDiagnosticsMode && string.IsNullOrEmpty(resultFromGetHostEntry)) + { + throw new InvalidOperationException($"IPHostEntry.HostName returned {GetTextFor(resultFromGetHostEntry)}."); + } + + return resultFromGetHostEntry; } - catch (Exception) + catch (Exception exception) { + if (IsInDiagnosticsMode) + { + throw new InvalidOperationException( + $"Failed to resolve hostname. GetHostName={GetTextFor(resultFromGetHostName)}, GetHostEntry={GetTextFor(resultFromGetHostEntry)}, WorkaroundApplied={workaroundApplied}", + exception); + } + if (throwOnError) { throw; @@ -66,4 +90,14 @@ private DomainNameResolver() return null; } } + + private static string GetTextFor(string? value) + { + if (value == null) + { + return "(null)"; + } + + return value.Length == 0 ? "(empty)" : value; + } } diff --git a/src/Common/src/Common/PublicAPI.Unshipped.txt b/src/Common/src/Common/PublicAPI.Unshipped.txt index 4d8338db45..37bf23d14d 100644 --- a/src/Common/src/Common/PublicAPI.Unshipped.txt +++ b/src/Common/src/Common/PublicAPI.Unshipped.txt @@ -1,4 +1,8 @@ #nullable enable +Steeltoe.Common.Calculator +Steeltoe.Common.Calculator.Add(int left, int right) -> int +Steeltoe.Common.Calculator.Calculator() -> void +Steeltoe.Common.Calculator.Subtract(int left, int right) -> int Steeltoe.Common.Discovery.IServiceInstance.InstanceId.get -> string! Steeltoe.Common.Discovery.IServiceInstance.NonSecureUri.get -> System.Uri? Steeltoe.Common.Discovery.IServiceInstance.SecureUri.get -> System.Uri? diff --git a/src/Common/test/Common.Test/CalculatorTest.cs b/src/Common/test/Common.Test/CalculatorTest.cs new file mode 100644 index 0000000000..0707844391 --- /dev/null +++ b/src/Common/test/Common.Test/CalculatorTest.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +namespace Steeltoe.Common.Test; + +public sealed class CalculatorTest +{ + [Fact] + public void Add_Returns_Correct_Sum() + { + var calculator = new Calculator(); + int result = calculator.Add(3, 5); + result.Should().Be(8); + } + + [Fact(Skip = "ExampleSkippedTest")] + public void SkippedTest() + { + true.Should().BeFalse(); + } +} diff --git a/src/Common/test/TestResources/FluentAssertionsExtensions.cs b/src/Common/test/TestResources/FluentAssertionsExtensions.cs index ef96ceb3b3..2b41838878 100644 --- a/src/Common/test/TestResources/FluentAssertionsExtensions.cs +++ b/src/Common/test/TestResources/FluentAssertionsExtensions.cs @@ -52,4 +52,48 @@ private static string ToJsonString(JsonDocument document) writer.Flush(); return Encoding.UTF8.GetString(stream.ToArray()); } + + /// + /// Same as the built-in Be() method, but allows specifying a custom comparer. + /// + /// + /// The source text to assert on. + /// + /// + /// The expected text. + /// + /// + /// An equality comparer to compare values. + /// + [CustomAssertion] + public static void Be(this StringAssertions source, string expected, IEqualityComparer comparer) + { + ArgumentNullException.ThrowIfNull(source); + ArgumentNullException.ThrowIfNull(expected); + ArgumentNullException.ThrowIfNull(comparer); + + object subject = source.Subject; + subject.Should().Be(expected, comparer); + } + + /// + /// Same as the built-in Contain() method, but normalizes line endings upfront. + /// + /// + /// The source text to assert on. + /// + /// + /// The expected text. + /// + [CustomAssertion] + public static void ContainLines(this StringAssertions source, string expected) + { + ArgumentNullException.ThrowIfNull(source); + ArgumentNullException.ThrowIfNull(expected); + + string sourceText = source.Subject.ReplaceLineEndings(); + string expectedText = expected.ReplaceLineEndings(); + + sourceText.Should().Contain(expectedText); + } } diff --git a/src/Connectors/test/Connectors.Test/Steeltoe.Connectors.Test.csproj b/src/Connectors/test/Connectors.Test/Steeltoe.Connectors.Test.csproj index bf2405d3f8..4002d54b0e 100644 --- a/src/Connectors/test/Connectors.Test/Steeltoe.Connectors.Test.csproj +++ b/src/Connectors/test/Connectors.Test/Steeltoe.Connectors.Test.csproj @@ -14,6 +14,7 @@ + diff --git a/src/Discovery/src/Consul/Registry/ConsulRegistration.cs b/src/Discovery/src/Consul/Registry/ConsulRegistration.cs index c8861fd4d4..81bd573afc 100644 --- a/src/Discovery/src/Consul/Registry/ConsulRegistration.cs +++ b/src/Discovery/src/Consul/Registry/ConsulRegistration.cs @@ -35,7 +35,7 @@ internal sealed class ConsulRegistration : IServiceInstance public bool IsSecure => _optionsMonitor.CurrentValue.EffectiveScheme == "https"; /// - public Uri Uri => new($"{_optionsMonitor.CurrentValue.EffectiveScheme}://{Host}:{Port}"); + public Uri Uri => FormatUri(); /// public Uri? NonSecureUri => IsSecure ? null : Uri; @@ -73,6 +73,20 @@ internal ConsulRegistration(AgentServiceRegistration innerRegistration, IOptions Metadata = innerRegistration.Meta.AsReadOnly(); } + private Uri FormatUri() + { + string scheme = _optionsMonitor.CurrentValue.EffectiveScheme; + + try + { + return new Uri($"{scheme}://{Host}:{Port}"); + } + catch (UriFormatException exception) + { + throw new UriFormatException($"Failed to build URI from components. Scheme={scheme}, Host={Host},Port={Port}.", exception); + } + } + /// /// Creates a registration for the currently running app, to be submitted to the Consul server. /// diff --git a/src/Logging/test/DynamicConsole.Test/DynamicConsoleLoggerProviderTest.cs b/src/Logging/test/DynamicConsole.Test/DynamicConsoleLoggerProviderTest.cs index 9e237a86a9..3e85796499 100644 --- a/src/Logging/test/DynamicConsole.Test/DynamicConsoleLoggerProviderTest.cs +++ b/src/Logging/test/DynamicConsole.Test/DynamicConsoleLoggerProviderTest.cs @@ -504,7 +504,7 @@ public async Task CanUseJsonFormatterWithScopes() ] } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] diff --git a/src/Logging/test/DynamicSerilog.Test/DynamicSerilogLoggerProviderTest.cs b/src/Logging/test/DynamicSerilog.Test/DynamicSerilogLoggerProviderTest.cs index 36c985c212..682a90fdc4 100644 --- a/src/Logging/test/DynamicSerilog.Test/DynamicSerilogLoggerProviderTest.cs +++ b/src/Logging/test/DynamicSerilog.Test/DynamicSerilogLoggerProviderTest.cs @@ -287,7 +287,7 @@ public void CanUseScopes() [INF] Fully.Qualified.Type: {InnerScopeKey="InnerScopeValue", Scope=["OuterScope", "InnerScope=InnerScopeValue"]} TestInfo - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -331,7 +331,7 @@ public void CanUseSerilogEnrichers() [INF] Fully.Qualified.Type: {A=1} Carries property A = 1, again - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -360,7 +360,7 @@ public void CanUseSerilogDestructuring() logOutput.Should().Be(""" [INF] Fully.Qualified.Type: Processing of {"RequestUrl": "https://www.example.com", "UserAgent": "Steeltoe"} started. - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -391,7 +391,7 @@ public void CallsIntoMessageProcessors() [INF] {SourceContext="Test", Scope=["TwoOne"]} Three - """); + """, IgnoreLineEndingsComparer.Instance); } private static IDynamicLoggerProvider CreateLoggerProvider(Action? configure = null) diff --git a/src/Logging/test/DynamicSerilog.Test/HostBuilderTest.cs b/src/Logging/test/DynamicSerilog.Test/HostBuilderTest.cs index fa38276223..151b001ca2 100644 --- a/src/Logging/test/DynamicSerilog.Test/HostBuilderTest.cs +++ b/src/Logging/test/DynamicSerilog.Test/HostBuilderTest.cs @@ -91,12 +91,12 @@ public async Task CanPreserveDefaultConsoleLoggerProvider() logOutput.Should().Contain("SERILOG [INF] TestInfo"); logOutput.Should().Contain("SERILOG [ERR] TestError"); - logOutput.Should().Contain($""" + logOutput.Should().ContainLines($""" info: {typeof(HostBuilderTest)}[0] TestInfo """); - logOutput.Should().Contain($""" + logOutput.Should().ContainLines($""" fail: {typeof(HostBuilderTest)}[0] TestError """); @@ -133,7 +133,7 @@ public async Task CanConfigureSerilogWithoutLevelsConfiguration() [INF] TestInfo [ERR] TestError - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -167,7 +167,7 @@ public async Task CanConfigureSerilogFromConfigurationWithDefaultLevel() logOutput.Should().Be(""" [ERR] TestError - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -201,7 +201,7 @@ public async Task CanConfigureSerilogFromConfigurationWithShortKeyForDefaultLeve logOutput.Should().Be(""" [ERR] TestError - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -236,7 +236,7 @@ public async Task CanConfigureSerilogFromConfigurationWithOnlyOverrides() logOutput.Should().Be(""" [ERR] TestError - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -273,7 +273,7 @@ public async Task CanConfigureSerilogFromCodeWithDefaultLevel() logOutput.Should().Be(""" [ERR] TestError - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -311,7 +311,7 @@ public async Task CanConfigureSerilogFromCodeWithOnlyOverrides() logOutput.Should().Be(""" [ERR] TestError - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] diff --git a/src/Management/src/Endpoint/Actuators/Health/Contributors/FileSystem/NetworkShareWrapper.cs b/src/Management/src/Endpoint/Actuators/Health/Contributors/FileSystem/NetworkShareWrapper.cs index a62227d27d..c39452957d 100644 --- a/src/Management/src/Endpoint/Actuators/Health/Contributors/FileSystem/NetworkShareWrapper.cs +++ b/src/Management/src/Endpoint/Actuators/Health/Contributors/FileSystem/NetworkShareWrapper.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. -using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; namespace Steeltoe.Management.Endpoint.Actuators.Health.Contributors.FileSystem; @@ -27,7 +26,6 @@ private NetworkShareWrapper(ulong freeBytesAvailable, ulong totalNumberOfBytes) : null; } - [ExcludeFromCodeCoverage(Justification = "Workaround for https://github.com/coverlet-coverage/coverlet/issues/1762")] private static partial class NativeMethods { [LibraryImport("kernel32.dll", EntryPoint = "GetDiskFreeSpaceExW", StringMarshalling = StringMarshalling.Utf16, SetLastError = true)] diff --git a/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/ApiControllerTest.cs b/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/ApiControllerTest.cs index 24036e793d..5d17186e73 100644 --- a/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/ApiControllerTest.cs +++ b/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/ApiControllerTest.cs @@ -91,7 +91,7 @@ public async Task Can_get_routes_for_simple_controller() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -208,7 +208,7 @@ public async Task Can_get_routes_for_controller_with_parameters_and_annotations( } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -398,7 +398,7 @@ public async Task Can_get_routes_for_multiple_verbs_in_single_action_method() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -461,7 +461,7 @@ public async Task Can_get_routes_for_any_verb_in_single_action_method() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -536,7 +536,7 @@ public async Task Can_get_routes_using_WebHostBuilder() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -613,6 +613,6 @@ public async Task Can_get_routes_using_HostBuilder() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } } diff --git a/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/MinimalApiTest.cs b/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/MinimalApiTest.cs index f4c586a17f..774a7248e1 100644 --- a/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/MinimalApiTest.cs +++ b/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/MinimalApiTest.cs @@ -83,7 +83,7 @@ public async Task Can_get_routes_for_handler_method() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -145,7 +145,7 @@ public async Task Can_get_routes_for_inline_lambda() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -268,7 +268,7 @@ public async Task Can_get_routes_for_inline_lambda_with_parameters_and_annotatio } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -364,7 +364,7 @@ public async Task Can_get_routes_for_multiple_verbs_in_single_endpoint() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -432,7 +432,7 @@ public async Task Can_get_routes_for_any_verb_in_single_endpoint() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -523,7 +523,7 @@ public async Task Can_get_routes_for_separate_verbs_in_single_endpoint() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -615,7 +615,7 @@ public async Task Can_get_routes_for_groups_using_same_handler_method() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -720,7 +720,7 @@ public async Task Can_get_routes_for_groups_using_inline_lambdas() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -781,7 +781,7 @@ public async Task Can_get_routes_using_WebHostBuilder() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -845,7 +845,7 @@ public async Task Can_get_routes_using_HostBuilder() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } private static string HandlePingRequest() diff --git a/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/MvcControllerTest.cs b/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/MvcControllerTest.cs index f261f0b125..f61f0f26ff 100644 --- a/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/MvcControllerTest.cs +++ b/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/MvcControllerTest.cs @@ -136,7 +136,7 @@ public async Task Can_get_routes_for_simple_controller() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -300,7 +300,7 @@ public async Task Can_get_routes_for_controller_with_parameters_and_annotations( } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -432,7 +432,7 @@ public async Task Can_get_routes_for_multiple_verbs_in_single_action_method() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -511,7 +511,7 @@ public async Task Can_get_routes_for_any_verb_in_single_action_method() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -630,7 +630,7 @@ public async Task Can_get_routes_using_WebHostBuilder() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } [Fact] @@ -750,6 +750,6 @@ public async Task Can_get_routes_using_HostBuilder() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } } diff --git a/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/RazorPagesExternalAppTest.cs b/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/RazorPagesExternalAppTest.cs index 83bbcdaa92..8b0f91b08a 100644 --- a/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/RazorPagesExternalAppTest.cs +++ b/src/Management/test/Endpoint.Test/Actuators/RouteMappings/AppTypes/RazorPagesExternalAppTest.cs @@ -3,14 +3,13 @@ // See the LICENSE file in the project root for more information. using System.Net; -using Microsoft.AspNetCore.Mvc.Testing; -using Steeltoe.Management.Endpoint.RazorPagesTestWebApp.Pages; +using Steeltoe.Common.TestResources; namespace Steeltoe.Management.Endpoint.Test.Actuators.RouteMappings.AppTypes; -public sealed class RazorPagesExternalAppTest(WebApplicationFactory factory) : IClassFixture> +public sealed class RazorPagesExternalAppTest(RazorPagesWebApplicationFactory factory) : IClassFixture { - private readonly WebApplicationFactory _factory = factory; + private readonly RazorPagesWebApplicationFactory _factory = factory; [Fact] public async Task Can_get_routes_for_razor_pages() @@ -272,6 +271,6 @@ public async Task Can_get_routes_for_razor_pages() } } } - """); + """, IgnoreLineEndingsComparer.Instance); } } diff --git a/src/Management/test/Endpoint.Test/Actuators/RouteMappings/RazorPagesWebApplicationFactory.cs b/src/Management/test/Endpoint.Test/Actuators/RouteMappings/RazorPagesWebApplicationFactory.cs new file mode 100644 index 0000000000..322e07311b --- /dev/null +++ b/src/Management/test/Endpoint.Test/Actuators/RouteMappings/RazorPagesWebApplicationFactory.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License. +// See the LICENSE file in the project root for more information. + +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; +using Steeltoe.Management.Endpoint.RazorPagesTestWebApp.Pages; +using Steeltoe.Management.Endpoint.Test.Actuators.RouteMappings.AppTypes; + +namespace Steeltoe.Management.Endpoint.Test.Actuators.RouteMappings; + +public sealed class RazorPagesWebApplicationFactory : WebApplicationFactory +{ + protected override void ConfigureWebHost(IWebHostBuilder builder) + { + string? testAssemblyName = typeof(RazorPagesExternalAppTest).Assembly.GetName().Name; + string? appAssemblyName = typeof(IndexModel).Assembly.GetName().Name; + + string absoluteContentRoot = System.Environment.CurrentDirectory; + absoluteContentRoot = absoluteContentRoot.Replace($"/{testAssemblyName}/", $"/{appAssemblyName}/", StringComparison.Ordinal); + absoluteContentRoot = absoluteContentRoot.Replace($@"\{testAssemblyName}\", $@"\{appAssemblyName}\", StringComparison.Ordinal); + + // Workaround for https://github.com/dotnet/aspnetcore/issues/55867. + builder.UseContentRoot(absoluteContentRoot); + + // Workaround for https://github.com/dotnet/aspnetcore/issues/55867#issuecomment-3046941805. + builder.UseEnvironment("Production"); + } +} diff --git a/src/Steeltoe.All.sln b/src/Steeltoe.All.sln index 1e8a438ee2..61e38a2678 100644 --- a/src/Steeltoe.All.sln +++ b/src/Steeltoe.All.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 18 -VisualStudioVersion = 18.0.11222.15 d18.0 +VisualStudioVersion = 18.0.11222.15 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Steeltoe.Common", "Common\src\Common\Steeltoe.Common.csproj", "{61812938-5132-4AB6-B48D-2DF4189B3E37}" EndProject @@ -29,7 +29,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_shared", "_shared", "{DC1B ..\.gitattributes = ..\.gitattributes ..\.gitignore = ..\.gitignore ..\cleanupcode.ps1 = ..\cleanupcode.ps1 - ..\coverlet.runsettings = ..\coverlet.runsettings + ..\coverage.config = ..\coverage.config + ..\coverage.sonar.config = ..\coverage.sonar.config ..\Directory.Build.targets = ..\Directory.Build.targets ..\nuget.config = ..\nuget.config ..\PackageReadme.md = ..\PackageReadme.md diff --git a/src/testenvironments.json b/src/testenvironments.json index 539ead6b04..ebd64f1380 100644 --- a/src/testenvironments.json +++ b/src/testenvironments.json @@ -1,10 +1,15 @@ { - "version": "1", - "environments": [ - { - "name": "Ubuntu", - "type": "wsl", - "wslDistribution": "Ubuntu" - } - ] + "version": "1", + "environments": [ + { + "name": "Ubuntu", + "type": "wsl", + "wslDistribution": "Ubuntu" + }, + { + "name": "Ubuntu-22.04", + "type": "wsl", + "wslDistribution": "Ubuntu-22.04" + } + ] } diff --git a/versions.props b/versions.props index 20d9d10375..160c46d1b1 100644 --- a/versions.props +++ b/versions.props @@ -6,10 +6,11 @@ --> 9.0.* - 6.0.* 7.2.* 3.54.* 4.14.* + 18.3.0-preview.25611.1 + 2.1.0-preview.25611.7 6.1.* 7.0.* 3.5.* @@ -26,9 +27,7 @@ 2.0.* 8.14.* 4.9.* - 18.0.* 3.2.* - 3.1.*