Skip to content

Commit

Permalink
Updated response to include an array of behaviors (#131)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattherman authored Apr 4, 2023
1 parent 1ab59b7 commit dd98b7e
Show file tree
Hide file tree
Showing 15 changed files with 147 additions and 81 deletions.
9 changes: 5 additions & 4 deletions MbDotNet.Tests/Models/Responses/FaultResponseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ public void FaultResponse_Constructor_SetsFault()
}

[TestMethod]
public void FaultResponse_Constructor_SetsBehavior()
public void FaultResponse_Constructor_SetsBehaviors()
{
var behavior = new Behavior();
var response = new FaultResponse(Fault.ConnectionResetByPeer, behavior);
Assert.AreSame(behavior, response.Behavior);
var behavior = new WaitBehavior(1000);
var response = new FaultResponse(Fault.ConnectionResetByPeer, new []{ behavior });
Assert.AreEqual(1, response.Behaviors.Count);
Assert.AreSame(behavior, response.Behaviors[0]);
}
}
}
Expand Down
9 changes: 5 additions & 4 deletions MbDotNet.Tests/Models/Responses/IsResponseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ public void TestResponse_Constructor_SetsFields()
}

[TestMethod]
public void TestResponse_Constructor_SetsBehavior()
public void TestResponse_Constructor_SetsBehaviors()
{
var behavior = new Behavior();
var response = new IsResponse<TestResponseFields>(new TestResponseFields(), behavior);
Assert.AreSame(behavior, response.Behavior);
var behavior = new WaitBehavior(1000);
var response = new IsResponse<TestResponseFields>(new TestResponseFields(), new []{ behavior });
Assert.AreEqual(1, response.Behaviors.Count);
Assert.AreSame(behavior, response.Behaviors[0]);
}
}
}
11 changes: 10 additions & 1 deletion MbDotNet.Tests/Models/Responses/ProxyResponseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,20 @@ public class ProxyResponseTests
private class TestResponseFields : ResponseFields { }

[TestMethod]
public void TestResponse_Constructor_SetsFields()
public void ProxyResponse_Constructor_SetsFields()
{
var expectedFields = new TestResponseFields();
var response = new ProxyResponse<TestResponseFields>(expectedFields);
Assert.AreSame(expectedFields, response.Fields);
}

[TestMethod]
public void ProxyResponse_Constructor_SetsBehaviors()
{
var behavior = new WaitBehavior(1000);
var response = new ProxyResponse<TestResponseFields>(new TestResponseFields(), new []{ behavior });
Assert.AreEqual(1, response.Behaviors.Count);
Assert.AreSame(behavior, response.Behaviors[0]);
}
}
}
17 changes: 17 additions & 0 deletions MbDotNet.Tests/Models/Responses/WaitBehaviorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using MbDotNet.Models.Responses;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MbDotNet.Tests.Models.Responses
{
[TestClass, TestCategory("Unit")]
public class WaitBehaviorTests
{
[TestMethod]
public void WaitBehavior_Constructor_SetsLatency()
{
const int latencyInMilliseconds = 1500;
var behavior = new WaitBehavior(latencyInMilliseconds);
Assert.AreEqual(latencyInMilliseconds, behavior.LatencyInMilliseconds);
}
}
}
13 changes: 7 additions & 6 deletions MbDotNet.Tests/Models/Stubs/HttpStubTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,9 @@ public void HttpStub_Returns_AddsResponse_LatencySet()
stub.Returns(expectedStatusCode, headers, "test", latencyInMilliseconds: expectedLatencyInMilliseconds);

var response = stub.Responses.First() as IsResponse<HttpResponseFields>;
Assert.IsNotNull(response);
Assert.IsNotNull(response.Behavior);
Assert.IsNotNull(response.Behavior.LatencyInMilliseconds);
Assert.AreEqual(expectedLatencyInMilliseconds, response.Behavior.LatencyInMilliseconds);
Assert.IsNotNull(response?.Behaviors);
var responseBehavior = response.Behaviors[0] as WaitBehavior;
Assert.AreEqual(expectedLatencyInMilliseconds, responseBehavior?.LatencyInMilliseconds);
}

