Add an launch inspector command to Aspire Dashboard (#1283)

* Upgrade to Aspire 9.2.0

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* Remove workload installs from CI pipeline

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* Missed package upgrade

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* Fix usings

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* Add Open Inspector command

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* Fix broken test

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* PR comments

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

* More PR comments

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>

---------

Signed-off-by: Jonathan Mezach <jonathan.mezach@rr-wfm.com>
This commit is contained in:
Jonathan Mezach
2025-04-25 20:23:19 +02:00
committed by GitHub
parent 9392069f8a
commit 8a07286b89
9 changed files with 706 additions and 618 deletions

View File

@@ -1,185 +1,176 @@
variables:
Prerelease: 'ci'
buildId: "1$(Build.BuildId)"
buildProjects: '**/src/**/*.csproj'
jobs:
- job: Linux_Build_Test_SonarCloud
pool:
vmImage: 'ubuntu-22.04'
steps:
- script: |
echo "BuildId = $(buildId)"
displayName: 'Print buildId'
- task: CmdLine@2
displayName: 'Install .NET Aspire workload'
inputs:
script: 'dotnet workload install aspire'
- script: |
dotnet tool install --global dotnet-sonarscanner
dotnet tool install --global dotnet-coverage
displayName: 'Install dotnet tools'
- script: |
dotnet workload install aspire
displayName: 'Install aspire'
- task: PowerShell@2
displayName: "Use JDK17 by default"
inputs:
targetType: 'inline'
script: |
$jdkPath = $env:JAVA_HOME_17_X64
Write-Host "##vso[task.setvariable variable=JAVA_HOME]$jdkPath"
- script: |
dotnet dev-certs https --trust || true
displayName: 'dotnet dev-certs https'
# See: https://docs.sonarsource.com/sonarcloud/enriching/test-coverage/dotnet-test-coverage
- script: |
dotnet sonarscanner begin /k:"WireMock-Net_WireMock.Net" /o:"wiremock-net" /d:sonar.branch.name=$(Build.SourceBranchName) /d:sonar.host.url="https://sonarcloud.io" /d:sonar.token="$(SONAR_TOKEN)" /d:sonar.pullrequest.provider=github /d:sonar.cs.vscoveragexml.reportsPaths=**/wiremock-coverage-*.xml /d:sonar.verbose=true
displayName: 'Begin analysis on SonarCloud'
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
- task: DotNetCoreCLI@2
displayName: 'Build Unit tests'
inputs:
command: 'build'
projects: '**/test/**/*.csproj'
arguments: '--configuration Debug --framework net8.0'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Tests/WireMock.Net.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-xunit.xml"
displayName: 'WireMock.Net.Tests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-tunit.xml"
displayName: 'WireMock.Net.TUnitTests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-middleware.xml"
displayName: 'WireMock.Net.Middleware.Tests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Aspire.Tests/WireMock.Net.Aspire.Tests.csproj --configuration Debug --no-build" -f xml -o "wiremock-coverage-aspire.xml"
displayName: 'WireMock.Net.Aspire.Tests with Coverage'
- task: CmdLine@2
displayName: 'Merge coverage files'
inputs:
script: 'dotnet coverage merge **/wiremock-coverage-*.xml --output ./test/wiremock-coverage.xml --output-format xml'
- script: |
dotnet sonarscanner end /d:sonar.token="$(SONAR_TOKEN)"
displayName: 'End analysis on SonarCloud'
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
- task: whitesource.ws-bolt.bolt.wss.WhiteSource Bolt@19
displayName: 'WhiteSource Bolt'
condition: and(succeeded(), eq(variables['RUN_WHITESOURCE'], 'yes'))
- script: |
bash <(curl https://codecov.io/bash) -t $(CODECOV_TOKEN) -f ./test/wiremock-coverage.xml
displayName: 'Upload coverage results to codecov'
- task: PublishTestResults@2
condition: and(succeeded(), eq(variables['PUBLISH_TESTRESULTS'], 'yes'))
inputs:
testRunner: VSTest
testResultsFiles: '**/*.trx'
- task: PublishBuildArtifacts@1
displayName: Publish coverage files
inputs:
PathtoPublish: './test/WireMock.Net.Tests/coverage.net8.0.opencover.xml'
- job: Windows_Build_Test
pool:
vmImage: 'windows-2022'
steps:
- task: UseDotNet@2
displayName: Use .NET 8.0
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.Tests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.TUnitTests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.Middleware.Tests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- job: Windows_Release_to_MyGet
dependsOn: Windows_Build_Test
pool:
vmImage: 'windows-2022'
steps:
- task: UseDotNet@2
displayName: Use .NET 8.0
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: Build Release
inputs:
command: 'build'
arguments: /p:Configuration=Release
projects: $(buildProjects)
- task: DotNetCoreCLI@2
displayName: Pack
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: pack
configuration: 'Release'
packagesToPack: $(buildProjects)
nobuild: true
packDirectory: '$(Build.ArtifactStagingDirectory)/packages'
verbosityPack: 'normal'
- task: PublishBuildArtifacts@1
displayName: Publish Artifacts
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
- task: DotNetCoreCLI@2
displayName: Push to MyGet
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: custom
custom: nuget
variables:
Prerelease: 'ci'
buildId: "1$(Build.BuildId)"
buildProjects: '**/src/**/*.csproj'
jobs:
- job: Linux_Build_Test_SonarCloud
pool:
vmImage: 'ubuntu-22.04'
steps:
- script: |
echo "BuildId = $(buildId)"
displayName: 'Print buildId'
- script: |
dotnet tool install --global dotnet-sonarscanner
dotnet tool install --global dotnet-coverage
displayName: 'Install dotnet tools'
- task: PowerShell@2
displayName: "Use JDK17 by default"
inputs:
targetType: 'inline'
script: |
$jdkPath = $env:JAVA_HOME_17_X64
Write-Host "##vso[task.setvariable variable=JAVA_HOME]$jdkPath"
- script: |
dotnet dev-certs https --trust || true
displayName: 'dotnet dev-certs https'
# See: https://docs.sonarsource.com/sonarcloud/enriching/test-coverage/dotnet-test-coverage
- script: |
dotnet sonarscanner begin /k:"WireMock-Net_WireMock.Net" /o:"wiremock-net" /d:sonar.branch.name=$(Build.SourceBranchName) /d:sonar.host.url="https://sonarcloud.io" /d:sonar.token="$(SONAR_TOKEN)" /d:sonar.pullrequest.provider=github /d:sonar.cs.vscoveragexml.reportsPaths=**/wiremock-coverage-*.xml /d:sonar.verbose=true
displayName: 'Begin analysis on SonarCloud'
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
- task: DotNetCoreCLI@2
displayName: 'Build Unit tests'
inputs:
command: 'build'
projects: '**/test/**/*.csproj'
arguments: '--configuration Debug --framework net8.0'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Tests/WireMock.Net.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-xunit.xml"
displayName: 'WireMock.Net.Tests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-tunit.xml"
displayName: 'WireMock.Net.TUnitTests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj --configuration Debug --no-build --framework net8.0" -f xml -o "wiremock-coverage-middleware.xml"
displayName: 'WireMock.Net.Middleware.Tests with Coverage'
- task: CmdLine@2
inputs:
script: |
dotnet-coverage collect "dotnet test ./test/WireMock.Net.Aspire.Tests/WireMock.Net.Aspire.Tests.csproj --configuration Debug --no-build" -f xml -o "wiremock-coverage-aspire.xml"
displayName: 'WireMock.Net.Aspire.Tests with Coverage'
- task: CmdLine@2
displayName: 'Merge coverage files'
inputs:
script: 'dotnet coverage merge **/wiremock-coverage-*.xml --output ./test/wiremock-coverage.xml --output-format xml'
- script: |
dotnet sonarscanner end /d:sonar.token="$(SONAR_TOKEN)"
displayName: 'End analysis on SonarCloud'
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
- task: whitesource.ws-bolt.bolt.wss.WhiteSource Bolt@19
displayName: 'WhiteSource Bolt'
condition: and(succeeded(), eq(variables['RUN_WHITESOURCE'], 'yes'))
- script: |
bash <(curl https://codecov.io/bash) -t $(CODECOV_TOKEN) -f ./test/wiremock-coverage.xml
displayName: 'Upload coverage results to codecov'
- task: PublishTestResults@2
condition: and(succeeded(), eq(variables['PUBLISH_TESTRESULTS'], 'yes'))
inputs:
testRunner: VSTest
testResultsFiles: '**/*.trx'
- task: PublishBuildArtifacts@1
displayName: Publish coverage files
inputs:
PathtoPublish: './test/WireMock.Net.Tests/coverage.net8.0.opencover.xml'
- job: Windows_Build_Test
pool:
vmImage: 'windows-2022'
steps:
- task: UseDotNet@2
displayName: Use .NET 8.0
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.Tests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Tests/WireMock.Net.Tests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.TUnitTests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.TUnitTests/WireMock.Net.TUnitTests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- task: DotNetCoreCLI@2
displayName: 'WireMock.Net.Middleware.Tests with Coverage'
inputs:
command: 'test'
projects: './test/WireMock.Net.Middleware.Tests/WireMock.Net.Middleware.Tests.csproj'
arguments: '--configuration Debug --framework net8.0 --collect:"XPlat Code Coverage" --logger trx'
- job: Windows_Release_to_MyGet
dependsOn: Windows_Build_Test
pool:
vmImage: 'windows-2022'
steps:
- task: UseDotNet@2
displayName: Use .NET 8.0
inputs:
packageType: 'sdk'
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: Build Release
inputs:
command: 'build'
arguments: /p:Configuration=Release
projects: $(buildProjects)
- task: DotNetCoreCLI@2
displayName: Pack
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: pack
configuration: 'Release'
packagesToPack: $(buildProjects)
nobuild: true
packDirectory: '$(Build.ArtifactStagingDirectory)/packages'
verbosityPack: 'normal'
- task: PublishBuildArtifacts@1
displayName: Publish Artifacts
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
- task: DotNetCoreCLI@2
displayName: Push to MyGet
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
inputs:
command: custom
custom: nuget
arguments: push $(Build.ArtifactStagingDirectory)\packages\*.nupkg -n -s https://www.myget.org/F/wiremock-net/api/v3/index.json -k $(MyGetKey)

View File

@@ -1,23 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AspireApp1.ApiService\AspireApp1.ApiService.csproj" />
<ProjectReference Include="..\AspireApp1.Web\AspireApp1.Web.csproj" />
<!-- https://learn.microsoft.com/en-us/dotnet/aspire/extensibility/custom-resources?tabs=windows#create-library-for-resource-extension -->
<ProjectReference Include="..\..\src\WireMock.Net.Aspire\WireMock.Net.Aspire.csproj" IsAspireProjectResource="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.2.0" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.2.0" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AspireApp1.ApiService\AspireApp1.ApiService.csproj" />
<ProjectReference Include="..\AspireApp1.Web\AspireApp1.Web.csproj" />
<!-- https://learn.microsoft.com/en-us/dotnet/aspire/extensibility/custom-resources?tabs=windows#create-library-for-resource-extension -->
<ProjectReference Include="..\..\src\WireMock.Net.Aspire\WireMock.Net.Aspire.csproj" IsAspireProjectResource="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.2.0" />
</ItemGroup>
</Project>

View File

@@ -1,20 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AspireApp1.ApiService\AspireApp1.ApiService.csproj" />
<ProjectReference Include="..\AspireApp1.Web\AspireApp1.Web.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.2.0" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.2.0" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AspireApp1.ApiService\AspireApp1.ApiService.csproj" />
<ProjectReference Include="..\AspireApp1.Web\AspireApp1.Web.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.2.0" />
</ItemGroup>
</Project>

View File

@@ -1,49 +1,49 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Description>Aspire extension to start a WireMock.Net server to stub an api.</Description>
<AssemblyTitle>WireMock.Net.Aspire</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.Aspire</AssemblyName>
<PackageId>WireMock.Net.Aspire</PackageId>
<PackageTags>dotnet;aspire;wiremock;extension</PackageTags>
<ProjectGuid>{B6269AAC-170A-4346-8B9A-579DED3D9A12}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>WireMock.Net-LogoAspire.png</PackageIcon>
<ApplicationIcon>../../resources/WireMock.Net-LogoAspire.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="../../resources/WireMock.Net-Logo.png" />
<None Include="../../resources/WireMock.Net-LogoAspire.png" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\WireMock.Net\Util\EnhancedFileSystemWatcher.cs" Link="Utils\EnhancedFileSystemWatcher.cs" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting" Version="8.2.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
</ItemGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Description>Aspire extension to start a WireMock.Net server to stub an api.</Description>
<AssemblyTitle>WireMock.Net.Aspire</AssemblyTitle>
<Authors>Stef Heyenrath</Authors>
<TargetFramework>net8.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>WireMock.Net.Aspire</AssemblyName>
<PackageId>WireMock.Net.Aspire</PackageId>
<PackageTags>dotnet;aspire;wiremock;extension</PackageTags>
<ProjectGuid>{B6269AAC-170A-4346-8B9A-579DED3D9A12}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>WireMock.Net-LogoAspire.png</PackageIcon>
<ApplicationIcon>../../resources/WireMock.Net-LogoAspire.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="../../resources/WireMock.Net-Logo.png" />
<None Include="../../resources/WireMock.Net-LogoAspire.png" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\WireMock.Net\Util\EnhancedFileSystemWatcher.cs" Link="Utils\EnhancedFileSystemWatcher.cs" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting" Version="9.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,43 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Aspire.Hosting.WireMock;
internal static class WireMockInspector
{
/// <summary>
/// Opens the WireMockInspector tool to inspect the WireMock server.
/// </summary>
/// <param name="wireMockUrl"></param>
/// <param name="title"></param>
/// <exception cref="InvalidOperationException"></exception>
/// <remarks>
/// Copy of <see href="https://github.com/WireMock-Net/WireMockInspector/blob/main/src/WireMock.Net.Extensions.WireMockInspector/WireMockServerExtensions.cs" />
/// without requestFilters and no call to WaitForExit() method in the process so it doesn't block the caller.
/// </remarks>
public static void Inspect(string wireMockUrl, [CallerMemberName] string title = "")
{
try
{
var arguments = $"attach --adminUrl {wireMockUrl} --autoLoad --instanceName \"{title}\"";
Process.Start(new ProcessStartInfo
{
FileName = "wiremockinspector",
Arguments = arguments,
UseShellExecute = false
});
}
catch (Exception e)
{
throw new InvalidOperationException
(
message: @"Cannot find installation of WireMockInspector.
Execute the following command to install WireMockInspector dotnet tool:
> dotnet tool install WireMockInspector --global --no-cache --ignore-failed-sources
To get more info please visit https://github.com/WireMock-Net/WireMockInspector",
innerException: e
);
}
}
}

View File

@@ -1,175 +1,222 @@
// Copyright © WireMock.Net
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Lifecycle;
using Stef.Validation;
using WireMock.Client.Builders;
using WireMock.Net.Aspire;
// ReSharper disable once CheckNamespace
namespace Aspire.Hosting;
/// <summary>
/// Provides extension methods for adding WireMock.Net Server resources to the application model.
/// </summary>
public static class WireMockServerBuilderExtensions
{
// Linux only (https://github.com/dotnet/aspire/issues/854)
private const string DefaultLinuxImage = "sheyenrath/wiremock.net-alpine";
private const string DefaultLinuxMappingsPath = "/app/__admin/mappings";
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="port">The HTTP port for the WireMock Server.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, int? port = null)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.Condition(port, p => p is null or > 0 and <= ushort.MaxValue);
return builder.AddWireMock(name, callback =>
{
callback.HttpPort = port;
});
}
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="arguments">The arguments to start the WireMock.Net Server.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, WireMockServerArguments arguments)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.NotNull(arguments);
var wireMockContainerResource = new WireMockServerResource(name, arguments);
var resourceBuilder = builder
.AddResource(wireMockContainerResource)
.WithImage(DefaultLinuxImage)
.WithEnvironment(ctx => ctx.EnvironmentVariables.Add("DOTNET_USE_POLLING_FILE_WATCHER", "1")) // https://khalidabuhakmeh.com/aspnet-docker-gotchas-and-workarounds#configuration-reloads-and-filesystemwatcher
.WithHttpEndpoint(port: arguments.HttpPort, targetPort: WireMockServerArguments.HttpContainerPort);
if (!string.IsNullOrEmpty(arguments.MappingsPath))
{
resourceBuilder = resourceBuilder.WithBindMount(arguments.MappingsPath, DefaultLinuxMappingsPath);
}
resourceBuilder = resourceBuilder.WithArgs(ctx =>
{
foreach (var arg in arguments.GetArgs())
{
ctx.Args.Add(arg);
}
});
return resourceBuilder;
}
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="callback">A callback that allows for setting the <see cref="WireMockServerArguments"/>.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, Action<WireMockServerArguments> callback)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.NotNull(callback);
var arguments = new WireMockServerArguments();
callback(arguments);
return builder.AddWireMock(name, arguments);
}
/// <summary>
/// Defines if the static mappings should be read at startup.
///
/// Default set to <c>false</c>.
/// </summary>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithReadStaticMappings(this IResourceBuilder<WireMockServerResource> wiremock)
{
Guard.NotNull(wiremock).Resource.Arguments.ReadStaticMappings = true;
return wiremock;
}
/// <summary>
/// Watch the static mapping files + folder for changes when running.
///
/// Default set to <c>false</c>.
/// </summary>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithWatchStaticMappings(this IResourceBuilder<WireMockServerResource> wiremock)
{
Guard.NotNull(wiremock).Resource.Arguments.WatchStaticMappings = true;
return wiremock;
}
/// <summary>
/// Specifies the path for the (static) mapping json files.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="mappingsPath">The local path.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithMappingsPath(this IResourceBuilder<WireMockServerResource> wiremock, string mappingsPath)
{
Guard.NotNullOrWhiteSpace(mappingsPath);
Guard.NotNull(wiremock).Resource.Arguments.MappingsPath = mappingsPath;
return wiremock.WithBindMount(mappingsPath, DefaultLinuxMappingsPath);
}
/// <summary>
/// Set the admin username and password for accessing the admin interface from WireMock.Net via HTTP.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="username">The admin username.</param>
/// <param name="password">The admin password.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithAdminUserNameAndPassword(this IResourceBuilder<WireMockServerResource> wiremock, string username, string password)
{
Guard.NotNull(wiremock);
wiremock.Resource.Arguments.AdminUsername = Guard.NotNull(username);
wiremock.Resource.Arguments.AdminPassword = Guard.NotNull(password);
return wiremock;
}
/// <summary>
/// Use WireMock Client's AdminApiMappingBuilder to configure the WireMock.Net resource.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, Task> configure)
{
return wiremock.WithApiMappingBuilder((adminApiMappingBuilder, _) => configure.Invoke(adminApiMappingBuilder));
}
/// <summary>
/// Use WireMock Client's AdminApiMappingBuilder to configure the WireMock.Net resource.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, CancellationToken, Task> configure)
{
Guard.NotNull(wiremock);
wiremock.ApplicationBuilder.Services.TryAddLifecycleHook<WireMockServerLifecycleHook>();
wiremock.Resource.Arguments.ApiMappingBuilder = configure;
return wiremock;
}
// Copyright © WireMock.Net
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Lifecycle;
using Aspire.Hosting.WireMock;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Stef.Validation;
using WireMock.Client.Builders;
using WireMock.Net.Aspire;
// ReSharper disable once CheckNamespace
namespace Aspire.Hosting;
/// <summary>
/// Provides extension methods for adding WireMock.Net Server resources to the application model.
/// </summary>
public static class WireMockServerBuilderExtensions
{
// Linux only (https://github.com/dotnet/aspire/issues/854)
private const string DefaultLinuxImage = "sheyenrath/wiremock.net-alpine";
private const string DefaultLinuxMappingsPath = "/app/__admin/mappings";
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="port">The HTTP port for the WireMock Server.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, int? port = null)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.Condition(port, p => p is null or > 0 and <= ushort.MaxValue);
return builder.AddWireMock(name, callback =>
{
callback.HttpPort = port;
});
}
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="arguments">The arguments to start the WireMock.Net Server.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, WireMockServerArguments arguments)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.NotNull(arguments);
var wireMockContainerResource = new WireMockServerResource(name, arguments);
var resourceBuilder = builder
.AddResource(wireMockContainerResource)
.WithImage(DefaultLinuxImage)
.WithEnvironment(ctx => ctx.EnvironmentVariables.Add("DOTNET_USE_POLLING_FILE_WATCHER", "1")) // https://khalidabuhakmeh.com/aspnet-docker-gotchas-and-workarounds#configuration-reloads-and-filesystemwatcher
.WithHttpEndpoint(port: arguments.HttpPort, targetPort: WireMockServerArguments.HttpContainerPort)
.WithWireMockInspectorCommand();
if (!string.IsNullOrEmpty(arguments.MappingsPath))
{
resourceBuilder = resourceBuilder.WithBindMount(arguments.MappingsPath, DefaultLinuxMappingsPath);
}
resourceBuilder = resourceBuilder.WithArgs(ctx =>
{
foreach (var arg in arguments.GetArgs())
{
ctx.Args.Add(arg);
}
});
return resourceBuilder;
}
/// <summary>
/// Adds a WireMock.Net Server resource to the application model.
/// </summary>
/// <param name="builder">The <see cref="IDistributedApplicationBuilder"/>.</param>
/// <param name="name">The name of the resource. This name will be used as the connection string name when referenced in a dependency.</param>
/// <param name="callback">A callback that allows for setting the <see cref="WireMockServerArguments"/>.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> AddWireMock(this IDistributedApplicationBuilder builder, string name, Action<WireMockServerArguments> callback)
{
Guard.NotNull(builder);
Guard.NotNullOrWhiteSpace(name);
Guard.NotNull(callback);
var arguments = new WireMockServerArguments();
callback(arguments);
return builder.AddWireMock(name, arguments);
}
/// <summary>
/// Defines if the static mappings should be read at startup.
///
/// Default set to <c>false</c>.
/// </summary>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithReadStaticMappings(this IResourceBuilder<WireMockServerResource> wiremock)
{
Guard.NotNull(wiremock).Resource.Arguments.ReadStaticMappings = true;
return wiremock;
}
/// <summary>
/// Watch the static mapping files + folder for changes when running.
///
/// Default set to <c>false</c>.
/// </summary>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithWatchStaticMappings(this IResourceBuilder<WireMockServerResource> wiremock)
{
Guard.NotNull(wiremock).Resource.Arguments.WatchStaticMappings = true;
return wiremock;
}
/// <summary>
/// Specifies the path for the (static) mapping json files.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="mappingsPath">The local path.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithMappingsPath(this IResourceBuilder<WireMockServerResource> wiremock, string mappingsPath)
{
Guard.NotNullOrWhiteSpace(mappingsPath);
Guard.NotNull(wiremock).Resource.Arguments.MappingsPath = mappingsPath;
return wiremock.WithBindMount(mappingsPath, DefaultLinuxMappingsPath);
}
/// <summary>
/// Set the admin username and password for accessing the admin interface from WireMock.Net via HTTP.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="username">The admin username.</param>
/// <param name="password">The admin password.</param>
/// <returns>A reference to the <see cref="IResourceBuilder{WireMockServerResource}"/>.</returns>
public static IResourceBuilder<WireMockServerResource> WithAdminUserNameAndPassword(this IResourceBuilder<WireMockServerResource> wiremock, string username, string password)
{
Guard.NotNull(wiremock);
wiremock.Resource.Arguments.AdminUsername = Guard.NotNull(username);
wiremock.Resource.Arguments.AdminPassword = Guard.NotNull(password);
return wiremock;
}
/// <summary>
/// Use WireMock Client's AdminApiMappingBuilder to configure the WireMock.Net resource.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, Task> configure)
{
return wiremock.WithApiMappingBuilder((adminApiMappingBuilder, _) => configure.Invoke(adminApiMappingBuilder));
}
/// <summary>
/// Use WireMock Client's AdminApiMappingBuilder to configure the WireMock.Net resource.
/// </summary>
/// <param name="wiremock">The <see cref="IResourceBuilder{WireMockServerResource}"/>.</param>
/// <param name="configure">Delegate that will be invoked to configure the WireMock.Net resource.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithApiMappingBuilder(this IResourceBuilder<WireMockServerResource> wiremock, Func<AdminApiMappingBuilder, CancellationToken, Task> configure)
{
Guard.NotNull(wiremock);
wiremock.ApplicationBuilder.Services.TryAddLifecycleHook<WireMockServerLifecycleHook>();
wiremock.Resource.Arguments.ApiMappingBuilder = configure;
return wiremock;
}
/// <summary>
/// Enables the WireMockInspect, a cross-platform UI app that facilitates WireMock troubleshooting.
/// This requires installation of the WireMockInspector tool.
/// <code>
/// dotnet tool install WireMockInspector --global --no-cache --ignore-failed-sources
/// </code>
/// </summary>
/// <param name="builder">The <see cref="IResourceBuilder{WireMockNetResource}"/>.</param>
/// <returns></returns>
public static IResourceBuilder<WireMockServerResource> WithWireMockInspectorCommand(this IResourceBuilder<WireMockServerResource> builder)
{
Guard.NotNull(builder);
CommandOptions commandOptions = new()
{
Description = "Requires installation of the WireMockInspector (https://github.com/WireMock-Net/WireMockInspector) tool:\ndotnet tool install WireMockInspector --global --no-cache --ignore-failed-sources",
UpdateState = OnUpdateResourceState,
IconName = "BoxSearch",
IconVariant = IconVariant.Filled
};
builder.WithCommand(
name: "wiremock-inspector",
displayName: "WireMock Inspector",
executeCommand: context => OnRunOpenInspectorCommandAsync(builder),
commandOptions: commandOptions);
return builder;
}
private static Task<ExecuteCommandResult> OnRunOpenInspectorCommandAsync(IResourceBuilder<WireMockServerResource> builder)
{
WireMockInspector.Inspect(builder.Resource.GetEndpoint().Url);
return Task.FromResult(CommandResults.Success());
}
private static ResourceCommandState OnUpdateResourceState(UpdateCommandStateContext context)
{
return context.ResourceSnapshot.HealthStatus is HealthStatus.Healthy
? ResourceCommandState.Enabled
: ResourceCommandState.Disabled;
}
}

