173 lines
5.3 KiB
C#
173 lines
5.3 KiB
C#
namespace PS.IPAM.Tests.Mocks;
|
|
|
|
using System.Net;
|
|
|
|
/// <summary>
|
|
/// A mock HTTP message handler for testing HTTP requests without making actual network calls.
|
|
/// This handler does not dispose itself when the HttpClient is disposed, allowing reuse in tests.
|
|
/// </summary>
|
|
public class MockHttpMessageHandler : HttpMessageHandler
|
|
{
|
|
private readonly Queue<MockResponse> _responses = new();
|
|
private readonly List<HttpRequestMessage> _requests = new();
|
|
private bool _disposed = false;
|
|
|
|
/// <summary>
|
|
/// Gets all requests that were sent through this handler.
|
|
/// </summary>
|
|
public IReadOnlyList<HttpRequestMessage> Requests => _requests.AsReadOnly();
|
|
|
|
/// <summary>
|
|
/// Gets the last request that was sent through this handler.
|
|
/// </summary>
|
|
public HttpRequestMessage? LastRequest => _requests.LastOrDefault();
|
|
|
|
/// <summary>
|
|
/// Queues a response to be returned for the next request.
|
|
/// </summary>
|
|
public MockHttpMessageHandler WithResponse(HttpStatusCode statusCode, string content, string contentType = "application/json")
|
|
{
|
|
_responses.Enqueue(new MockResponse(statusCode, content, contentType));
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Queues a successful JSON response.
|
|
/// </summary>
|
|
public MockHttpMessageHandler WithJsonResponse(string jsonContent)
|
|
{
|
|
return WithResponse(HttpStatusCode.OK, jsonContent, "application/json");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Queues a successful response with phpIPAM-style wrapper.
|
|
/// </summary>
|
|
public MockHttpMessageHandler WithSuccessResponse(string dataJson)
|
|
{
|
|
var response = $"{{\"code\":200,\"success\":true,\"data\":{dataJson}}}";
|
|
return WithJsonResponse(response);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Queues a 404 Not Found response.
|
|
/// </summary>
|
|
public MockHttpMessageHandler WithNotFoundResponse()
|
|
{
|
|
return WithResponse(HttpStatusCode.NotFound, "{\"code\":404,\"success\":false,\"message\":\"Not found\"}", "application/json");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Queues an error response.
|
|
/// </summary>
|
|
public MockHttpMessageHandler WithErrorResponse(HttpStatusCode statusCode, string message)
|
|
{
|
|
var response = $"{{\"code\":{(int)statusCode},\"success\":false,\"message\":\"{message}\"}}";
|
|
return WithResponse(statusCode, response, "application/json");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Queues an exception to be thrown on the next request.
|
|
/// </summary>
|
|
public MockHttpMessageHandler WithException(Exception exception)
|
|
{
|
|
_responses.Enqueue(new MockResponse(exception));
|
|
return this;
|
|
}
|
|
|
|
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
|
{
|
|
if (_disposed)
|
|
{
|
|
throw new ObjectDisposedException(nameof(MockHttpMessageHandler));
|
|
}
|
|
|
|
_requests.Add(request);
|
|
|
|
if (_responses.Count == 0)
|
|
{
|
|
throw new InvalidOperationException("No mock response configured. Call WithResponse() before making requests.");
|
|
}
|
|
|
|
var mockResponse = _responses.Dequeue();
|
|
|
|
if (mockResponse.Exception != null)
|
|
{
|
|
throw mockResponse.Exception;
|
|
}
|
|
|
|
var response = new HttpResponseMessage(mockResponse.StatusCode)
|
|
{
|
|
Content = new StringContent(mockResponse.Content, System.Text.Encoding.UTF8, mockResponse.ContentType),
|
|
RequestMessage = request
|
|
};
|
|
|
|
return Task.FromResult(response);
|
|
}
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
// Don't actually dispose - allow reuse in tests
|
|
// The test itself is responsible for cleanup
|
|
}
|
|
|
|
/// <summary>
|
|
/// Actually disposes the handler. Call this in test cleanup.
|
|
/// </summary>
|
|
public void ForceDispose()
|
|
{
|
|
_disposed = true;
|
|
base.Dispose(true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that a request was made to the expected URL.
|
|
/// </summary>
|
|
public bool WasRequestMadeTo(string urlContains)
|
|
{
|
|
return _requests.Any(r => r.RequestUri?.ToString().Contains(urlContains) == true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that a request with the expected method was made.
|
|
/// </summary>
|
|
public bool WasRequestMadeWithMethod(HttpMethod method)
|
|
{
|
|
return _requests.Any(r => r.Method == method);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the value of a header from the last request.
|
|
/// </summary>
|
|
public string? GetLastRequestHeader(string headerName)
|
|
{
|
|
if (LastRequest?.Headers.TryGetValues(headerName, out var values) == true)
|
|
{
|
|
return values.FirstOrDefault();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private class MockResponse
|
|
{
|
|
public HttpStatusCode StatusCode { get; }
|
|
public string Content { get; }
|
|
public string ContentType { get; }
|
|
public Exception? Exception { get; }
|
|
|
|
public MockResponse(HttpStatusCode statusCode, string content, string contentType)
|
|
{
|
|
StatusCode = statusCode;
|
|
Content = content;
|
|
ContentType = contentType;
|
|
}
|
|
|
|
public MockResponse(Exception exception)
|
|
{
|
|
Exception = exception;
|
|
StatusCode = HttpStatusCode.InternalServerError;
|
|
Content = string.Empty;
|
|
ContentType = string.Empty;
|
|
}
|
|
}
|
|
}
|