[TestMethod]
Expand Down Expand Up @@ -116,13 +115,15 @@ public void HttpStub_Returns_AddsResponse()
[TestMethod]
public void HttpStub_Returns_AddsBehavior()
{
var expectedResponse = new IsResponse<HttpResponseFields>(new HttpResponseFields(), new Behavior());
var behavior = new WaitBehavior(1000);
var expectedResponse = new IsResponse<HttpResponseFields>(new HttpResponseFields(), new[] { behavior });

var stub = new HttpStub();
stub.Returns(expectedResponse);

var response = stub.Responses.First() as IsResponse<HttpResponseFields>;
Assert.AreEqual(expectedResponse.Behavior, response?.Behavior);
var responseBehavior = response?.Behaviors?[0];
Assert.AreEqual(behavior, responseBehavior);
}

[TestMethod]
Expand Down
36 changes: 7 additions & 29 deletions MbDotNet.Tests/Models/Stubs/TcpStubTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,47 +56,25 @@ public void TcpStub_Returns_AddsResponse_SetsFields()
Assert.AreEqual(expectedFields, response.Fields);
}

[TestMethod]
public void TcpStub_Returns_AddsResponse_LatencySet()
{
var expectedFields = new TcpResponseFields
{
Data = "TestData"
};
const int expectedLatencyInMilliseconds = 1000;

var behavior = new Behavior
{
LatencyInMilliseconds = expectedLatencyInMilliseconds
};

var stub = new TcpStub();
stub.Returns(new IsResponse<TcpResponseFields>(expectedFields, behavior));

var response = stub.Responses.First() as IsResponse<TcpResponseFields>;
Assert.IsNotNull(response);
Assert.IsNotNull(response.Behavior);
Assert.IsNotNull(response.Behavior.LatencyInMilliseconds);
Assert.AreEqual(expectedLatencyInMilliseconds, response.Behavior.LatencyInMilliseconds);
}

[TestMethod]
public void TcpStub_Returns_AddsResponse_BehaviorSet()
{
var expectedFields = new TcpResponseFields
{
Data = "TestData"
};
const int expectedLatencyInMilliseconds = 1000;

var behavior = new Behavior();
var behavior = new WaitBehavior(expectedLatencyInMilliseconds);

var stub = new TcpStub();
stub.Returns(new IsResponse<TcpResponseFields>(expectedFields, behavior));
stub.Returns(new IsResponse<TcpResponseFields>(expectedFields, new []{ behavior }));

var response = stub.Responses.First() as IsResponse<TcpResponseFields>;
Assert.IsNotNull(response);
Assert.IsNotNull(response.Behavior);
Assert.AreEqual(behavior, response.Behavior);
Assert.IsNotNull(response?.Behaviors);
Assert.AreEqual(1, response.Behaviors.Count);
var responseBehavior = response.Behaviors[0] as WaitBehavior;
Assert.AreSame(behavior, responseBehavior);
}

[TestMethod]
Expand Down
4 changes: 2 additions & 2 deletions MbDotNet/Models/Predicates/Predicate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ public abstract class Predicate
public JsonPathSelector JsonPathSelector { get; private set; }

/// <summary>
/// Create a new PredicateBase instance
/// Create a new Predicate instance
/// </summary>
protected Predicate() { }

/// <summary>
/// Create a new PredicateBase instance
/// Create a new Predicate instance
/// </summary>
/// <param name="isCaseSensitive">Whether or not predicate matching is case sensitive</param>
/// <param name="exceptExpression">A regular expression for eliminating parts of a predicate value</param>
Expand Down
11 changes: 2 additions & 9 deletions MbDotNet/Models/Responses/Behavior.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
using Newtonsoft.Json;