View File

@@ -1,30 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsAspireHost>true</IsAspireHost>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../../src/WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
</PropertyGroup>
<ItemGroup>
<!-- https://learn.microsoft.com/en-us/dotnet/aspire/extensibility/custom-resources?tabs=windows#create-library-for-resource-extension -->
<ProjectReference Include="..\..\src\WireMock.Net.Aspire\WireMock.Net.Aspire.csproj" IsAspireProjectResource="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="8.2.2" />
</ItemGroup>
<ItemGroup>
<None Update="WireMockMappings\*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.2.0" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../../src/WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
</PropertyGroup>
<ItemGroup>
<!-- https://learn.microsoft.com/en-us/dotnet/aspire/extensibility/custom-resources?tabs=windows#create-library-for-resource-extension -->
<ProjectReference Include="..\..\src\WireMock.Net.Aspire\WireMock.Net.Aspire.csproj" IsAspireProjectResource="false" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.2.0" />
</ItemGroup>
<ItemGroup>
<None Update="WireMockMappings\*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@@ -1,46 +1,48 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<SonarQubeExclude>true</SonarQubeExclude>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../../src/WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="8.2.2" />
<PackageReference Include="Codecov" Version="1.13.0" />
<PackageReference Include="coverlet.msbuild" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="xunit" Version="2.8.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Aspire\WireMock.Net.Aspire.csproj" IsAspireProjectResource="false" />
<ProjectReference Include="..\WireMock.Net.Aspire.TestAppHost\WireMock.Net.Aspire.TestAppHost.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Aspire.Hosting.Testing" />
<Using Include="Xunit" />
</ItemGroup>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<SonarQubeExclude>true</SonarQubeExclude>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../../src/WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.Testing" Version="9.2.0" />
<PackageReference Include="Codecov" Version="1.13.0" />
<PackageReference Include="coverlet.msbuild" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="xunit" Version="2.8.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Aspire\WireMock.Net.Aspire.csproj" IsAspireProjectResource="false" />
<ProjectReference Include="..\WireMock.Net.Aspire.TestAppHost\WireMock.Net.Aspire.TestAppHost.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="Aspire.Hosting" />
<Using Include="Aspire.Hosting.ApplicationModel" />
<Using Include="Aspire.Hosting.Testing" />
<Using Include="Xunit" />
</ItemGroup>
</Project>

