Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update the OpenApiPathsMapper to handle Value/Wildcard #691

Merged
merged 1 commit into from
Nov 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions examples/WireMock.Net.OpenApiParser.ConsoleApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ class Program
private const string Folder = "OpenApiFiles";
static void Main(string[] args)
{
var serverOpenAPIExamples = Run.RunServer(Path.Combine(Folder, "openAPIExamples.yaml"), "http://localhost:9091/");
var serverPetstore_V2_json = Run.RunServer(Path.Combine(Folder, "Swagger_Petstore_V2.0.json"), "http://localhost:9092/");
var serverPetstore_V2_yaml = Run.RunServer(Path.Combine(Folder, "Swagger_Petstore_V2.0.yaml"), "http://localhost:9093/");
var serverPetstore_V300_yaml = Run.RunServer(Path.Combine(Folder, "Swagger_Petstore_V3.0.0.yaml"), "http://localhost:9094/");
var serverPetstore_V302_json = Run.RunServer(Path.Combine(Folder, "Swagger_Petstore_V3.0.2.json"), "http://localhost:9095/");
var serverOpenAPIExamples = Run.RunServer(Path.Combine(Folder, "openAPIExamples.yaml"), "https://localhost:9091/");
var serverPetstore_V2_json = Run.RunServer(Path.Combine(Folder, "Swagger_Petstore_V2.0.json"), "https://localhost:9092/");
var serverPetstore_V2_yaml = Run.RunServer(Path.Combine(Folder, "Swagger_Petstore_V2.0.yaml"), "https://localhost:9093/");
var serverPetstore_V300_yaml = Run.RunServer(Path.Combine(Folder, "Swagger_Petstore_V3.0.0.yaml"), "https://localhost:9094/");
var serverPetstore_V302_json = Run.RunServer(Path.Combine(Folder, "Swagger_Petstore_V3.0.2.json"), "https://localhost:9095/");

Console.WriteLine("Press any key to stop the servers");
Console.ReadKey();
Expand Down
6 changes: 4 additions & 2 deletions examples/WireMock.Net.OpenApiParser.ConsoleApp/Run.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace WireMock.Net.OpenApiParser.ConsoleApp
{
public static class Run
{
public static WireMockServer RunServer(string path, string url)
public static WireMockServer RunServer(string path, string url, bool dynamicExamples = true)
{
var server = WireMockServer.Start(new WireMockServerSettings
{
Expand All @@ -31,7 +31,9 @@ public static WireMockServer RunServer(string path, string url)

var settings = new WireMockOpenApiParserSettings
{
PathPatternToUse = ExampleValueType.Wildcard
DynamicExamples = dynamicExamples,
PathPatternToUse = ExampleValueType.Wildcard,
HeaderPatternToUse = ExampleValueType.Wildcard
};

server.WithMappingFromOpenApiFile(path, settings, out var diag);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
Expand Down
21 changes: 21 additions & 0 deletions src/WireMock.Net.OpenApiParser/Extensions/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#if NET46 || NETSTANDARD2_0
using System.Collections.Generic;

namespace WireMock.Net.OpenApiParser.Extensions
{
internal static class DictionaryExtensions
{
public static bool TryAdd<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue value)
{
if (dictionary is null || dictionary.ContainsKey(key))
{
return false;
}

dictionary[key] = value;

return true;
}
}
}
#endif
57 changes: 21 additions & 36 deletions src/WireMock.Net.OpenApiParser/Mappers/OpenApiPathsMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ namespace WireMock.Net.OpenApiParser.Mappers
{
internal class OpenApiPathsMapper
{
private const string HeaderContentType = "Content-Type";

private readonly WireMockOpenApiParserSettings _settings;
private readonly ExampleValueGenerator _exampleValueGenerator;

Expand Down Expand Up @@ -248,6 +250,7 @@ private object MapPropertyAsJObject(OpenApiSchema openApiSchema, string key)
return new JProperty(key, _exampleValueGenerator.GetExampleValue(openApiSchema));
}
}

private string MapPathWithParameters(string path, IEnumerable<OpenApiParameter> parameters)
{
if (parameters == null)
Expand All @@ -258,7 +261,8 @@ private string MapPathWithParameters(string path, IEnumerable<OpenApiParameter>
string newPath = path;
foreach (var parameter in parameters)
{
newPath = newPath.Replace($"{{{parameter.Name}}}", GetExampleValue(parameter.Schema, _settings.PathPatternToUse));
var exampleMatcherModel = GetExampleMatcherModel(parameter.Schema, _settings.PathPatternToUse);
newPath = newPath.Replace($"{{{parameter.Name}}}", exampleMatcherModel.Pattern as string);
}

return newPath;
Expand Down Expand Up @@ -305,19 +309,12 @@ private IDictionary<string, object> MapHeaders(string responseContentType, IDict
{
var mappedHeaders = headers.ToDictionary(
item => item.Key,
item => GetExampleValue(null, _settings.HeaderPatternToUse) as object
item => GetExampleMatcherModel(null, _settings.HeaderPatternToUse).Pattern
);

if (!string.IsNullOrEmpty(responseContentType))
{
if (!mappedHeaders.ContainsKey("Content-Type"))
{
mappedHeaders.Add("Content-Type", responseContentType);
}
else
{
mappedHeaders["Content-Type"] = responseContentType;
}
mappedHeaders.TryAdd(HeaderContentType, responseContentType);
}

return mappedHeaders.Keys.Any() ? mappedHeaders : null;
Expand All @@ -331,11 +328,7 @@ private IList<ParamModel> MapQueryParameters(IEnumerable<OpenApiParameter> query
Name = qp.Name,
Matchers = new[]
{
new MatcherModel
{
Name = "ExactMatcher",
Pattern = GetDefaultValueAsStringForSchemaType(qp.Schema)
}
GetExampleMatcherModel(qp.Schema, _settings.QueryParameterPatternToUse)
}
})
.ToList();
Expand All @@ -351,42 +344,34 @@ private IList<HeaderModel> MapRequestHeaders(IEnumerable<OpenApiParameter> heade
Name = qp.Name,
Matchers = new[]
{
new MatcherModel
{
Name = "ExactMatcher",
Pattern = GetDefaultValueAsStringForSchemaType(qp.Schema)
}
GetExampleMatcherModel(qp.Schema, _settings.HeaderPatternToUse)
}
})
.ToList();

return list.Any() ? list : null;
}

private string GetDefaultValueAsStringForSchemaType(OpenApiSchema schema)
private MatcherModel GetExampleMatcherModel(OpenApiSchema schema, ExampleValueType type)
{
var value = _exampleValueGenerator.GetExampleValue(schema);

switch (value)
return type switch
{
case string valueAsString:
return valueAsString;
ExampleValueType.Value => new MatcherModel { Name = "ExactMatcher", Pattern = GetExampleValueAsStringForSchemaType(schema) },

default:
return value.ToString();
}
_ => new MatcherModel { Name = "WildcardMatcher", Pattern = "*" }
};
}

private string GetExampleValue(OpenApiSchema schema, ExampleValueType type)
private string GetExampleValueAsStringForSchemaType(OpenApiSchema schema)
{
switch (type)
var value = _exampleValueGenerator.GetExampleValue(schema);

return value switch
{
case ExampleValueType.Value:
return GetDefaultValueAsStringForSchemaType(schema);
string valueAsString => valueAsString,

default:
return "*";
}
_ => value.ToString(),
};
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using WireMock.Net.OpenApiParser.Types;
using WireMock.Net.OpenApiParser.Types;

namespace WireMock.Net.OpenApiParser.Settings
{
Expand All @@ -22,10 +22,15 @@ public class WireMockOpenApiParserSettings
/// </summary>
public ExampleValueType HeaderPatternToUse { get; set; } = ExampleValueType.Value;

/// <summary>
/// The example value type to use when generating a Query Parameter
/// </summary>
public ExampleValueType QueryParameterPatternToUse { get; set; } = ExampleValueType.Value;

/// <summary>
/// The example values to use
/// </summary>
public IWireMockOpenApiParserExampleValues ExampleValues { get; set; } = new WireMockOpenApiParserExampleValues();
public IWireMockOpenApiParserExampleValues ExampleValues { get; set; }

/// <summary>
/// Are examples generated dynamically?
Expand Down
6 changes: 4 additions & 2 deletions src/WireMock.Net.OpenApiParser/Types/ExampleValueType.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
namespace WireMock.Net.OpenApiParser.Types
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).
/// 1. Use a generated example value based on the SchemaType (default).
/// 2. If there is no example value defined in the schema,
/// then the <see cref="Settings.IWireMockOpenApiParserExampleValues"/> will be used (custom, fixed or dynamic).
/// </summary>
Value,

Expand Down
16 changes: 10 additions & 6 deletions src/WireMock.Net.OpenApiParser/Utils/ExampleValueGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@ public ExampleValueGenerator(WireMockOpenApiParserSettings settings)
{
_settings = Guard.NotNull(settings, nameof(settings));

if (_settings.DynamicExamples)
// Check if user provided an own implementation
if (settings.ExampleValues is null)
{
_settings.ExampleValues = new WireMockOpenApiParserDynamicExampleValues();
}
else
{
_settings.ExampleValues = new WireMockOpenApiParserExampleValues();
if (_settings.DynamicExamples)
{
_settings.ExampleValues = new WireMockOpenApiParserDynamicExampleValues();
}
else
{
_settings.ExampleValues = new WireMockOpenApiParserExampleValues();
}
}
}

Expand Down