mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-01-14 07:33:33 +01:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ca394b7f6 | ||
|
|
b04000bfdd | ||
|
|
93ab4e1853 | ||
|
|
80b5eaac6e | ||
|
|
a1dc2ba646 | ||
|
|
934c444902 | ||
|
|
83d178bdb5 | ||
|
|
d91b5d5831 | ||
|
|
43b96ce340 | ||
|
|
4d8cf43357 |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,3 +1,17 @@
|
||||
# 1.4.15 (19 May 2021)
|
||||
- [#615](https://github.com/WireMock-Net/WireMock.Net/pull/615) - Add support for multiple webhooks [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#614](https://github.com/WireMock-Net/WireMock.Net/issues/614) - Is it possible to some how send multiple webhooks? [feature]
|
||||
|
||||
# 1.4.14 (11 May 2021)
|
||||
- [#610](https://github.com/WireMock-Net/WireMock.Net/pull/610) - Fix some SonarCloud issues in UnitTests contributed by [StefH](https://github.com/StefH)
|
||||
- [#611](https://github.com/WireMock-Net/WireMock.Net/pull/611) - Allow to add custom service registrations when using ASP.NET Core [feature] contributed by [starkpl](https://github.com/starkpl)
|
||||
- [#612](https://github.com/WireMock-Net/WireMock.Net/pull/612) - Don't run SonarCloud tasks for PullRequests [feature] contributed by [StefH](https://github.com/StefH)
|
||||
|
||||
# 1.4.13 (26 April 2021)
|
||||
- [#607](https://github.com/WireMock-Net/WireMock.Net/pull/607) - Bump System.Text.Encodings.Web from 4.5.0 to 4.5.1 in /examples/WireMock.Net.StandAlone.Net461 [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
|
||||
- [#609](https://github.com/WireMock-Net/WireMock.Net/pull/609) - Add possibility to use settings to generate MappingModel models with wildcard path parameters. [feature] contributed by [StefH](https://github.com/StefH)
|
||||
- [#608](https://github.com/WireMock-Net/WireMock.Net/issues/608) - Import from OpenApi generates model with path parameter narrowed in range (example value=42 instead of '*') [feature]
|
||||
|
||||
# 1.4.12 (22 April 2021)
|
||||
- [#605](https://github.com/WireMock-Net/WireMock.Net/pull/605) - Bump System.Net.Http from 4.3.3 to 4.3.4 in /src/WireMock.Net [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
|
||||
- [#606](https://github.com/WireMock-Net/WireMock.Net/pull/606) - Bump System.Net.Http from 4.3.3 to 4.3.4 in /examples/WireMock.Net.Service [dependencies] contributed by [dependabot[bot]](https://github.com/apps/dependabot)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>1.4.12</VersionPrefix>
|
||||
<VersionPrefix>1.4.15</VersionPrefix>
|
||||
<PackageReleaseNotes>See CHANGELOG.md</PackageReleaseNotes>
|
||||
<PackageIconUrl>https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/WireMock.Net-Logo.png</PackageIconUrl>
|
||||
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
https://github.com/StefH/GitHubReleaseNotes
|
||||
|
||||
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc --version 1.4.12
|
||||
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc --version 1.4.15
|
||||
@@ -36,6 +36,7 @@ For more info, see also this WIKI page: [What is WireMock.Net](https://github.co
|
||||
| **WireMock.Net.FluentAssertions** | [](https://www.nuget.org/packages/WireMock.Net.FluentAssertions) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.FluentAssertions)
|
||||
| **WireMock.Net.RestClient** | [](https://www.nuget.org/packages/WireMock.Net.RestClient) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.RestClient)
|
||||
| **WireMock.Net.Matchers.CSharpCode** | [](https://www.nuget.org/packages/WireMock.Net.Matchers.CSharpCode) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.Matchers.CSharpCode)
|
||||
| **WireMock.Net.OpenApiParser** | [](https://www.nuget.org/packages/WireMock.Net.OpenApiParser) | [](https://www.myget.org/feed/wiremock-net/package/nuget/WireMock.Net.OpenApiParser)
|
||||
|
||||
## Development
|
||||
For the supported frameworks and build information, see [this](https://github.com/WireMock-Net/WireMock.Net/wiki/Development-Information) page.
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=funcs/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Heyenrath/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Jmes/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Raml/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=randomizer/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Stef/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Webhook/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Webhooks/@EntryIndexedValue">True</s:Boolean>
|
||||
</wpf:ResourceDictionary>
|
||||
@@ -28,6 +28,7 @@ jobs:
|
||||
|
||||
- task: SonarCloudPrepare@1
|
||||
displayName: 'Prepare analysis on SonarCloud'
|
||||
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
|
||||
inputs:
|
||||
SonarCloud: SonarCloud
|
||||
organization: wiremock-net
|
||||
@@ -52,9 +53,11 @@ jobs:
|
||||
|
||||
- task: SonarCloudAnalyze@1
|
||||
displayName: 'SonarCloud: Run Code Analysis'
|
||||
condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) # Do not run for PullRequests
|
||||
|
||||
- task: SonarCloudPublish@1
|
||||
displayName: 'SonarCloud: Publish Quality Gate Result'
|
||||
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'
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace WireMock.Net.ConsoleApplication
|
||||
//},
|
||||
PreWireMockMiddlewareInit = app => { System.Console.WriteLine($"PreWireMockMiddlewareInit : {app.GetType()}"); },
|
||||
PostWireMockMiddlewareInit = app => { System.Console.WriteLine($"PostWireMockMiddlewareInit : {app.GetType()}"); },
|
||||
AdditionalServiceRegistration = services => { System.Console.WriteLine($"AdditionalServiceRegistration : {services.GetType()}"); },
|
||||
Logger = new WireMockConsoleLogger(),
|
||||
|
||||
HandlebarsRegistrationCallback = (handlebarsContext, fileSystemHandler) =>
|
||||
|
||||
@@ -3,9 +3,11 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using WireMock.Admin.Mappings;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Net.OpenApiParser.Extensions;
|
||||
using WireMock.Net.OpenApiParser.Settings;
|
||||
using WireMock.Net.OpenApiParser.Types;
|
||||
using WireMock.Server;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Net.OpenApiParser.Extensions;
|
||||
|
||||
namespace WireMock.Net.OpenApiParser.ConsoleApp
|
||||
{
|
||||
@@ -23,13 +25,18 @@ namespace WireMock.Net.OpenApiParser.ConsoleApp
|
||||
ReadStaticMappings = false,
|
||||
WatchStaticMappings = false,
|
||||
WatchStaticMappingsInSubdirectories = false,
|
||||
Logger = new WireMockConsoleLogger(),
|
||||
Logger = new WireMockConsoleLogger()
|
||||
});
|
||||
Console.WriteLine("WireMockServer listening at {0}", string.Join(",", server.Urls));
|
||||
|
||||
server.SetBasicAuthentication("a", "b");
|
||||
|
||||
server.WithMappingFromOpenApiFile(path, out var diag);
|
||||
var settings = new WireMockOpenApiParserSettings
|
||||
{
|
||||
PathPatternToUse = ExampleValueType.Wildcard
|
||||
};
|
||||
|
||||
server.WithMappingFromOpenApiFile(path, settings, out var diag);
|
||||
|
||||
Console.WriteLine("Press any key to stop the server");
|
||||
System.Console.ReadKey();
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
|
||||
<package id="System.Security.Principal.Windows" version="4.5.1" targetFramework="net461" />
|
||||
<package id="System.Text.Encodings.Web" version="4.5.0" targetFramework="net461" />
|
||||
<package id="System.Text.Encodings.Web" version="4.5.1" targetFramework="net461" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net461" />
|
||||
<package id="XPath2" version="1.1.0" targetFramework="net461" />
|
||||
</packages>
|
||||
@@ -57,5 +57,10 @@ namespace WireMock.Admin.Mappings
|
||||
/// The Webhook.
|
||||
/// </summary>
|
||||
public WebhookModel Webhook { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Webhooks.
|
||||
/// </summary>
|
||||
public WebhookModel[] Webhooks { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,19 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.OpenApi.Readers;
|
||||
using SharpYaml.Model;
|
||||
using Stef.Validation;
|
||||
using WireMock.Net.OpenApiParser.Settings;
|
||||
using WireMock.Server;
|
||||
|
||||
namespace WireMock.Net.OpenApiParser.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Some extension methods for <see cref="IWireMockServer"/>.
|
||||
/// </summary>
|
||||
public static class WireMockServerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
@@ -15,18 +22,26 @@ namespace WireMock.Net.OpenApiParser.Extensions
|
||||
/// <param name="server">The WireMockServer instance</param>
|
||||
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
||||
/// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing</param>
|
||||
[PublicAPI]
|
||||
public static IWireMockServer WithMappingFromOpenApiFile(this IWireMockServer server, string path, out OpenApiDiagnostic diagnostic)
|
||||
{
|
||||
if (server == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(server));
|
||||
}
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(path));
|
||||
}
|
||||
return WithMappingFromOpenApiFile(server, path, null, out diagnostic);
|
||||
}
|
||||
|
||||
var mappings = new WireMockOpenApiParser().FromFile(path, out diagnostic);
|
||||
/// <summary>
|
||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 file.
|
||||
/// </summary>
|
||||
/// <param name="server">The WireMockServer instance</param>
|
||||
/// <param name="path">Path containing OpenAPI file to parse and use the mappings.</param>
|
||||
/// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing</param>
|
||||
/// <param name="settings">Additional settings</param>
|
||||
[PublicAPI]
|
||||
public static IWireMockServer WithMappingFromOpenApiFile(this IWireMockServer server, string path, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
||||
{
|
||||
Guard.NotNull(server, nameof(server));
|
||||
Guard.NotNullOrEmpty(path, nameof(path));
|
||||
|
||||
var mappings = new WireMockOpenApiParser().FromFile(path, settings, out diagnostic);
|
||||
|
||||
return server.WithMapping(mappings.ToArray());
|
||||
}
|
||||
@@ -37,9 +52,27 @@ namespace WireMock.Net.OpenApiParser.Extensions
|
||||
/// <param name="server">The WireMockServer instance</param>
|
||||
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
||||
/// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing</param>
|
||||
[PublicAPI]
|
||||
public static IWireMockServer WithMappingFromOpenApiStream(this IWireMockServer server, Stream stream, out OpenApiDiagnostic diagnostic)
|
||||
{
|
||||
var mappings = new WireMockOpenApiParser().FromStream(stream, out diagnostic);
|
||||
return WithMappingFromOpenApiStream(server, stream, null, out diagnostic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register the mappings via an OpenAPI (swagger) V2 or V3 stream.
|
||||
/// </summary>
|
||||
/// <param name="server">The WireMockServer instance</param>
|
||||
/// <param name="stream">Stream containing OpenAPI description to parse and use the mappings.</param>
|
||||
/// <param name="settings">Additional settings</param>
|
||||
/// <param name="diagnostic">Returns diagnostic object containing errors detected during parsing</param>
|
||||
[PublicAPI]
|
||||
public static IWireMockServer WithMappingFromOpenApiStream(this IWireMockServer server, Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
||||
{
|
||||
Guard.NotNull(server, nameof(server));
|
||||
Guard.NotNull(stream, nameof(stream));
|
||||
Guard.NotNull(settings, nameof(settings));
|
||||
|
||||
var mappings = new WireMockOpenApiParser().FromStream(stream, settings, out diagnostic);
|
||||
|
||||
return server.WithMapping(mappings.ToArray());
|
||||
}
|
||||
@@ -49,9 +82,14 @@ namespace WireMock.Net.OpenApiParser.Extensions
|
||||
/// </summary>
|
||||
/// <param name="server">The WireMockServer instance</param>
|
||||
/// <param name="document">The OpenAPI document to use as mappings.</param>
|
||||
public static IWireMockServer WithMappingFromOpenApiDocument(this IWireMockServer server, OpenApiDocument document)
|
||||
/// <param name="settings">Additional settings [optional]</param>
|
||||
[PublicAPI]
|
||||
public static IWireMockServer WithMappingFromOpenApiDocument(this IWireMockServer server, OpenApiDocument document, WireMockOpenApiParserSettings settings = null)
|
||||
{
|
||||
var mappings = new WireMockOpenApiParser().FromDocument(document);
|
||||
Guard.NotNull(server, nameof(server));
|
||||
Guard.NotNull(document, nameof(document));
|
||||
|
||||
var mappings = new WireMockOpenApiParser().FromDocument(document, settings);
|
||||
|
||||
return server.WithMapping(mappings.ToArray());
|
||||
}
|
||||
|
||||
@@ -1,37 +1,57 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.OpenApi.Readers;
|
||||
using WireMock.Admin.Mappings;
|
||||
|
||||
namespace WireMock.Net.OpenApiParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Parse a OpenApi/Swagger/V2/V3 or Raml to WireMock MappingModels.
|
||||
/// </summary>
|
||||
public interface IWireMockOpenApiParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Generate <see cref="IEnumerable{MappingModel}"/> from an <seealso cref="OpenApiDocument"/>.
|
||||
/// </summary>
|
||||
/// <param name="document">The source OpenApiDocument</param>
|
||||
/// <returns>MappingModel</returns>
|
||||
IEnumerable<MappingModel> FromDocument(OpenApiDocument document);
|
||||
|
||||
/// <summary>
|
||||
/// Generate <see cref="IEnumerable{MappingModel}"/> from a <seealso cref="Stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The source stream</param>
|
||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
||||
/// <returns>MappingModel</returns>
|
||||
IEnumerable<MappingModel> FromStream(Stream stream, out OpenApiDiagnostic diagnostic);
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.OpenApi.Readers;
|
||||
using WireMock.Admin.Mappings;
|
||||
using WireMock.Net.OpenApiParser.Settings;
|
||||
|
||||
namespace WireMock.Net.OpenApiParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Parse a OpenApi/Swagger/V2/V3 or Raml to WireMock MappingModels.
|
||||
/// </summary>
|
||||
public interface IWireMockOpenApiParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Generate <see cref="IEnumerable{MappingModel}"/> from a file-path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3 or Raml file.</param>
|
||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
||||
/// <returns>MappingModel</returns>
|
||||
IEnumerable<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic);
|
||||
}
|
||||
/// <returns>MappingModel</returns>
|
||||
IEnumerable<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic);
|
||||
|
||||
/// <summary>
|
||||
/// Generate <see cref="IEnumerable{MappingModel}"/> from a file-path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to read the OpenApi/Swagger/V2/V3 or Raml file.</param>
|
||||
/// <param name="settings">Additional settings</param>
|
||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
||||
/// <returns>MappingModel</returns>
|
||||
IEnumerable<MappingModel> FromFile(string path, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic);
|
||||
|
||||
/// <summary>
|
||||
/// Generate <see cref="IEnumerable{MappingModel}"/> from an <seealso cref="OpenApiDocument"/>.
|
||||
/// </summary>
|
||||
/// <param name="document">The source OpenApiDocument</param>
|
||||
/// <param name="settings">Additional settings [optional]</param>
|
||||
/// <returns>MappingModel</returns>
|
||||
IEnumerable<MappingModel> FromDocument(OpenApiDocument document, WireMockOpenApiParserSettings settings = null);
|
||||
|
||||
/// <summary>
|
||||
/// Generate <see cref="IEnumerable{MappingModel}"/> from a <seealso cref="Stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The source stream</param>
|
||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
||||
/// <returns>MappingModel</returns>
|
||||
IEnumerable<MappingModel> FromStream(Stream stream, out OpenApiDiagnostic diagnostic);
|
||||
|
||||
/// <summary>
|
||||
/// Generate <see cref="IEnumerable{MappingModel}"/> from a <seealso cref="Stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The source stream</param>
|
||||
/// <param name="settings">Additional settings</param>
|
||||
/// <param name="diagnostic">OpenApiDiagnostic output</param>
|
||||
/// <returns>MappingModel</returns>
|
||||
IEnumerable<MappingModel> FromStream(Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic);
|
||||
}
|
||||
}
|
||||
276
src/WireMock.Net.OpenApiParser/Mappers/OpenApiPathsMapper.cs
Normal file
276
src/WireMock.Net.OpenApiParser/Mappers/OpenApiPathsMapper.cs
Normal file
@@ -0,0 +1,276 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.OpenApi;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.OpenApi.Writers;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using WireMock.Admin.Mappings;
|
||||
using WireMock.Net.OpenApiParser.Extensions;
|
||||
using WireMock.Net.OpenApiParser.Settings;
|
||||
using WireMock.Net.OpenApiParser.Types;
|
||||
using WireMock.Net.OpenApiParser.Utils;
|
||||
|
||||
namespace WireMock.Net.OpenApiParser.Mappers
|
||||
{
|
||||
internal class OpenApiPathsMapper
|
||||
{
|
||||
private readonly WireMockOpenApiParserSettings _settings;
|
||||
private readonly ExampleValueGenerator _exampleValueGenerator;
|
||||
|
||||
public OpenApiPathsMapper(WireMockOpenApiParserSettings settings)
|
||||
{
|
||||
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
||||
_exampleValueGenerator = new ExampleValueGenerator(settings);
|
||||
}
|
||||
|
||||
public IEnumerable<MappingModel> ToMappingModels(OpenApiPaths paths)
|
||||
{
|
||||
return paths.Select(p => MapPath(p.Key, p.Value)).SelectMany(x => x);
|
||||
}
|
||||
|
||||
private IEnumerable<MappingModel> MapPaths(OpenApiPaths paths)
|
||||
{
|
||||
return paths.Select(p => MapPath(p.Key, p.Value)).SelectMany(x => x);
|
||||
}
|
||||
|
||||
private IEnumerable<MappingModel> MapPath(string path, OpenApiPathItem pathItem)
|
||||
{
|
||||
return pathItem.Operations.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value));
|
||||
}
|
||||
|
||||
private MappingModel MapOperationToMappingModel(string path, string httpMethod, OpenApiOperation operation)
|
||||
{
|
||||
var queryParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Query);
|
||||
var pathParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Path);
|
||||
var response = operation.Responses.FirstOrDefault();
|
||||
|
||||
TryGetContent(response.Value?.Content, out OpenApiMediaType responseContent, out string responseContentType);
|
||||
var responseSchema = response.Value?.Content?.FirstOrDefault().Value?.Schema;
|
||||
var responseExample = responseContent?.Example;
|
||||
|
||||
var body = responseExample != null ? MapOpenApiAnyToJToken(responseExample) : MapSchemaToObject(responseSchema);
|
||||
|
||||
if (int.TryParse(response.Key, out var httpStatusCode))
|
||||
{
|
||||
httpStatusCode = 200;
|
||||
}
|
||||
|
||||
return new MappingModel
|
||||
{
|
||||
Guid = Guid.NewGuid(),
|
||||
Request = new RequestModel
|
||||
{
|
||||
Methods = new[] { httpMethod },
|
||||
Path = MapPathWithParameters(path, pathParameters),
|
||||
Params = MapQueryParameters(queryParameters)
|
||||
},
|
||||
Response = new ResponseModel
|
||||
{
|
||||
StatusCode = httpStatusCode,
|
||||
Headers = MapHeaders(responseContentType, response.Value?.Headers),
|
||||
BodyAsJson = body
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private bool TryGetContent(IDictionary<string, OpenApiMediaType> contents, out OpenApiMediaType openApiMediaType, out string contentType)
|
||||
{
|
||||
openApiMediaType = null;
|
||||
contentType = null;
|
||||
|
||||
if (contents == null || contents.Values.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (contents.TryGetValue("application/json", out var content))
|
||||
{
|
||||
openApiMediaType = content;
|
||||
contentType = "application/json";
|
||||
}
|
||||
else
|
||||
{
|
||||
var first = contents.FirstOrDefault();
|
||||
openApiMediaType = first.Value;
|
||||
contentType = first.Key;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private object MapSchemaToObject(OpenApiSchema schema, string name = null)
|
||||
{
|
||||
if (schema == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (schema.GetSchemaType())
|
||||
{
|
||||
case SchemaType.Array:
|
||||
var jArray = new JArray();
|
||||
for (int i = 0; i < _settings.NumberOfArrayItems; i++)
|
||||
{
|
||||
if (schema.Items.Properties.Count > 0)
|
||||
{
|
||||
var arrayItem = new JObject();
|
||||
foreach (var property in schema.Items.Properties)
|
||||
{
|
||||
var objectValue = MapSchemaToObject(property.Value, property.Key);
|
||||
if (objectValue is JProperty jp)
|
||||
{
|
||||
arrayItem.Add(jp);
|
||||
}
|
||||
else
|
||||
{
|
||||
arrayItem.Add(new JProperty(property.Key, objectValue));
|
||||
}
|
||||
}
|
||||
|
||||
jArray.Add(arrayItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
jArray.Add(MapSchemaToObject(schema.Items, name));
|
||||
}
|
||||
}
|
||||
|
||||
return jArray;
|
||||
|
||||
case SchemaType.Boolean:
|
||||
case SchemaType.Integer:
|
||||
case SchemaType.Number:
|
||||
case SchemaType.String:
|
||||
return _exampleValueGenerator.GetExampleValue(schema);
|
||||
|
||||
case SchemaType.Object:
|
||||
var propertyAsJObject = new JObject();
|
||||
foreach (var schemaProperty in schema.Properties)
|
||||
{
|
||||
string propertyName = schemaProperty.Key;
|
||||
var openApiSchema = schemaProperty.Value;
|
||||
if (openApiSchema.GetSchemaType() == SchemaType.Object)
|
||||
{
|
||||
var mapped = MapSchemaToObject(schemaProperty.Value, schemaProperty.Key);
|
||||
if (mapped is JProperty jp)
|
||||
{
|
||||
propertyAsJObject.Add(jp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool propertyIsNullable = openApiSchema.Nullable || (openApiSchema.TryGetXNullable(out bool x) && x);
|
||||
|
||||
propertyAsJObject.Add(new JProperty(propertyName, _exampleValueGenerator.GetExampleValue(openApiSchema)));
|
||||
}
|
||||
}
|
||||
|
||||
return name != null ? new JProperty(name, propertyAsJObject) : (JToken)propertyAsJObject;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private string MapPathWithParameters(string path, IEnumerable<OpenApiParameter> parameters)
|
||||
{
|
||||
if (parameters == null)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
string newPath = path;
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
newPath = newPath.Replace($"{{{parameter.Name}}}", GetExampleValue(parameter.Schema, _settings.PathPatternToUse));
|
||||
}
|
||||
|
||||
return newPath;
|
||||
}
|
||||
|
||||
private JToken MapOpenApiAnyToJToken(IOpenApiAny any)
|
||||
{
|
||||
if (any == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using var outputString = new StringWriter();
|
||||
var writer = new OpenApiJsonWriter(outputString);
|
||||
any.Write(writer, OpenApiSpecVersion.OpenApi3_0);
|
||||
|
||||
return JObject.Parse(outputString.ToString());
|
||||
}
|
||||
|
||||
private IDictionary<string, object> MapHeaders(string responseContentType, IDictionary<string, OpenApiHeader> headers)
|
||||
{
|
||||
var mappedHeaders = headers.ToDictionary(
|
||||
item => item.Key,
|
||||
item => GetExampleValue(null, _settings.HeaderPatternToUse) as object
|
||||
);
|
||||
|
||||
if (!string.IsNullOrEmpty(responseContentType))
|
||||
{
|
||||
if (!mappedHeaders.ContainsKey("Content-Type"))
|
||||
{
|
||||
mappedHeaders.Add("Content-Type", responseContentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
mappedHeaders["Content-Type"] = responseContentType;
|
||||
}
|
||||
}
|
||||
|
||||
return mappedHeaders.Keys.Any() ? mappedHeaders : null;
|
||||
}
|
||||
|
||||
private IList<ParamModel> MapQueryParameters(IEnumerable<OpenApiParameter> queryParameters)
|
||||
{
|
||||
var list = queryParameters
|
||||
.Select(qp => new ParamModel
|
||||
{
|
||||
Name = qp.Name,
|
||||
Matchers = new[]
|
||||
{
|
||||
new MatcherModel
|
||||
{
|
||||
Name = "ExactMatcher",
|
||||
Pattern = GetDefaultValueAsStringForSchemaType(qp.Schema)
|
||||
}
|
||||
}
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return list.Any() ? list : null;
|
||||
}
|
||||
|
||||
private string GetDefaultValueAsStringForSchemaType(OpenApiSchema schema)
|
||||
{
|
||||
var value = _exampleValueGenerator.GetExampleValue(schema);
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case string valueAsString:
|
||||
return valueAsString;
|
||||
|
||||
default:
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private string GetExampleValue(OpenApiSchema schema, ExampleValueType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ExampleValueType.Value:
|
||||
return GetDefaultValueAsStringForSchemaType(schema);
|
||||
|
||||
default:
|
||||
return "*";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace WireMock.Net.OpenApiParser.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// A class defining the example values to use for the different types.
|
||||
/// </summary>
|
||||
public class WireMockOpenApiParserExampleValues
|
||||
{
|
||||
#pragma warning disable 1591
|
||||
public bool Boolean { get; set; } = true;
|
||||
|
||||
public int Integer { get; set; } = 42;
|
||||
|
||||
public float Float { get; set; } = 4.2f;
|
||||
|
||||
public double Double { get; set; } = 4.2d;
|
||||
|
||||
public Func<DateTime> Date { get; set; } = () => System.DateTime.UtcNow.Date;
|
||||
|
||||
public Func<DateTime> DateTime { get; set; } = () => System.DateTime.UtcNow;
|
||||
|
||||
public byte[] Bytes { get; set; } = { 48, 49, 50 };
|
||||
|
||||
public object Object { get; set; } = "example-object";
|
||||
|
||||
public string String { get; set; } = "example-string";
|
||||
#pragma warning restore 1591
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using WireMock.Net.OpenApiParser.Types;
|
||||
|
||||
namespace WireMock.Net.OpenApiParser.Settings
|
||||
{
|
||||
/// <summary>
|
||||
/// The WireMockOpenApiParser Settings
|
||||
/// </summary>
|
||||
public class WireMockOpenApiParserSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of array items to generate (default is 3).
|
||||
/// </summary>
|
||||
public int NumberOfArrayItems { get; set; } = 3;
|
||||
|
||||
/// <summary>
|
||||
/// The example value type to use when generating a Path
|
||||
/// </summary>
|
||||
public ExampleValueType PathPatternToUse { get; set; } = ExampleValueType.Value;
|
||||
|
||||
/// <summary>
|
||||
/// The example value type to use when generating a Header
|
||||
/// </summary>
|
||||
public ExampleValueType HeaderPatternToUse { get; set; } = ExampleValueType.Value;
|
||||
|
||||
/// <summary>
|
||||
/// The example values to use
|
||||
/// </summary>
|
||||
public WireMockOpenApiParserExampleValues ExampleValues { get; } = new WireMockOpenApiParserExampleValues();
|
||||
}
|
||||
}
|
||||
18
src/WireMock.Net.OpenApiParser/Types/ExampleValueType.cs
Normal file
18
src/WireMock.Net.OpenApiParser/Types/ExampleValueType.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace WireMock.Net.OpenApiParser.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// The example value to use
|
||||
/// </summary>
|
||||
public enum ExampleValueType
|
||||
{
|
||||
/// <summary>
|
||||
/// Use a generated example value based on the SchemaType (default).
|
||||
/// </summary>
|
||||
Value,
|
||||
|
||||
/// <summary>
|
||||
/// Just use a Wildcard (*) character.
|
||||
/// </summary>
|
||||
Wildcard
|
||||
}
|
||||
}
|
||||
@@ -1,49 +1,57 @@
|
||||
using System;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using WireMock.Net.OpenApiParser.Extensions;
|
||||
using WireMock.Net.OpenApiParser.Settings;
|
||||
using WireMock.Net.OpenApiParser.Types;
|
||||
|
||||
namespace WireMock.Net.OpenApiParser.Utils
|
||||
{
|
||||
internal static class ExampleValueGenerator
|
||||
internal class ExampleValueGenerator
|
||||
{
|
||||
public static object GetExampleValue(OpenApiSchema schema)
|
||||
private readonly WireMockOpenApiParserSettings _settings;
|
||||
|
||||
public ExampleValueGenerator(WireMockOpenApiParserSettings settings)
|
||||
{
|
||||
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
||||
}
|
||||
|
||||
public object GetExampleValue(OpenApiSchema schema)
|
||||
{
|
||||
switch (schema?.GetSchemaType())
|
||||
{
|
||||
case SchemaType.Boolean:
|
||||
return true;
|
||||
return _settings.ExampleValues.Boolean;
|
||||
|
||||
case SchemaType.Integer:
|
||||
return 42;
|
||||
return _settings.ExampleValues.Integer;
|
||||
|
||||
case SchemaType.Number:
|
||||
switch (schema?.GetSchemaFormat())
|
||||
{
|
||||
case SchemaFormat.Float:
|
||||
return 4.2f;
|
||||
return _settings.ExampleValues.Float;
|
||||
|
||||
default:
|
||||
return 4.2d;
|
||||
return _settings.ExampleValues.Double;
|
||||
}
|
||||
|
||||
default:
|
||||
switch (schema?.GetSchemaFormat())
|
||||
{
|
||||
case SchemaFormat.Date:
|
||||
return DateTimeUtils.ToRfc3339Date(DateTime.UtcNow);
|
||||
return DateTimeUtils.ToRfc3339Date(_settings.ExampleValues.Date());
|
||||
|
||||
case SchemaFormat.DateTime:
|
||||
return DateTimeUtils.ToRfc3339DateTime(DateTime.UtcNow);
|
||||
return DateTimeUtils.ToRfc3339DateTime(_settings.ExampleValues.DateTime());
|
||||
|
||||
case SchemaFormat.Byte:
|
||||
return new byte[] { 48, 49, 50 };
|
||||
return _settings.ExampleValues.Bytes;
|
||||
|
||||
case SchemaFormat.Binary:
|
||||
return "example-object";
|
||||
return _settings.ExampleValues.Object;
|
||||
|
||||
default:
|
||||
return "example-string";
|
||||
return _settings.ExampleValues.String;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
|
||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
@@ -24,14 +25,11 @@
|
||||
<PackageReference Include="RamlToOpenApiConverter" Version="0.1.1" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
<PackageReference Include="Stef.Validation" Version="0.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Options\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,34 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.OpenApi;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.OpenApi.Readers;
|
||||
using Microsoft.OpenApi.Writers;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using RamlToOpenApiConverter;
|
||||
using WireMock.Admin.Mappings;
|
||||
using WireMock.Net.OpenApiParser.Extensions;
|
||||
using WireMock.Net.OpenApiParser.Types;
|
||||
using WireMock.Net.OpenApiParser.Utils;
|
||||
using WireMock.Net.OpenApiParser.Mappers;
|
||||
using WireMock.Net.OpenApiParser.Settings;
|
||||
|
||||
namespace WireMock.Net.OpenApiParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Parse a OpenApi/Swagger/V2/V3 or Raml to WireMock MappingModels.
|
||||
/// Parse a OpenApi/Swagger/V2/V3 or Raml to WireMock.Net MappingModels.
|
||||
/// </summary>
|
||||
public class WireMockOpenApiParser : IWireMockOpenApiParser
|
||||
{
|
||||
private const int ArrayItems = 3;
|
||||
|
||||
private readonly OpenApiStreamReader _reader = new OpenApiStreamReader();
|
||||
|
||||
/// <inheritdoc cref="IWireMockOpenApiParser.FromFile" />
|
||||
/// <inheritdoc cref="IWireMockOpenApiParser.FromFile(string, out OpenApiDiagnostic)" />
|
||||
[PublicAPI]
|
||||
public IEnumerable<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic)
|
||||
{
|
||||
return FromFile(path, new WireMockOpenApiParserSettings(), out diagnostic);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IWireMockOpenApiParser.FromFile(string, WireMockOpenApiParserSettings, out OpenApiDiagnostic)" />
|
||||
[PublicAPI]
|
||||
public IEnumerable<MappingModel> FromFile(string path, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
||||
{
|
||||
OpenApiDocument document;
|
||||
if (Path.GetExtension(path).EndsWith("raml", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -42,248 +41,28 @@ namespace WireMock.Net.OpenApiParser
|
||||
document = reader.Read(File.OpenRead(path), out diagnostic);
|
||||
}
|
||||
|
||||
return FromDocument(document);
|
||||
return FromDocument(document, settings);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IWireMockOpenApiParser.FromStream" />
|
||||
/// <inheritdoc cref="IWireMockOpenApiParser.FromStream(Stream, out OpenApiDiagnostic)" />
|
||||
[PublicAPI]
|
||||
public IEnumerable<MappingModel> FromStream(Stream stream, out OpenApiDiagnostic diagnostic)
|
||||
{
|
||||
return FromDocument(_reader.Read(stream, out diagnostic));
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IWireMockOpenApiParser.FromDocument" />
|
||||
/// <inheritdoc cref="IWireMockOpenApiParser.FromStream(Stream, WireMockOpenApiParserSettings, out OpenApiDiagnostic)" />
|
||||
[PublicAPI]
|
||||
public IEnumerable<MappingModel> FromDocument(OpenApiDocument openApiDocument)
|
||||
public IEnumerable<MappingModel> FromStream(Stream stream, WireMockOpenApiParserSettings settings, out OpenApiDiagnostic diagnostic)
|
||||
{
|
||||
return MapPaths(openApiDocument.Paths);
|
||||
return FromDocument(_reader.Read(stream, out diagnostic), settings);
|
||||
}
|
||||
|
||||
private static IEnumerable<MappingModel> MapPaths(OpenApiPaths paths)
|
||||
/// <inheritdoc cref="IWireMockOpenApiParser.FromDocument(OpenApiDocument, WireMockOpenApiParserSettings)" />
|
||||
[PublicAPI]
|
||||
public IEnumerable<MappingModel> FromDocument(OpenApiDocument openApiDocument, WireMockOpenApiParserSettings settings = null)
|
||||
{
|
||||
return paths.Select(p => MapPath(p.Key, p.Value)).SelectMany(x => x);
|
||||
}
|
||||
|
||||
private static IEnumerable<MappingModel> MapPath(string path, OpenApiPathItem pathItem)
|
||||
{
|
||||
return pathItem.Operations.Select(o => MapOperationToMappingModel(path, o.Key.ToString().ToUpperInvariant(), o.Value));
|
||||
}
|
||||
|
||||
private static MappingModel MapOperationToMappingModel(string path, string httpMethod, OpenApiOperation operation)
|
||||
{
|
||||
var queryParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Query);
|
||||
var pathParameters = operation.Parameters.Where(p => p.In == ParameterLocation.Path);
|
||||
var response = operation.Responses.FirstOrDefault();
|
||||
TryGetContent(response.Value?.Content, out OpenApiMediaType responseContent, out string responseContentType);
|
||||
var responseSchema = response.Value?.Content?.FirstOrDefault().Value?.Schema;
|
||||
var responseExample = responseContent?.Example;
|
||||
|
||||
var body = responseExample != null ? MapOpenApiAnyToJToken(responseExample) : MapSchemaToObject(responseSchema);
|
||||
|
||||
if (int.TryParse(response.Key, out var httpStatusCode))
|
||||
{
|
||||
httpStatusCode = 200;
|
||||
}
|
||||
|
||||
return new MappingModel
|
||||
{
|
||||
Guid = Guid.NewGuid(),
|
||||
Request = new RequestModel
|
||||
{
|
||||
Methods = new[] { httpMethod },
|
||||
Path = MapPathWithParameters(path, pathParameters),
|
||||
Params = MapQueryParameters(queryParameters)
|
||||
},
|
||||
Response = new ResponseModel
|
||||
{
|
||||
StatusCode = httpStatusCode,
|
||||
Headers = MapHeaders(responseContentType, response.Value?.Headers),
|
||||
BodyAsJson = body
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static bool TryGetContent(IDictionary<string, OpenApiMediaType> contents, out OpenApiMediaType openApiMediaType, out string contentType)
|
||||
{
|
||||
openApiMediaType = null;
|
||||
contentType = null;
|
||||
|
||||
if (contents == null || contents.Values.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (contents.TryGetValue("application/json", out var content))
|
||||
{
|
||||
openApiMediaType = content;
|
||||
contentType = "application/json";
|
||||
}
|
||||
else
|
||||
{
|
||||
var first = contents.FirstOrDefault();
|
||||
openApiMediaType = first.Value;
|
||||
contentType = first.Key;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static object MapSchemaToObject(OpenApiSchema schema, string name = null)
|
||||
{
|
||||
if (schema == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (schema.GetSchemaType())
|
||||
{
|
||||
case SchemaType.Array:
|
||||
var jArray = new JArray();
|
||||
for (int i = 0; i < ArrayItems; i++)
|
||||
{
|
||||
if (schema.Items.Properties.Count > 0)
|
||||
{
|
||||
var arrayItem = new JObject();
|
||||
foreach (var property in schema.Items.Properties)
|
||||
{
|
||||
var objectValue = MapSchemaToObject(property.Value, property.Key);
|
||||
if (objectValue is JProperty jp)
|
||||
{
|
||||
arrayItem.Add(jp);
|
||||
}
|
||||
else
|
||||
{
|
||||
arrayItem.Add(new JProperty(property.Key, objectValue));
|
||||
}
|
||||
}
|
||||
|
||||
jArray.Add(arrayItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
jArray.Add(MapSchemaToObject(schema.Items, name));
|
||||
}
|
||||
}
|
||||
|
||||
return jArray;
|
||||
|
||||
case SchemaType.Boolean:
|
||||
case SchemaType.Integer:
|
||||
case SchemaType.Number:
|
||||
case SchemaType.String:
|
||||
return ExampleValueGenerator.GetExampleValue(schema);
|
||||
|
||||
case SchemaType.Object:
|
||||
var propertyAsJObject = new JObject();
|
||||
foreach (var schemaProperty in schema.Properties)
|
||||
{
|
||||
string propertyName = schemaProperty.Key;
|
||||
var openApiSchema = schemaProperty.Value;
|
||||
if (openApiSchema.GetSchemaType() == SchemaType.Object)
|
||||
{
|
||||
var mapped = MapSchemaToObject(schemaProperty.Value, schemaProperty.Key);
|
||||
if (mapped is JProperty jp)
|
||||
{
|
||||
propertyAsJObject.Add(jp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool propertyIsNullable = openApiSchema.Nullable || (openApiSchema.TryGetXNullable(out bool x) && x);
|
||||
|
||||
propertyAsJObject.Add(new JProperty(propertyName, ExampleValueGenerator.GetExampleValue(openApiSchema)));
|
||||
}
|
||||
}
|
||||
|
||||
return name != null ? new JProperty(name, propertyAsJObject) : (JToken)propertyAsJObject;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static string MapPathWithParameters(string path, IEnumerable<OpenApiParameter> parameters)
|
||||
{
|
||||
if (parameters == null)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
string newPath = path;
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
newPath = newPath.Replace($"{{{parameter.Name}}}", ExampleValueGenerator.GetExampleValue(parameter.Schema).ToString());
|
||||
}
|
||||
|
||||
return newPath;
|
||||
}
|
||||
|
||||
private static JToken MapOpenApiAnyToJToken(IOpenApiAny any)
|
||||
{
|
||||
if (any == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using (var outputString = new StringWriter())
|
||||
{
|
||||
var writer = new OpenApiJsonWriter(outputString);
|
||||
any.Write(writer, OpenApiSpecVersion.OpenApi3_0);
|
||||
|
||||
return JObject.Parse(outputString.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static IDictionary<string, object> MapHeaders(string responseContentType, IDictionary<string, OpenApiHeader> headers)
|
||||
{
|
||||
var mappedHeaders = headers.ToDictionary(item => item.Key, item => ExampleValueGenerator.GetExampleValue(null));
|
||||
if (!string.IsNullOrEmpty(responseContentType))
|
||||
{
|
||||
if (!mappedHeaders.ContainsKey("Content-Type"))
|
||||
{
|
||||
mappedHeaders.Add("Content-Type", responseContentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
mappedHeaders["Content-Type"] = responseContentType;
|
||||
}
|
||||
}
|
||||
|
||||
return mappedHeaders.Keys.Any() ? mappedHeaders : null;
|
||||
}
|
||||
|
||||
private static IList<ParamModel> MapQueryParameters(IEnumerable<OpenApiParameter> queryParameters)
|
||||
{
|
||||
var list = queryParameters
|
||||
.Select(qp => new ParamModel
|
||||
{
|
||||
Name = qp.Name,
|
||||
Matchers = new[]
|
||||
{
|
||||
new MatcherModel
|
||||
{
|
||||
Name = "ExactMatcher",
|
||||
Pattern = GetDefaultValueAsStringForSchemaType(qp.Schema)
|
||||
}
|
||||
}
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return list.Any() ? list : null;
|
||||
}
|
||||
|
||||
private static string GetDefaultValueAsStringForSchemaType(OpenApiSchema schema)
|
||||
{
|
||||
var value = ExampleValueGenerator.GetExampleValue(schema);
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case string valueAsString:
|
||||
return valueAsString;
|
||||
|
||||
default:
|
||||
return value.ToString();
|
||||
}
|
||||
return new OpenApiPathsMapper(settings).ToMappingModels(openApiDocument.Paths);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,9 +95,9 @@ namespace WireMock
|
||||
bool LogMapping { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Webhook.
|
||||
/// The Webhooks.
|
||||
/// </summary>
|
||||
IWebhook Webhook { get; }
|
||||
IWebhook[] Webhooks { get; }
|
||||
|
||||
/// <summary>
|
||||
/// ProvideResponseAsync
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Admin.Mappings;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Models;
|
||||
using WireMock.ResponseProviders;
|
||||
@@ -56,8 +55,8 @@ namespace WireMock
|
||||
/// <inheritdoc cref="IMapping.LogMapping" />
|
||||
public bool LogMapping => !(Provider is DynamicResponseProvider || Provider is DynamicAsyncResponseProvider);
|
||||
|
||||
/// <inheritdoc cref="IMapping.Webhook" />
|
||||
public IWebhook Webhook { get; }
|
||||
/// <inheritdoc cref="IMapping.Webhooks" />
|
||||
public IWebhook[] Webhooks { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Mapping"/> class.
|
||||
@@ -73,7 +72,7 @@ namespace WireMock
|
||||
/// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param>
|
||||
/// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param>
|
||||
/// <param name="stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional]</param>
|
||||
/// <param name="webhook">The Webhook. [Optional]</param>
|
||||
/// <param name="webhooks">The Webhooks. [Optional]</param>
|
||||
public Mapping(
|
||||
Guid guid,
|
||||
[CanBeNull] string title,
|
||||
@@ -86,7 +85,7 @@ namespace WireMock
|
||||
[CanBeNull] string executionConditionState,
|
||||
[CanBeNull] string nextState,
|
||||
[CanBeNull] int? stateTimes,
|
||||
[CanBeNull] IWebhook webhook)
|
||||
[CanBeNull] IWebhook[] webhooks)
|
||||
{
|
||||
Guid = guid;
|
||||
Title = title;
|
||||
@@ -99,7 +98,7 @@ namespace WireMock
|
||||
ExecutionConditionState = executionConditionState;
|
||||
NextState = nextState;
|
||||
StateTimes = stateTimes;
|
||||
Webhook = webhook;
|
||||
Webhooks = webhooks;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="IMapping.ProvideResponseAsync" />
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Types;
|
||||
|
||||
namespace WireMock.Models
|
||||
namespace WireMock.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Webhook
|
||||
|
||||
@@ -66,6 +66,8 @@ namespace WireMock.Owin
|
||||
services.AddSingleton<IMappingMatcher, MappingMatcher>();
|
||||
services.AddSingleton<IOwinRequestMapper, OwinRequestMapper>();
|
||||
services.AddSingleton<IOwinResponseMapper, OwinResponseMapper>();
|
||||
|
||||
_wireMockMiddlewareOptions.AdditionalServiceRegistration?.Invoke(services);
|
||||
})
|
||||
.Configure(appBuilder =>
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ using WireMock.Util;
|
||||
using Owin;
|
||||
#else
|
||||
using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin
|
||||
@@ -36,6 +37,10 @@ namespace WireMock.Owin
|
||||
|
||||
Action<IAppBuilder> PostWireMockMiddlewareInit { get; set; }
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
|
||||
#endif
|
||||
|
||||
IFileSystemHandler FileSystemHandler { get; set; }
|
||||
|
||||
bool? AllowBodyForAllHttpMethods { get; set; }
|
||||
|
||||
@@ -156,9 +156,9 @@ namespace WireMock.Owin
|
||||
UpdateScenarioState(targetMapping);
|
||||
}
|
||||
|
||||
if (!targetMapping.IsAdminInterface && targetMapping.Webhook != null)
|
||||
if (!targetMapping.IsAdminInterface && targetMapping.Webhooks?.Length > 0)
|
||||
{
|
||||
await SendToWebhookAsync(targetMapping, request, response).ConfigureAwait(false);
|
||||
await SendToWebhooksAsync(targetMapping, request, response).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -191,18 +191,21 @@ namespace WireMock.Owin
|
||||
await CompletedTask;
|
||||
}
|
||||
|
||||
private async Task SendToWebhookAsync(IMapping mapping, RequestMessage request, ResponseMessage response)
|
||||
private async Task SendToWebhooksAsync(IMapping mapping, RequestMessage request, ResponseMessage response)
|
||||
{
|
||||
var httpClientForWebhook = HttpClientBuilder.Build(mapping.Settings.WebhookSettings ?? new WebhookSettings());
|
||||
var webhookSender = new WebhookSender(mapping.Settings);
|
||||
for (int index = 0; index < mapping.Webhooks.Length; index++)
|
||||
{
|
||||
var httpClientForWebhook = HttpClientBuilder.Build(mapping.Settings.WebhookSettings ?? new WebhookSettings());
|
||||
var webhookSender = new WebhookSender(mapping.Settings);
|
||||
|
||||
try
|
||||
{
|
||||
await webhookSender.SendAsync(httpClientForWebhook, mapping.Webhook.Request, request, response).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_options.Logger.Error($"Sending message to Webhook Mapping '{mapping.Guid}' failed. Exception: {ex}");
|
||||
try
|
||||
{
|
||||
await webhookSender.SendAsync(httpClientForWebhook, mapping.Webhooks[index].Request, request, response).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_options.Logger.Error($"Sending message to Webhook [{index}] from Mapping '{mapping.Guid}' failed. Exception: {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using WireMock.Util;
|
||||
using Owin;
|
||||
#else
|
||||
using IAppBuilder = Microsoft.AspNetCore.Builder.IApplicationBuilder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Owin
|
||||
@@ -36,6 +37,10 @@ namespace WireMock.Owin
|
||||
|
||||
public Action<IAppBuilder> PostWireMockMiddlewareInit { get; set; }
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
public Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
|
||||
#endif
|
||||
|
||||
/// <inheritdoc cref="IWireMockMiddlewareOptions.FileSystemHandler"/>
|
||||
public IFileSystemHandler FileSystemHandler { get; set; }
|
||||
|
||||
|
||||
@@ -84,10 +84,18 @@ namespace WireMock.Serialization
|
||||
Response = new ResponseModel
|
||||
{
|
||||
Delay = (int?)response.Delay?.TotalMilliseconds
|
||||
},
|
||||
Webhook = WebhookMapper.Map(mapping.Webhook)
|
||||
}
|
||||
};
|
||||
|
||||
if (mapping.Webhooks?.Length == 1)
|
||||
{
|
||||
mappingModel.Webhook = WebhookMapper.Map(mapping.Webhooks[0]);
|
||||
}
|
||||
else if (mapping.Webhooks?.Length > 1)
|
||||
{
|
||||
mappingModel.Webhooks = mapping.Webhooks.Select(WebhookMapper.Map).ToArray();
|
||||
}
|
||||
|
||||
if (bodyMatcher?.Matchers != null)
|
||||
{
|
||||
mappingModel.Request.Body = new BodyModel();
|
||||
|
||||
@@ -103,14 +103,14 @@ namespace WireMock.Server
|
||||
IRespondWithAProvider WillSetStateTo(int state, int? times = 1);
|
||||
|
||||
/// <summary>
|
||||
/// Add a Webbook to call after the response has been generated.
|
||||
/// Add (multiple) Webhook(s) to call after the response has been generated.
|
||||
/// </summary>
|
||||
/// <param name="webhook">The Webhook</param>
|
||||
/// <param name="webhooks">The Webhooks</param>
|
||||
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
|
||||
IRespondWithAProvider WithWebhook(IWebhook webhook);
|
||||
IRespondWithAProvider WithWebhook(params IWebhook[] webhooks);
|
||||
|
||||
/// <summary>
|
||||
/// Add a Webbook to call after the response has been generated.
|
||||
/// Add a Webhook to call after the response has been generated.
|
||||
/// </summary>
|
||||
/// <param name="url">The Webhook Url</param>
|
||||
/// <param name="method">The method to use. [optional]</param>
|
||||
@@ -129,7 +129,7 @@ namespace WireMock.Server
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Add a Webbook to call after the response has been generated.
|
||||
/// Add a Webhook to call after the response has been generated.
|
||||
/// </summary>
|
||||
/// <param name="url">The Webhook Url</param>
|
||||
/// <param name="method">The method to use. [optional]</param>
|
||||
|
||||
@@ -1,209 +1,212 @@
|
||||
// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License.
|
||||
// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root.
|
||||
using System;
|
||||
// This source file is based on mock4net by Alexandre Victoor which is licensed under the Apache 2.0 License.
|
||||
// For more details see 'mock4net/LICENSE.txt' and 'mock4net/readme.md' in this project root.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Models;
|
||||
using WireMock.ResponseProviders;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Matchers.Request;
|
||||
using WireMock.Models;
|
||||
using WireMock.ResponseProviders;
|
||||
using WireMock.Settings;
|
||||
using WireMock.Types;
|
||||
using WireMock.Util;
|
||||
using WireMock.Validation;
|
||||
|
||||
namespace WireMock.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// The respond with a provider.
|
||||
/// </summary>
|
||||
internal class RespondWithAProvider : IRespondWithAProvider
|
||||
{
|
||||
private int _priority;
|
||||
private string _title;
|
||||
private string _path;
|
||||
private string _executionConditionState;
|
||||
private string _nextState;
|
||||
private string _scenario;
|
||||
private int _timesInSameState = 1;
|
||||
private readonly RegistrationCallback _registrationCallback;
|
||||
private readonly IRequestMatcher _requestMatcher;
|
||||
private readonly IWireMockServerSettings _settings;
|
||||
private readonly bool _saveToFile;
|
||||
|
||||
public Guid Guid { get; private set; } = Guid.NewGuid();
|
||||
|
||||
public IWebhook[] Webhooks { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RespondWithAProvider"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registrationCallback">The registration callback.</param>
|
||||
/// <param name="requestMatcher">The request matcher.</param>
|
||||
/// <param name="settings">The WireMockServerSettings.</param>
|
||||
/// <param name="saveToFile">Optional boolean to indicate if this mapping should be saved as static mapping file.</param>
|
||||
public RespondWithAProvider(RegistrationCallback registrationCallback, IRequestMatcher requestMatcher, IWireMockServerSettings settings, bool saveToFile = false)
|
||||
{
|
||||
_registrationCallback = registrationCallback;
|
||||
_requestMatcher = requestMatcher;
|
||||
_settings = settings;
|
||||
_saveToFile = saveToFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The respond with.
|
||||
/// </summary>
|
||||
/// <param name="provider">The provider.</param>
|
||||
public void RespondWith(IResponseProvider provider)
|
||||
{
|
||||
_registrationCallback(new Mapping(Guid, _title, _path, _settings, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState, _timesInSameState, Webhooks), _saveToFile);
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithGuid(string)"/>
|
||||
public IRespondWithAProvider WithGuid(string guid)
|
||||
{
|
||||
return WithGuid(Guid.Parse(guid));
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithGuid(Guid)"/>
|
||||
public IRespondWithAProvider WithGuid(Guid guid)
|
||||
{
|
||||
Guid = guid;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithTitle"/>
|
||||
public IRespondWithAProvider WithTitle(string title)
|
||||
{
|
||||
_title = title;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithPath"/>
|
||||
public IRespondWithAProvider WithPath(string path)
|
||||
{
|
||||
_path = path;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.AtPriority"/>
|
||||
public IRespondWithAProvider AtPriority(int priority)
|
||||
{
|
||||
_priority = priority;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.InScenario(string)"/>
|
||||
public IRespondWithAProvider InScenario(string scenario)
|
||||
{
|
||||
_scenario = scenario;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.InScenario(int)"/>
|
||||
public IRespondWithAProvider InScenario(int scenario)
|
||||
{
|
||||
return InScenario(scenario.ToString());
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WhenStateIs(string)"/>
|
||||
public IRespondWithAProvider WhenStateIs(string state)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_scenario))
|
||||
{
|
||||
throw new NotSupportedException("Unable to set state condition when no scenario is defined.");
|
||||
}
|
||||
|
||||
_executionConditionState = state;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WhenStateIs(int)"/>
|
||||
public IRespondWithAProvider WhenStateIs(int state)
|
||||
{
|
||||
return WhenStateIs(state.ToString());
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WillSetStateTo(string, int?)"/>
|
||||
public IRespondWithAProvider WillSetStateTo(string state, int? times = 1)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_scenario))
|
||||
{
|
||||
throw new NotSupportedException("Unable to set next state when no scenario is defined.");
|
||||
}
|
||||
|
||||
_nextState = state;
|
||||
_timesInSameState = times ?? 1;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WillSetStateTo(int, int?)"/>
|
||||
public IRespondWithAProvider WillSetStateTo(int state, int? times = 1)
|
||||
{
|
||||
return WillSetStateTo(state.ToString(), times);
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithWebhook(IWebhook[])"/>
|
||||
public IRespondWithAProvider WithWebhook(params IWebhook[] webhooks)
|
||||
{
|
||||
Check.HasNoNulls(webhooks, nameof(webhooks));
|
||||
|
||||
Webhooks = webhooks;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithWebhook(string, string, IDictionary{string, WireMockList{string}}, string, bool, TransformerType)"/>
|
||||
public IRespondWithAProvider WithWebhook(
|
||||
[NotNull] string url,
|
||||
[CanBeNull] string method = "post",
|
||||
[CanBeNull] IDictionary<string, WireMockList<string>> headers = null,
|
||||
[CanBeNull] string body = null,
|
||||
bool useTransformer = true,
|
||||
TransformerType transformerType = TransformerType.Handlebars)
|
||||
{
|
||||
Webhooks = new[] { InitWebhook(url, method, headers, useTransformer, transformerType) };
|
||||
|
||||
namespace WireMock.Server
|
||||
{
|
||||
/// <summary>
|
||||
/// The respond with a provider.
|
||||
/// </summary>
|
||||
internal class RespondWithAProvider : IRespondWithAProvider
|
||||
{
|
||||
private int _priority;
|
||||
private string _title;
|
||||
private string _path;
|
||||
private string _executionConditionState;
|
||||
private string _nextState;
|
||||
private string _scenario;
|
||||
private int _timesInSameState = 1;
|
||||
private readonly RegistrationCallback _registrationCallback;
|
||||
private readonly IRequestMatcher _requestMatcher;
|
||||
private readonly IWireMockServerSettings _settings;
|
||||
private readonly bool _saveToFile;
|
||||
|
||||
public Guid Guid { get; private set; } = Guid.NewGuid();
|
||||
|
||||
public IWebhook Webhook { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RespondWithAProvider"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registrationCallback">The registration callback.</param>
|
||||
/// <param name="requestMatcher">The request matcher.</param>
|
||||
/// <param name="settings">The WireMockServerSettings.</param>
|
||||
/// <param name="saveToFile">Optional boolean to indicate if this mapping should be saved as static mapping file.</param>
|
||||
public RespondWithAProvider(RegistrationCallback registrationCallback, IRequestMatcher requestMatcher, IWireMockServerSettings settings, bool saveToFile = false)
|
||||
{
|
||||
_registrationCallback = registrationCallback;
|
||||
_requestMatcher = requestMatcher;
|
||||
_settings = settings;
|
||||
_saveToFile = saveToFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The respond with.
|
||||
/// </summary>
|
||||
/// <param name="provider">The provider.</param>
|
||||
public void RespondWith(IResponseProvider provider)
|
||||
{
|
||||
_registrationCallback(new Mapping(Guid, _title, _path, _settings, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState, _timesInSameState, Webhook), _saveToFile);
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithGuid(string)"/>
|
||||
public IRespondWithAProvider WithGuid(string guid)
|
||||
{
|
||||
return WithGuid(Guid.Parse(guid));
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithGuid(Guid)"/>
|
||||
public IRespondWithAProvider WithGuid(Guid guid)
|
||||
{
|
||||
Guid = guid;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithTitle"/>
|
||||
public IRespondWithAProvider WithTitle(string title)
|
||||
{
|
||||
_title = title;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithPath"/>
|
||||
public IRespondWithAProvider WithPath(string path)
|
||||
{
|
||||
_path = path;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.AtPriority"/>
|
||||
public IRespondWithAProvider AtPriority(int priority)
|
||||
{
|
||||
_priority = priority;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.InScenario(string)"/>
|
||||
public IRespondWithAProvider InScenario(string scenario)
|
||||
{
|
||||
_scenario = scenario;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.InScenario(int)"/>
|
||||
public IRespondWithAProvider InScenario(int scenario)
|
||||
{
|
||||
return InScenario(scenario.ToString());
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WhenStateIs(string)"/>
|
||||
public IRespondWithAProvider WhenStateIs(string state)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_scenario))
|
||||
{
|
||||
throw new NotSupportedException("Unable to set state condition when no scenario is defined.");
|
||||
}
|
||||
|
||||
_executionConditionState = state;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WhenStateIs(int)"/>
|
||||
public IRespondWithAProvider WhenStateIs(int state)
|
||||
{
|
||||
return WhenStateIs(state.ToString());
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WillSetStateTo(string, int?)"/>
|
||||
public IRespondWithAProvider WillSetStateTo(string state, int? times = 1)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_scenario))
|
||||
{
|
||||
throw new NotSupportedException("Unable to set next state when no scenario is defined.");
|
||||
}
|
||||
|
||||
_nextState = state;
|
||||
_timesInSameState = times ?? 1;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WillSetStateTo(int, int?)"/>
|
||||
public IRespondWithAProvider WillSetStateTo(int state, int? times = 1)
|
||||
{
|
||||
return WillSetStateTo(state.ToString(), times);
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithWebhook(IWebhook)"/>
|
||||
public IRespondWithAProvider WithWebhook(IWebhook webhook)
|
||||
{
|
||||
Webhook = webhook;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithWebhook(string,string, IDictionary{string, WireMockList{string}}, string, bool, TransformerType)"/>
|
||||
public IRespondWithAProvider WithWebhook(
|
||||
[NotNull] string url,
|
||||
[CanBeNull] string method = "post",
|
||||
[CanBeNull] IDictionary<string, WireMockList<string>> headers = null,
|
||||
[CanBeNull] string body = null,
|
||||
bool useTransformer = true,
|
||||
TransformerType transformerType = TransformerType.Handlebars)
|
||||
{
|
||||
Webhook = InitWebhook(url, method, headers, useTransformer, transformerType);
|
||||
|
||||
if (body != null)
|
||||
{
|
||||
Webhook.Request.BodyData = new BodyData
|
||||
Webhooks[0].Request.BodyData = new BodyData
|
||||
{
|
||||
BodyAsString = body,
|
||||
DetectedBodyType = BodyType.String,
|
||||
DetectedBodyTypeFromContentType = BodyType.String
|
||||
};
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithWebhook(string, string, IDictionary{string, WireMockList{string}}, object, bool, TransformerType)"/>
|
||||
public IRespondWithAProvider WithWebhook(
|
||||
[NotNull] string url,
|
||||
[CanBeNull] string method = "post",
|
||||
[CanBeNull] IDictionary<string, WireMockList<string>> headers = null,
|
||||
[CanBeNull] object body = null,
|
||||
bool useTransformer = true,
|
||||
TransformerType transformerType = TransformerType.Handlebars)
|
||||
{
|
||||
Webhook = InitWebhook(url, method, headers, useTransformer, transformerType);
|
||||
|
||||
/// <see cref="IRespondWithAProvider.WithWebhook(string, string, IDictionary{string, WireMockList{string}}, object, bool, TransformerType)"/>
|
||||
public IRespondWithAProvider WithWebhook(
|
||||
[NotNull] string url,
|
||||
[CanBeNull] string method = "post",
|
||||
[CanBeNull] IDictionary<string, WireMockList<string>> headers = null,
|
||||
[CanBeNull] object body = null,
|
||||
bool useTransformer = true,
|
||||
TransformerType transformerType = TransformerType.Handlebars)
|
||||
{
|
||||
Webhooks = new[] { InitWebhook(url, method, headers, useTransformer, transformerType) };
|
||||
|
||||
if (body != null)
|
||||
{
|
||||
Webhook.Request.BodyData = new BodyData
|
||||
Webhooks[0].Request.BodyData = new BodyData
|
||||
{
|
||||
BodyAsJson = body,
|
||||
DetectedBodyType = BodyType.Json,
|
||||
DetectedBodyTypeFromContentType = BodyType.Json
|
||||
};
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private IWebhook InitWebhook(
|
||||
string url,
|
||||
string method,
|
||||
@@ -222,6 +225,6 @@ namespace WireMock.Server
|
||||
TransformerType = transformerType
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -470,10 +470,15 @@ namespace WireMock.Server
|
||||
respondProvider = respondProvider.WillSetStateTo(mappingModel.SetStateTo);
|
||||
}
|
||||
|
||||
if (mappingModel.Webhook?.Request != null)
|
||||
if (mappingModel.Webhook != null)
|
||||
{
|
||||
respondProvider = respondProvider.WithWebhook(WebhookMapper.Map(mappingModel.Webhook));
|
||||
}
|
||||
else if (mappingModel.Webhooks?.Length > 1)
|
||||
{
|
||||
var webhooks = mappingModel.Webhooks.Select(WebhookMapper.Map).ToArray();
|
||||
respondProvider = respondProvider.WithWebhook(webhooks);
|
||||
}
|
||||
|
||||
respondProvider.RespondWith(responseBuilder);
|
||||
|
||||
|
||||
@@ -242,6 +242,7 @@ namespace WireMock.Server
|
||||
_mappingToFileSaver = new MappingToFileSaver(_settings, _mappingConverter);
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
_options.AdditionalServiceRegistration = _settings.AdditionalServiceRegistration;
|
||||
_httpServer = new AspNetCoreSelfHost(_options, urlOptions);
|
||||
#else
|
||||
_httpServer = new OwinSelfHost(_options, urlOptions);
|
||||
|
||||
@@ -4,6 +4,9 @@ using JetBrains.Annotations;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Logging;
|
||||
using WireMock.Matchers;
|
||||
#if USE_ASPNETCORE
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Settings
|
||||
{
|
||||
@@ -109,6 +112,14 @@ namespace WireMock.Settings
|
||||
[PublicAPI]
|
||||
Action<object> PostWireMockMiddlewareInit { get; set; }
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
/// <summary>
|
||||
/// Action which is called with IServiceCollection when ASP.NET Core DI is being configured. [Optional]
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// The IWireMockLogger which logs Debug, Info, Warning or Error
|
||||
/// </summary>
|
||||
|
||||
@@ -4,6 +4,9 @@ using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using WireMock.Handlers;
|
||||
using WireMock.Logging;
|
||||
#if USE_ASPNETCORE
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
#endif
|
||||
|
||||
namespace WireMock.Settings
|
||||
{
|
||||
@@ -79,6 +82,13 @@ namespace WireMock.Settings
|
||||
[JsonIgnore]
|
||||
public Action<object> PostWireMockMiddlewareInit { get; set; }
|
||||
|
||||
#if USE_ASPNETCORE
|
||||
/// <inheritdoc cref="IWireMockServerSettings.AdditionalServiceRegistration"/>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
public Action<IServiceCollection> AdditionalServiceRegistration { get; set; }
|
||||
#endif
|
||||
|
||||
/// <inheritdoc cref="IWireMockServerSettings.Logger"/>
|
||||
[PublicAPI]
|
||||
[JsonIgnore]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using NFluent;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using WireMock.Http;
|
||||
using WireMock.Models;
|
||||
using WireMock.Types;
|
||||
@@ -28,7 +29,7 @@ namespace WireMock.Net.Tests.Http
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void HttpRequestMessageHelper_Create_Bytes()
|
||||
public async Task HttpRequestMessageHelper_Create_Bytes()
|
||||
{
|
||||
// Assign
|
||||
var body = new BodyData
|
||||
@@ -46,7 +47,7 @@ namespace WireMock.Net.Tests.Http
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void HttpRequestMessageHelper_Create_Json()
|
||||
public async Task HttpRequestMessageHelper_Create_Json()
|
||||
{
|
||||
// Assign
|
||||
var body = new BodyData
|
||||
@@ -64,7 +65,7 @@ namespace WireMock.Net.Tests.Http
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void HttpRequestMessageHelper_Create_Json_With_ContentType_ApplicationJson()
|
||||
public async Task HttpRequestMessageHelper_Create_Json_With_ContentType_ApplicationJson()
|
||||
{
|
||||
// Assign
|
||||
var headers = new Dictionary<string, string[]> { { "Content-Type", new[] { "application/json" } } };
|
||||
@@ -84,7 +85,7 @@ namespace WireMock.Net.Tests.Http
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void HttpRequestMessageHelper_Create_Json_With_ContentType_ApplicationJson_UTF8()
|
||||
public async Task HttpRequestMessageHelper_Create_Json_With_ContentType_ApplicationJson_UTF8()
|
||||
{
|
||||
// Assign
|
||||
var headers = new Dictionary<string, string[]> { { "Content-Type", new[] { "application/json; charset=utf-8" } } };
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace WireMock.Net.Tests
|
||||
public class ObservableLogEntriesTest
|
||||
{
|
||||
[Fact]
|
||||
public async void WireMockServer_LogEntriesChanged_WithException_Should_LogError()
|
||||
public async Task WireMockServer_LogEntriesChanged_WithException_Should_LogError()
|
||||
{
|
||||
// Assign
|
||||
string path = $"/log_{Guid.NewGuid()}";
|
||||
@@ -48,7 +48,7 @@ namespace WireMock.Net.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void WireMockServer_LogEntriesChanged()
|
||||
public async Task WireMockServer_LogEntriesChanged()
|
||||
{
|
||||
// Assign
|
||||
string path = $"/log_{Guid.NewGuid()}";
|
||||
|
||||
@@ -77,7 +77,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void WireMockMiddleware_Invoke_NoMatch()
|
||||
public async Task WireMockMiddleware_Invoke_NoMatch()
|
||||
{
|
||||
// Act
|
||||
await _sut.Invoke(_contextMock.Object);
|
||||
@@ -90,7 +90,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void WireMockMiddleware_Invoke_IsAdminInterface_EmptyHeaders_401()
|
||||
public async Task WireMockMiddleware_Invoke_IsAdminInterface_EmptyHeaders_401()
|
||||
{
|
||||
// Assign
|
||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary<string, string[]>());
|
||||
@@ -113,7 +113,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void WireMockMiddleware_Invoke_IsAdminInterface_MissingHeader_401()
|
||||
public async Task WireMockMiddleware_Invoke_IsAdminInterface_MissingHeader_401()
|
||||
{
|
||||
// Assign
|
||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary<string, string[]> { { "h", new[] { "x" } } });
|
||||
@@ -136,7 +136,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void WireMockMiddleware_Invoke_RequestLogExpirationDurationIsDefined()
|
||||
public async Task WireMockMiddleware_Invoke_RequestLogExpirationDurationIsDefined()
|
||||
{
|
||||
// Assign
|
||||
_optionsMock.SetupGet(o => o.RequestLogExpirationDuration).Returns(1);
|
||||
@@ -146,7 +146,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void WireMockMiddleware_Invoke_Mapping_Has_ProxyAndRecordSettings_And_SaveMapping_Is_True()
|
||||
public async Task WireMockMiddleware_Invoke_Mapping_Has_ProxyAndRecordSettings_And_SaveMapping_Is_True()
|
||||
{
|
||||
// Assign
|
||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary<string, string[]>());
|
||||
@@ -195,7 +195,7 @@ namespace WireMock.Net.Tests.Owin
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void WireMockMiddleware_Invoke_Mapping_Has_ProxyAndRecordSettings_And_SaveMapping_Is_False_But_WireMockServerSettings_SaveMapping_Is_True()
|
||||
public async Task WireMockMiddleware_Invoke_Mapping_Has_ProxyAndRecordSettings_And_SaveMapping_Is_False_But_WireMockServerSettings_SaveMapping_Is_True()
|
||||
{
|
||||
// Assign
|
||||
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "GET", "::1", null, new Dictionary<string, string[]>());
|
||||
|
||||
@@ -24,31 +24,34 @@ namespace WireMock.Net.Tests.Serialization
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToMappingModel()
|
||||
public void ToMappingModel_With_SingleWebHook()
|
||||
{
|
||||
// Assign
|
||||
var request = Request.Create();
|
||||
var response = Response.Create();
|
||||
var webhook = new Webhook
|
||||
var webhooks = new IWebhook[]
|
||||
{
|
||||
Request = new WebhookRequest
|
||||
new Webhook
|
||||
{
|
||||
Url = "https://test.com",
|
||||
Headers = new Dictionary<string, WireMockList<string>>
|
||||
Request = new WebhookRequest
|
||||
{
|
||||
{ "Single", new WireMockList<string>("x") },
|
||||
{ "Multi", new WireMockList<string>("a", "b") }
|
||||
},
|
||||
Method = "post",
|
||||
BodyData = new BodyData
|
||||
{
|
||||
BodyAsString = "b",
|
||||
DetectedBodyType = BodyType.String,
|
||||
DetectedBodyTypeFromContentType = BodyType.String
|
||||
Url = "https://test.com",
|
||||
Headers = new Dictionary<string, WireMockList<string>>
|
||||
{
|
||||
{ "Single", new WireMockList<string>("x") },
|
||||
{ "Multi", new WireMockList<string>("a", "b") }
|
||||
},
|
||||
Method = "post",
|
||||
BodyData = new BodyData
|
||||
{
|
||||
BodyAsString = "b",
|
||||
DetectedBodyType = BodyType.String,
|
||||
DetectedBodyTypeFromContentType = BodyType.String
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 0, null, null, null, null, webhook);
|
||||
var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 0, null, null, null, null, webhooks);
|
||||
|
||||
// Act
|
||||
var model = _sut.ToMappingModel(mapping);
|
||||
@@ -61,6 +64,8 @@ namespace WireMock.Net.Tests.Serialization
|
||||
model.Response.UseTransformer.Should().BeNull();
|
||||
model.Response.Headers.Should().BeNull();
|
||||
|
||||
model.Webhooks.Should().BeNull();
|
||||
|
||||
model.Webhook.Request.Method.Should().Be("post");
|
||||
model.Webhook.Request.Url.Should().Be("https://test.com");
|
||||
model.Webhook.Request.Headers.Should().HaveCount(2);
|
||||
@@ -68,6 +73,80 @@ namespace WireMock.Net.Tests.Serialization
|
||||
model.Webhook.Request.BodyAsJson.Should().BeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToMappingModel_With_MultipleWebHooks()
|
||||
{
|
||||
// Assign
|
||||
var request = Request.Create();
|
||||
var response = Response.Create();
|
||||
var webhooks = new IWebhook[]
|
||||
{
|
||||
new Webhook
|
||||
{
|
||||
Request = new WebhookRequest
|
||||
{
|
||||
Url = "https://test1.com",
|
||||
Headers = new Dictionary<string, WireMockList<string>>
|
||||
{
|
||||
{ "One", new WireMockList<string>("x") }
|
||||
},
|
||||
Method = "post",
|
||||
BodyData = new BodyData
|
||||
{
|
||||
BodyAsString = "1",
|
||||
DetectedBodyType = BodyType.String,
|
||||
DetectedBodyTypeFromContentType = BodyType.String
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
new Webhook
|
||||
{
|
||||
Request = new WebhookRequest
|
||||
{
|
||||
Url = "https://test2.com",
|
||||
Headers = new Dictionary<string, WireMockList<string>>
|
||||
{
|
||||
{ "First", new WireMockList<string>("x") },
|
||||
{ "Second", new WireMockList<string>("a", "b") }
|
||||
},
|
||||
Method = "post",
|
||||
BodyData = new BodyData
|
||||
{
|
||||
BodyAsString = "2",
|
||||
DetectedBodyType = BodyType.String,
|
||||
DetectedBodyTypeFromContentType = BodyType.String
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 0, null, null, null, null, webhooks
|
||||
);
|
||||
|
||||
// Act
|
||||
var model = _sut.ToMappingModel(mapping);
|
||||
|
||||
// Assert
|
||||
model.Should().NotBeNull();
|
||||
model.Priority.Should().BeNull();
|
||||
|
||||
model.Response.BodyAsJsonIndented.Should().BeNull();
|
||||
model.Response.UseTransformer.Should().BeNull();
|
||||
model.Response.Headers.Should().BeNull();
|
||||
|
||||
model.Webhook.Should().BeNull();
|
||||
|
||||
model.Webhooks[0].Request.Method.Should().Be("post");
|
||||
model.Webhooks[0].Request.Url.Should().Be("https://test1.com");
|
||||
model.Webhooks[0].Request.Headers.Should().HaveCount(1);
|
||||
model.Webhooks[0].Request.Body.Should().Be("1");
|
||||
|
||||
model.Webhooks[1].Request.Method.Should().Be("post");
|
||||
model.Webhooks[1].Request.Url.Should().Be("https://test2.com");
|
||||
model.Webhooks[1].Request.Headers.Should().HaveCount(2);
|
||||
model.Webhooks[1].Request.Body.Should().Be("2");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToMappingModel_WithPriority_ReturnsPriority()
|
||||
{
|
||||
|
||||
@@ -422,7 +422,7 @@ namespace WireMock.Net.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void WireMockServer_Admin_DeleteMappings()
|
||||
public async Task WireMockServer_Admin_DeleteMappings()
|
||||
{
|
||||
// Arrange
|
||||
var server = WireMockServer.Start(new WireMockServerSettings
|
||||
|
||||
@@ -16,6 +16,74 @@ namespace WireMock.Net.Tests
|
||||
{
|
||||
public class WireMockServerWebhookTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task WireMockServer_WithWebhooks_Should_Send_Message_To_Webhooks()
|
||||
{
|
||||
// Assign
|
||||
var serverReceivingTheWebhook1 = WireMockServer.Start();
|
||||
serverReceivingTheWebhook1.Given(Request.Create().UsingPost()).RespondWith(Response.Create().WithStatusCode(200));
|
||||
|
||||
var serverReceivingTheWebhook2 = WireMockServer.Start();
|
||||
serverReceivingTheWebhook2.Given(Request.Create().UsingPost()).RespondWith(Response.Create().WithStatusCode(200));
|
||||
|
||||
var webhook1 = new Webhook
|
||||
{
|
||||
Request = new WebhookRequest
|
||||
{
|
||||
Url = serverReceivingTheWebhook1.Urls[0],
|
||||
Method = "post",
|
||||
BodyData = new BodyData
|
||||
{
|
||||
BodyAsString = "1",
|
||||
DetectedBodyType = BodyType.String,
|
||||
DetectedBodyTypeFromContentType = BodyType.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var webhook2 = new Webhook
|
||||
{
|
||||
Request = new WebhookRequest
|
||||
{
|
||||
Url = serverReceivingTheWebhook2.Urls[0],
|
||||
Method = "post",
|
||||
BodyData = new BodyData
|
||||
{
|
||||
BodyAsString = "2",
|
||||
DetectedBodyType = BodyType.String,
|
||||
DetectedBodyTypeFromContentType = BodyType.String
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
var server = WireMockServer.Start();
|
||||
server.Given(Request.Create().UsingPost())
|
||||
.WithWebhook(webhook1, webhook2)
|
||||
.RespondWith(Response.Create().WithBody("a-response"));
|
||||
|
||||
var request = new HttpRequestMessage
|
||||
{
|
||||
Method = HttpMethod.Post,
|
||||
RequestUri = new Uri($"{server.Urls[0]}/TST"),
|
||||
Content = new StringContent("test")
|
||||
};
|
||||
|
||||
// Assert
|
||||
var response = await new HttpClient().SendAsync(request);
|
||||
string content = await response.Content.ReadAsStringAsync();
|
||||
|
||||
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
content.Should().Be("a-response");
|
||||
|
||||
serverReceivingTheWebhook1.LogEntries.Should().HaveCount(1);
|
||||
serverReceivingTheWebhook2.LogEntries.Should().HaveCount(1);
|
||||
|
||||
server.Dispose();
|
||||
serverReceivingTheWebhook1.Dispose();
|
||||
serverReceivingTheWebhook2.Dispose();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WireMockServer_WithWebhook_Should_Send_Message_To_Webhook()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user