mirror of
https://github.com/wiremock/WireMock.Net.git
synced 2026-01-19 01:47:08 +01:00
Compare commits
5 Commits
MappingSer
...
stef-Ignor
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dabe3a2a10 | ||
|
|
b609191095 | ||
|
|
b1ae9aaf46 | ||
|
|
ad3ef83c5e | ||
|
|
35ffbbc7d9 |
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
using WireMock.RequestBuilders;
|
using WireMock.RequestBuilders;
|
||||||
using WireMock.ResponseBuilders;
|
using WireMock.ResponseBuilders;
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ class Program
|
|||||||
private static void RunMockServerWithDynamicExampleGeneration()
|
private static void RunMockServerWithDynamicExampleGeneration()
|
||||||
{
|
{
|
||||||
// Run your mocking framework specifying your Example Values generator class.
|
// Run your mocking framework specifying your Example Values generator class.
|
||||||
var serverCustomer_V2_json = Run.RunServer(Path.Combine(Folder, "Swagger_Customer_V2.0.json"), "http://localhost:8090/", true, new DynamicDataGeneration(), Types.ExampleValueType.Value, Types.ExampleValueType.Value);
|
var serverCustomer_V2_json = Run.RunServer(Path.Combine(Folder, "Swagger_Customer_V2.0.json"), "http://localhost:8090/", true, new DynamicDataGeneration(), ExampleValueType.Value, ExampleValueType.Value);
|
||||||
Console.WriteLine("Press any key to stop the servers");
|
Console.WriteLine("Press any key to stop the servers");
|
||||||
|
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
|
|||||||
@@ -23,12 +23,14 @@ internal class OpenApiPathsMapper
|
|||||||
private const string HeaderContentType = "Content-Type";
|
private const string HeaderContentType = "Content-Type";
|
||||||
|
|
||||||
private readonly WireMockOpenApiParserSettings _settings;
|
private readonly WireMockOpenApiParserSettings _settings;
|
||||||
private readonly ExampleValueGenerator _exampleValueGenerator;
|
private readonly IExampleValueGenerator _exampleValueGenerator;
|
||||||
|
private readonly IExampleValueGenerator _regexExampleValueGenerator;
|
||||||
|
|
||||||
public OpenApiPathsMapper(WireMockOpenApiParserSettings settings)
|
public OpenApiPathsMapper(WireMockOpenApiParserSettings settings)
|
||||||
{
|
{
|
||||||
_settings = Guard.NotNull(settings);
|
_settings = Guard.NotNull(settings);
|
||||||
_exampleValueGenerator = new ExampleValueGenerator(settings);
|
_exampleValueGenerator = new ExampleValueGenerator(settings);
|
||||||
|
_regexExampleValueGenerator = new RegexExampleValueGenerator(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<MappingModel> ToMappingModels(OpenApiPaths? paths, IList<OpenApiServer> servers)
|
public IReadOnlyList<MappingModel> ToMappingModels(OpenApiPaths? paths, IList<OpenApiServer> servers)
|
||||||
@@ -37,18 +39,7 @@ internal class OpenApiPathsMapper
|
|||||||
.OrderBy(p => p.Key)
|
.OrderBy(p => p.Key)
|
||||||
.Select(p => MapPath(p.Key, p.Value, servers))
|
.Select(p => MapPath(p.Key, p.Value, servers))
|
||||||
.SelectMany(x => x)
|
.SelectMany(x => x)
|
||||||
.ToArray() ??
|
.ToArray() ?? Array.Empty<MappingModel>();
|
||||||
Array.Empty<MappingModel>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IReadOnlyList<MappingModel> MapPaths(OpenApiPaths? paths, IList<OpenApiServer> servers)
|
|
||||||
{
|
|
||||||
return paths?
|
|
||||||
.OrderBy(p => p.Key)
|
|
||||||
.Select(p => MapPath(p.Key, p.Value, servers))
|
|
||||||
.SelectMany(x => x)
|
|
||||||
.ToArray() ??
|
|
||||||
Array.Empty<MappingModel>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IReadOnlyList<MappingModel> MapPath(string path, OpenApiPathItem pathItem, IList<OpenApiServer> servers)
|
private IReadOnlyList<MappingModel> MapPath(string path, OpenApiPathItem pathItem, IList<OpenApiServer> servers)
|
||||||
@@ -280,41 +271,6 @@ internal class OpenApiPathsMapper
|
|||||||
return newPath;
|
return newPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string MapBasePath(IList<OpenApiServer>? servers)
|
|
||||||
{
|
|
||||||
if (servers == null || servers.Count == 0)
|
|
||||||
{
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenApiServer server = servers.First();
|
|
||||||
if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out Uri uriResult))
|
|
||||||
{
|
|
||||||
return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (any.AnyType == AnyType.Array)
|
|
||||||
{
|
|
||||||
return JArray.Parse(outputString.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return JObject.Parse(outputString.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private IDictionary<string, object>? MapHeaders(string? responseContentType, IDictionary<string, OpenApiHeader>? headers)
|
private IDictionary<string, object>? MapHeaders(string? responseContentType, IDictionary<string, OpenApiHeader>? headers)
|
||||||
{
|
{
|
||||||
var mappedHeaders = headers?.ToDictionary(
|
var mappedHeaders = headers?.ToDictionary(
|
||||||
@@ -366,28 +322,38 @@ internal class OpenApiPathsMapper
|
|||||||
return list.Any() ? list : null;
|
return list.Any() ? list : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MatcherModel GetExampleMatcherModel(OpenApiSchema? schema, ExampleValueType type)
|
private MatcherModel GetExampleMatcherModel(OpenApiSchema? schema, ExampleValueType exampleValueType)
|
||||||
{
|
{
|
||||||
return type switch
|
return exampleValueType switch
|
||||||
{
|
{
|
||||||
ExampleValueType.Value => new MatcherModel
|
ExampleValueType.Value => new MatcherModel
|
||||||
{
|
{
|
||||||
Name = "ExactMatcher",
|
Name = "ExactMatcher",
|
||||||
Pattern = GetExampleValueAsStringForSchemaType(schema),
|
Pattern = GetExampleValueAsStringForSchemaType(schema, exampleValueType),
|
||||||
|
IgnoreCase = _settings.IgnoreCaseExampleValues
|
||||||
|
},
|
||||||
|
|
||||||
|
ExampleValueType.Regex => new MatcherModel
|
||||||
|
{
|
||||||
|
Name = "RegexMatcher",
|
||||||
|
Pattern = GetExampleValueAsStringForSchemaType(schema, exampleValueType),
|
||||||
IgnoreCase = _settings.IgnoreCaseExampleValues
|
IgnoreCase = _settings.IgnoreCaseExampleValues
|
||||||
},
|
},
|
||||||
|
|
||||||
_ => new MatcherModel
|
_ => new MatcherModel
|
||||||
{
|
{
|
||||||
Name = "WildcardMatcher",
|
Name = "WildcardMatcher",
|
||||||
Pattern = "*"
|
Pattern = "*",
|
||||||
|
IgnoreCase = _settings.IgnoreCaseExampleValues
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema)
|
private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema, ExampleValueType exampleValueType)
|
||||||
{
|
{
|
||||||
var value = _exampleValueGenerator.GetExampleValue(schema);
|
var value = exampleValueType == ExampleValueType.Regex ?
|
||||||
|
_regexExampleValueGenerator.GetExampleValue(schema) :
|
||||||
|
_exampleValueGenerator.GetExampleValue(schema);
|
||||||
|
|
||||||
return value switch
|
return value switch
|
||||||
{
|
{
|
||||||
@@ -396,4 +362,39 @@ internal class OpenApiPathsMapper
|
|||||||
_ => value.ToString(),
|
_ => value.ToString(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string MapBasePath(IList<OpenApiServer>? servers)
|
||||||
|
{
|
||||||
|
if (servers == null || servers.Count == 0)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
var server = servers.First();
|
||||||
|
if (Uri.TryCreate(server.Url, UriKind.RelativeOrAbsolute, out Uri uriResult))
|
||||||
|
{
|
||||||
|
return uriResult.IsAbsoluteUri ? uriResult.AbsolutePath : uriResult.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (any.AnyType == AnyType.Array)
|
||||||
|
{
|
||||||
|
return JArray.Parse(outputString.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return JObject.Parse(outputString.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace WireMock.Net.OpenApiParser.Types;
|
namespace WireMock.Net.OpenApiParser.Types;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The example value to use
|
/// The (example) value pattern to use.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum ExampleValueType
|
public enum ExampleValueType
|
||||||
{
|
{
|
||||||
@@ -12,6 +12,11 @@ public enum ExampleValueType
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Value,
|
Value,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Build a Regex based on the SchemaType.
|
||||||
|
/// </summary>
|
||||||
|
Regex,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Just use a Wildcard (*) character.
|
/// Just use a Wildcard (*) character.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using WireMock.Net.OpenApiParser.Types;
|
|||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser.Utils;
|
namespace WireMock.Net.OpenApiParser.Utils;
|
||||||
|
|
||||||
internal class ExampleValueGenerator
|
internal class ExampleValueGenerator : IExampleValueGenerator
|
||||||
{
|
{
|
||||||
private readonly IWireMockOpenApiParserExampleValues _exampleValues;
|
private readonly IWireMockOpenApiParserExampleValues _exampleValues;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
|
||||||
|
namespace WireMock.Net.OpenApiParser.Utils;
|
||||||
|
|
||||||
|
internal interface IExampleValueGenerator
|
||||||
|
{
|
||||||
|
object GetExampleValue(OpenApiSchema? schema);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Stef.Validation;
|
||||||
|
using WireMock.Net.OpenApiParser.Extensions;
|
||||||
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
|
|
||||||
|
namespace WireMock.Net.OpenApiParser.Utils;
|
||||||
|
|
||||||
|
internal class RegexExampleValueGenerator : IExampleValueGenerator
|
||||||
|
{
|
||||||
|
public RegexExampleValueGenerator(WireMockOpenApiParserSettings settings)
|
||||||
|
{
|
||||||
|
Guard.NotNull(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetExampleValue(OpenApiSchema? schema)
|
||||||
|
{
|
||||||
|
switch (schema?.GetSchemaType())
|
||||||
|
{
|
||||||
|
case SchemaType.Boolean:
|
||||||
|
return @"(true|false)";
|
||||||
|
|
||||||
|
case SchemaType.Integer:
|
||||||
|
return @"-?\d+";
|
||||||
|
|
||||||
|
case SchemaType.Number:
|
||||||
|
return @"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return schema?.GetSchemaFormat() switch
|
||||||
|
{
|
||||||
|
SchemaFormat.Date => @"(\d{4})-([01]\d)-([0-3]\d)",
|
||||||
|
SchemaFormat.DateTime => @"(\d{4})-([01]\d)-([0-3]\d)T([0-2]\d):([0-5]\d):([0-5]\d)(\.\d+)?(Z|[+-][0-2]\d:[0-5]\d)",
|
||||||
|
SchemaFormat.Byte => @"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)",
|
||||||
|
SchemaFormat.Binary => @"[a-zA-Z0-9\+/]*={0,3}",
|
||||||
|
_ => ".*"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ using RamlToOpenApiConverter;
|
|||||||
using WireMock.Admin.Mappings;
|
using WireMock.Admin.Mappings;
|
||||||
using WireMock.Net.OpenApiParser.Mappers;
|
using WireMock.Net.OpenApiParser.Mappers;
|
||||||
using WireMock.Net.OpenApiParser.Settings;
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
|
|
||||||
namespace WireMock.Net.OpenApiParser;
|
namespace WireMock.Net.OpenApiParser;
|
||||||
|
|
||||||
@@ -17,13 +18,20 @@ namespace WireMock.Net.OpenApiParser;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class WireMockOpenApiParser : IWireMockOpenApiParser
|
public class WireMockOpenApiParser : IWireMockOpenApiParser
|
||||||
{
|
{
|
||||||
|
private readonly WireMockOpenApiParserSettings _wireMockOpenApiParserSettings = new WireMockOpenApiParserSettings
|
||||||
|
{
|
||||||
|
HeaderPatternToUse = ExampleValueType.Regex,
|
||||||
|
QueryParameterPatternToUse = ExampleValueType.Regex,
|
||||||
|
PathPatternToUse = ExampleValueType.Regex
|
||||||
|
};
|
||||||
|
|
||||||
private readonly OpenApiStreamReader _reader = new();
|
private readonly OpenApiStreamReader _reader = new();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IReadOnlyList<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic)
|
public IReadOnlyList<MappingModel> FromFile(string path, out OpenApiDiagnostic diagnostic)
|
||||||
{
|
{
|
||||||
return FromFile(path, new WireMockOpenApiParserSettings(), out diagnostic);
|
return FromFile(path, _wireMockOpenApiParserSettings, out diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -49,7 +57,7 @@ public class WireMockOpenApiParser : IWireMockOpenApiParser
|
|||||||
[PublicAPI]
|
[PublicAPI]
|
||||||
public IReadOnlyList<MappingModel> FromDocument(OpenApiDocument openApiDocument, WireMockOpenApiParserSettings? settings = null)
|
public IReadOnlyList<MappingModel> FromDocument(OpenApiDocument openApiDocument, WireMockOpenApiParserSettings? settings = null)
|
||||||
{
|
{
|
||||||
return new OpenApiPathsMapper(settings ?? new WireMockOpenApiParserSettings()).ToMappingModels(openApiDocument.Paths, openApiDocument.Servers);
|
return new OpenApiPathsMapper(settings ?? _wireMockOpenApiParserSettings).ToMappingModels(openApiDocument.Paths, openApiDocument.Servers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -2,20 +2,39 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using WireMock.Net.OpenApiParser;
|
using WireMock.Net.OpenApiParser;
|
||||||
|
using WireMock.Net.OpenApiParser.Settings;
|
||||||
|
using WireMock.Net.OpenApiParser.Types;
|
||||||
|
using WireMock.Serialization;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace WireMock.Server;
|
namespace WireMock.Server;
|
||||||
|
|
||||||
public partial class WireMockServer
|
public partial class WireMockServer
|
||||||
{
|
{
|
||||||
|
#if OPENAPIPARSER
|
||||||
|
private readonly WireMockOpenApiParserSettings _openApiParserSettings = new WireMockOpenApiParserSettings
|
||||||
|
{
|
||||||
|
PathPatternToUse = ExampleValueType.Regex,
|
||||||
|
HeaderPatternToUse = ExampleValueType.Regex,
|
||||||
|
QueryParameterPatternToUse = ExampleValueType.Regex
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
private IResponseMessage OpenApiConvertToMappings(IRequestMessage requestMessage)
|
private IResponseMessage OpenApiConvertToMappings(IRequestMessage requestMessage)
|
||||||
{
|
{
|
||||||
#if OPENAPIPARSER
|
#if OPENAPIPARSER
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body, out var diagnostic);
|
var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body, out var diagnostic);
|
||||||
return diagnostic.Errors.Any() ? ToJson(diagnostic, false, HttpStatusCode.BadRequest) : ToJson(mappingModels);
|
if (diagnostic.Errors.Any())
|
||||||
|
{
|
||||||
|
var diagnosticAsJson = JsonConvert.SerializeObject(diagnostic, JsonSerializationConstants.JsonSerializerSettingsDefault);
|
||||||
|
_settings.Logger.Warn("OpenApiError(s) while converting OpenAPI specification to MappingModel(s) : {0}", diagnosticAsJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ToJson(mappingModels);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -35,7 +54,8 @@ public partial class WireMockServer
|
|||||||
var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body, out var diagnostic);
|
var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body, out var diagnostic);
|
||||||
if (diagnostic.Errors.Any())
|
if (diagnostic.Errors.Any())
|
||||||
{
|
{
|
||||||
return ToJson(diagnostic, false, HttpStatusCode.BadRequest);
|
var diagnosticAsJson = JsonConvert.SerializeObject(diagnostic, JsonSerializationConstants.JsonSerializerSettingsDefault);
|
||||||
|
_settings.Logger.Warn("OpenApiError(s) while converting OpenAPI specification to MappingModel(s) : {0}", diagnosticAsJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvertMappingsAndRegisterAsRespondProvider(mappingModels);
|
ConvertMappingsAndRegisterAsRespondProvider(mappingModels);
|
||||||
|
|||||||
Reference in New Issue
Block a user