namespace MbDotNet.Models.Responses
{
/// <summary>
/// A "behavior" response
/// An abstract response behavior
/// </summary>
public class Behavior
public abstract class Behavior
{
/// <summary>
/// The latency to add to the response
/// </summary>
[JsonProperty("wait", NullValueHandling = NullValueHandling.Ignore)]
public int? LatencyInMilliseconds { get; set; }
}
}
14 changes: 4 additions & 10 deletions MbDotNet/Models/Responses/FaultResponse.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace MbDotNet.Models.Responses
Expand All @@ -15,21 +16,14 @@ public class FaultResponse : Response
[JsonConverter(typeof(StringEnumConverter))]
public Fault Fault { get; set; }

/// <summary>
/// Configured response behaviors
/// </summary>
[JsonProperty("_behaviors", NullValueHandling = NullValueHandling.Ignore)]
public Behavior Behavior { get; set; }

/// <summary>
/// Create a new FaultResponse instance
/// </summary>
/// <param name="fault">The fault to return in the response</param>
/// <param name="behavior">Optional response behavior</param>
public FaultResponse(Fault fault, Behavior behavior = null)
/// <param name="behaviors">Optional response behavior</param>
public FaultResponse(Fault fault, IEnumerable<Behavior> behaviors = null) : base(behaviors)
{
Fault = fault;
Behavior = behavior;
}
}
}
12 changes: 3 additions & 9 deletions MbDotNet/Models/Responses/IsResponse.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using MbDotNet.Models.Responses.Fields;
using Newtonsoft.Json;

Expand All @@ -15,21 +16,14 @@ namespace MbDotNet.Models.Responses
[JsonProperty("is")]
public T Fields { get; set; }

/// <summary>
/// Configured response behaviors
/// </summary>
[JsonProperty("_behaviors", NullValueHandling = NullValueHandling.Ignore)]
public Behavior Behavior { get; set; }

/// <summary>
/// Create a new IsResponse instance
/// </summary>
/// <param name="fields">The fields to return when matched</param>
/// <param name="behavior">Optional response behavior</param>
public IsResponse(T fields, Behavior behavior = null)
/// <param name="behaviors">Optional response behaviors</param>
public IsResponse(T fields, IEnumerable<Behavior> behaviors = null) : base(behaviors)
{
Fields = fields;
Behavior = behavior;
}
}
}
4 changes: 3 additions & 1 deletion MbDotNet/Models/Responses/ProxyResponse.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using MbDotNet.Models.Responses.Fields;
using Newtonsoft.Json;

Expand All @@ -19,7 +20,8 @@ namespace MbDotNet.Models.Responses
/// Create a new ProxyResponse instance
/// </summary>
/// <param name="fields">The fields that should be captured for generated predicates</param>
public ProxyResponse(T fields)
/// <param name="behaviors">Optional response behaviors</param>
public ProxyResponse(T fields, IEnumerable<Behavior> behaviors = null) : base(behaviors)
{
Fields = fields;
}
Expand Down
18 changes: 18 additions & 0 deletions MbDotNet/Models/Responses/Response.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;

namespace MbDotNet.Models.Responses
{
/// <summary>
/// An abstract representation of a response without a specific protocol
/// </summary>
public abstract class Response
{
/// <summary>
/// Configured response behaviors
/// </summary>
[JsonProperty("behaviors", NullValueHandling = NullValueHandling.Ignore)]
public IList<Behavior> Behaviors { get; set; }

/// <summary>
/// Construct a new Response instance
/// </summary>
/// <param name="responseBehaviors">Response behaviors to include on the response</param>
protected Response(IEnumerable<Behavior> responseBehaviors)
{
Behaviors = responseBehaviors?.ToList();
}
}
}
25 changes: 25 additions & 0 deletions MbDotNet/Models/Responses/WaitBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Newtonsoft.Json;

