mirror of
https://github.com/bitwarden/server
synced 2025-12-12 22:33:45 +00:00
Rewrite Icon fetching (#3023)
* Rewrite Icon fetching * Move validation to IconUri, Uri, or UriBuilder * `dotnet format` 🤖 * PR suggestions * Add not null compiler hint * Add twitter to test case * Move Uri manipulation to UriService * Implement MockedHttpClient Presents better, fluent handling of message matching and response building. * Add redirect handling tests * Add testing to models * More aggressively dispose content in icon link * Format 🤖 * Update icon lockfile * Convert to cloned stream for HttpResponseBuilder Content was being disposed when HttResponseMessage was being disposed. This avoids losing our reference to our content and allows multiple usages of the same `MockedHttpMessageResponse` * Move services to extension Extension is shared by testing and allows access to services from our service tests * Remove unused `using` * Prefer awaiting asyncs for better exception handling * `dotnet format` 🤖 * Await async * Update tests to use test TLD and ip ranges * Remove unused interfaces * Make assignments static when possible * Prefer invariant comparer to downcasing * Prefer injecting interface services to implementations * Prefer comparer set in HashSet initialization * Allow SVG icons * Filter out icons with unknown formats * Seek to beginning of MemoryStream after writing it * More appropriate to not return icon if it's invalid * Add svg icon test
This commit is contained in:
104
test/Common/MockedHttpClient/HttpRequestMatcher.cs
Normal file
104
test/Common/MockedHttpClient/HttpRequestMatcher.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Net;
|
||||
|
||||
namespace Bit.Test.Common.MockedHttpClient;
|
||||
|
||||
public class HttpRequestMatcher : IHttpRequestMatcher
|
||||
{
|
||||
private readonly Func<HttpRequestMessage, bool> _matcher;
|
||||
private HttpRequestMatcher? _childMatcher;
|
||||
private MockedHttpResponse _mockedResponse = new(HttpStatusCode.OK);
|
||||
private bool _responseSpecified = false;
|
||||
|
||||
public int NumberOfMatches { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether or not the provided request can be handled by this matcher chain.
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public bool Matches(HttpRequestMessage request) => _matcher(request) && (_childMatcher == null || _childMatcher.Matches(request));
|
||||
|
||||
public HttpRequestMatcher(HttpMethod method)
|
||||
{
|
||||
_matcher = request => request.Method == method;
|
||||
}
|
||||
|
||||
public HttpRequestMatcher(string uri)
|
||||
{
|
||||
_matcher = request => request.RequestUri == new Uri(uri);
|
||||
}
|
||||
|
||||
public HttpRequestMatcher(Uri uri)
|
||||
{
|
||||
_matcher = request => request.RequestUri == uri;
|
||||
}
|
||||
|
||||
public HttpRequestMatcher(HttpMethod method, string uri)
|
||||
{
|
||||
_matcher = request => request.Method == method && request.RequestUri == new Uri(uri);
|
||||
}
|
||||
|
||||
public HttpRequestMatcher(Func<HttpRequestMessage, bool> matcher)
|
||||
{
|
||||
_matcher = matcher;
|
||||
}
|
||||
|
||||
public HttpRequestMatcher WithHeader(string name, string value)
|
||||
{
|
||||
return AddChild(request => request.Headers.TryGetValues(name, out var values) && values.Contains(value));
|
||||
}
|
||||
|
||||
public HttpRequestMatcher WithQueryParameters(Dictionary<string, string> requiredQueryParameters) =>
|
||||
WithQueryParameters(requiredQueryParameters.Select(x => $"{x.Key}={x.Value}").ToArray());
|
||||
public HttpRequestMatcher WithQueryParameters(string name, string value) =>
|
||||
WithQueryParameters($"{name}={value}");
|
||||
public HttpRequestMatcher WithQueryParameters(params string[] queryKeyValues)
|
||||
{
|
||||
bool matcher(HttpRequestMessage request)
|
||||
{
|
||||
var query = request.RequestUri?.Query;
|
||||
if (query == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return queryKeyValues.All(queryKeyValue => query.Contains(queryKeyValue));
|
||||
}
|
||||
return AddChild(matcher);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure how this matcher should respond to matching HttpRequestMessages.
|
||||
/// Note, after specifying a response, you can no longer further specify match criteria.
|
||||
/// </summary>
|
||||
/// <param name="statusCode"></param>
|
||||
/// <returns></returns>
|
||||
public MockedHttpResponse RespondWith(HttpStatusCode statusCode)
|
||||
{
|
||||
_responseSpecified = true;
|
||||
_mockedResponse = new MockedHttpResponse(statusCode);
|
||||
return _mockedResponse;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to produce an HttpResponseMessage for the given request. This is probably something you want to leave alone
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
public async Task<HttpResponseMessage> RespondToAsync(HttpRequestMessage request)
|
||||
{
|
||||
NumberOfMatches++;
|
||||
return await (_childMatcher == null ? _mockedResponse.RespondToAsync(request) : _childMatcher.RespondToAsync(request));
|
||||
}
|
||||
|
||||
private HttpRequestMatcher AddChild(Func<HttpRequestMessage, bool> matcher)
|
||||
{
|
||||
if (_responseSpecified)
|
||||
{
|
||||
throw new Exception("Cannot continue to configure a matcher after a response has been specified");
|
||||
}
|
||||
_childMatcher = new HttpRequestMatcher(matcher);
|
||||
return _childMatcher;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user