pact-foundation / pact-reference

Reference implementations for the pact specifications
https://pact.io
MIT License
91 stars 46 forks source link

Multipart: Mismatch when comparing 2 identical strings #318

Closed tienvx closed 1 year ago

tienvx commented 1 year ago

consumer's tests failed because of mismatch when comparing 2 identical strings (testing !== testing)

How to reproduce:

Partial logs:

2023-08-30T04:42:58.653223Z DEBUG ThreadId(03) matches_with{self="testing" actual="testing" matcher=ContentType("text/plain") cascaded=false}: pact_matching::matchers: String -> String: comparing 'testing' to 'testing' ==> false cascaded=false matcher=ContentType("text/plain")
2023-08-30T04:42:58.653226Z TRACE ThreadId(03) pact_matching::matchers: match_values: &str -> &str result=Err(["Unable to match 'testing' using ContentType(\"text/plain\")"])
2023-08-30T04:42:58.653231Z DEBUG ThreadId(03) pact_matching::binary_utils: Comparing file part 'MimeFile { index: 2, name: "personal_note", content_type: Some("text/plain"), filename: "note.txt", data: b"testing", headers: {"content-disposition": "form-data; name=\"personal_note\"; filename=\"note.txt\"", "content-type": "text/plain"} }' to 'MimeFile { index: 2, name: "personal_note", content_type: Some("text/plain"), filename: "note.txt", data: b"testing", headers: {"content-disposition": "form-data; name=\"personal_note\"; filename=\"note.txt\"", "content-length": "7", "content-type": "text/plain"} }' at path '$.personal_note' -> BodyMismatches({"$": [BodyMismatch { path: "$", expected: Some(b"testing"), actual: Some(b"testing"), mismatch: "Unable to match 'testing' using ContentType(\"text/plain\")" }]})
2023-08-30T04:42:58.652142Z DEBUG ThreadId(03) matches_with{self="Colten Ziemann" actual="Zoey Turcotte" matcher=ContentType("text/plain") cascaded=false}: pact_matching::matchers: String -> String: comparing 'Colten Ziemann' to 'Zoey Turcotte' ==> false cascaded=false matcher=ContentType("text/plain")
2023-08-30T04:42:58.652147Z TRACE ThreadId(03) pact_matching::matchers: match_values: &str -> &str result=Err(["Unable to match 'Colten Ziemann' using ContentType(\"text/plain\")"])
2023-08-30T04:42:58.652154Z DEBUG ThreadId(03) pact_matching::binary_utils: Comparing file part 'MimeFile { index: 0, name: "full_name", content_type: Some("text/plain"), filename: "full_name.txt", data: b"Colten Ziemann", headers: {"content-disposition": "form-data; name=\"full_name\"; filename=\"full_name.txt\"", "content-type": "text/plain"} }' to 'MimeFile { index: 0, name: "full_name", content_type: Some("text/plain"), filename: "full_name.txt", data: b"Zoey Turcotte", headers: {"content-disposition": "form-data; name=\"full_name\"; filename=\"full_name.txt\"", "content-length": "13", "content-type": "text/plain"} }' at path '$.full_name' -> BodyMismatches({"$": [BodyMismatch { path: "$", expected: Some(b"Colten Ziemann"), actual: Some(b"Zoey Turcotte"), mismatch: "Unable to match 'Colten Ziemann' using ContentType(\"text/plain\")" }]})

Full log: log.txt

Info:

Slack's discussion: https://pact-foundation.slack.com/archives/C02BXLDJ7JR/p1692696366946609

tienvx commented 1 year ago

Translate to ffi language:

I call pactffi_with_multipart_file 3 times:

$ffi->pactffi_with_multipart_file($interaction, $ffi->InteractionPart_Request, 'text/plain', '/path/to/full_name.txt', 'full_name');
$ffi->pactffi_with_multipart_file($interaction, $ffi->InteractionPart_Request, 'image/jpeg', '/path/to/image.jpg', 'profile_image');
$ffi->pactffi_with_multipart_file($interaction, $ffi->InteractionPart_Request, 'text/plain', '/path/to/note.txt', 'personal_note');

After starting the mock server, I make a multipart request to it:

$response = $this->httpClient->post("{$this->baseUri}/user-profile", [
            'multipart' => [
                [
                    'name' => 'full_name',
                    'contents' => 'Zoey Turcotte',
                    'filename' => 'full_name.txt',
                ],
                [
                    'name' => 'profile_image',
                    'contents' => file_get_contents(__DIR__ . '/../_resource/image.jpg'),
                    'filename' => 'image.jpg',
                ],
                [
                    'name' => 'personal_note',
                    'contents' => 'testing',
                    'filename' => 'note.txt',
                ],
            ],
            'headers' => [
                'Accept' => 'application/json',
                'Authorization' => 'Bearer ZmluLWFwaTphcGktc2VjcmV0',
            ],
        ]);

Mock server will start to compare the values using ContentType("x/y") matcher: