WatchStaticMappingsInSubdirectories (#374)

* WatchStaticMappingsInSubdirectories

* 37

* IEnumerable<string> EnumerateFiles([NotNull] string path, bool includeSubdirectories);

* reloadStaticMappings
This commit is contained in:
Stef Heyenrath
2019-11-07 15:31:43 +01:00
committed by GitHub
parent ea6a8d3b73
commit 395be3c583
15 changed files with 70 additions and 25 deletions

View File

@@ -4,7 +4,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<VersionPrefix>1.0.36</VersionPrefix> <VersionPrefix>1.0.37</VersionPrefix>
</PropertyGroup> </PropertyGroup>
<Choose> <Choose>

View File

@@ -1,3 +1,3 @@
https://github.com/StefH/GitHubReleaseNotes https://github.com/StefH/GitHubReleaseNotes
GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid --version 1.0.36.0 GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid --version 1.0.37.0

View File

@@ -3,13 +3,14 @@ using RestEase;
using System; using System;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Text; using System.Text;
using System.Threading.Tasks;
using WireMock.Client; using WireMock.Client;
namespace WireMock.Net.Client namespace WireMock.Net.Client
{ {
class Program class Program
{ {
static void Main(string[] args) static async Task Main(string[] args)
{ {
// Create an implementation of the IFluentMockServerAdmin and pass in the base URL for the API. // Create an implementation of the IFluentMockServerAdmin and pass in the base URL for the API.
var api = RestClient.For<IFluentMockServerAdmin>("http://localhost:9091"); var api = RestClient.For<IFluentMockServerAdmin>("http://localhost:9091");
@@ -18,29 +19,29 @@ namespace WireMock.Net.Client
var value = Convert.ToBase64String(Encoding.ASCII.GetBytes("a:b")); var value = Convert.ToBase64String(Encoding.ASCII.GetBytes("a:b"));
api.Authorization = new AuthenticationHeaderValue("Basic", value); api.Authorization = new AuthenticationHeaderValue("Basic", value);
var settings1 = api.GetSettingsAsync().Result; var settings1 = await api.GetSettingsAsync();
Console.WriteLine($"settings1 = {JsonConvert.SerializeObject(settings1)}"); Console.WriteLine($"settings1 = {JsonConvert.SerializeObject(settings1)}");
settings1.GlobalProcessingDelay = 1077; settings1.GlobalProcessingDelay = 1077;
api.PostSettingsAsync(settings1).Wait(); api.PostSettingsAsync(settings1).Wait();
var settings2 = api.GetSettingsAsync().Result; var settings2 = await api.GetSettingsAsync();
Console.WriteLine($"settings2 = {JsonConvert.SerializeObject(settings2)}"); Console.WriteLine($"settings2 = {JsonConvert.SerializeObject(settings2)}");
var mappings = api.GetMappingsAsync().Result; var mappings = await api.GetMappingsAsync();
Console.WriteLine($"mappings = {JsonConvert.SerializeObject(mappings)}"); Console.WriteLine($"mappings = {JsonConvert.SerializeObject(mappings)}");
try try
{ {
var guid = Guid.Parse("11111110-a633-40e8-a244-5cb80bc0ab66"); var guid = Guid.Parse("11111110-a633-40e8-a244-5cb80bc0ab66");
var mapping = api.GetMappingAsync(guid).Result; var mapping = await api.GetMappingAsync(guid);
Console.WriteLine($"mapping = {JsonConvert.SerializeObject(mapping)}"); Console.WriteLine($"mapping = {JsonConvert.SerializeObject(mapping)}");
} }
catch (Exception e) catch (Exception e)
{ {
} }
var request = api.GetRequestsAsync().Result; var request = await api.GetRequestsAsync();
Console.WriteLine($"request = {JsonConvert.SerializeObject(request)}"); Console.WriteLine($"request = {JsonConvert.SerializeObject(request)}");
//var deleteRequestsAsync = api.DeleteRequestsAsync().Result; //var deleteRequestsAsync = api.DeleteRequestsAsync().Result;
@@ -49,15 +50,21 @@ namespace WireMock.Net.Client
//var resetRequestsAsync = api.ResetRequestsAsync().Result; //var resetRequestsAsync = api.ResetRequestsAsync().Result;
//Console.WriteLine($"ResetRequestsAsync = {resetRequestsAsync.Status}"); //Console.WriteLine($"ResetRequestsAsync = {resetRequestsAsync.Status}");
var scenarioStates = api.GetScenariosAsync().Result; var scenarioStates = await api.GetScenariosAsync();
Console.WriteLine($"GetScenariosAsync = {JsonConvert.SerializeObject(scenarioStates)}"); Console.WriteLine($"GetScenariosAsync = {JsonConvert.SerializeObject(scenarioStates)}");
var postFileResult = api.PostFileAsync("1.cs", "C# Hello").GetAwaiter().GetResult(); var postFileResult = await api.PostFileAsync("1.cs", "C# Hello");
Console.WriteLine($"postFileResult = {JsonConvert.SerializeObject(postFileResult)}"); Console.WriteLine($"postFileResult = {JsonConvert.SerializeObject(postFileResult)}");
var getFileResult = api.GetFileAsync("1.cs").GetAwaiter().GetResult(); var getFileResult = await api.GetFileAsync("1.cs");
Console.WriteLine($"getFileResult = {getFileResult}"); 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.WriteLine("Press any key to quit");
Console.ReadKey(); Console.ReadKey();
} }

View File

@@ -2,8 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
<!-- <RuntimeFrameworkVersion>1.0.1</RuntimeFrameworkVersion> -->
<ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon> <ApplicationIcon>../../WireMock.Net-Logo.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>

View File

@@ -0,0 +1 @@
C# Hello

View File

@@ -21,9 +21,9 @@ namespace WireMock.Net.ConsoleApplication
} }
/// <inheritdoc cref="IFileSystemHandler.EnumerateFiles"/> /// <inheritdoc cref="IFileSystemHandler.EnumerateFiles"/>
public IEnumerable<string> EnumerateFiles(string path) public IEnumerable<string> EnumerateFiles(string path, bool includeSubdirectories)
{ {
return Directory.EnumerateFiles(path); return includeSubdirectories ? Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories) : Directory.EnumerateFiles(path);
} }
/// <inheritdoc cref="IFileSystemHandler.GetMappingFolder"/> /// <inheritdoc cref="IFileSystemHandler.GetMappingFolder"/>

View File

@@ -46,6 +46,7 @@ namespace WireMock.Net.ConsoleApplication
StartAdminInterface = true, StartAdminInterface = true,
ReadStaticMappings = true, ReadStaticMappings = true,
WatchStaticMappings = true, WatchStaticMappings = true,
WatchStaticMappingsInSubdirectories = true,
//ProxyAndRecordSettings = new ProxyAndRecordSettings //ProxyAndRecordSettings = new ProxyAndRecordSettings
//{ //{
// SaveMapping = true // SaveMapping = true

View File

@@ -47,6 +47,7 @@ namespace WireMock.Net.StandAlone
StartAdminInterface = parser.GetBoolValue("StartAdminInterface", true), StartAdminInterface = parser.GetBoolValue("StartAdminInterface", true),
ReadStaticMappings = parser.GetBoolValue("ReadStaticMappings"), ReadStaticMappings = parser.GetBoolValue("ReadStaticMappings"),
WatchStaticMappings = parser.GetBoolValue("WatchStaticMappings"), WatchStaticMappings = parser.GetBoolValue("WatchStaticMappings"),
WatchStaticMappingsInSubdirectories = parser.GetBoolValue("WatchStaticMappingsInSubdirectories"),
AllowPartialMapping = parser.GetBoolValue("AllowPartialMapping"), AllowPartialMapping = parser.GetBoolValue("AllowPartialMapping"),
AdminUsername = parser.GetStringValue("AdminUsername"), AdminUsername = parser.GetStringValue("AdminUsername"),
AdminPassword = parser.GetStringValue("AdminPassword"), AdminPassword = parser.GetStringValue("AdminPassword"),

View File

@@ -75,8 +75,9 @@ namespace WireMock.Client
/// <summary> /// <summary>
/// Delete (reset) all mappings. /// Delete (reset) all mappings.
/// </summary> /// </summary>
/// <param name="reloadStaticMappings">A value indicating whether to reload the static mappings after the reset.</param>
[Post("__admin/mappings/reset")] [Post("__admin/mappings/reset")]
Task<StatusModel> ResetMappingsAsync(); Task<StatusModel> ResetMappingsAsync(bool? reloadStaticMappings = false);
/// <summary> /// <summary>
/// Get a mapping based on the guid /// Get a mapping based on the guid

View File

@@ -31,8 +31,9 @@ namespace WireMock.Handlers
/// Returns an enumerable collection of file names in a specified path. /// Returns an enumerable collection of file names in a specified path.
/// </summary> /// </summary>
/// <param name="path">The path.</param> /// <param name="path">The path.</param>
/// <returns>An enumerable collection of the full names (including paths) for the files in the directory specified by path.</returns> /// <param name="includeSubdirectories">A value indicating whether subdirectories should also included when enumerating files.</param>
IEnumerable<string> EnumerateFiles([NotNull] string path); /// <returns>An enumerable collection of the full names (including paths) for the files in the directory (and optionally subdirectories) specified by path.</returns>
IEnumerable<string> EnumerateFiles([NotNull] string path, bool includeSubdirectories);
/// <summary> /// <summary>
/// Read a static mapping file as text. /// Read a static mapping file as text.

View File

@@ -46,11 +46,11 @@ namespace WireMock.Handlers
} }
/// <inheritdoc cref="IFileSystemHandler.EnumerateFiles"/> /// <inheritdoc cref="IFileSystemHandler.EnumerateFiles"/>
public IEnumerable<string> EnumerateFiles(string path) public IEnumerable<string> EnumerateFiles(string path, bool includeSubdirectories)
{ {
Check.NotNullOrEmpty(path, nameof(path)); Check.NotNullOrEmpty(path, nameof(path));
return Directory.EnumerateFiles(path); return includeSubdirectories ? Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories) : Directory.EnumerateFiles(path);
} }
/// <inheritdoc cref="IFileSystemHandler.GetMappingFolder"/> /// <inheritdoc cref="IFileSystemHandler.GetMappingFolder"/>

