Multipart matcher
Hi, I would like to match multipart requests. In the request there can be several parts and I only need to match some of them and not all. It seems when passing an array of matchers to .WithMultipart it has to be one to one associated with the request but in my case there can be different number of parts in the request and I always want to only match the first two parts based on some conditions.
In the example below request has 3 parts but how can I check if the part that has text/json content-type has specific content regardless of other parts or regardless of position of the json part.
I commented out some elements of matchers array and it fails.
static void Main(string[] args)
{
// Arrange
var server = WireMockServer.Start();
var textPlainContent = "This is some plain text";
var textPlainContentType = "text/plain";
var textPlainContentTypeMatcher = new ContentTypeMatcher(textPlainContentType);
var textPlainContentMatcher = new ExactMatcher(textPlainContent);
var textPlainMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textPlainContentTypeMatcher, null, null, textPlainContentMatcher);
var textJson = "{ \"Key\" : \"Value\" }";
var textJsonContentType = "text/json";
var textJsonContentTypeMatcher = new ContentTypeMatcher(textJsonContentType);
var textJsonContentMatcher = new JsonMatcher(new { Key = "Value" }, true);
var jsonMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, textJsonContentTypeMatcher, null, null, textJsonContentMatcher);
var imagePngBytes = Convert.FromBase64String("iVBORw0KGgoAAAANSUhEUgAAAAIAAAACAgMAAAAP2OW3AAAADFBMVEX/tID/vpH/pWX/sHidUyjlAAAADElEQVR4XmMQYNgAAADkAMHebX3mAAAAAElFTkSuQmCC");
var imagePngContentMatcher = new ExactObjectMatcher(imagePngBytes);
var imagePngMatcher = new MimePartMatcher(MatchBehaviour.AcceptOnMatch, null, null, null, imagePngContentMatcher);
var matchers = new IMatcher[]
{
//textPlainMatcher,
jsonMatcher,
//imagePngMatcher
};
server
.Given(
Request.Create()
.UsingPost()
.WithPath("/multipart")
.WithMultiPart(matchers))
.RespondWith(Response.Create());
// Act
var formDataContent = new MultipartFormDataContent();
formDataContent.Add(new StringContent(textPlainContent, Encoding.UTF8, textPlainContentType), "text");
formDataContent.Add(new StringContent(textJson, Encoding.UTF8, textJsonContentType), "json");
var fileContent = new ByteArrayContent(imagePngBytes);
fileContent.Headers.ContentType = new MediaTypeHeaderValue("image/png");
formDataContent.Add(fileContent, "somefile", "image.png");
var client = server.CreateClient();
var response = client.PostAsync("/multipart", formDataContent).GetAwaiter().GetResult();
// Assert
Console.WriteLine(response.StatusCode);
Console.ReadLine();
server.Stop();
}
I think it is a bug. in the file ~\Matchers\Request\RequestMessageMultiPartMatcher.cs, the logic of GetMatchingScore method should be changed to have two loops with the outer loop to be matchers and inner loop each part.
I tried the following and it worked but there might be better ways to implement it:
public double GetMatchingScore(IRequestMessage requestMessage, IRequestMatchResult requestMatchResult)
{
#if !MIMEKIT
throw new System.NotSupportedException("The MultiPartMatcher can not be used for .NETStandard1.3 or .NET Framework 4.6.1 or lower.");
#else
var score = MatchScores.Mismatch;
Exception? exception = null;
if (Matchers?.Any() != true)
{
return requestMatchResult.AddScore(GetType(), score, null);
}
if (!MimeKitUtils.TryGetMimeMessage(requestMessage, out var message))
{
return requestMatchResult.AddScore(GetType(), score, null);
}
try
{
foreach (var mimePartMatcher in Matchers.OfType<MimePartMatcher>().ToArray())
{
score = MatchScores.Mismatch;
foreach (var mimeBodyPart in message.BodyParts.OfType<MimeKit.MimePart>())
{
var matchResult = mimePartMatcher.IsMatch(mimeBodyPart);
if (matchResult.IsPerfect())
{
score = MatchScores.Perfect;
break;
}
}
if ((MatchOperator == MatchOperator.Or && MatchScores.IsPerfect(score))
|| (MatchOperator == MatchOperator.And && !MatchScores.IsPerfect(score)))
{
break;
}
}
}
catch (Exception ex)
{
exception = ex;
}
return requestMatchResult.AddScore(GetType(), score, exception);
#endif
}
@rmeshksar Can you please create a fix PR which also includes a unit-test?
I will do it in this week. Thanks