diff --git a/Directory.Build.props b/Directory.Build.props index 5569f9fd..5e41ca65 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ - 1.0.36 + 1.0.37 diff --git a/GitHubReleaseNotes.txt b/GitHubReleaseNotes.txt index 4012570d..15575e63 100644 --- a/GitHubReleaseNotes.txt +++ b/GitHubReleaseNotes.txt @@ -1,3 +1,3 @@ https://github.com/StefH/GitHubReleaseNotes -GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid --version 1.0.36.0 \ No newline at end of file +GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid --version 1.0.37.0 \ No newline at end of file diff --git a/examples/WireMock.Net.Client/Program.cs b/examples/WireMock.Net.Client/Program.cs index 4a8dabfa..4d3eb682 100644 --- a/examples/WireMock.Net.Client/Program.cs +++ b/examples/WireMock.Net.Client/Program.cs @@ -3,13 +3,14 @@ using RestEase; using System; using System.Net.Http.Headers; using System.Text; +using System.Threading.Tasks; using WireMock.Client; namespace WireMock.Net.Client { 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. var api = RestClient.For("http://localhost:9091"); @@ -18,29 +19,29 @@ namespace WireMock.Net.Client var value = Convert.ToBase64String(Encoding.ASCII.GetBytes("a:b")); api.Authorization = new AuthenticationHeaderValue("Basic", value); - var settings1 = api.GetSettingsAsync().Result; + var settings1 = await api.GetSettingsAsync(); Console.WriteLine($"settings1 = {JsonConvert.SerializeObject(settings1)}"); settings1.GlobalProcessingDelay = 1077; api.PostSettingsAsync(settings1).Wait(); - var settings2 = api.GetSettingsAsync().Result; + var settings2 = await api.GetSettingsAsync(); Console.WriteLine($"settings2 = {JsonConvert.SerializeObject(settings2)}"); - var mappings = api.GetMappingsAsync().Result; + var mappings = await api.GetMappingsAsync(); Console.WriteLine($"mappings = {JsonConvert.SerializeObject(mappings)}"); try { 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)}"); } catch (Exception e) { } - var request = api.GetRequestsAsync().Result; + var request = await api.GetRequestsAsync(); Console.WriteLine($"request = {JsonConvert.SerializeObject(request)}"); //var deleteRequestsAsync = api.DeleteRequestsAsync().Result; @@ -49,15 +50,21 @@ namespace WireMock.Net.Client //var resetRequestsAsync = api.ResetRequestsAsync().Result; //Console.WriteLine($"ResetRequestsAsync = {resetRequestsAsync.Status}"); - var scenarioStates = api.GetScenariosAsync().Result; + var scenarioStates = await api.GetScenariosAsync(); 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)}"); - var getFileResult = api.GetFileAsync("1.cs").GetAwaiter().GetResult(); + var getFileResult = await api.GetFileAsync("1.cs"); 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.ReadKey(); } diff --git a/examples/WireMock.Net.Client/WireMock.Net.Client.csproj b/examples/WireMock.Net.Client/WireMock.Net.Client.csproj index f5a04dc3..2a23350b 100644 --- a/examples/WireMock.Net.Client/WireMock.Net.Client.csproj +++ b/examples/WireMock.Net.Client/WireMock.Net.Client.csproj @@ -2,8 +2,7 @@ Exe - netcoreapp2.0 - + netcoreapp2.1 ../../WireMock.Net-Logo.ico diff --git a/examples/WireMock.Net.Console.NETCoreApp2/__admin/mappings/1.cs b/examples/WireMock.Net.Console.NETCoreApp2/__admin/mappings/1.cs new file mode 100644 index 00000000..3310d6a2 --- /dev/null +++ b/examples/WireMock.Net.Console.NETCoreApp2/__admin/mappings/1.cs @@ -0,0 +1 @@ +C# Hello \ No newline at end of file diff --git a/examples/WireMock.Net.Console.Net452.Classic/CustomFileSystemFileHandler.cs b/examples/WireMock.Net.Console.Net452.Classic/CustomFileSystemFileHandler.cs index 699ec4b4..012b3350 100644 --- a/examples/WireMock.Net.Console.Net452.Classic/CustomFileSystemFileHandler.cs +++ b/examples/WireMock.Net.Console.Net452.Classic/CustomFileSystemFileHandler.cs @@ -21,9 +21,9 @@ namespace WireMock.Net.ConsoleApplication } /// - public IEnumerable EnumerateFiles(string path) + public IEnumerable EnumerateFiles(string path, bool includeSubdirectories) { - return Directory.EnumerateFiles(path); + return includeSubdirectories ? Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories) : Directory.EnumerateFiles(path); } /// diff --git a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs index 9c80f6cd..294a1e6d 100644 --- a/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs +++ b/examples/WireMock.Net.Console.Net452.Classic/MainApp.cs @@ -46,6 +46,7 @@ namespace WireMock.Net.ConsoleApplication StartAdminInterface = true, ReadStaticMappings = true, WatchStaticMappings = true, + WatchStaticMappingsInSubdirectories = true, //ProxyAndRecordSettings = new ProxyAndRecordSettings //{ // SaveMapping = true diff --git a/src/WireMock.Net.StandAlone/StandAloneApp.cs b/src/WireMock.Net.StandAlone/StandAloneApp.cs index b49bb88f..a1b22056 100644 --- a/src/WireMock.Net.StandAlone/StandAloneApp.cs +++ b/src/WireMock.Net.StandAlone/StandAloneApp.cs @@ -47,6 +47,7 @@ namespace WireMock.Net.StandAlone StartAdminInterface = parser.GetBoolValue("StartAdminInterface", true), ReadStaticMappings = parser.GetBoolValue("ReadStaticMappings"), WatchStaticMappings = parser.GetBoolValue("WatchStaticMappings"), + WatchStaticMappingsInSubdirectories = parser.GetBoolValue("WatchStaticMappingsInSubdirectories"), AllowPartialMapping = parser.GetBoolValue("AllowPartialMapping"), AdminUsername = parser.GetStringValue("AdminUsername"), AdminPassword = parser.GetStringValue("AdminPassword"), diff --git a/src/WireMock.Net/Client/IFluentMockServerAdmin.cs b/src/WireMock.Net/Client/IFluentMockServerAdmin.cs index bddaf37f..1328a906 100644 --- a/src/WireMock.Net/Client/IFluentMockServerAdmin.cs +++ b/src/WireMock.Net/Client/IFluentMockServerAdmin.cs @@ -75,8 +75,9 @@ namespace WireMock.Client /// /// Delete (reset) all mappings. /// + /// A value indicating whether to reload the static mappings after the reset. [Post("__admin/mappings/reset")] - Task ResetMappingsAsync(); + Task ResetMappingsAsync(bool? reloadStaticMappings = false); /// /// Get a mapping based on the guid diff --git a/src/WireMock.Net/Handlers/IFileSystemHandler.cs b/src/WireMock.Net/Handlers/IFileSystemHandler.cs index d01e0469..498c5826 100644 --- a/src/WireMock.Net/Handlers/IFileSystemHandler.cs +++ b/src/WireMock.Net/Handlers/IFileSystemHandler.cs @@ -31,8 +31,9 @@ namespace WireMock.Handlers /// Returns an enumerable collection of file names in a specified path. /// /// The path. - /// An enumerable collection of the full names (including paths) for the files in the directory specified by path. - IEnumerable EnumerateFiles([NotNull] string path); + /// A value indicating whether subdirectories should also included when enumerating files. + /// An enumerable collection of the full names (including paths) for the files in the directory (and optionally subdirectories) specified by path. + IEnumerable EnumerateFiles([NotNull] string path, bool includeSubdirectories); /// /// Read a static mapping file as text. diff --git a/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs b/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs index f349d9fc..57bedc64 100644 --- a/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs +++ b/src/WireMock.Net/Handlers/LocalFileSystemHandler.cs @@ -46,11 +46,11 @@ namespace WireMock.Handlers } /// - public IEnumerable EnumerateFiles(string path) + public IEnumerable EnumerateFiles(string path, bool includeSubdirectories) { Check.NotNullOrEmpty(path, nameof(path)); - return Directory.EnumerateFiles(path); + return includeSubdirectories ? Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories) : Directory.EnumerateFiles(path); } /// diff --git a/src/WireMock.Net/Server/FluentMockServer.Admin.cs b/src/WireMock.Net/Server/FluentMockServer.Admin.cs index 36c55ab7..c83d108d 100644 --- a/src/WireMock.Net/Server/FluentMockServer.Admin.cs +++ b/src/WireMock.Net/Server/FluentMockServer.Admin.cs @@ -39,6 +39,7 @@ namespace WireMock.Server private const string AdminRequests = "/__admin/requests"; private const string AdminSettings = "/__admin/settings"; private const string AdminScenarios = "/__admin/scenarios"; + private const string QueryParamReloadStaticMappings = "reloadStaticMappings"; 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})$"); @@ -69,7 +70,7 @@ namespace WireMock.Server Given(Request.Create().WithPath(AdminMappings).UsingDelete()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingsDelete)); // __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} Given(Request.Create().WithPath(_adminMappingsGuidPathMatcher).UsingGet()).AtPriority(AdminPriority).RespondWith(new DynamicResponseProvider(MappingGet)); @@ -141,7 +142,7 @@ namespace WireMock.Server 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); @@ -173,9 +174,14 @@ namespace WireMock.Server 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); + watcher.IncludeSubdirectories = includeSubdirectories; + watcher.Created += (sender, args) => { _settings.Logger.Info("MappingFile created : '{0}', reading file.", args.FullPath); @@ -551,6 +557,24 @@ namespace WireMock.Server 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 #region Request/{guid} diff --git a/src/WireMock.Net/Settings/FluentMockServerSettings.cs b/src/WireMock.Net/Settings/FluentMockServerSettings.cs index 9d47cb98..072f5aca 100644 --- a/src/WireMock.Net/Settings/FluentMockServerSettings.cs +++ b/src/WireMock.Net/Settings/FluentMockServerSettings.cs @@ -33,6 +33,10 @@ namespace WireMock.Settings [PublicAPI] public bool? WatchStaticMappings { get; set; } + /// + [PublicAPI] + public bool? WatchStaticMappingsInSubdirectories { get; set; } + /// [PublicAPI] public IProxyAndRecordSettings ProxyAndRecordSettings { get; set; } diff --git a/src/WireMock.Net/Settings/IFluentMockServerSettings.cs b/src/WireMock.Net/Settings/IFluentMockServerSettings.cs index f7840d15..ee10c4d1 100644 --- a/src/WireMock.Net/Settings/IFluentMockServerSettings.cs +++ b/src/WireMock.Net/Settings/IFluentMockServerSettings.cs @@ -42,6 +42,12 @@ namespace WireMock.Settings [PublicAPI] bool? WatchStaticMappings { get; set; } + /// + /// A value indicating whether subdirectories within the static mappings path should be monitored. + /// + [PublicAPI] + bool? WatchStaticMappingsInSubdirectories { get; set; } + /// /// Gets or sets if the proxy and record settings. /// diff --git a/test/WireMock.Net.Tests/FluentMockServerTests.Admin.cs b/test/WireMock.Net.Tests/FluentMockServerTests.Admin.cs index 6f07ca08..038f1d6c 100644 --- a/test/WireMock.Net.Tests/FluentMockServerTests.Admin.cs +++ b/test/WireMock.Net.Tests/FluentMockServerTests.Admin.cs @@ -171,7 +171,7 @@ namespace WireMock.Net.Tests var staticMappingHandlerMock = new Mock(); staticMappingHandlerMock.Setup(m => m.GetMappingFolder()).Returns("folder"); staticMappingHandlerMock.Setup(m => m.FolderExists(It.IsAny())).Returns(true); - staticMappingHandlerMock.Setup(m => m.EnumerateFiles(It.IsAny())).Returns(new string[0]); + staticMappingHandlerMock.Setup(m => m.EnumerateFiles(It.IsAny(), It.IsAny())).Returns(new string[0]); var server = FluentMockServer.Start(new FluentMockServerSettings { @@ -184,7 +184,7 @@ namespace WireMock.Net.Tests // Assert and Verify staticMappingHandlerMock.Verify(m => m.GetMappingFolder(), 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]