namespace MbDotNet.Models.Responses
{
/// <summary>
/// The "wait" response behavior
/// </summary>
public class WaitBehavior : Behavior
{
/// <summary>
/// The latency to add to the response
/// </summary>
[JsonProperty("wait", NullValueHandling = NullValueHandling.Ignore)]
public int LatencyInMilliseconds { get; set; }

/// <summary>
/// Creates a new WaitBehavior instance
/// </summary>
/// <param name="latencyInMilliseconds">The latency that should be added to the response</param>
public WaitBehavior(int latencyInMilliseconds)
{
LatencyInMilliseconds = latencyInMilliseconds;
}
}
}
9 changes: 3 additions & 6 deletions MbDotNet/Models/Stubs/HttpStub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,11 @@ public HttpStub Returns(HttpStatusCode statusCode, IDictionary<string, object> h
Mode = mode
};

var behavior = latencyInMilliseconds.HasValue
? new Behavior
{
LatencyInMilliseconds = latencyInMilliseconds
}
var behaviors = latencyInMilliseconds.HasValue
? new [] { new WaitBehavior(latencyInMilliseconds.Value) }
: null;

var response = new IsResponse<HttpResponseFields>(fields, behavior);
var response = new IsResponse<HttpResponseFields>(fields, behaviors);

return Returns(response);
}
Expand Down
36 changes: 36 additions & 0 deletions docs/v4-to-v5-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ There were a handful of breaking changes introduced in v5.x of the library. Thes
- The `CreateHttpImposter`, `CreateHttpsImposter`, and `CreateTcpImposter` methods on `MountebankClient` have been updated to actually create imposters in Mountebank rather than act as simple factory methods for the imposter objects
- The `Submit` methods on `MountebankClient` have been removed since the imposter creation methods now handle submission to Mountebank
- Imposter configuration (ex. `RecordRequests`) is now exposed via properties on the imposters themselves rather than through arguments to the imposter creation methods
- The `Behavior` class has been renamed to `WaitBehavior` and a constructor was added for setting the latency value
- Responses now require an array of behaviors instead of a single one
- The `Headers` and `QueryParameters` properties on `HttpPredicateFields` now have a type of `IDictionary<string, object>` instead of `IDictionary<string, string>` to support specifying arrays of values
- The `Headers` property on `HttpResponseFields` now has a type of `IDictionary<string, object>` instead of `IDictionary<string, string>` to support returning arrays of values
- Various collection types in the models have been changed. See [#119](https://github.com/mattherman/MbDotNet/pull/119) for details.
Expand Down Expand Up @@ -119,6 +121,40 @@ var imposter = new HttpImposter(4545, "MyImposter", new HttpImposterConfiguratio
});
```

## `Behavior` Renamed to `WaitBehavior`

The `Behavior` class has been renamed to `WaitBehavior` to support adding additional behavior types in the future. A constructor has also been added which requires the `latencyInMilliseconds` to be provided when the class is instantiated.

_v4_

```
var behavior = new Behavior { LatencyInMilliseconds = 1000 };
```

_v5_

```
var behavior = new WaitBehavior(1000);
```

## Response Behavior Array

Responses now accept an array of behaviors instead of a single behavior. The JSON property for behaviors has also been updated from `_behaviors` to `behaviors` to match the current Mountebank contracts.

This resulted in changes to the constructor signatures of `IsResponse` and `ProxyResponse`.

_v4_

```
var response = new IsResponse(fields, new WaitBehavior(1000));
```

_v5_

```
var response = new IsResponse(fields, new []{ new WaitBehavior(1000) });
```

## Updates to `Headers` and `QueryParameters` Types

The `Headers` and `QueryParameters` properties on `HttpPredicateFields` and the `Headers` property on `HttpResponseFields` have had their type updated from `IDictionary<string, string>` to `IDictionary<string, object>`. This was done to support setting the keys in those collections to arrays of values instead of a single string.
Expand Down

0 comments on commit dd98b7e

Please sign in to comment.