View File

@@ -39,6 +39,7 @@ namespace WireMock.Server
private const string AdminRequests = "/__admin/requests"; private const string AdminRequests = "/__admin/requests";
private const string AdminSettings = "/__admin/settings"; private const string AdminSettings = "/__admin/settings";
private const string AdminScenarios = "/__admin/scenarios"; private const string AdminScenarios = "/__admin/scenarios";
private const string QueryParamReloadStaticMappings = "reloadStaticMappings";
private readonly RegexMatcher _adminRequestContentTypeJson = new ContentTypeMatcher(ContentTypeJson, true); private readonly RegexMatcher _adminRequestContentTypeJson = new ContentTypeMatcher(ContentTypeJson, true);
private readonly RegexMatcher _adminMappingsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/mappings\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$"); private readonly RegexMatcher _adminMappingsGuidPathMatcher = new RegexMatcher(@"^\/__admin\/mappings\/([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$");
@@ -69,7 +70,7 @@ namespace WireMock.Server
Given(Request.Create().WithPath(AdminMappings).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsDelete)); Given(Request.Create().WithPath(AdminMappings).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsDelete));
// __admin/mappings/reset // __admin/mappings/reset
Given(Request.Create().WithPath(AdminMappings + "/reset").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsDelete)); Given(Request.Create().WithPath(AdminMappings + "/reset").UsingPost()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsReset));
// __admin/mappings/{guid} // __admin/mappings/{guid}
Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingGet)); Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingGet));
@@ -141,7 +142,7 @@ namespace WireMock.Server
return; return;
} }
foreach (string filename in _settings.FileSystemHandler.EnumerateFiles(folder).OrderBy(f => f)) foreach (string filename in _settings.FileSystemHandler.EnumerateFiles(folder, _settings.WatchStaticMappingsInSubdirectories == true).OrderBy(f => f))
{ {
_settings.Logger.Info("Reading Static MappingFile : '{0}'", filename); _settings.Logger.Info("Reading Static MappingFile : '{0}'", filename);
@@ -173,9 +174,14 @@ namespace WireMock.Server
return; return;
} }
_settings.Logger.Info("Watching folder '{0}' for new, updated and deleted MappingFiles.", folder); bool includeSubdirectories = _settings.WatchStaticMappingsInSubdirectories == true;
string includeSubdirectoriesText = includeSubdirectories ? " and Subdirectories" : string.Empty;
_settings.Logger.Info($"Watching folder '{folder}'{includeSubdirectoriesText} for new, updated and deleted MappingFiles.");
var watcher = new EnhancedFileSystemWatcher(folder, "*.json", EnhancedFileSystemWatcherTimeoutMs); var watcher = new EnhancedFileSystemWatcher(folder, "*.json", EnhancedFileSystemWatcherTimeoutMs);
watcher.IncludeSubdirectories = includeSubdirectories;
watcher.Created += (sender, args) => watcher.Created += (sender, args) =>
{ {
_settings.Logger.Info("MappingFile created : '{0}', reading file.", args.FullPath); _settings.Logger.Info("MappingFile created : '{0}', reading file.", args.FullPath);
@@ -551,6 +557,24 @@ namespace WireMock.Server
return ResponseMessageBuilder.Create("Mappings deleted"); return ResponseMessageBuilder.Create("Mappings deleted");
} }
private ResponseMessage MappingsReset(RequestMessage requestMessage)
{
ResetMappings();
ResetScenarios();
string message = "Mappings reset";
if (requestMessage.Query.ContainsKey(QueryParamReloadStaticMappings) &&
bool.TryParse(requestMessage.Query[QueryParamReloadStaticMappings].ToString(), out bool reloadStaticMappings)
&& reloadStaticMappings)
{
ReadStaticMappings();
message = $"{message} and static mappings reloaded";
}
return ResponseMessageBuilder.Create(message);
}
#endregion Mappings #endregion Mappings
#region Request/{guid} #region Request/{guid}

