RegexExampleValueGenerator

This commit is contained in:
Stef Heyenrath
2023-05-28 23:10:09 +02:00
parent c1e71707c5
commit 35ffbbc7d9
6 changed files with 133 additions and 58 deletions

View File

@@ -18,7 +18,7 @@ class Program
private static void RunMockServerWithDynamicExampleGeneration()
{
// 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(), Types.PatternType.Value, Types.PatternType.Value);
Console.WriteLine("Press any key to stop the servers");
Console.ReadKey();

View File

@@ -18,8 +18,8 @@ public static class Run
string url,
bool dynamicExamples = true,
IWireMockOpenApiParserExampleValues? examplesValuesGenerator = null,
ExampleValueType pathPatternToUse = ExampleValueType.Wildcard,
ExampleValueType headerPatternToUse = ExampleValueType.Wildcard
PatternType pathPatternToUse = PatternType.Wildcard,
PatternType headerPatternToUse = PatternType.Wildcard
)
{
var server = WireMockServer.Start(new WireMockServerSettings

View File

@@ -37,18 +37,7 @@ internal class OpenApiPathsMapper
.OrderBy(p => p.Key)
.Select(p => MapPath(p.Key, p.Value, servers))
.SelectMany(x => x)
.ToArray() ??
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>();
.ToArray() ?? Array.Empty<MappingModel>();
}
private IReadOnlyList<MappingModel> MapPath(string path, OpenApiPathItem pathItem, IList<OpenApiServer> servers)
@@ -280,41 +269,6 @@ internal class OpenApiPathsMapper
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)
{
var mappedHeaders = headers?.ToDictionary(
@@ -366,26 +320,34 @@ internal class OpenApiPathsMapper
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
{
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
},
_ => new MatcherModel
{
Name = "WildcardMatcher",
Pattern = "*"
Pattern = "*",
IgnoreCase = _settings.IgnoreCaseExampleValues
}
};
}
private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema)
private string GetExampleValueAsStringForSchemaType(OpenApiSchema? schema, ExampleValueType exampleValueType)
{
var value = _exampleValueGenerator.GetExampleValue(schema);
@@ -396,4 +358,39 @@ internal class OpenApiPathsMapper
_ => 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());
}
}

View File

@@ -1,7 +1,7 @@
namespace WireMock.Net.OpenApiParser.Types;
/// <summary>
/// The example value to use
/// The (example) value pattern to use.
/// </summary>
public enum ExampleValueType
{
@@ -12,6 +12,11 @@ public enum ExampleValueType
/// </summary>
Value,
/// <summary>
/// Build a Regex based on the SchemaType.
/// </summary>
Regex,
/// <summary>
/// Just use a Wildcard (*) character.
/// </summary>

View File

@@ -0,0 +1,53 @@
using System.Linq;
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
{
public RegexExampleValueGenerator(WireMockOpenApiParserSettings settings)
{
Guard.NotNull(settings);
}
public string GetExampleValue(OpenApiSchema? schema)
{
var schemaExample = schema?.Example;
var schemaEnum = schema?.Enum?.FirstOrDefault();
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:
switch (schema?.GetSchemaFormat())
{
case SchemaFormat.Date:
return @"^(\d{4})-([01]\d)-([0-3]\d)$";
case SchemaFormat.DateTime:
return @"^(\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)$";
case SchemaFormat.Byte:
return @"^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
case SchemaFormat.Binary:
return @"^[a-zA-Z0-9\+/]*={0,3}$";
default:
return ".*";
}
}
}
}

View File

@@ -2,20 +2,39 @@
using System;
using System.Linq;
using System.Net;
using Newtonsoft.Json;
using WireMock.Net.OpenApiParser;
using WireMock.Net.OpenApiParser.Settings;
using WireMock.Net.OpenApiParser.Types;
using WireMock.Serialization;
#endif
namespace WireMock.Server;
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)
{
#if OPENAPIPARSER
try
{
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)
{
@@ -35,7 +54,8 @@ public partial class WireMockServer
var mappingModels = new WireMockOpenApiParser().FromText(requestMessage.Body, out var diagnostic);
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);