Compare commits

..

4 Commits

Author SHA1 Message Date
Stef Heyenrath
2ac9ca207a 1.5.17 2023-02-25 12:53:41 +01:00
Stef Heyenrath
f099f3a288 AdminApiMappingBuilder (#890)
* AdminApiMappingBuilder

* .

* IWireMockAdminApi

* add methods

* .
2023-02-25 12:47:06 +01:00
Stef Heyenrath
02b607cc95 Slow test (#882) 2023-02-18 18:09:21 +01:00
Stef Heyenrath
7ac89e85b7 Add WithBodyAsJson builder method with accepts a Func (#881)
* Add WithBodyAsJson builder method with accepts a Func

* ut
2023-02-06 20:50:11 +01:00
17 changed files with 852 additions and 325 deletions

View File

@@ -1,3 +1,8 @@
# 1.5.17 (25 February 2023)
- [#881](https://github.com/WireMock-Net/WireMock.Net/pull/881) - Add WithBodyAsJson builder method with accepts a Func [feature] contributed by [StefH](https://github.com/StefH)
- [#882](https://github.com/WireMock-Net/WireMock.Net/pull/882) - Add example code to test HTTP Status 400 and 500 [test] contributed by [StefH](https://github.com/StefH)
- [#890](https://github.com/WireMock-Net/WireMock.Net/pull/890) - AdminApiMappingBuilder [feature] contributed by [StefH](https://github.com/StefH)
# 1.5.16 (01 February 2023)
- [#880](https://github.com/WireMock-Net/WireMock.Net/pull/880) - Add `WithProxy(string proxyUrl, X509Certificate2 certificate)` [feature] contributed by [StefH](https://github.com/StefH)
- [#879](https://github.com/WireMock-Net/WireMock.Net/issues/879) - Possibility to pass a X509Certificate2 to WithProxy() or specifiy certificate loading options [feature]
@@ -651,8 +656,8 @@
- [#263](https://github.com/WireMock-Net/WireMock.Net/issues/263) - Content-Type multipart/form-data is not serialized in proxy and recording mode [bug]
# 1.0.11.0 (30 March 2019)
- [#261](https://github.com/WireMock-Net/WireMock.Net/pull/261) - Fix BodyAsJson transform bug in ResponseMessageTransformer contributed by [psypilat](https://github.com/psypilat)
- [#262](https://github.com/WireMock-Net/WireMock.Net/pull/262) - Add ProvideResponse_WithJsonBodyAndTransform test contributed by [psypilat](https://github.com/psypilat)
- [#261](https://github.com/WireMock-Net/WireMock.Net/pull/261) - Fix BodyAsJson transform bug in ResponseMessageTransformer contributed by [ghost](https://github.com/ghost)
- [#262](https://github.com/WireMock-Net/WireMock.Net/pull/262) - Add ProvideResponse_WithJsonBodyAndTransform test contributed by [ghost](https://github.com/ghost)
# 1.0.10.0 (27 March 2019)
- [#260](https://github.com/WireMock-Net/WireMock.Net/pull/260) - Fix Response.Delay property serialization [bug] contributed by [StefH](https://github.com/StefH)

View File

@@ -4,7 +4,7 @@
</PropertyGroup>
<PropertyGroup>
<VersionPrefix>1.5.16</VersionPrefix>
<VersionPrefix>1.5.17</VersionPrefix>
<PackageIcon>WireMock.Net-Logo.png</PackageIcon>
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>

View File

@@ -1,6 +1,6 @@
rem https://github.com/StefH/GitHubReleaseNotes
SET version=1.5.16
SET version=1.5.17
GitHubReleaseNotes --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc duplicate --version %version% --token %GH_TOKEN%

View File

@@ -1,5 +1,6 @@
# 1.5.16 (01 February 2023)
- #880 Add `WithProxy(string proxyUrl, X509Certificate2 certificate)` [feature]
- #879 Possibility to pass a X509Certificate2 to WithProxy() or specifiy certificate loading options [feature]
# 1.5.17 (25 February 2023)
- #881 Add WithBodyAsJson builder method with accepts a Func [feature]
- #882 Add example code to test HTTP Status 400 and 500 [test]
- #890 AdminApiMappingBuilder [feature]
The full release notes can be found here: https://github.com/WireMock-Net/WireMock.Net/blob/master/CHANGELOG.md

View File

@@ -1,78 +1,125 @@
using Newtonsoft.Json;
using RestEase;
using System;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using RestEase;
using WireMock.Admin.Settings;
using WireMock.Client;
using WireMock.Client.Extensions;
namespace WireMock.Net.Client
namespace WireMock.Net.Client;
class Program
{
class Program
static async Task Main(string[] args)
{
static async Task Main(string[] args)
// Create an implementation of the IWireMockAdminApi and pass in the base URL for the API.
var api = RestClient.For<IWireMockAdminApi>("http://localhost:9091");
// await api.ResetMappingsAsync().ConfigureAwait(false);
var mappingBuilder = api.GetMappingBuilder();
mappingBuilder.Given(m => m
.WithTitle("This is my title 1")
.WithRequest(req => req
.UsingGet()
.WithPath("/bla1")
)
.WithResponse(rsp => rsp
.WithBody("x1")
.WithHeaders(h => h.Add("h1", "v1"))
)
);
mappingBuilder.Given(m => m
.WithTitle("This is my title 2")
.WithRequest(req => req
.UsingGet()
.WithPath("/bla2")
)
.WithResponse(rsp => rsp
.WithBody("x2")
.WithHeaders(h => h.Add("h2", "v2"))
)
);
mappingBuilder.Given(m => m
.WithTitle("This is my title 3")
.WithRequest(req => req
.UsingGet()
.WithPath("/bla3")
)
.WithResponse(rsp => rsp
.WithBodyAsJson(new
{
x = "test"
}, true)
)
);
var result = await mappingBuilder.BuildAndPostAsync().ConfigureAwait(false);
Console.WriteLine($"result = {JsonConvert.SerializeObject(result)}");
var mappings = await api.GetMappingsAsync();
Console.WriteLine($"mappings = {JsonConvert.SerializeObject(mappings)}");
// Set BASIC Auth
var value = Convert.ToBase64String(Encoding.ASCII.GetBytes("a:b"));
api.Authorization = new AuthenticationHeaderValue("Basic", value);
var settings1 = await api.GetSettingsAsync();
Console.WriteLine($"settings1 = {JsonConvert.SerializeObject(settings1)}");
var settingsViaBuilder = new SettingsModelBuilder()
.WithGlobalProcessingDelay(1077)
.WithoutGlobalProcessingDelay()
.Build();
settings1.GlobalProcessingDelay = 1077;
api.PostSettingsAsync(settings1).Wait();
var settings2 = await api.GetSettingsAsync();
Console.WriteLine($"settings2 = {JsonConvert.SerializeObject(settings2)}");
mappings = await api.GetMappingsAsync();
Console.WriteLine($"mappings = {JsonConvert.SerializeObject(mappings)}");
try
{
// Create an implementation of the IWireMockAdminApi and pass in the base URL for the API.
var api = RestClient.For<IWireMockAdminApi>("http://localhost:9091");
// Set BASIC Auth
var value = Convert.ToBase64String(Encoding.ASCII.GetBytes("a:b"));
api.Authorization = new AuthenticationHeaderValue("Basic", value);
var settings1 = await api.GetSettingsAsync();
Console.WriteLine($"settings1 = {JsonConvert.SerializeObject(settings1)}");
var settingsViaBuilder = new SettingsModelBuilder()
.WithGlobalProcessingDelay(1077)
.WithoutGlobalProcessingDelay()
.Build();
settings1.GlobalProcessingDelay = 1077;
api.PostSettingsAsync(settings1).Wait();
var settings2 = await api.GetSettingsAsync();
Console.WriteLine($"settings2 = {JsonConvert.SerializeObject(settings2)}");
var mappings = await api.GetMappingsAsync();
Console.WriteLine($"mappings = {JsonConvert.SerializeObject(mappings)}");
try
{
var guid = Guid.Parse("11111110-a633-40e8-a244-5cb80bc0ab66");
var mapping = await api.GetMappingAsync(guid);
Console.WriteLine($"mapping = {JsonConvert.SerializeObject(mapping)}");
}
catch (Exception e)
{
}
var request = await api.GetRequestsAsync();
Console.WriteLine($"request = {JsonConvert.SerializeObject(request)}");
//var deleteRequestsAsync = api.DeleteRequestsAsync().Result;
//Console.WriteLine($"DeleteRequestsAsync = {deleteRequestsAsync.Status}");
//var resetRequestsAsync = api.ResetRequestsAsync().Result;
//Console.WriteLine($"ResetRequestsAsync = {resetRequestsAsync.Status}");
var scenarioStates = await api.GetScenariosAsync();
Console.WriteLine($"GetScenariosAsync = {JsonConvert.SerializeObject(scenarioStates)}");
var postFileResult = await api.PostFileAsync("1.cs", "C# Hello");
Console.WriteLine($"postFileResult = {JsonConvert.SerializeObject(postFileResult)}");
var getFileResult = await api.GetFileAsync("1.cs");
Console.WriteLine($"getFileResult = {getFileResult}");
var resetMappingsAsync = await api.ResetMappingsAsync();
Console.WriteLine($"resetMappingsAsync = {resetMappingsAsync.Status}");
var resetMappingsAndReloadStaticMappingsAsync = await api.ResetMappingsAsync(true);
Console.WriteLine($"resetMappingsAndReloadStaticMappingsAsync = {resetMappingsAndReloadStaticMappingsAsync.Status}");
Console.WriteLine("Press any key to quit");
Console.ReadKey();
var guid = Guid.Parse("11111110-a633-40e8-a244-5cb80bc0ab66");
var mapping = await api.GetMappingAsync(guid);
Console.WriteLine($"mapping = {JsonConvert.SerializeObject(mapping)}");
}
catch (Exception e)
{
}
var request = await api.GetRequestsAsync();
Console.WriteLine($"request = {JsonConvert.SerializeObject(request)}");
//var deleteRequestsAsync = api.DeleteRequestsAsync().Result;
//Console.WriteLine($"DeleteRequestsAsync = {deleteRequestsAsync.Status}");
//var resetRequestsAsync = api.ResetRequestsAsync().Result;
//Console.WriteLine($"ResetRequestsAsync = {resetRequestsAsync.Status}");
var scenarioStates = await api.GetScenariosAsync();
Console.WriteLine($"GetScenariosAsync = {JsonConvert.SerializeObject(scenarioStates)}");
var postFileResult = await api.PostFileAsync("1.cs", "C# Hello");
Console.WriteLine($"postFileResult = {JsonConvert.SerializeObject(postFileResult)}");
var getFileResult = await api.GetFileAsync("1.cs");
Console.WriteLine($"getFileResult = {getFileResult}");
var resetMappingsAsync = await api.ResetMappingsAsync();
Console.WriteLine($"resetMappingsAsync = {resetMappingsAsync.Status}");
var resetMappingsAndReloadStaticMappingsAsync = await api.ResetMappingsAsync(true);
Console.WriteLine($"resetMappingsAndReloadStaticMappingsAsync = {resetMappingsAndReloadStaticMappingsAsync.Status}");
Console.WriteLine("Press any key to quit");
Console.ReadKey();
}
}

View File

@@ -1,19 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ApplicationIcon>../../resources/WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ApplicationIcon>../../resources/WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="RestEase" Version="1.5.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
<ProjectReference Include="..\..\src\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\WireMock.Net.RestClient\WireMock.Net.RestClient.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Newtonsoft.Json;
@@ -33,6 +35,11 @@ namespace WireMock.Net.ConsoleApplication
}
}
public class Todo
{
public int Id { get; set; }
}
public static class MainApp
{
public static void Run()
@@ -51,8 +58,31 @@ namespace WireMock.Net.ConsoleApplication
var json = mappingBuilder.ToJson();
System.Console.WriteLine("mappingBuilder : Json = {0}", json);
var s = WireMockServer.Start();
s.Stop();
var todos = new Dictionary<int, Todo>();
var server = WireMockServer.Start();
server
.Given(Request.Create()
.WithPath("todos")
.UsingGet()
)
.RespondWith(Response.Create()
.WithBodyAsJson(todos.Values)
);
server
.Given(Request.Create()
.UsingGet()
.WithPath("todos")
.WithParam("id")
)
.RespondWith(Response.Create()
.WithBodyAsJson(rm => todos[int.Parse(rm.Query!["id"].ToString())])
);
var httpClient = server.CreateClient();
//server.Stop();
var httpAndHttpsWithPort = WireMockServer.Start(new WireMockServerSettings
{
@@ -71,7 +101,7 @@ namespace WireMock.Net.ConsoleApplication
string url2 = "http://localhost:9092/";
string url3 = "https://localhost:9443/";
var server = WireMockServer.Start(new WireMockServerSettings
server = WireMockServer.Start(new WireMockServerSettings
{
AllowCSharpCodeMatcher = true,
Urls = new[] { url1, url2, url3 },
@@ -106,6 +136,31 @@ namespace WireMock.Net.ConsoleApplication
//server.SetAzureADAuthentication("6c2a4722-f3b9-4970-b8fc-fac41e29stef", "8587fde1-7824-42c7-8592-faf92b04stef");
// server.AllowPartialMapping();
// 400 ms
server
.Given(Request.Create()
.WithPath("/slow/400")
.UsingPost())
.RespondWith(
Response.Create()
.WithStatusCode(400)
.WithBody("return 400")
.WithHeader("Content-Type", "text/plain")
);
// 4 sec
server
.Given(Request.Create()
.WithPath("/slow/500")
.UsingPost())
.RespondWith(
Response.Create()
.WithStatusCode(500)
.WithBody("return 500")
.WithHeader("Content-Type", "text/plain")
);
server
.Given(Request.Create()
.UsingMethod("GET")

View File

@@ -0,0 +1,139 @@
using System;
// ReSharper disable once CheckNamespace
namespace WireMock.Admin.Mappings;
/// <summary>
/// RequestModelBuilder
/// </summary>
public partial class RequestModelBuilder
{
/// <summary>
/// UsingConnect: add HTTP Method matching on `CONNECT`.
/// </summary>
/// <returns>The <see cref="RequestModelBuilder"/>.</returns>
public RequestModelBuilder UsingConnect() => WithMethods("CONNECT");
/// <summary>
/// UsingDelete: add HTTP Method matching on `DELETE`.
/// </summary>
/// <returns>The <see cref="RequestModelBuilder"/>.</returns>
public RequestModelBuilder UsingDelete() => WithMethods("DELETE");
/// <summary>
/// UsingGet: add HTTP Method matching on `GET`.
/// </summary>
/// <returns>The <see cref="RequestModelBuilder"/>.</returns>
public RequestModelBuilder UsingGet() => WithMethods("GET");
/// <summary>
/// UsingHead: Add HTTP Method matching on `HEAD`.
/// </summary>
/// <returns>The <see cref="RequestModelBuilder"/>.</returns>
public RequestModelBuilder UsingHead() => WithMethods("HEAD");
/// <summary>
/// UsingPost: add HTTP Method matching on `POST`.
/// </summary>
/// <returns>The <see cref="RequestModelBuilder"/>.</returns>
public RequestModelBuilder UsingPost() => WithMethods("POST");
/// <summary>
/// UsingPatch: add HTTP Method matching on `PATCH`.
/// </summary>
/// <returns>The <see cref="RequestModelBuilder"/>.</returns>
public RequestModelBuilder UsingPatch() => WithMethods("PATCH");
/// <summary>
/// UsingPut: add HTTP Method matching on `OPTIONS`.
/// </summary>
/// <returns>The <see cref="RequestModelBuilder"/>.</returns>
public RequestModelBuilder UsingOptions() => WithMethods("OPTIONS");
/// <summary>
/// UsingPut: add HTTP Method matching on `PUT`.
/// </summary>
/// <returns>The <see cref="RequestModelBuilder"/>.</returns>
public RequestModelBuilder UsingPut() => WithMethods("PUT");
/// <summary>
/// UsingTrace: add HTTP Method matching on `TRACE`.
/// </summary>
/// <returns>The <see cref="RequestModelBuilder"/>.</returns>
public RequestModelBuilder UsingTrace() => WithMethods("TRACE");
/// <summary>
/// UsingAnyMethod: add HTTP Method matching on any method.
/// </summary>
/// <returns>The <see cref="RequestModelBuilder"/>.</returns>
public RequestModelBuilder UsingAnyMethod() => this;
/// <summary>
/// Set the ClientIP.
/// </summary>
public RequestModelBuilder WithClientIP(string value) => WithClientIP(() => value);
/// <summary>
/// Set the ClientIP.
/// </summary>
public RequestModelBuilder WithClientIP(ClientIPModel value) => WithClientIP(() => value);
/// <summary>
/// Set the ClientIP.
/// </summary>
public RequestModelBuilder WithClientIP(Action<ClientIPModelBuilder> action)
{
return WithClientIP(() =>
{
var builder = new ClientIPModelBuilder();
action(builder);
return builder.Build();
});
}
/// <summary>
/// Set the Path.
/// </summary>
public RequestModelBuilder WithPath(string value) => WithPath(() => value);
/// <summary>
/// Set the Path.
/// </summary>
public RequestModelBuilder WithPath(PathModel value) => WithPath(() => value);
/// <summary>
/// Set the Path.
/// </summary>
public RequestModelBuilder WithPath(Action<PathModelBuilder> action)
{
return WithPath(() =>
{
var builder = new PathModelBuilder();
action(builder);
return builder.Build();
});
}
/// <summary>
/// Set the Url.
/// </summary>
public RequestModelBuilder WithUrl(string value) => WithUrl(() => value);
/// <summary>
/// Set the Url.
/// </summary>
public RequestModelBuilder WithUrl(UrlModel value) => WithUrl(() => value);
/// <summary>
/// Set the Url.
/// </summary>
public RequestModelBuilder WithUrl(Action<UrlModelBuilder> action)
{
return WithUrl(() =>
{
var builder = new UrlModelBuilder();
action(builder);
return builder.Build();
});
}
}

View File

@@ -0,0 +1,36 @@
using System;
using System.Net;
// ReSharper disable once CheckNamespace
namespace WireMock.Admin.Mappings;
/// <summary>
/// ResponseModelBuilder
/// </summary>
public partial class ResponseModelBuilder
{
/// <summary>
/// Set the StatusCode.
/// </summary>
public ResponseModelBuilder WithStatusCode(int value) => WithStatusCode(() => value);
/// <summary>
/// Set the StatusCode.
/// </summary>
public ResponseModelBuilder WithStatusCode(HttpStatusCode value) => WithStatusCode(() => value);
/// <summary>
/// Set the Delay.
/// </summary>
public ResponseModelBuilder WithDelay(TimeSpan value) => WithDelay((int) value.TotalMilliseconds);
/// <summary>
/// Set the MinimumRandomDelay.
/// </summary>
public ResponseModelBuilder WithMinimumRandomDelay(TimeSpan value) => WithMinimumRandomDelay((int)value.TotalMilliseconds);
/// <summary>
/// Set the MaximumRandomDelay.
/// </summary>
public ResponseModelBuilder WithMaximumRandomDelay(TimeSpan value) => WithMaximumRandomDelay((int)value.TotalMilliseconds);
}

View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Stef.Validation;
using WireMock.Admin.Mappings;
namespace WireMock.Client.Builders;
/// <summary>
/// AdminApiMappingBuilder
/// </summary>
public class AdminApiMappingBuilder
{
private readonly List<Action<MappingModelBuilder>> _mappingModelBuilderActions = new();
private readonly IWireMockAdminApi _api;
/// <summary>
/// AdminApiMappingBuilder
/// </summary>
/// <param name="api">The <see cref="IWireMockAdminApi"/>.</param>
public AdminApiMappingBuilder(IWireMockAdminApi api)
{
_api = Guard.NotNull(api);
}
/// <summary>
/// The Given
/// </summary>
/// <param name="mappingModelBuilderAction">The action.</param>
public void Given(Action<MappingModelBuilder> mappingModelBuilderAction)
{
_mappingModelBuilderActions.Add(Guard.NotNull(mappingModelBuilderAction));
}
/// <summary>
/// Build the mappings and post these using the <see cref="IWireMockAdminApi"/> to the WireMock.Net server.
/// </summary>
/// <param name="cancellationToken">The optional CancellationToken.</param>
/// <returns><see cref="StatusModel"/></returns>
public Task<StatusModel> BuildAndPostAsync(CancellationToken cancellationToken = default)
{
var modelMappings = new List<MappingModel>();
foreach (var mappingModelBuilderAction in _mappingModelBuilderActions)
{
cancellationToken.ThrowIfCancellationRequested();
var mappingModelBuilder = new MappingModelBuilder();
mappingModelBuilderAction(mappingModelBuilder);
modelMappings.Add(mappingModelBuilder.Build());
}
return _api.PostMappingsAsync(modelMappings, cancellationToken);
}
}

View File

@@ -0,0 +1,46 @@
using System.Text;
using JsonConverter.Abstractions;
using JsonConverter.Newtonsoft.Json;
using WireMock.Admin.Mappings;
namespace WireMock.Client.Extensions;
/// <summary>
/// ResponseModelBuilder
/// </summary>
public static class ResponseModelBuilderExtensions
{
private static readonly Encoding Utf8NoBom = new UTF8Encoding(false);
private static readonly IJsonConverter JsonConverter = new NewtonsoftJsonConverter();
/// <summary>
/// WithBodyAsJson
/// </summary>
/// <param name="builder">The ResponseModelBuilder.</param>
/// <param name="body">The body.</param>
/// <param name="encoding">The body encoding.</param>
/// <param name="indented">Define whether child objects to be indented.</param>
public static ResponseModelBuilder WithBodyAsJson(this ResponseModelBuilder builder, object body, Encoding? encoding = null, bool? indented = null)
{
return builder.WithBodyAsBytes(() =>
{
var options = new JsonConverterOptions
{
WriteIndented = indented == true
};
var jsonBody = JsonConverter.Serialize(body, options);
return (encoding ?? Utf8NoBom).GetBytes(jsonBody);
});
}
/// <summary>
/// WithBodyAsJson
/// </summary>
/// <param name="builder">The ResponseModelBuilder.</param>
/// <param name="body">The body.</param>
/// <param name="indented">Define whether child objects to be indented.</param>
public static ResponseModelBuilder WithBodyAsJson(this ResponseModelBuilder builder, object body, bool indented)
{
return builder.WithBodyAsJson(body, null, indented);
}
}

View File

@@ -0,0 +1,19 @@
using WireMock.Client.Builders;
namespace WireMock.Client.Extensions;
/// <summary>
/// Some extensions for <see cref="IWireMockAdminApi"/>.
/// </summary>
public static class WireMockAdminApiExtensions
{
/// <summary>
/// Get a new <see cref="AdminApiMappingBuilder"/> for the <see cref="IWireMockAdminApi"/>.
/// </summary>
/// <param name="api">See <see cref="IWireMockAdminApi"/>.</param>
/// <returns></returns>
public static AdminApiMappingBuilder GetMappingBuilder(this IWireMockAdminApi api)
{
return new AdminApiMappingBuilder(api);
}
}

View File

@@ -1,250 +1,283 @@
using RestEase;
using System;
using System.Collections.Generic;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using RestEase;
using WireMock.Admin.Mappings;
using WireMock.Admin.Requests;
using WireMock.Admin.Scenarios;
using WireMock.Admin.Settings;
using WireMock.Types;
namespace WireMock.Client
namespace WireMock.Client;
/// <summary>
/// The RestEase interface which defines all admin commands.
/// </summary>
[BasePath("__admin")]
public interface IWireMockAdminApi
{
/// <summary>
/// The RestEase interface which defines all admin commands.
/// Authentication header
/// </summary>
[BasePath("__admin")]
public interface IWireMockAdminApi
{
/// <summary>
/// Authentication header
/// </summary>
[Header("Authorization")]
AuthenticationHeaderValue Authorization { get; set; }
[Header("Authorization")]
AuthenticationHeaderValue Authorization { get; set; }
/// <summary>
/// Get the settings.
/// </summary>
/// <returns>SettingsModel</returns>
[Get("settings")]
Task<SettingsModel> GetSettingsAsync();
/// <summary>
/// Get the settings.
/// </summary>
/// <returns>SettingsModel</returns>
[Get("settings")]
Task<SettingsModel> GetSettingsAsync();
/// <summary>
/// Update the settings.
/// </summary>
/// <param name="settings">SettingsModel</param>
[Put("settings")]
[Header("Content-Type", "application/json")]
Task<StatusModel> PutSettingsAsync([Body] SettingsModel settings);
/// <summary>
/// Update the settings.
/// </summary>
/// <param name="settings">SettingsModel</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Put("settings")]
[Header("Content-Type", "application/json")]
Task<StatusModel> PutSettingsAsync([Body] SettingsModel settings, CancellationToken cancellationToken = default);
/// <summary>
/// Update the settings
/// </summary>
/// <param name="settings">SettingsModel</param>
[Post("settings")]
[Header("Content-Type", "application/json")]
Task<StatusModel> PostSettingsAsync([Body] SettingsModel settings);
/// <summary>
/// Update the settings
/// </summary>
/// <param name="settings">SettingsModel</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("settings")]
[Header("Content-Type", "application/json")]
Task<StatusModel> PostSettingsAsync([Body] SettingsModel settings, CancellationToken cancellationToken = default);
/// <summary>
/// Get the mappings.
/// </summary>
/// <returns>MappingModels</returns>
[Get("mappings")]
Task<IList<MappingModel>> GetMappingsAsync();
/// <summary>
/// Get the mappings.
/// </summary>
/// <returns>MappingModels</returns>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Get("mappings")]
Task<IList<MappingModel>> GetMappingsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Get the C# code from all mappings
/// </summary>
/// <returns>C# code</returns>
[Get("mappings/code")]
Task<string> GetMappingsCodeAsync([Query] MappingConverterType mappingConverterType = MappingConverterType.Server);
/// <summary>
/// Add a new mapping.
/// </summary>
/// <param name="mapping">MappingModel</param>
[Post("mappings")]
[Header("Content-Type", "application/json")]
Task<StatusModel> PostMappingAsync([Body] MappingModel mapping);
/// <summary>
/// Get the C# code from all mappings
/// </summary>
/// <returns>C# code</returns>
/// <param name="mappingConverterType">The <see cref="MappingConverterType"/>, default is Server.</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Get("mappings/code")]
Task<string> GetMappingsCodeAsync([Query] MappingConverterType mappingConverterType = MappingConverterType.Server, CancellationToken cancellationToken = default);
/// <summary>
/// Add new mappings.
/// </summary>
/// <param name="mappings">MappingModels</param>
[Post("mappings")]
[Header("Content-Type", "application/json")]
Task<StatusModel> PostMappingsAsync([Body] IList<MappingModel> mappings);
/// <summary>
/// Add a new mapping.
/// </summary>
/// <param name="mapping">MappingModel</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("mappings")]
[Header("Content-Type", "application/json")]
Task<StatusModel> PostMappingAsync([Body] MappingModel mapping, CancellationToken cancellationToken = default);
/// <summary>
/// Delete all mappings.
/// </summary>
[Delete("mappings")]
Task<StatusModel> DeleteMappingsAsync();
/// <summary>
/// Add new mappings.
/// </summary>
/// <param name="mappings">MappingModels</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("mappings")]
[Header("Content-Type", "application/json")]
Task<StatusModel> PostMappingsAsync([Body] IList<MappingModel> mappings, CancellationToken cancellationToken = default);
/// <summary>
/// Delete mappings according to GUIDs
/// </summary>
/// <param name="mappings">MappingModels</param>
[Delete("mappings")]
[Header("Content-Type", "application/json")]
Task<StatusModel> DeleteMappingsAsync([Body] IList<MappingModel> mappings);
/// <summary>
/// Delete all mappings.
/// </summary>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Delete("mappings")]
Task<StatusModel> DeleteMappingsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Delete (reset) all mappings.
/// </summary>
/// <param name="reloadStaticMappings">A value indicating whether to reload the static mappings after the reset.</param>
[Post("mappings/reset")]
Task<StatusModel> ResetMappingsAsync(bool? reloadStaticMappings = false);
/// <summary>
/// Delete mappings according to GUIDs
/// </summary>
/// <param name="mappings">MappingModels</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Delete("mappings")]
[Header("Content-Type", "application/json")]
Task<StatusModel> DeleteMappingsAsync([Body] IList<MappingModel> mappings, CancellationToken cancellationToken = default);
/// <summary>
/// Get a mapping based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
/// <returns>MappingModel</returns>
[Get("mappings/{guid}")]
Task<MappingModel> GetMappingAsync([Path] Guid guid);
/// <summary>
/// Delete (reset) all mappings.
/// </summary>
/// <param name="reloadStaticMappings">A value indicating whether to reload the static mappings after the reset.</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("mappings/reset")]
Task<StatusModel> ResetMappingsAsync(bool? reloadStaticMappings = false, CancellationToken cancellationToken = default);
/// <summary>
/// Get the C# code from a mapping based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
/// <param name="mappingConverterType">The optional mappingConverterType (can be Server or Builder)</param>
/// <returns>C# code</returns>
[Get("mappings/code/{guid}")]
Task<string> GetMappingCodeAsync([Path] Guid guid, [Query] MappingConverterType mappingConverterType = MappingConverterType.Server);
/// <summary>
/// Update a mapping based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
/// <param name="mapping">MappingModel</param>
[Put("mappings/{guid}")]
[Header("Content-Type", "application/json")]
Task<StatusModel> PutMappingAsync([Path] Guid guid, [Body] MappingModel mapping);
/// <summary>
/// Get a mapping based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
/// <returns>MappingModel</returns>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Get("mappings/{guid}")]
Task<MappingModel> GetMappingAsync([Path] Guid guid, CancellationToken cancellationToken = default);
/// <summary>
/// Delete a mapping based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
[Delete("mappings/{guid}")]
Task<StatusModel> DeleteMappingAsync([Path] Guid guid);
/// <summary>
/// Get the C# code from a mapping based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
/// <param name="mappingConverterType">The optional mappingConverterType (can be Server or Builder)</param>
/// <returns>C# code</returns>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Get("mappings/code/{guid}")]
Task<string> GetMappingCodeAsync([Path] Guid guid, [Query] MappingConverterType mappingConverterType = MappingConverterType.Server, CancellationToken cancellationToken = default);
/// <summary>
/// Save the mappings
/// </summary>
[Post("mappings/save")]
Task<StatusModel> SaveMappingAsync();
/// <summary>
/// Update a mapping based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
/// <param name="mapping">MappingModel</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Put("mappings/{guid}")]
[Header("Content-Type", "application/json")]
Task<StatusModel> PutMappingAsync([Path] Guid guid, [Body] MappingModel mapping, CancellationToken cancellationToken = default);
/// <summary>
/// Get the requests.
/// </summary>
/// <returns>LogRequestModels</returns>
[Get("requests")]
Task<IList<LogEntryModel>> GetRequestsAsync();
/// <summary>
/// Delete a mapping based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Delete("mappings/{guid}")]
Task<StatusModel> DeleteMappingAsync([Path] Guid guid, CancellationToken cancellationToken = default);
/// <summary>
/// Delete all requests.
/// </summary>
[Delete("requests")]
Task<StatusModel> DeleteRequestsAsync();
/// <summary>
/// Save the mappings
/// </summary>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("mappings/save")]
Task<StatusModel> SaveMappingAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Delete (reset) all requests.
/// </summary>
[Post("requests/reset")]
Task<StatusModel> ResetRequestsAsync();
/// <summary>
/// Get the requests.
/// </summary>
/// <returns>LogRequestModels</returns>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Get("requests")]
Task<IList<LogEntryModel>> GetRequestsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Get a request based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
/// <returns>MappingModel</returns>
[Get("requests/{guid}")]
Task<LogEntryModel> GetRequestAsync([Path] Guid guid);
/// <summary>
/// Delete all requests.
/// </summary>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Delete("requests")]
Task<StatusModel> DeleteRequestsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Delete a request based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
[Delete("requests/{guid}")]
Task<StatusModel> DeleteRequestAsync([Path] Guid guid);
/// <summary>
/// Delete (reset) all requests.
/// </summary>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("requests/reset")]
Task<StatusModel> ResetRequestsAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Find a request based on the criteria
/// </summary>
/// <param name="model">The RequestModel</param>
[Post("requests/find")]
[Header("Content-Type", "application/json")]
Task<IList<LogEntryModel>> FindRequestsAsync([Body] RequestModel model);
/// <summary>
/// Get a request based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
/// <returns>MappingModel</returns>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Get("requests/{guid}")]
Task<LogEntryModel> GetRequestAsync([Path] Guid guid, CancellationToken cancellationToken = default);
/// <summary>
/// Get all scenarios
/// </summary>
[Get("scenarios")]
Task<IList<ScenarioStateModel>> GetScenariosAsync();
/// <summary>
/// Delete a request based on the guid
/// </summary>
/// <param name="guid">The Guid</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Delete("requests/{guid}")]
Task<StatusModel> DeleteRequestAsync([Path] Guid guid, CancellationToken cancellationToken = default);
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
[Delete("scenarios")]
Task<StatusModel> DeleteScenariosAsync();
/// <summary>
/// Find a request based on the criteria
/// </summary>
/// <param name="model">The RequestModel</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("requests/find")]
[Header("Content-Type", "application/json")]
Task<IList<LogEntryModel>> FindRequestsAsync([Body] RequestModel model, CancellationToken cancellationToken = default);
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
[Post("scenarios")]
Task<StatusModel> ResetScenariosAsync();
/// <summary>
/// Get all scenarios
/// </summary>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Get("scenarios")]
Task<IList<ScenarioStateModel>> GetScenariosAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Delete (reset) a specific scenario
/// </summary>
[Delete("scenarios/{name}")]
[AllowAnyStatusCode]
Task<StatusModel> DeleteScenarioAsync([Path] string name);
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Delete("scenarios")]
Task<StatusModel> DeleteScenariosAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
[Post("scenarios/{name}/reset")]
[AllowAnyStatusCode]
Task<StatusModel> ResetScenarioAsync([Path] string name);
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("scenarios")]
Task<StatusModel> ResetScenariosAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Create a new File
/// </summary>
/// <param name="filename">The filename</param>
/// <param name="body">The body</param>
[Post("files/{filename}")]
Task<StatusModel> PostFileAsync([Path] string filename, [Body] string body);
/// <summary>
/// Delete (reset) a specific scenario
/// </summary>
/// <param name="name">Scenario name.</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Delete("scenarios/{name}")]
[AllowAnyStatusCode]
Task<StatusModel> DeleteScenarioAsync([Path] string name, CancellationToken cancellationToken = default);
/// <summary>
/// Update an existing File
/// </summary>
/// <param name="filename">The filename</param>
/// <param name="body">The body</param>
[Put("files/{filename}")]
Task<StatusModel> PutFileAsync([Path] string filename, [Body] string body);
/// <summary>
/// Delete (reset) all scenarios
/// </summary>
/// <param name="name">Scenario name.</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("scenarios/{name}/reset")]
[AllowAnyStatusCode]
Task<StatusModel> ResetScenarioAsync([Path] string name, CancellationToken cancellationToken = default);
/// <summary>
/// Get the content of an existing File
/// </summary>
/// <param name="filename">The filename</param>
[Get("files/{filename}")]
Task<string> GetFileAsync([Path] string filename);
/// <summary>
/// Create a new File
/// </summary>
/// <param name="filename">The filename</param>
/// <param name="body">The body</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Post("files/{filename}")]
Task<StatusModel> PostFileAsync([Path] string filename, [Body] string body, CancellationToken cancellationToken = default);
/// <summary>
/// Delete an existing File
/// </summary>
/// <param name="filename">The filename</param>
[Delete("files/{filename}")]
Task<StatusModel> DeleteFileAsync([Path] string filename);
/// <summary>
/// Update an existing File
/// </summary>
/// <param name="filename">The filename</param>
/// <param name="body">The body</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Put("files/{filename}")]
Task<StatusModel> PutFileAsync([Path] string filename, [Body] string body, CancellationToken cancellationToken = default);
/// <summary>
/// Check if a file exists
/// </summary>
/// <param name="filename">The filename</param>
[Head("files/{filename}")]
Task FileExistsAsync([Path] string filename);
}
/// <summary>
/// Get the content of an existing File
/// </summary>
/// <param name="filename">The filename</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Get("files/{filename}")]
Task<string> GetFileAsync([Path] string filename, CancellationToken cancellationToken = default);
/// <summary>
/// Delete an existing File
/// </summary>
/// <param name="filename">The filename</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Delete("files/{filename}")]
Task<StatusModel> DeleteFileAsync([Path] string filename, CancellationToken cancellationToken = default);
/// <summary>
/// Check if a file exists
/// </summary>
/// <param name="filename">The filename</param>
/// <param name="cancellationToken">The optional cancellationToken.</param>
[Head("files/{filename}")]
Task FileExistsAsync([Path] string filename, CancellationToken cancellationToken = default);
}

View File

@@ -30,8 +30,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JsonConverter.Newtonsoft.Json" Version="0.3.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="RestEase" Version="1.5.7" />
<PackageReference Include="Stef.Validation" Version="0.1.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -29,7 +29,7 @@ public interface IBodyResponseBuilder : IFaultResponseBuilder
IResponseBuilder WithBody(Func<IRequestMessage, string> bodyFactory, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null);
/// <summary>
/// WithBody : Create a ... response based on a callback function.
/// WithBody : Create a ... response based on a async callback function.
/// </summary>
/// <param name="bodyFactory">The async delegate to build the body.</param>
/// <param name="destination">The Body Destination format (SameAsSource, String or Bytes).</param>
@@ -51,7 +51,7 @@ public interface IBodyResponseBuilder : IFaultResponseBuilder
/// </summary>
/// <param name="body">The body.</param>
/// <param name="encoding">The body encoding.</param>
/// <param name="indented">Use JSON indented.</param>
/// <param name="indented">Define whether child objects to be indented according to the Newtonsoft.Json.JsonTextWriter.Indentation and Newtonsoft.Json.JsonTextWriter.IndentChar settings.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBodyAsJson(object body, Encoding? encoding = null, bool? indented = null);
@@ -63,6 +63,22 @@ public interface IBodyResponseBuilder : IFaultResponseBuilder
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBodyAsJson(object body, bool indented);
/// <summary>
/// WithBodyAsJson : Create a ... response based on a callback function.
/// </summary>
/// <param name="bodyFactory">The delegate to build the body.</param>
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBodyAsJson(Func<IRequestMessage, object> bodyFactory, Encoding? encoding = null);
/// <summary>
/// WithBodyAsJson : Create a ... response based on a async callback function.
/// </summary>
/// <param name="bodyFactory">The async delegate to build the body.</param>
/// <param name="encoding">The body encoding.</param>
/// <returns>A <see cref="IResponseBuilder"/>.</returns>
IResponseBuilder WithBodyAsJson(Func<IRequestMessage, Task<object>> bodyFactory, Encoding? encoding = null);
/// <summary>
/// WithBodyFromFile : Create a ... response based on a File.
/// </summary>

View File

@@ -13,7 +13,7 @@ public partial class Response
/// <inheritdoc />
public IResponseBuilder WithBody(Func<IRequestMessage, string> bodyFactory, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null)
{
Guard.NotNull(bodyFactory, nameof(bodyFactory));
Guard.NotNull(bodyFactory);
return WithCallbackInternal(true, req => new ResponseMessage
{
@@ -30,7 +30,7 @@ public partial class Response
/// <inheritdoc />
public IResponseBuilder WithBody(Func<IRequestMessage, Task<string>> bodyFactory, string? destination = BodyDestinationFormat.SameAsSource, Encoding? encoding = null)
{
Guard.NotNull(bodyFactory, nameof(bodyFactory));
Guard.NotNull(bodyFactory);
return WithCallbackInternal(true, async req => new ResponseMessage
{
@@ -70,7 +70,7 @@ public partial class Response
return this;
}
/// <inheritdoc cref="IBodyResponseBuilder.WithBodyFromFile"/>
/// <inheritdoc />
public IResponseBuilder WithBodyFromFile(string filename, bool cache = true)
{
Guard.NotNull(filename);
@@ -127,7 +127,7 @@ public partial class Response
return this;
}
/// <inheritdoc cref="IBodyResponseBuilder.WithBodyAsJson(object, Encoding, bool?)"/>
/// <inheritdoc />
public IResponseBuilder WithBodyAsJson(object body, Encoding? encoding = null, bool? indented = null)
{
Guard.NotNull(body);
@@ -144,12 +144,46 @@ public partial class Response
return this;
}
/// <inheritdoc cref="IBodyResponseBuilder.WithBodyAsJson(object, bool)"/>
/// <inheritdoc />
public IResponseBuilder WithBodyAsJson(object body, bool indented)
{
return WithBodyAsJson(body, null, indented);
}
/// <inheritdoc />
public IResponseBuilder WithBodyAsJson(Func<IRequestMessage, object> bodyFactory, Encoding? encoding = null)
{
Guard.NotNull(bodyFactory);
return WithCallbackInternal(true, req => new ResponseMessage
{
BodyData = new BodyData
{
Encoding = encoding ?? Encoding.UTF8,
DetectedBodyType = BodyType.Json,
BodyAsJson = bodyFactory(req),
IsFuncUsed = "Func<IRequestMessage, object>"
}
});
}
/// <inheritdoc />
public IResponseBuilder WithBodyAsJson(Func<IRequestMessage, Task<object>> bodyFactory, Encoding? encoding = null)
{
Guard.NotNull(bodyFactory);
return WithCallbackInternal(true, async req => new ResponseMessage
{
BodyData = new BodyData
{
Encoding = encoding ?? Encoding.UTF8,
DetectedBodyType = BodyType.Json,
BodyAsJson = await bodyFactory(req).ConfigureAwait(false),
IsFuncUsed = "Func<IRequestMessage, Task<object>>"
}
});
}
/// <inheritdoc />
public IResponseBuilder WithBody(object body, IJsonConverter converter, JsonConverterOptions? options = null)
{

View File

@@ -120,28 +120,6 @@ public class ResponseWithBodyTests
Check.That(response.Message.BodyData.Encoding).Equals(Encoding.ASCII);
}
[Fact]
public async Task Response_ProvideResponse_WithBody_Object_Indented()
{
// given
var body = new BodyData
{
DetectedBodyType = BodyType.String,
BodyAsString = "abc"
};
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
object x = new { message = "Hello" };
var responseBuilder = Response.Create().WithBodyAsJson(x, true);
// act
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
// then
Check.That(response.Message.BodyData.BodyAsJson).Equals(x);
Check.That(response.Message.BodyData.BodyAsJsonIndented).IsEqualTo(true);
}
[Fact]
public async Task Response_ProvideResponse_WithBody_String_SameAsSource_Encoding()
{
@@ -196,6 +174,70 @@ public class ResponseWithBodyTests
Check.That(response.Message.BodyData.Encoding).Equals(Encoding.ASCII);
}
[Fact]
public async Task Response_ProvideResponse_WithBodyAsJson_Object_Indented()
{
// given
var body = new BodyData
{
DetectedBodyType = BodyType.String,
BodyAsString = "abc"
};
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, body);
object x = new { message = "Hello" };
var responseBuilder = Response.Create().WithBodyAsJson(x, true);
// act
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
// then
Check.That(response.Message.BodyData.BodyAsJson).Equals(x);
Check.That(response.Message.BodyData.BodyAsJsonIndented).IsEqualTo(true);
}
[Fact]
public async Task Response_ProvideResponse_WithBodyAsJson_FuncObject()
{
// Arrange
var requestBody = new BodyData
{
DetectedBodyType = BodyType.String,
BodyAsString = "abc"
};
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, requestBody);
object responseBody = new { message = "Hello" };
var responseBuilder = Response.Create().WithBodyAsJson(requestMessage => responseBody);
// Act
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
// Assert
response.Message.BodyData!.BodyAsJson.Should().BeEquivalentTo(responseBody);
}
[Fact]
public async Task Response_ProvideResponse_WithBodyAsJson_AsyncFuncObject()
{
// Arrange
var requestBody = new BodyData
{
DetectedBodyType = BodyType.String,
BodyAsString = "abc"
};
var request = new RequestMessage(new UrlDetails("http://localhost/foo"), "POST", ClientIp, requestBody);
object responseBody = new { message = "Hello" };
var responseBuilder = Response.Create().WithBodyAsJson(requestMessage => Task.FromResult(responseBody));
// Act
var response = await responseBuilder.ProvideResponseAsync(_mappingMock.Object, request, _settings).ConfigureAwait(false);
// Assert
response.Message.BodyData!.BodyAsJson.Should().BeEquivalentTo(responseBody);
}
[Fact]
public async Task Response_ProvideResponse_WithJsonBodyAndTransform()
{