View File

@@ -33,6 +33,10 @@ namespace WireMock.Settings
[PublicAPI] [PublicAPI]
public bool? WatchStaticMappings { get; set; } public bool? WatchStaticMappings { get; set; }
/// <inheritdoc cref="IFluentMockServerSettings.WatchStaticMappingsInSubdirectories"/>
[PublicAPI]
public bool? WatchStaticMappingsInSubdirectories { get; set; }
/// <inheritdoc cref="IFluentMockServerSettings.ProxyAndRecordSettings"/> /// <inheritdoc cref="IFluentMockServerSettings.ProxyAndRecordSettings"/>
[PublicAPI] [PublicAPI]
public IProxyAndRecordSettings ProxyAndRecordSettings { get; set; } public IProxyAndRecordSettings ProxyAndRecordSettings { get; set; }

View File

@@ -42,6 +42,12 @@ namespace WireMock.Settings
[PublicAPI] [PublicAPI]
bool? WatchStaticMappings { get; set; } bool? WatchStaticMappings { get; set; }
/// <summary>
/// A value indicating whether subdirectories within the static mappings path should be monitored.
/// </summary>
[PublicAPI]
bool? WatchStaticMappingsInSubdirectories { get; set; }
/// <summary> /// <summary>
/// Gets or sets if the proxy and record settings. /// Gets or sets if the proxy and record settings.
/// </summary> /// </summary>