View File

@@ -1,96 +1,98 @@
// Copyright © WireMock.Net
using System.Net.Sockets;
using FluentAssertions;
using Moq;
namespace WireMock.Net.Aspire.Tests;
public class WireMockServerBuilderExtensionsTests
{
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("\t")]
public void AddWireMock_WithNullOrWhiteSpaceName_ShouldThrowException(string? name)
{
// Arrange
var builder = Mock.Of<IDistributedApplicationBuilder>();
// Act
Action act = () => builder.AddWireMock(name!, 12345);
// Assert
act.Should().Throw<Exception>();
}
[Fact]
public void AddWireMock_WithInvalidPort_ShouldThrowArgumentOutOfRangeException()
{
// Arrange
const int invalidPort = -1;
var builder = Mock.Of<IDistributedApplicationBuilder>();
// Act
Action act = () => builder.AddWireMock("ValidName", invalidPort);
// Assert
act.Should().Throw<ArgumentOutOfRangeException>().WithMessage("Specified argument was out of the range of valid values. (Parameter 'port')");
}
[Fact]
public void AddWireMock()
{
// Arrange
var name = $"apiservice{Guid.NewGuid()}";
const int port = 12345;
const string username = "admin";
const string password = "test";
var builder = DistributedApplication.CreateBuilder();
// Act
var wiremock = builder
.AddWireMock(name, port)
.WithAdminUserNameAndPassword(username, password)
.WithReadStaticMappings();
// Assert
wiremock.Resource.Should().NotBeNull();
wiremock.Resource.Name.Should().Be(name);
wiremock.Resource.Arguments.Should().BeEquivalentTo(new WireMockServerArguments
{
AdminPassword = password,
AdminUsername = username,
ReadStaticMappings = true,
WatchStaticMappings = false,
MappingsPath = null,
HttpPort = port
});
wiremock.Resource.Annotations.Should().HaveCount(4);
var containerImageAnnotation = wiremock.Resource.Annotations.OfType<ContainerImageAnnotation>().FirstOrDefault();
containerImageAnnotation.Should().BeEquivalentTo(new ContainerImageAnnotation
{
Image = "sheyenrath/wiremock.net-alpine",
Registry = null,
Tag = "latest"
});
var endpointAnnotation = wiremock.Resource.Annotations.OfType<EndpointAnnotation>().FirstOrDefault();
endpointAnnotation.Should().BeEquivalentTo(new EndpointAnnotation(
protocol: ProtocolType.Tcp,
uriScheme: "http",
transport: null,
name: null,
port: port,
targetPort: 80,
isExternal: null,
isProxied: true
));
wiremock.Resource.Annotations.OfType<EnvironmentCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
wiremock.Resource.Annotations.OfType<CommandLineArgsCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
}
// Copyright © WireMock.Net
using System.Net.Sockets;
using FluentAssertions;
using Moq;
namespace WireMock.Net.Aspire.Tests;
public class WireMockServerBuilderExtensionsTests
{
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("\t")]
public void AddWireMock_WithNullOrWhiteSpaceName_ShouldThrowException(string? name)
{
// Arrange
var builder = Mock.Of<IDistributedApplicationBuilder>();
// Act
Action act = () => builder.AddWireMock(name!, 12345);
// Assert
act.Should().Throw<Exception>();
}
[Fact]
public void AddWireMock_WithInvalidPort_ShouldThrowArgumentOutOfRangeException()
{
// Arrange
const int invalidPort = -1;
var builder = Mock.Of<IDistributedApplicationBuilder>();
// Act
Action act = () => builder.AddWireMock("ValidName", invalidPort);
// Assert
act.Should().Throw<ArgumentOutOfRangeException>().WithMessage("Specified argument was out of the range of valid values. (Parameter 'port')");
}
[Fact]
public void AddWireMock()
{
// Arrange
var name = $"apiservice{Guid.NewGuid()}";
const int port = 12345;
const string username = "admin";
const string password = "test";
var builder = DistributedApplication.CreateBuilder();
// Act
var wiremock = builder
.AddWireMock(name, port)
.WithAdminUserNameAndPassword(username, password)
.WithReadStaticMappings();
// Assert
wiremock.Resource.Should().NotBeNull();
wiremock.Resource.Name.Should().Be(name);
wiremock.Resource.Arguments.Should().BeEquivalentTo(new WireMockServerArguments
{
AdminPassword = password,
AdminUsername = username,
ReadStaticMappings = true,
WatchStaticMappings = false,
MappingsPath = null,
HttpPort = port
});
wiremock.Resource.Annotations.Should().HaveCount(5);
var containerImageAnnotation = wiremock.Resource.Annotations.OfType<ContainerImageAnnotation>().FirstOrDefault();
containerImageAnnotation.Should().BeEquivalentTo(new ContainerImageAnnotation
{
Image = "sheyenrath/wiremock.net-alpine",
Registry = null,
Tag = "latest"
});
var endpointAnnotation = wiremock.Resource.Annotations.OfType<EndpointAnnotation>().FirstOrDefault();
endpointAnnotation.Should().BeEquivalentTo(new EndpointAnnotation(
protocol: ProtocolType.Tcp,
uriScheme: "http",
transport: null,
name: null,
port: port,
targetPort: 80,
isExternal: null,
isProxied: true
));
wiremock.Resource.Annotations.OfType<EnvironmentCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
wiremock.Resource.Annotations.OfType<CommandLineArgsCallbackAnnotation>().FirstOrDefault().Should().NotBeNull();
wiremock.Resource.Annotations.OfType<ResourceCommandAnnotation>().FirstOrDefault().Should().NotBeNull();
}
}