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

Implement prefix for saved mapping file #1040

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
/// The clientCertificate thumbprint or subject name fragment to use.
/// Example thumbprint : "D2DBF135A8D06ACCD0E1FAD9BFB28678DF7A9818". Example subject name: "www.google.com""
/// </summary>
public string ClientX509Certificate2ThumbprintOrSubjectName { get; set; }

Check warning on line 10 in src/WireMock.Net.Abstractions/Admin/Settings/ProxyAndRecordSettingsModel.cs

View workflow job for this annotation

GitHub Actions / linux-build-and-run

Non-nullable property 'ClientX509Certificate2ThumbprintOrSubjectName' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

/// <summary>
/// Defines the WebProxySettings.
Expand Down Expand Up @@ -69,6 +69,11 @@
/// </summary>
public bool AppendGuidToSavedMappingFile { get; set; }

/// <summary>
/// Set prefix for saved mapping file.
/// </summary>
public string PrefixForSavedMappingFile { get; set; }

/// <summary>
/// Defines the Replace Settings.
/// </summary>
Expand Down
48 changes: 48 additions & 0 deletions src/WireMock.Net/Serialization/MappingFileNameSanitizer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using System.IO;
using System.Linq;
using Stef.Validation;
using WireMock.Settings;

namespace WireMock.Serialization;

/// <summary>
/// Creates sanitized file names for mappings
/// </summary>
public class MappingFileNameSanitizer
{
private const char ReplaceChar = '_';

private readonly WireMockServerSettings _settings;

public MappingFileNameSanitizer(WireMockServerSettings settings)
{
_settings = Guard.NotNull(settings);
}

/// <summary>
/// Creates sanitized file names for mappings
/// </summary>
public string BuildSanitizedFileName(IMapping mapping)
{
string name;
if (!string.IsNullOrEmpty(mapping.Title))
{
// remove 'Proxy Mapping for ' and an extra space character after the HTTP request method
name = mapping.Title.Replace(ProxyAndRecordSettings.DefaultPrefixForSavedMappingFile, "").Replace(' '.ToString(), string.Empty);
if (_settings.ProxyAndRecordSettings?.AppendGuidToSavedMappingFile == true)
{
name += $"{ReplaceChar}{mapping.Guid}";
}
}
else
{
name = mapping.Guid.ToString();
}

if (!string.IsNullOrEmpty(_settings.ProxyAndRecordSettings?.PrefixForSavedMappingFile))
{
name = $"{_settings.ProxyAndRecordSettings.PrefixForSavedMappingFile}{ReplaceChar}{name}";
}
return $"{Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, ReplaceChar))}.json";
}
}
23 changes: 3 additions & 20 deletions src/WireMock.Net/Serialization/MappingToFileSaver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ internal class MappingToFileSaver
{
private readonly WireMockServerSettings _settings;
private readonly MappingConverter _mappingConverter;
private readonly MappingFileNameSanitizer _fileNameSanitizer;

public MappingToFileSaver(WireMockServerSettings settings, MappingConverter mappingConverter)
{
_settings = Guard.NotNull(settings);
_mappingConverter = Guard.NotNull(mappingConverter);
_fileNameSanitizer = new MappingFileNameSanitizer(settings);
}

public void SaveMappingsToFile(IMapping[] mappings, string? folder = null)
Expand Down Expand Up @@ -42,7 +44,7 @@ public void SaveMappingToFile(IMapping mapping, string? folder = null)

var model = _mappingConverter.ToMappingModel(mapping);

var filename = BuildSanitizedFileName(mapping);
var filename = _fileNameSanitizer.BuildSanitizedFileName(mapping);
var path = Path.Combine(folder, filename);

Save(model, path);
Expand All @@ -54,23 +56,4 @@ private void Save(object value, string path)

_settings.FileSystemHandler.WriteMappingFile(path, JsonConvert.SerializeObject(value, JsonSerializationConstants.JsonSerializerSettingsDefault));
}

