I am moving from mocking calls to Elasticsearch (through NEST) to using the InMemoryConnection
class and some hard-coded JSON to simulate a real Elasticsearch answering the requests made from C# code. Works great and much better than mocks, which require deep understanding and knowledge about how NEST is implemented and breaks very easily.
My question is, if I want to simulate multiple calls to Elasticsearch, I don't see any easy way to do this. InMemoryConnection
accepts a single JSON string only:
var connection = new InMemoryConnection(Encoding.UTF8.GetBytes(json));
It would be nice to say something like, return x on the first call and y on the second.
Similar issue is when verifying calls to Elasticsearch. I can use OnRequestCompleted
to set a couple of booleans like this:
OnRequestCompleted(response =>
{
if (response.Uri.ToString().Contains("/blabla/_search")) {}
else if (response.HttpMethod == HttpMethod.POST && response.Success && response.Uri.ToString().StartsWith("http://localhost:9200/blabla"))
wasCalled = true;
else // We don't expect any other calls
failed = true;
})
When asserting on those booleans. But that doesn't feel right.
Any ideas would be appreciated.
InMemoryConnection
is geared more towards an individual request/response as opposed to stubbing multiple different requests/responses, however, an IConnection
can be derived from it to achieve this purpose
public class TestConnection : InMemoryConnection
{
private (byte[], int, string) DetermineResponse(RequestData requestData)
{
byte[] responseBody = null;
int statusCode = 200;
string contentType = RequestData.MimeType;
// do the switching here e.g. ctor might take a dictionary of Predicate<RequestData> -> Responses
if (requestData.Uri.AbsolutePath == "/_search")
{
responseBody = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { }));
}
return (responseBody, statusCode, contentType);
}
public override TResponse Request<TResponse>(RequestData requestData)
{
var (responseBody, statusCode, contentType) = DetermineResponse(requestData);
return base.ReturnConnectionStatus<TResponse>(requestData, responseBody, statusCode, contentType);
}
public override Task<TResponse> RequestAsync<TResponse>(RequestData requestData, CancellationToken cancellationToken)
{
var (responseBody, statusCode, contentType) = DetermineResponse(requestData);
return base.ReturnConnectionStatusAsync<TResponse>(requestData, cancellationToken, responseBody, statusCode, contentType);
}
}
Something like this would probably be a great addition to Elasticsearch.Net.VirtualizedCluster.
Similar issue is when verifying calls to Elasticsearch. I can use OnRequestCompleted to set a couple of booleans like this:
OnRequestCompleted(response => { if (response.Uri.ToString().Contains("/blabla/_search")) {} else if (response.HttpMethod == HttpMethod.POST && response.Success && response.Uri.ToString().StartsWith("http://localhost:9200/blabla")) wasCalled = true; else // We don't expect any other calls failed = true; })
Rather than asserting these in OnRequestCompleted
, I'd either
TestConnection
and assert they were called there. I wonder if what might be being asserted in this manner could be deduced from the response instead somehow, though.or
response.ApiCall