View File

@@ -171,7 +171,7 @@ namespace WireMock.Net.Tests
var staticMappingHandlerMock = new Mock<IFileSystemHandler>(); var staticMappingHandlerMock = new Mock<IFileSystemHandler>();
staticMappingHandlerMock.Setup(m => m.GetMappingFolder()).Returns("folder"); staticMappingHandlerMock.Setup(m => m.GetMappingFolder()).Returns("folder");
staticMappingHandlerMock.Setup(m => m.FolderExists(It.IsAny<string>())).Returns(true); staticMappingHandlerMock.Setup(m => m.FolderExists(It.IsAny<string>())).Returns(true);
staticMappingHandlerMock.Setup(m => m.EnumerateFiles(It.IsAny<string>())).Returns(new string[0]); staticMappingHandlerMock.Setup(m => m.EnumerateFiles(It.IsAny<string>(), It.IsAny<bool>())).Returns(new string[0]);
var server = FluentMockServer.Start(new FluentMockServerSettings var server = FluentMockServer.Start(new FluentMockServerSettings
{ {
@@ -184,7 +184,7 @@ namespace WireMock.Net.Tests
// Assert and Verify // Assert and Verify
staticMappingHandlerMock.Verify(m => m.GetMappingFolder(), Times.Once); staticMappingHandlerMock.Verify(m => m.GetMappingFolder(), Times.Once);
staticMappingHandlerMock.Verify(m => m.FolderExists("folder"), Times.Once); staticMappingHandlerMock.Verify(m => m.FolderExists("folder"), Times.Once);
staticMappingHandlerMock.Verify(m => m.EnumerateFiles("folder"), Times.Once); staticMappingHandlerMock.Verify(m => m.EnumerateFiles("folder", false), Times.Once);
} }
[Fact] [Fact]