private string BuildSanitizedFileName(IMapping mapping, char replaceChar = '_')
{
string name;
if (!string.IsNullOrEmpty(mapping.Title))
{
name = mapping.Title!;
if (_settings.ProxyAndRecordSettings?.AppendGuidToSavedMappingFile == true)
{
name += $"{replaceChar}{mapping.Guid}";
}
}
else
{
name = mapping.Guid.ToString();
}

return $"{Path.GetInvalidFileNameChars().Aggregate(name, (current, c) => current.Replace(c, replaceChar))}.json";
}
}
12 changes: 11 additions & 1 deletion src/WireMock.Net/Settings/ProxyAndRecordSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ namespace WireMock.Settings;
/// </summary>
public class ProxyAndRecordSettings : HttpClientSettings
{
/// <summary>
/// Default prefix value for saved mapping file
/// </summary>
public const string DefaultPrefixForSavedMappingFile = "Proxy Mapping for ";

/// <summary>
/// The URL to proxy.
/// </summary>
Expand Down Expand Up @@ -95,9 +100,14 @@ public string SaveMappingForStatusCodePattern
/// </summary>
public bool AppendGuidToSavedMappingFile { get; set; }

/// <summary>
/// Set prefix for saved mapping file.
/// </summary>
public string PrefixForSavedMappingFile { get; set; } = DefaultPrefixForSavedMappingFile;

/// <summary>
/// Proxy all Api calls, irrespective of any condition
/// </summary>
[PublicAPI]
public bool ProxyAll { get; set; } = false;
}
}
1 change: 1 addition & 0 deletions src/WireMock.Net/Settings/WireMockServerSettingsParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ private static void ParseProxyAndRecordSettings(WireMockServerSettings settings,
SaveMappingToFile = parser.GetBoolValue("SaveMappingToFile"),
UseDefinedRequestMatchers = parser.GetBoolValue(nameof(ProxyAndRecordSettings.UseDefinedRequestMatchers)),
AppendGuidToSavedMappingFile = parser.GetBoolValue(nameof(ProxyAndRecordSettings.AppendGuidToSavedMappingFile)),
PrefixForSavedMappingFile = parser.GetStringValue(nameof(ProxyAndRecordSettings.PrefixForSavedMappingFile), null),
Url = proxyUrl!,
SaveMappingSettings = new ProxySaveMappingSettings
{
Expand Down
160 changes: 160 additions & 0 deletions test/WireMock.Net.Tests/Serialization/MappingFileNameSanitizerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
using System;
using Moq;
using WireMock.Serialization;
using WireMock.Settings;
using Xunit;

namespace WireMock.Net.Tests.Serialization;

public class MappingFileNameSanitizerTests
{
private const string MappingGuid = "ce216a13-e7d6-42d7-91ac-8ae709e2add1";
private const string MappingTitle = "Proxy Mapping for POST _ordermanagement_v1_orders_cancel";

[Fact]
public void BuildSanitizedFileName_WithTitleAndGuid_AppendsGuid()
{
// Arrange
var mappingMock = new Mock<IMapping>();
mappingMock.Setup(m => m.Title).Returns(MappingTitle);
mappingMock.Setup(m => m.Guid).Returns(new Guid(MappingGuid));

var settings = new WireMockServerSettings
{
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
AppendGuidToSavedMappingFile = true
}
};

var sanitizer = new MappingFileNameSanitizer(settings);

// Act
var result = sanitizer.BuildSanitizedFileName(mappingMock.Object);

// Assert
Assert.Equal($"Proxy Mapping for _POST_ordermanagement_v1_orders_cancel_{MappingGuid}.json", result);
}

[Fact]
public void BuildSanitizedFileName_WithoutTitle_UsesGuid()
{
// Arrange
var mappingMock = new Mock<IMapping>();
mappingMock.Setup(m => m.Title).Returns((string?)null);
mappingMock.Setup(m => m.Guid).Returns(new Guid(MappingGuid));

var settings = new WireMockServerSettings
{
ProxyAndRecordSettings = new ()
};
var sanitizer = new MappingFileNameSanitizer(settings);

// Act
var result = sanitizer.BuildSanitizedFileName(mappingMock.Object);

// Assert
Assert.Equal($"Proxy Mapping for _{MappingGuid}.json", result);
}

[Fact]
public void BuildSanitizedFileName_WithTitleAndGuid_NoAppendGuidSetting()
{
// Arrange
var mappingMock = new Mock<IMapping>();
mappingMock.Setup(m => m.Title).Returns(MappingTitle);
mappingMock.Setup(m => m.Guid).Returns(new Guid(MappingGuid));

var settings = new WireMockServerSettings
{
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
AppendGuidToSavedMappingFile = false
}
};

var sanitizer = new MappingFileNameSanitizer(settings);

// Act
var result = sanitizer.BuildSanitizedFileName(mappingMock.Object);

// Assert
Assert.Equal("Proxy Mapping for _POST_ordermanagement_v1_orders_cancel.json", result);
}

[Fact]
public void BuildSanitizedFileName_WithPrefix_AddsPrefix()
{
// Arrange
var mappingMock = new Mock<IMapping>();
mappingMock.Setup(m => m.Title).Returns(MappingTitle);
mappingMock.Setup(m => m.Guid).Returns(new Guid(MappingGuid));

var settings = new WireMockServerSettings
{
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
PrefixForSavedMappingFile = "Prefix"
}
};

var sanitizer = new MappingFileNameSanitizer(settings);

// Act
var result = sanitizer.BuildSanitizedFileName(mappingMock.Object);

// Assert
Assert.Equal($"Prefix_POST_ordermanagement_v1_orders_cancel.json", result);
}

