Compare commits

..

7 Commits

Author SHA1 Message Date
Stef Heyenrath
c4ee91c614 1.2.17 2020-08-01 18:42:50 +02:00
Stef Heyenrath
4d0373d4ca Scenario : stay on current state for a number of times (#495)
* state

* xml comment
2020-08-01 18:40:35 +02:00
Stef Heyenrath
6c27820659 1.2.16 2020-07-27 19:26:03 +02:00
Stef Heyenrath
9a532108b8 Mark BlacklistedHeaders and BlacklistedCookies as obsolete (#492)
* #489

* .

* FluentMockServerSettings
2020-07-27 17:24:24 +02:00
Stef Heyenrath
9491280fd2 1.2.15 2020-07-19 10:11:12 +02:00
Mahmoud Ali
da62a43875 Add fluent assertions for headers (#485)
* Add headers assertions

* Update FluentAssertions tests with suggested changes
2020-07-19 10:09:07 +02:00
Stef Heyenrath
197f96e303 . 2020-07-13 20:18:26 +02:00
27 changed files with 399 additions and 97 deletions

View File

@@ -1,3 +1,14 @@
# 1.2.17 (01 August 2020)
- [#495](https://github.com/WireMock-Net/WireMock.Net/pull/495) - Scenario : stay on current state for a number of times contributed by [StefH](https://github.com/StefH)
- [#494](https://github.com/WireMock-Net/WireMock.Net/issues/494) - Stay in Current State for specified number of requests [feature]
# 1.2.16 (27 July 2020)
- [#492](https://github.com/WireMock-Net/WireMock.Net/pull/492) - Mark FluentMockServer, FluentMockServerSettings, BlacklistedHeaders and BlacklistedCookies as obsolete [feature] contributed by [StefH](https://github.com/StefH)
- [#489](https://github.com/WireMock-Net/WireMock.Net/issues/489) - Change "blacklist" and "whitelist" terms [feature]
# 1.2.15 (19 July 2020)
- [#485](https://github.com/WireMock-Net/WireMock.Net/pull/485) - Add fluent assertions for headers [test] contributed by [akamud](https://github.com/akamud)
# 1.2.14 (09 July 2020) # 1.2.14 (09 July 2020)
- [#479](https://github.com/WireMock-Net/WireMock.Net/pull/479) - An OpenApi (swagger) parser to generate MappingModel or mapping.json file [feature] contributed by [StefH](https://github.com/StefH) - [#479](https://github.com/WireMock-Net/WireMock.Net/pull/479) - An OpenApi (swagger) parser to generate MappingModel or mapping.json file [feature] contributed by [StefH](https://github.com/StefH)
- [#482](https://github.com/WireMock-Net/WireMock.Net/pull/482) - Add PartialMatch to logging / logentries [feature] contributed by [StefH](https://github.com/StefH) - [#482](https://github.com/WireMock-Net/WireMock.Net/pull/482) - Add PartialMatch to logging / logentries [feature] contributed by [StefH](https://github.com/StefH)

View File

@@ -4,7 +4,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<VersionPrefix>1.2.14</VersionPrefix> <VersionPrefix>1.2.17</VersionPrefix>
<PackageReleaseNotes>See CHANGELOG.md</PackageReleaseNotes> <PackageReleaseNotes>See CHANGELOG.md</PackageReleaseNotes>
<PackageIconUrl>https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/WireMock.Net-Logo.png</PackageIconUrl> <PackageIconUrl>https://raw.githubusercontent.com/WireMock-Net/WireMock.Net/master/WireMock.Net-Logo.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl> <PackageProjectUrl>https://github.com/WireMock-Net/WireMock.Net</PackageProjectUrl>

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 doc --version 1.2.14 GitHubReleaseNotes.exe --output CHANGELOG.md --skip-empty-releases --exclude-labels question invalid doc --version 1.2.17

View File

@@ -24,5 +24,10 @@
/// Gets or sets a value indicating whether this <see cref="ScenarioStateModel"/> is finished. /// Gets or sets a value indicating whether this <see cref="ScenarioStateModel"/> is finished.
/// </summary> /// </summary>
public bool Finished { get; set; } public bool Finished { get; set; }
/// <summary>
/// Gets or sets the state counter.
/// </summary>
public int Counter { get; set; }
} }
} }

View File

@@ -27,9 +27,9 @@ namespace WireMock.Server
/// </summary> /// </summary>
IEnumerable<MappingModel> MappingModels { get; } IEnumerable<MappingModel> MappingModels { get; }
/// <summary> // <summary>
/// Gets the mappings. // Gets the mappings.
/// </summary> // </summary>
//[PublicAPI] //[PublicAPI]
//IEnumerable<IMapping> Mappings { get; } //IEnumerable<IMapping> Mappings { get; }

View File

@@ -8,19 +8,20 @@ namespace WireMock.FluentAssertions
{ {
public class WireMockAssertions public class WireMockAssertions
{ {
private readonly IWireMockServer _instance; private readonly IWireMockServer _subject;
public WireMockAssertions(IWireMockServer instance, int? callsCount) public WireMockAssertions(IWireMockServer subject, int? callsCount)
{ {
_instance = instance; _subject = subject;
} }
[CustomAssertion] [CustomAssertion]
public AndConstraint<WireMockAssertions> AtAbsoluteUrl(string absoluteUrl, string because = "", params object[] becauseArgs) public AndConstraint<WireMockAssertions> AtAbsoluteUrl(string absoluteUrl, string because = "",
params object[] becauseArgs)
{ {
Execute.Assertion Execute.Assertion
.BecauseOf(because, becauseArgs) .BecauseOf(because, becauseArgs)
.Given(() => _instance.LogEntries.Select(x => x.RequestMessage).ToList()) .Given(() => _subject.LogEntries.Select(x => x.RequestMessage).ToList())
.ForCondition(requests => requests.Any()) .ForCondition(requests => requests.Any())
.FailWith( .FailWith(
"Expected {context:wiremockserver} to have been called at address matching the absolute url {0}{reason}, but no calls were made.", "Expected {context:wiremockserver} to have been called at address matching the absolute url {0}{reason}, but no calls were made.",
@@ -33,5 +34,43 @@ namespace WireMock.FluentAssertions
return new AndConstraint<WireMockAssertions>(this); return new AndConstraint<WireMockAssertions>(this);
} }
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithHeader(string expectedKey, string value,
string because = "", params object[] becauseArgs)
=> WithHeader(expectedKey, new[] {value}, because, becauseArgs);
[CustomAssertion]
public AndConstraint<WireMockAssertions> WithHeader(string expectedKey, string[] expectedValues,
string because = "", params object[] becauseArgs)
{
var headersDictionary = _subject.LogEntries.SelectMany(x => x.RequestMessage.Headers)
.ToDictionary(x => x.Key, x => x.Value);
using (new AssertionScope("headers from requests sent"))
{
headersDictionary.Should().ContainKey(expectedKey, because, becauseArgs);
}
using (new AssertionScope($"header \"{expectedKey}\" from requests sent with value(s)"))
{
if (expectedValues.Length == 1)
{
headersDictionary[expectedKey].Should().Contain(expectedValues.First());
}
else
{
var trimmedHeaderValues = string.Join(",", headersDictionary[expectedKey].Select(x => x)).Split(',')
.Select(x => x.Trim())
.ToList();
foreach (var expectedValue in expectedValues)
{
trimmedHeaderValues.Should().Contain(expectedValue);
}
}
}
return new AndConstraint<WireMockAssertions>(this);
}
} }
} }

View File

@@ -1,37 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Description>An OpenApi (swagger) parser to generate MappingModel or mapping.json file.</Description> <Description>An OpenApi (swagger) parser to generate MappingModel or mapping.json file.</Description>
<!--<VersionPrefix>1.2.4-preview-01</VersionPrefix>--> <TargetFrameworks>net46;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net46;netstandard2.0</TargetFrameworks> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <PackageTags>wiremock;openapi;OAS;converter;parser;openapiparser</PackageTags>
<PackageTags>wiremock;openapi;OAS;converter;parser;openapiparser</PackageTags> <ProjectGuid>{D3804228-91F4-4502-9595-39584E5AADAD}</ProjectGuid>
<ProjectGuid>{D3804228-91F4-4502-9595-39584E5AADAD}</ProjectGuid> <PublishRepositoryUrl>true</PublishRepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl> <CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet> <SignAssembly>true</SignAssembly>
<SignAssembly>true</SignAssembly> <AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile> <PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign> </PropertyGroup>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'"> <PropertyGroup Condition="'$(Configuration)' == 'Release'">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="Microsoft.OpenApi.Readers" Version="1.2.0" /> <PackageReference Include="Microsoft.OpenApi.Readers" Version="1.2.0" />
<PackageReference Include="RamlToOpenApiConverter" Version="0.1.1" /> <PackageReference Include="RamlToOpenApiConverter" Version="0.1.1" />
<PackageReference Include="JetBrains.Annotations" Version="2020.1.0" PrivateAssets="All" /> <PackageReference Include="JetBrains.Annotations" Version="2020.1.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" /> <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" /> <ProjectReference Include="..\WireMock.Net.Abstractions\WireMock.Net.Abstractions.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Options\" /> <Folder Include="Options\" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -13,9 +13,9 @@ namespace WireMock.Net.StandAlone
public static class StandAloneApp public static class StandAloneApp
{ {
/// <summary> /// <summary>
/// Start WireMock.Net standalone Server based on the FluentMockServerSettings. /// Start WireMock.Net standalone Server based on the IWireMockServerSettings.
/// </summary> /// </summary>
/// <param name="settings">The FluentMockServerSettings</param> /// <param name="settings">The IWireMockServerSettings</param>
[PublicAPI] [PublicAPI]
public static WireMockServer Start([NotNull] IWireMockServerSettings settings) public static WireMockServer Start([NotNull] IWireMockServerSettings settings)
{ {

View File

@@ -51,6 +51,12 @@ namespace WireMock
[CanBeNull] [CanBeNull]
string NextState { get; } string NextState { get; }
/// <summary>
/// The number of times this match should be matched before the state will be changed to the next state.
/// </summary>
[CanBeNull]
int? StateTimes { get; }
/// <summary> /// <summary>
/// The Request matcher. /// The Request matcher.
/// </summary> /// </summary>

View File

@@ -33,6 +33,9 @@ namespace WireMock
/// <inheritdoc cref="IMapping.NextState" /> /// <inheritdoc cref="IMapping.NextState" />
public string NextState { get; } public string NextState { get; }
/// <inheritdoc cref="IMapping.StateTimes" />
public int? StateTimes { get; }
/// <inheritdoc cref="IMapping.RequestMatcher" /> /// <inheritdoc cref="IMapping.RequestMatcher" />
public IRequestMatcher RequestMatcher { get; } public IRequestMatcher RequestMatcher { get; }
@@ -64,9 +67,10 @@ namespace WireMock
/// <param name="scenario">The scenario. [Optional]</param> /// <param name="scenario">The scenario. [Optional]</param>
/// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param> /// <param name="executionConditionState">State in which the current mapping can occur. [Optional]</param>
/// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param> /// <param name="nextState">The next state which will occur after the current mapping execution. [Optional]</param>
/// <param name="stateTimes">Only when the current state is executed this number, the next state which will occur. [Optional]</param>
public Mapping(Guid guid, [CanBeNull] string title, [CanBeNull] string path, public Mapping(Guid guid, [CanBeNull] string title, [CanBeNull] string path,
[NotNull] IWireMockServerSettings settings, [NotNull] IRequestMatcher requestMatcher, [NotNull] IResponseProvider provider, [NotNull] IWireMockServerSettings settings, [NotNull] IRequestMatcher requestMatcher, [NotNull] IResponseProvider provider,
int priority, [CanBeNull] string scenario, [CanBeNull] string executionConditionState, [CanBeNull] string nextState) int priority, [CanBeNull] string scenario, [CanBeNull] string executionConditionState, [CanBeNull] string nextState, [CanBeNull] int? stateTimes)
{ {
Guid = guid; Guid = guid;
Title = title; Title = title;
@@ -78,6 +82,7 @@ namespace WireMock
Scenario = scenario; Scenario = scenario;
ExecutionConditionState = executionConditionState; ExecutionConditionState = executionConditionState;
NextState = nextState; NextState = nextState;
StateTimes = stateTimes;
} }
/// <inheritdoc cref="IMapping.ProvideResponseAsync" /> /// <inheritdoc cref="IMapping.ProvideResponseAsync" />

View File

@@ -23,12 +23,12 @@ namespace WireMock.Owin
{ {
try try
{ {
string scenario = mapping.Scenario != null && _options.Scenarios.ContainsKey(mapping.Scenario) ? _options.Scenarios[mapping.Scenario].NextState : null; string nextState = GetNextState(mapping);
mappings.Add(new MappingMatcherResult mappings.Add(new MappingMatcherResult
{ {
Mapping = mapping, Mapping = mapping,
RequestMatchResult = mapping.GetRequestMatchResult(request, scenario) RequestMatchResult = mapping.GetRequestMatchResult(request, nextState)
}); });
} }
catch (Exception ex) catch (Exception ex)
@@ -56,5 +56,18 @@ namespace WireMock.Owin
return (match, partialMatch); return (match, partialMatch);
} }
private string GetNextState(IMapping mapping)
{
// If the mapping does not have a scenario or _options.Scenarios does not contain this scenario from the mapping,
// just return null to indicate that there is no next state.
if (mapping.Scenario == null || !_options.Scenarios.ContainsKey(mapping.Scenario))
{
return null;
}
// Else just return the next state
return _options.Scenarios[mapping.Scenario].NextState;
}
} }
} }

View File

@@ -79,7 +79,7 @@ namespace WireMock.Owin
{ {
foreach (var mapping in _options.Mappings.Values.Where(m => m?.Scenario != null)) foreach (var mapping in _options.Mappings.Values.Where(m => m?.Scenario != null))
{ {
// Set start // Set scenario start
if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState) if (!_options.Scenarios.ContainsKey(mapping.Scenario) && mapping.IsStartState)
{ {
_options.Scenarios.TryAdd(mapping.Scenario, new ScenarioState _options.Scenarios.TryAdd(mapping.Scenario, new ScenarioState
@@ -122,9 +122,7 @@ namespace WireMock.Owin
if (targetMapping.Scenario != null) if (targetMapping.Scenario != null)
{ {
_options.Scenarios[targetMapping.Scenario].NextState = targetMapping.NextState; UpdateScenarioState(targetMapping);
_options.Scenarios[targetMapping.Scenario].Started = true;
_options.Scenarios[targetMapping.Scenario].Finished = targetMapping.NextState == null;
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -157,6 +155,25 @@ namespace WireMock.Owin
await CompletedTask; await CompletedTask;
} }
private void UpdateScenarioState(IMapping mapping)
{
var scenario = _options.Scenarios[mapping.Scenario];
// Increase the number of times this state has been executed
scenario.Counter++;
// Only if the number of times this state is executed equals the required StateTimes, proceed to next state and reset the counter to 0
if (scenario.Counter == (mapping.StateTimes ?? 1))
{
scenario.NextState = mapping.NextState;
scenario.Counter = 0;
}
// Else just update Started and Finished
scenario.Started = true;
scenario.Finished = mapping.NextState == null;
}
private void LogRequest(LogEntry entry, bool addRequest) private void LogRequest(LogEntry entry, bool addRequest)
{ {
_options.Logger.DebugRequestResponse(LogEntryMapper.Map(entry), entry.RequestMessage.Path.StartsWith("/__admin/")); _options.Logger.DebugRequestResponse(LogEntryMapper.Map(entry), entry.RequestMessage.Path.StartsWith("/__admin/"));

View File

@@ -24,5 +24,10 @@
/// Gets or sets a value indicating whether this <see cref="ScenarioState"/> is finished. /// Gets or sets a value indicating whether this <see cref="ScenarioState"/> is finished.
/// </summary> /// </summary>
public bool Finished { get; set; } public bool Finished { get; set; }
/// <summary>
/// Gets or sets the state counter.
/// </summary>
public int Counter { get; set; }
} }
} }

View File

@@ -1,7 +1,9 @@
using WireMock.Settings; using System;
using WireMock.Settings;
namespace WireMock.Server namespace WireMock.Server
{ {
[Obsolete("Use WireMockServer. This will removed in next version (1.3.x)")]
public class FluentMockServer : WireMockServer public class FluentMockServer : WireMockServer
{ {
public FluentMockServer(IFluentMockServerSettings settings) : base((IWireMockServerSettings) settings) public FluentMockServer(IFluentMockServerSettings settings) : base((IWireMockServerSettings) settings)

View File

@@ -86,14 +86,16 @@ namespace WireMock.Server
/// Once this mapping is executed the state will be changed to specified one. /// Once this mapping is executed the state will be changed to specified one.
/// </summary> /// </summary>
/// <param name="state">Any object which identifies the new state</param> /// <param name="state">Any object which identifies the new state</param>
/// <param name="times">The number of times this match should be matched before the state will be changed to the specified one. Default value is 1.</param>
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns> /// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
IRespondWithAProvider WillSetStateTo(string state); IRespondWithAProvider WillSetStateTo(string state, int? times = 1);
/// <summary> /// <summary>
/// Once this mapping is executed the state will be changed to specified one. /// Once this mapping is executed the state will be changed to specified one.
/// </summary> /// </summary>
/// <param name="state">Any object which identifies the new state</param> /// <param name="state">Any object which identifies the new state</param>
/// <param name="times">The number of times this match should be matched before the state will be changed to the specified one. Default value is 1.</param>
/// <returns>The <see cref="IRespondWithAProvider"/>.</returns> /// <returns>The <see cref="IRespondWithAProvider"/>.</returns>
IRespondWithAProvider WillSetStateTo(int state); IRespondWithAProvider WillSetStateTo(int state, int? times = 1);
} }
} }

View File

@@ -18,6 +18,7 @@ namespace WireMock.Server
private string _executionConditionState; private string _executionConditionState;
private string _nextState; private string _nextState;
private string _scenario; private string _scenario;
private int _timesInSameState = 1;
private readonly RegistrationCallback _registrationCallback; private readonly RegistrationCallback _registrationCallback;
private readonly IRequestMatcher _requestMatcher; private readonly IRequestMatcher _requestMatcher;
private readonly IWireMockServerSettings _settings; private readonly IWireMockServerSettings _settings;
@@ -46,7 +47,7 @@ namespace WireMock.Server
/// <param name="provider">The provider.</param> /// <param name="provider">The provider.</param>
public void RespondWith(IResponseProvider provider) public void RespondWith(IResponseProvider provider)
{ {
_registrationCallback(new Mapping(Guid, _title, _path, _settings, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState), _saveToFile); _registrationCallback(new Mapping(Guid, _title, _path, _settings, _requestMatcher, provider, _priority, _scenario, _executionConditionState, _nextState, _timesInSameState), _saveToFile);
} }
/// <see cref="IRespondWithAProvider.WithGuid(string)"/> /// <see cref="IRespondWithAProvider.WithGuid(string)"/>
@@ -120,8 +121,8 @@ namespace WireMock.Server
return WhenStateIs(state.ToString()); return WhenStateIs(state.ToString());
} }
/// <see cref="IRespondWithAProvider.WillSetStateTo(string)"/> /// <see cref="IRespondWithAProvider.WillSetStateTo(string, int?)"/>
public IRespondWithAProvider WillSetStateTo(string state) public IRespondWithAProvider WillSetStateTo(string state, int? times = 1)
{ {
if (string.IsNullOrEmpty(_scenario)) if (string.IsNullOrEmpty(_scenario))
{ {
@@ -129,14 +130,15 @@ namespace WireMock.Server
} }
_nextState = state; _nextState = state;
_timesInSameState = times ?? 1;
return this; return this;
} }
/// <see cref="IRespondWithAProvider.WillSetStateTo(int)"/> /// <see cref="IRespondWithAProvider.WillSetStateTo(int, int?)"/>
public IRespondWithAProvider WillSetStateTo(int state) public IRespondWithAProvider WillSetStateTo(int state, int? times = 1)
{ {
return WillSetStateTo(state.ToString()); return WillSetStateTo(state.ToString(), times);
} }
} }
} }

View File

@@ -290,7 +290,7 @@ namespace WireMock.Server
return responseMessage; return responseMessage;
} }
private IMapping ToMapping(RequestMessage requestMessage, ResponseMessage responseMessage, string[] blacklistedHeaders, string[] blacklistedCookies) private IMapping ToMapping(RequestMessage requestMessage, ResponseMessage responseMessage, string[] excludedHeaders, string[] excludedCookies)
{ {
var request = Request.Create(); var request = Request.Create();
request.WithPath(requestMessage.Path); request.WithPath(requestMessage.Path);
@@ -299,16 +299,16 @@ namespace WireMock.Server
requestMessage.Query.Loop((key, value) => request.WithParam(key, false, value.ToArray())); requestMessage.Query.Loop((key, value) => request.WithParam(key, false, value.ToArray()));
requestMessage.Cookies.Loop((key, value) => requestMessage.Cookies.Loop((key, value) =>
{ {
if (!blacklistedCookies.Contains(key, StringComparer.OrdinalIgnoreCase)) if (!excludedCookies.Contains(key, StringComparer.OrdinalIgnoreCase))
{ {
request.WithCookie(key, value); request.WithCookie(key, value);
} }
}); });
var allBlackListedHeaders = new List<string>(blacklistedHeaders) { "Cookie" }; var allExcludedHeaders = new List<string>(excludedHeaders) { "Cookie" };
requestMessage.Headers.Loop((key, value) => requestMessage.Headers.Loop((key, value) =>
{ {
if (!allBlackListedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase)) if (!allExcludedHeaders.Contains(key, StringComparer.OrdinalIgnoreCase))
{ {
request.WithHeader(key, value.ToArray()); request.WithHeader(key, value.ToArray());
} }
@@ -331,7 +331,7 @@ namespace WireMock.Server
var response = Response.Create(responseMessage); var response = Response.Create(responseMessage);
return new Mapping(Guid.NewGuid(), string.Empty, null, _settings, request, response, 0, null, null, null); return new Mapping(Guid.NewGuid(), string.Empty, null, _settings, request, response, 0, null, null, null, null);
} }
#endregion #endregion
@@ -706,7 +706,8 @@ namespace WireMock.Server
Name = s.Name, Name = s.Name,
NextState = s.NextState, NextState = s.NextState,
Started = s.Started, Started = s.Started,
Finished = s.Finished Finished = s.Finished,
Counter = s.Counter
}); });
return ToJson(scenariosStates, true); return ToJson(scenariosStates, true);

View File

@@ -1,8 +1,11 @@
namespace WireMock.Settings using System;
namespace WireMock.Settings
{ {
/// <summary> /// <summary>
/// FluentMockServerSettings /// FluentMockServerSettings
/// </summary> /// </summary>
[Obsolete("Use WireMockServerSettings. This will removed in next version (1.3.x)")]
public class FluentMockServerSettings : WireMockServerSettings public class FluentMockServerSettings : WireMockServerSettings
{ {
} }

View File

@@ -1,8 +1,11 @@
namespace WireMock.Settings using System;
namespace WireMock.Settings
{ {
/// <summary> /// <summary>
/// IFluentMockServerSettings /// IFluentMockServerSettings
/// </summary> /// </summary>
[Obsolete("Use IWireMockServerSettings. This will removed in next version (1.3.x)")]
public interface IFluentMockServerSettings : IWireMockServerSettings public interface IFluentMockServerSettings : IWireMockServerSettings
{ {
} }

View File

@@ -1,4 +1,5 @@
using JetBrains.Annotations; using System;
using JetBrains.Annotations;
namespace WireMock.Settings namespace WireMock.Settings
{ {
@@ -36,13 +37,15 @@ namespace WireMock.Settings
string ClientX509Certificate2ThumbprintOrSubjectName { get; set; } string ClientX509Certificate2ThumbprintOrSubjectName { get; set; }
/// <summary> /// <summary>
/// Defines a list from headers which will excluded from the saved mappings. /// Defines a list from headers which will be excluded from the saved mappings.
/// </summary> /// </summary>
[Obsolete("Will be renamed to ExcludedHeaders in next version (1.3.x)")]
string[] BlackListedHeaders { get; set; } string[] BlackListedHeaders { get; set; }
/// <summary> /// <summary>
/// Defines a list of cookies which will excluded from the saved mappings. /// Defines a list of cookies which will be excluded from the saved mappings.
/// </summary> /// </summary>
[Obsolete("Will be renamed to ExcludedCookies in next version (1.3.x)")]
string[] BlackListedCookies { get; set; } string[] BlackListedCookies { get; set; }
/// <summary> /// <summary>

View File

@@ -1,4 +1,5 @@
using JetBrains.Annotations; using System;
using JetBrains.Annotations;
namespace WireMock.Settings namespace WireMock.Settings
{ {
@@ -39,16 +40,14 @@ namespace WireMock.Settings
[PublicAPI] [PublicAPI]
public string ClientX509Certificate2ThumbprintOrSubjectName { get; set; } public string ClientX509Certificate2ThumbprintOrSubjectName { get; set; }
/// <summary> /// <inheritdoc cref="IProxyAndRecordSettings.BlackListedHeaders"/>
/// Defines a list from headers which will excluded from the saved mappings.
/// </summary>
[PublicAPI] [PublicAPI]
[Obsolete("Will be renamed to ExcludedHeaders in next version (1.3.x)")]
public string[] BlackListedHeaders { get; set; } public string[] BlackListedHeaders { get; set; }
/// <summary> /// <inheritdoc cref="IProxyAndRecordSettings.BlackListedCookies"/>
/// Defines a list of cookies which will excluded from the saved mappings.
/// </summary>
[PublicAPI] [PublicAPI]
[Obsolete("Will be renamed to ExcludedCookies in next version (1.3.x)")]
public string[] BlackListedCookies { get; set; } public string[] BlackListedCookies { get; set; }
/// <inheritdoc cref="IProxyAndRecordSettings.WebProxySettings"/> /// <inheritdoc cref="IProxyAndRecordSettings.WebProxySettings"/>

View File

@@ -1,12 +1,15 @@
using FluentAssertions; using FluentAssertions;
using System; using System;
using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers;
using WireMock.RequestBuilders; using WireMock.RequestBuilders;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
using WireMock.Server; using WireMock.Server;
using Xunit; using Xunit;
using WireMock.FluentAssertions; using WireMock.FluentAssertions;
using System.Threading.Tasks; using System.Threading.Tasks;
using static System.Environment;
namespace WireMock.Net.Tests.FluentAssertions namespace WireMock.Net.Tests.FluentAssertions
{ {
@@ -14,15 +17,26 @@ namespace WireMock.Net.Tests.FluentAssertions
{ {
private WireMockServer _server; private WireMockServer _server;
private HttpClient _httpClient; private HttpClient _httpClient;
private const int Port = 42000; private int _portUsed;
public WireMockAssertionsTests() public WireMockAssertionsTests()
{ {
_server = WireMockServer.Start(Port); _server = WireMockServer.Start();
_server.Given(Request.Create().UsingAnyMethod()) _server.Given(Request.Create().UsingAnyMethod())
.RespondWith(Response.Create().WithStatusCode(200)); .RespondWith(Response.Create().WithStatusCode(200));
_portUsed = _server.Ports.First();
_httpClient = new HttpClient { BaseAddress = new Uri($"http://localhost:{Port}") }; _httpClient = new HttpClient { BaseAddress = new Uri($"http://localhost:{_portUsed}") };
}
[Fact]
public async Task AtAbsoluteUrl_WhenACallWasMadeToAbsoluteUrl_Should_BeOK()
{
await _httpClient.GetAsync("anyurl");
_server.Should()
.HaveReceivedACall()
.AtAbsoluteUrl($"http://localhost:{_portUsed}/anyurl");
} }
[Fact] [Fact]
@@ -50,7 +64,96 @@ namespace WireMock.Net.Tests.FluentAssertions
act.Should().Throw<Exception>() act.Should().Throw<Exception>()
.And.Message.Should() .And.Message.Should()
.Be( .Be(
$"Expected _server to have been called at address matching the absolute url \"anyurl\", but didn't find it among the calls to {{\"http://localhost:{Port}/\"}}."); $"Expected _server to have been called at address matching the absolute url \"anyurl\", but didn't find it among the calls to {{\"http://localhost:{_portUsed}/\"}}.");
}
[Fact]
public async Task WithHeader_WhenACallWasMadeWithExpectedHeader_Should_BeOK()
{
_httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer a");
await _httpClient.GetAsync("");
_server.Should()
.HaveReceivedACall()
.WithHeader("Authorization", "Bearer a");
}
[Fact]
public async Task WithHeader_WhenACallWasMadeWithExpectedHeaderAmongMultipleHeaderValues_Should_BeOK()
{
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
await _httpClient.GetAsync("");
_server.Should()
.HaveReceivedACall()
.WithHeader("Accept", new[] { "application/xml", "application/json" });
}
[Fact]
public async Task WithHeader_Should_ThrowWhenNoCallsMatchingTheHeaderNameWereMade()
{
await _httpClient.GetAsync("");
Action act = () => _server.Should()
.HaveReceivedACall()
.WithHeader("Authorization", "value");
var sentHeaders = _server.LogEntries.SelectMany(x => x.RequestMessage.Headers)
.ToDictionary(x => x.Key, x => x.Value)
.ToList();
var sentHeaderString = "{" + string.Join(", ", sentHeaders) + "}";
act.Should().Throw<Exception>()
.And.Message.Should()
.Be(
$"Expected headers from requests sent {sentHeaderString} to contain key \"Authorization\".{NewLine}");
}
[Fact]
public async Task WithHeader_Should_ThrowWhenNoCallsMatchingTheHeaderValuesWereMade()
{
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
await _httpClient.GetAsync("");
Action act = () => _server.Should()
.HaveReceivedACall()
.WithHeader("Accept", "missing-value");
var sentHeaders = _server.LogEntries.SelectMany(x => x.RequestMessage.Headers)
.ToDictionary(x => x.Key, x => x.Value)["Accept"]
.Select(x => $"\"{x}\"")
.ToList();
var sentHeaderString = "{" + string.Join(", ", sentHeaders) + "}";
act.Should().Throw<Exception>()
.And.Message.Should()
.Be(
$"Expected header \"Accept\" from requests sent with value(s) {sentHeaderString} to contain \"missing-value\".{NewLine}");
}
[Fact]
public async Task WithHeader_Should_ThrowWhenNoCallsMatchingTheHeaderWithMultipleValuesWereMade()
{
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
await _httpClient.GetAsync("");
Action act = () => _server.Should()
.HaveReceivedACall()
.WithHeader("Accept", new[] { "missing-value1", "missing-value2" });
const string missingValue1Message =
"Expected header \"Accept\" from requests sent with value(s) {\"application/xml\", \"application/json\"} to contain \"missing-value1\".";
const string missingValue2Message =
"Expected header \"Accept\" from requests sent with value(s) {\"application/xml\", \"application/json\"} to contain \"missing-value2\".";
act.Should().Throw<Exception>()
.And.Message.Should()
.Be($"{string.Join(NewLine, missingValue1Message, missingValue2Message)}{NewLine}");
} }
public void Dispose() public void Dispose()
@@ -59,4 +162,4 @@ namespace WireMock.Net.Tests.FluentAssertions
_server?.Dispose(); _server?.Dispose();
} }
} }
} }

View File

@@ -34,10 +34,10 @@ namespace WireMock.Net.Tests.RequestBuilders
} }
[Fact] [Fact]
public void RequestBuilder_WithParam_String_IExactMatcher() public void RequestBuilder_WithParam_String_IStringMatcher()
{ {
// Act // Act
var requestBuilder = (Request)Request.Create().WithParam("p", new ExactMatcher("v")); var requestBuilder = (Request)Request.Create().WithParam("p", new RegexMatcher("[012]"));
// Assert // Assert
var matchers = requestBuilder.GetPrivateFieldValue<IList<IRequestMatcher>>("_requestMatchers"); var matchers = requestBuilder.GetPrivateFieldValue<IList<IRequestMatcher>>("_requestMatchers");

View File

@@ -11,7 +11,7 @@ namespace WireMock.Net.Tests.ResponseBuilders
{ {
public class ResponseWithStatusCodeTests public class ResponseWithStatusCodeTests
{ {
private readonly Mock<IFluentMockServerSettings> _settingsMock = new Mock<IFluentMockServerSettings>(); private readonly Mock<IWireMockServerSettings> _settingsMock = new Mock<IWireMockServerSettings>();
private const string ClientIp = "::1"; private const string ClientIp = "::1";
[Theory] [Theory]

View File

@@ -25,7 +25,7 @@ namespace WireMock.Net.Tests.Serialization
// Assign // Assign
var request = Request.Create(); var request = Request.Create();
var response = Response.Create(); var response = Response.Create();
var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 0, null, null, null); var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 0, null, null, null, null);
// Act // Act
var model = _sut.ToMappingModel(mapping); var model = _sut.ToMappingModel(mapping);
@@ -44,7 +44,7 @@ namespace WireMock.Net.Tests.Serialization
// Assign // Assign
var request = Request.Create(); var request = Request.Create();
var response = Response.Create().WithBodyAsJson(new { x = "x" }).WithTransformer(); var response = Response.Create().WithBodyAsJson(new { x = "x" }).WithTransformer();
var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 42, null, null, null); var mapping = new Mapping(Guid.NewGuid(), "", null, _settings, request, response, 42, null, null, null, null);
// Act // Act
var model = _sut.ToMappingModel(mapping); var model = _sut.ToMappingModel(mapping);

View File

@@ -3,6 +3,7 @@ using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using FluentAssertions;
using NFluent; using NFluent;
using WireMock.RequestBuilders; using WireMock.RequestBuilders;
using WireMock.ResponseBuilders; using WireMock.ResponseBuilders;
@@ -61,6 +62,89 @@ namespace WireMock.Net.Tests
Check.That(responseWithState).Equals("Test state msg"); Check.That(responseWithState).Equals("Test state msg");
} }
[Fact]
public async Task Scenarios_With_Same_Path_Should_Use_Times_When_Moving_To_Next_State()
{
// given
const int times = 2;
string path = $"/foo_{Guid.NewGuid()}";
string body1 = "Scenario S1, No State, Setting State T2";
string body2 = "Scenario S1, State T2, End";
var server = WireMockServer.Start();
server
.Given(Request.Create().WithPath(path).UsingGet())
.InScenario(1)
.WillSetStateTo(2, times)
.RespondWith(Response.Create().WithBody(body1));
server
.Given(Request.Create().WithPath(path).UsingGet())
.InScenario(1)
.WhenStateIs(2)
.RespondWith(Response.Create().WithBody(body2));
// when
var client = new HttpClient();
var responseScenario1 = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path);
var responseScenario2 = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path);
var responseWithState = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path);
// then
responseScenario1.Should().Be(body1);
responseScenario2.Should().Be(body1);
responseWithState.Should().Be(body2);
}
[Fact]
public async Task Scenarios_With_Different_Paths_Should_Use_Times_When_Moving_To_Next_State()
{
// given
const int times = 2;
string path1 = $"/a_{Guid.NewGuid()}";
string path2 = $"/b_{Guid.NewGuid()}";
string path3 = $"/c_{Guid.NewGuid()}";
string body1 = "Scenario S1, No State, Setting State T2";
string body2 = "Scenario S1, State T2, Setting State T3";
string body3 = "Scenario S1, State T3, End";
var server = WireMockServer.Start();
server
.Given(Request.Create().WithPath(path1).UsingGet())
.InScenario("S1")
.WillSetStateTo("T2", times)
.RespondWith(Response.Create().WithBody(body1));
server
.Given(Request.Create().WithPath(path2).UsingGet())
.InScenario("S1")
.WhenStateIs("T2")
.WillSetStateTo("T3", times)
.RespondWith(Response.Create().WithBody(body2));
server
.Given(Request.Create().WithPath(path3).UsingGet())
.InScenario("S1")
.WhenStateIs("T3")
.RespondWith(Response.Create().WithBody(body3));
// when
var client = new HttpClient();
var t1a = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path1);
var t1b = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path1);
var t2a = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path2);
var t2b = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path2);
var t3 = await client.GetStringAsync("http://localhost:" + server.Ports[0] + path3);
// then
t1a.Should().Be(body1);
t1b.Should().Be(body1);
t2a.Should().Be(body2);
t2b.Should().Be(body2);
t3.Should().Be(body3);
}
[Fact] [Fact]
public async Task Scenarios_Should_Respect_Int_Valued_Scenarios_and_States() public async Task Scenarios_Should_Respect_Int_Valued_Scenarios_and_States()
{ {

View File

@@ -33,9 +33,9 @@ namespace WireMock.Net.Tests
SaveMappingToFile = false SaveMappingToFile = false
} }
}; };
var server = WireMockServer.Start(settings); var server = WireMockServer.Start(settings);
// Act // Act
var requestMessage = new HttpRequestMessage var requestMessage = new HttpRequestMessage
{ {
Method = HttpMethod.Get, Method = HttpMethod.Get,
@@ -47,8 +47,8 @@ namespace WireMock.Net.Tests
// Assert // Assert
Check.That(server.Mappings).HasSize(2); Check.That(server.Mappings).HasSize(2);
Check.That(server.LogEntries).HasSize(1); Check.That(server.LogEntries).HasSize(1);
} }
[Fact] [Fact]
public async Task WireMockServer_Proxy_Should_proxy_responses() public async Task WireMockServer_Proxy_Should_proxy_responses()
{ {
@@ -123,7 +123,7 @@ namespace WireMock.Net.Tests
} }
[Fact] [Fact]
public async Task WireMockServer_Proxy_Should_exclude_blacklisted_content_header_in_mapping() public async Task WireMockServer_Proxy_Should_exclude_ExcludedHeaders_in_mapping()
{ {
// Assign // Assign
string path = $"/prx_{Guid.NewGuid()}"; string path = $"/prx_{Guid.NewGuid()}";
@@ -139,7 +139,7 @@ namespace WireMock.Net.Tests
Url = serverForProxyForwarding.Urls[0], Url = serverForProxyForwarding.Urls[0],
SaveMapping = true, SaveMapping = true,
SaveMappingToFile = false, SaveMappingToFile = false,
BlackListedHeaders = new[] { "blacklisted" } BlackListedHeaders = new[] { "excluded-header-X" }
} }
}; };
var server = WireMockServer.Start(settings); var server = WireMockServer.Start(settings);
@@ -152,7 +152,7 @@ namespace WireMock.Net.Tests
RequestUri = new Uri($"{server.Urls[0]}{path}"), RequestUri = new Uri($"{server.Urls[0]}{path}"),
Content = new StringContent("stringContent") Content = new StringContent("stringContent")
}; };
requestMessage.Headers.Add("blacklisted", "exact_match"); requestMessage.Headers.Add("foobar", "exact_match");
requestMessage.Headers.Add("ok", "ok-value"); requestMessage.Headers.Add("ok", "ok-value");
await new HttpClient().SendAsync(requestMessage); await new HttpClient().SendAsync(requestMessage);
@@ -160,12 +160,12 @@ namespace WireMock.Net.Tests
var mapping = server.Mappings.FirstOrDefault(m => m.Guid != defaultMapping.Guid); var mapping = server.Mappings.FirstOrDefault(m => m.Guid != defaultMapping.Guid);
Check.That(mapping).IsNotNull(); Check.That(mapping).IsNotNull();
var matchers = ((Request)mapping.RequestMatcher).GetRequestMessageMatchers<RequestMessageHeaderMatcher>().Select(m => m.Name).ToList(); var matchers = ((Request)mapping.RequestMatcher).GetRequestMessageMatchers<RequestMessageHeaderMatcher>().Select(m => m.Name).ToList();
Check.That(matchers).Not.Contains("blacklisted"); Check.That(matchers).Not.Contains("excluded-header-X");
Check.That(matchers).Contains("ok"); Check.That(matchers).Contains("ok");
} }
[Fact] [Fact]
public async Task WireMockServer_Proxy_Should_exclude_blacklisted_cookies_in_mapping() public async Task WireMockServer_Proxy_Should_exclude_ExcludedCookies_in_mapping()
{ {
// Assign // Assign
string path = $"/prx_{Guid.NewGuid()}"; string path = $"/prx_{Guid.NewGuid()}";
@@ -515,7 +515,7 @@ namespace WireMock.Net.Tests
content.Should().Contain("known"); // On Linux it's "Name or service not known". On Windows it's "No such host is known.". content.Should().Contain("known"); // On Linux it's "Name or service not known". On Windows it's "No such host is known.".
server.LogEntries.Should().HaveCount(1); server.LogEntries.Should().HaveCount(1);
((StatusModel) server.LogEntries.First().ResponseMessage.BodyData.BodyAsJson).Status.Should().Contain("known"); ((StatusModel)server.LogEntries.First().ResponseMessage.BodyData.BodyAsJson).Status.Should().Contain("known");
} }
} }
} }