-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Support http request multipart body
- Loading branch information
Showing
23 changed files
with
559 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<phpunit bootstrap="../../../vendor/autoload.php" colors="true"> | ||
<testsuites> | ||
<testsuite name="PhpPact Example Tests"> | ||
<directory>./tests</directory> | ||
</testsuite> | ||
</testsuites> | ||
<php> | ||
<env name="PACT_LOGLEVEL" value="DEBUG"/> | ||
</php> | ||
</phpunit> |
52 changes: 52 additions & 0 deletions
52
example/multipart/consumer/src/Service/HttpClientService.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
<?php | ||
|
||
namespace MultipartConsumer\Service; | ||
|
||
use GuzzleHttp\Client; | ||
|
||
/** | ||
* Example HTTP Service | ||
*/ | ||
class HttpClientService | ||
{ | ||
private Client $httpClient; | ||
|
||
private string $baseUri; | ||
|
||
public function __construct(string $baseUri) | ||
{ | ||
$this->httpClient = new Client(); | ||
$this->baseUri = $baseUri; | ||
} | ||
|
||
public function updateUserProfile(): string | ||
{ | ||
$response = $this->httpClient->post("{$this->baseUri}/user-profile", [ | ||
'multipart' => [ | ||
[ | ||
'name' => 'full_name', | ||
'contents' => 'Zoey Turcotte' | ||
], | ||
[ | ||
'name' => 'profile_image', | ||
'contents' => file_get_contents(__DIR__ . '/../_resource/image.jpg') | ||
], | ||
[ | ||
'name' => 'personal_note', | ||
'contents' => 'testing', | ||
'filename' => 'note.txt', | ||
'headers' => [ | ||
'X-Foo' => 'this is a note', | ||
'Content-Type' => 'application/octet-stream', | ||
], | ||
], | ||
], | ||
'headers' => [ | ||
'Accept' => 'application/json', | ||
'Authorization' => 'Bearer ZmluLWFwaTphcGktc2VjcmV0', | ||
], | ||
]); | ||
|
||
return $response->getBody(); | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
95 changes: 95 additions & 0 deletions
95
example/multipart/consumer/tests/Service/HttpClientServiceTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
<?php | ||
|
||
namespace MultipartConsumer\Tests\Service; | ||
|
||
use MultipartConsumer\Service\HttpClientService; | ||
use PhpPact\Consumer\InteractionBuilder; | ||
use PhpPact\Consumer\Matcher\Matcher; | ||
use PhpPact\Consumer\Model\Body\Multipart; | ||
use PhpPact\Consumer\Model\Body\Part; | ||
use PhpPact\Consumer\Model\ConsumerRequest; | ||
use PhpPact\Consumer\Model\ProviderResponse; | ||
use PhpPact\Standalone\MockService\MockServerConfig; | ||
use PHPUnit\Framework\TestCase; | ||
|
||
class HttpClientServiceTest extends TestCase | ||
{ | ||
public const URL_FORMAT = '^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)'; | ||
|
||
public function testUpdateUserProfile() | ||
{ | ||
$matcher = new Matcher(); | ||
$fullName = 'Colten Ziemann'; | ||
$profileImageUrl = 'http://example.test/profile-image.jpg'; | ||
$personalNote = 'testing'; | ||
|
||
$request = new ConsumerRequest(); | ||
$request | ||
->setMethod('POST') | ||
->setPath('/user-profile') | ||
->setHeaders([ | ||
'Accept' => 'application/json', | ||
'Authorization' => [ | ||
\json_encode($matcher->like('Bearer eyJhbGciOiJIUzI1NiIXVCJ9')) | ||
], | ||
]) | ||
->setBody(new Multipart([ | ||
new Part($fullNameTempFile = $this->createTempFile($fullName), 'full_name', 'text/plain'), | ||
new Part(__DIR__ . '/../_resource/image.jpg', 'profile_image', 'image/jpeg'), | ||
new Part($personalNoteTempFile = $this->createTempFile($personalNote), 'personal_note', 'text/plain'), | ||
])); | ||
|
||
$response = new ProviderResponse(); | ||
$response | ||
->setStatus(200) | ||
->addHeader('Content-Type', 'application/json') | ||
->setBody([ | ||
'full_name' => $matcher->like($fullName), | ||
'profile_image' => $matcher->regex($profileImageUrl, self::URL_FORMAT), | ||
'personal_note' => $matcher->like($personalNote), | ||
]); | ||
|
||
$config = new MockServerConfig(); | ||
$config | ||
->setConsumer('multipartConsumer') | ||
->setProvider('multipartProvider') | ||
->setPactDir(__DIR__.'/../../../pacts'); | ||
if ($logLevel = \getenv('PACT_LOGLEVEL')) { | ||
$config->setLogLevel($logLevel); | ||
} | ||
$builder = new InteractionBuilder($config); | ||
$builder | ||
->given('User exists') | ||
->uponReceiving('A put request to /user-profile') | ||
->with($request) | ||
->willRespondWith($response); | ||
|
||
$service = new HttpClientService($config->getBaseUri()); | ||
$userProfileResponse = $service->updateUserProfile(); | ||
$verifyResult = $builder->verify(); | ||
|
||
unlink($fullNameTempFile); | ||
unlink($personalNoteTempFile); | ||
|
||
$this->assertTrue($verifyResult); | ||
$this->assertEquals([ | ||
'full_name' => $fullName, | ||
'profile_image' => $profileImageUrl, | ||
'personal_note' => $personalNote, | ||
], \json_decode($userProfileResponse, true, 512, JSON_THROW_ON_ERROR)); | ||
} | ||
|
||
private function createTempFile(string $contents): string | ||
{ | ||
$path = tempnam(sys_get_temp_dir(), 'pact'); | ||
//$newPath = "$path.txt"; | ||
//rename($path, $newPath); | ||
$newPath = $path; | ||
|
||
$handle = fopen($newPath, 'w'); | ||
fwrite($handle, $contents); | ||
fclose($handle); | ||
|
||
return $newPath; | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
137 changes: 137 additions & 0 deletions
137
example/multipart/pacts/multipartConsumer-multipartProvider.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
{ | ||
"consumer": { | ||
"name": "multipartConsumer" | ||
}, | ||
"interactions": [ | ||
{ | ||
"description": "A put request to /user-profile", | ||
"providerStates": [ | ||
{ | ||
"name": "User exists" | ||
} | ||
], | ||
"request": { | ||
"body": "--MxafNCX4RAVZ1d2c\r\nContent-Disposition: form-data; name=\"personal_note\"; filename=\"pactmk99lD\"\r\nContent-Type: application/octet-stream\r\n\r\ntesting\r\n--MxafNCX4RAVZ1d2c--\r\n", | ||
"headers": { | ||
"Accept": "application/json", | ||
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIXVCJ9", | ||
"Content-Type": "multipart/form-data; boundary=MxafNCX4RAVZ1d2c" | ||
}, | ||
"matchingRules": { | ||
"body": { | ||
"$.full_name": { | ||
"combine": "AND", | ||
"matchers": [ | ||
{ | ||
"match": "contentType", | ||
"value": "text/plain" | ||
} | ||
] | ||
}, | ||
"$.personal_note": { | ||
"combine": "AND", | ||
"matchers": [ | ||
{ | ||
"match": "contentType", | ||
"value": "text/plain" | ||
} | ||
] | ||
}, | ||
"$.profile_image": { | ||
"combine": "AND", | ||
"matchers": [ | ||
{ | ||
"match": "contentType", | ||
"value": "image/jpeg" | ||
} | ||
] | ||
} | ||
}, | ||
"header": { | ||
"$.Authorization[0]": { | ||
"combine": "AND", | ||
"matchers": [ | ||
{ | ||
"match": "type" | ||
} | ||
] | ||
}, | ||
"Content-Type": { | ||
"combine": "AND", | ||
"matchers": [ | ||
{ | ||
"match": "regex", | ||
"regex": "multipart/form-data;(\\s*charset=[^;]*;)?\\s*boundary=.*" | ||
}, | ||
{ | ||
"match": "regex", | ||
"regex": "multipart/form-data;(\\s*charset=[^;]*;)?\\s*boundary=.*" | ||
}, | ||
{ | ||
"match": "regex", | ||
"regex": "multipart/form-data;(\\s*charset=[^;]*;)?\\s*boundary=.*" | ||
} | ||
] | ||
} | ||
} | ||
}, | ||
"method": "POST", | ||
"path": "/user-profile" | ||
}, | ||
"response": { | ||
"body": { | ||
"full_name": "Colten Ziemann", | ||
"personal_note": "testing", | ||
"profile_image": "http://example.test/profile-image.jpg" | ||
}, | ||
"headers": { | ||
"Content-Type": "application/json" | ||
}, | ||
"matchingRules": { | ||
"body": { | ||
"$.full_name": { | ||
"combine": "AND", | ||
"matchers": [ | ||
{ | ||
"match": "type" | ||
} | ||
] | ||
}, | ||
"$.personal_note": { | ||
"combine": "AND", | ||
"matchers": [ | ||
{ | ||
"match": "type" | ||
} | ||
] | ||
}, | ||
"$.profile_image": { | ||
"combine": "AND", | ||
"matchers": [ | ||
{ | ||
"match": "regex", | ||
"regex": "^https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()!@:%_\\+.~#?&\\/\\/=]*)" | ||
} | ||
] | ||
} | ||
}, | ||
"header": {} | ||
}, | ||
"status": 200 | ||
} | ||
} | ||
], | ||
"metadata": { | ||
"pactRust": { | ||
"ffi": "0.4.7", | ||
"mockserver": "1.2.3", | ||
"models": "1.1.9" | ||
}, | ||
"pactSpecification": { | ||
"version": "3.0.0" | ||
} | ||
}, | ||
"provider": { | ||
"name": "multipartProvider" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<phpunit bootstrap="../../../vendor/autoload.php" colors="true"> | ||
<testsuites> | ||
<testsuite name="PhpPact Example Tests"> | ||
<directory>./tests</directory> | ||
</testsuite> | ||
</testsuites> | ||
<php> | ||
<env name="PACT_LOGLEVEL" value="DEBUG"/> | ||
</php> | ||
</phpunit> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php | ||
|
||
use Psr\Http\Message\ResponseInterface as Response; | ||
use Psr\Http\Message\ServerRequestInterface as Request; | ||
use Slim\Factory\AppFactory; | ||
|
||
require __DIR__ . '/../../../../vendor/autoload.php'; | ||
|
||
$app = AppFactory::create(); | ||
$app->addBodyParsingMiddleware(); | ||
|
||
$app->post('/user-profile', function (Request $request, Response $response) { | ||
$fileName = (string)$request->getUploadedFiles()['profile_image']->getClientFilename(); | ||
$response->getBody()->write(\json_encode([ | ||
'full_name' => (string)$request->getUploadedFiles()['full_name']->getStream(), | ||
'profile_image' => "http://example.test/$fileName", | ||
'personal_note' => (string)$request->getUploadedFiles()['personal_note']->getStream(), | ||
])); | ||
|
||
return $response->withHeader('Content-Type', 'application/json'); | ||
}); | ||
|
||
$app->run(); |
Oops, something went wrong.