[Fact]
public void BuildSanitizedFileName_WithPrefix_AddsPrefixEmptyString()
{
// Arrange
var mappingMock = new Mock<IMapping>();
mappingMock.Setup(m => m.Title).Returns(MappingTitle);
mappingMock.Setup(m => m.Guid).Returns(new Guid(MappingGuid));

var settings = new WireMockServerSettings
{
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
PrefixForSavedMappingFile = string.Empty
}
};

var sanitizer = new MappingFileNameSanitizer(settings);

// Act
var result = sanitizer.BuildSanitizedFileName(mappingMock.Object);

// Assert
Assert.Equal($"POST_ordermanagement_v1_orders_cancel.json", result);
}

[Fact]
public void BuildSanitizedFileName_WithTitleAndGuid_WithPrefixAndAppendGuidSetting()
{
// Arrange
var mappingMock = new Mock<IMapping>();
mappingMock.Setup(m => m.Title).Returns(MappingTitle);
mappingMock.Setup(m => m.Guid).Returns(new Guid(MappingGuid));

var settings = new WireMockServerSettings
{
ProxyAndRecordSettings = new ProxyAndRecordSettings
{
PrefixForSavedMappingFile = "Prefix",
AppendGuidToSavedMappingFile = true
}
};

var sanitizer = new MappingFileNameSanitizer(settings);

// Act
var result = sanitizer.BuildSanitizedFileName(mappingMock.Object);

// Assert
Assert.Equal($"Prefix_POST_ordermanagement_v1_orders_cancel_{MappingGuid}.json", result);
}
}
2 changes: 1 addition & 1 deletion test/WireMock.Net.Tests/WireMockServer.Proxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public async Task WireMockServer_Proxy_With_SaveMappingToFile_Is_True_ShouldSave
server.Mappings.Should().HaveCount(2);

// Verify
fileSystemHandlerMock.Verify(f => f.WriteMappingFile($"m{System.IO.Path.DirectorySeparatorChar}{title}.json", It.IsRegex(stringBody)), Times.Once);
fileSystemHandlerMock.Verify(f => f.WriteMappingFile($"m{System.IO.Path.DirectorySeparatorChar}Proxy Mapping for _{title}.json", It.IsRegex(stringBody)), Times.Once);
}

[Fact]
Expand Down
Loading