Skip to content

Commit

Permalink
chore: Add form urlencoded example
Browse files Browse the repository at this point in the history
  • Loading branch information
tienvx committed Sep 5, 2024
1 parent 41c63a8 commit 99ea25f
Show file tree
Hide file tree
Showing 10 changed files with 372 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ jobs:
example: 'protobuf-async-message'
- os: windows-latest
example: 'stub-server'
- os: windows-latest
example: 'form-urlencoded-message'
timeout-minutes: 5

steps:
Expand Down
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@
"ProtobufAsyncMessageConsumer\\Tests\\": "example/protobuf-async-message/consumer/tests",
"ProtobufAsyncMessageProvider\\Tests\\": "example/protobuf-async-message/provider/tests",
"StubServerConsumer\\": "example/stub-server/consumer/src",
"StubServerConsumer\\Tests\\": "example/stub-server/consumer/tests"
"StubServerConsumer\\Tests\\": "example/stub-server/consumer/tests",
"FormUrlEncodedConsumer\\": "example/form-urlencoded/consumer/src",
"FormUrlEncodedConsumer\\Tests\\": "example/form-urlencoded/consumer/tests",
"FormUrlEncodedProvider\\Tests\\": "example/form-urlencoded/provider/tests"
}
},
"scripts": {
Expand Down
11 changes: 11 additions & 0 deletions example/form-urlencoded/consumer/phpunit.xml
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>
40 changes: 40 additions & 0 deletions example/form-urlencoded/consumer/src/Service/HttpClientService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace FormUrlEncodedConsumer\Service;

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Uri;

class HttpClientService
{
private Client $httpClient;

private string $baseUri;

public function __construct(string $baseUri)
{
$this->httpClient = new Client();
$this->baseUri = $baseUri;
}

public function createUser(): string
{
$response = $this->httpClient->post(new Uri("{$this->baseUri}/users"), [
'body' => http_build_query([
'empty' => '',
'agree' => 'true',
'fullname' => 'First Last Name',
'email' => '[email protected]',
'password' => 'very@secure&password123',
'age' => 41,
]) .
'&roles[]=User&roles[]=Manager',
'headers' => [
'Accept' => 'application/json',
'Content-Type' => 'application/x-www-form-urlencoded',
],
]);

return $response->getBody();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace FormUrlEncodedConsumer\Tests\Service;

use PhpPact\Consumer\Matcher\Matcher;
use FormUrlEncodedConsumer\Service\HttpClientService;
use PhpPact\Consumer\InteractionBuilder;
use PhpPact\Consumer\Model\Body\Text;
use PhpPact\Consumer\Model\ConsumerRequest;
use PhpPact\Consumer\Model\ProviderResponse;
use PhpPact\Standalone\MockService\MockServerConfig;
use PHPUnit\Framework\TestCase;

class HttpClientServiceTest extends TestCase
{
public function testGetMovies()
{
$matcher = new Matcher();

$request = new ConsumerRequest();
$request
->setMethod('POST')
->setPath('/users')
->addHeader('Content-Type', 'application/x-www-form-urlencoded')
->addHeader('Accept', 'application/json')
->setBody(
new Text(
json_encode([
'null' => $matcher->nullValue(),
'empty' => $matcher->equal(''),
'agree' => $matcher->regex('false', 'true|false'),
'fullname' => $matcher->string('User name'),
'email' => $matcher->email('[email protected]'),
'password' => $matcher->regex('user@password111', '^[\w\d@$!%*#?&^_-]{8,}$'),
'age' => $matcher->number(27),
'roles[]' => $matcher->eachValue(['User'], [$matcher->regex('User', 'Admin|User|Manager')]),
// Boolean value is not supported, and will panic
// 'boolean' => $matcher->booleanV3(true),
// Object value is not supported, and will panic
// 'object' => $matcher->like([
// 'key' => $matcher->string('value',)
// ]),
]),
'application/x-www-form-urlencoded'
)
)
;

$response = new ProviderResponse();
$response
->setStatus(201)
->addHeader('Content-Type', 'application/json')
->setBody([
'id' => $matcher->uuid('6e58b1df-ff80-4031-b7b9-5191e4c74ee8'),
]);

$config = new MockServerConfig();
$config
->setConsumer('formUrlEncodedConsumer')
->setProvider('formUrlEncodedProvider')
->setPactDir(__DIR__.'/../../../pacts');
if ($logLevel = \getenv('PACT_LOGLEVEL')) {
$config->setLogLevel($logLevel);
}
$builder = new InteractionBuilder($config);
$builder
->given('Endpoint is protected')
->uponReceiving('A post request to /users')
->with($request)
->willRespondWith($response);

$service = new HttpClientService($config->getBaseUri());
$body = json_decode($service->createUser(), true);
$verifyResult = $builder->verify();

$this->assertTrue($verifyResult);
$this->assertArrayHasKey('id', $body);
$pattern = Matcher::UUID_V4_FORMAT;
$this->assertEquals(1, preg_match("/{$pattern}/", $body['id']));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
{
"consumer": {
"name": "formUrlEncodedConsumer"
},
"interactions": [
{
"description": "A post request to /users",
"providerStates": [
{
"name": "Endpoint is protected"
}
],
"request": {
"body": "age=27&agree=false&email=user%40email.test&empty=&fullname=User+name&password=user%40password111&roles%5B%5D=User",
"headers": {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
"matchingRules": {
"body": {
"$.age": {
"combine": "AND",
"matchers": [
{
"match": "number"
}
]
},
"$.agree": {
"combine": "AND",
"matchers": [
{
"match": "regex",
"regex": "true|false"
}
]
},
"$.email": {
"combine": "AND",
"matchers": [
{
"match": "regex",
"regex": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$"
}
]
},
"$.empty": {
"combine": "AND",
"matchers": [
{
"match": "equality"
}
]
},
"$.fullname": {
"combine": "AND",
"matchers": [
{
"match": "type"
}
]
},
"$.null": {
"combine": "AND",
"matchers": [
{
"match": "null"
}
]
},
"$.password": {
"combine": "AND",
"matchers": [
{
"match": "regex",
"regex": "^[\\w\\d@$!%*#?&^_-]{8,}$"
}
]
},
"$['roles[]']": {
"combine": "AND",
"matchers": [
{
"match": "eachValue",
"rules": [
{
"match": "regex",
"regex": "Admin|User|Manager"
}
],
"value": "[\"User\"]"
}
]
}
}
},
"method": "POST",
"path": "/users"
},
"response": {
"body": {
"id": "6e58b1df-ff80-4031-b7b9-5191e4c74ee8"
},
"headers": {
"Content-Type": "application/json"
},
"matchingRules": {
"body": {
"$.id": {
"combine": "AND",
"matchers": [
{
"match": "regex",
"regex": "^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$"
}
]
}
}
},
"status": 201
}
}
],
"metadata": {
"pactRust": {
"ffi": "0.4.24",
"mockserver": "1.2.10",
"models": "1.2.5"
},
"pactSpecification": {
"version": "3.0.0"
}
},
"provider": {
"name": "formUrlEncodedProvider"
}
}
11 changes: 11 additions & 0 deletions example/form-urlencoded/provider/phpunit.xml
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>
31 changes: 31 additions & 0 deletions example/form-urlencoded/provider/public/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?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('/users', function (Request $request, Response $response) {
$auth = $request->getHeader('Authorization');
if ($auth != 'Bearer 1a2b3c4d5e6f7g8h9i0k') {
$response->withStatus(403);
}

error_log(sprintf('request body: %s', json_encode($request->getParsedBody())));

$response->getBody()->write(\json_encode(['id' => '49dcfd3f-a5c9-49cb-a09e-a40a1da936b9']));

return $response
->withStatus(201)
->withHeader('Content-Type', 'application/json');
});

$app->post('/pact-change-state', function (Request $request, Response $response) {
return $response;
});

$app->run();
52 changes: 52 additions & 0 deletions example/form-urlencoded/provider/tests/PactVerifyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace FormUrlEncodedProvider\Tests;

use GuzzleHttp\Psr7\Uri;
use PhpPact\Standalone\ProviderVerifier\Model\VerifierConfig;
use PhpPact\Standalone\ProviderVerifier\Verifier;
use PhpPactTest\Helper\PhpProcess;
use PHPUnit\Framework\TestCase;

class PactVerifyTest extends TestCase
{
private PhpProcess $process;

protected function setUp(): void
{
$this->process = new PhpProcess(__DIR__ . '/../public/');
$this->process->start();
}

protected function tearDown(): void
{
$this->process->stop();
}

/**
* This test will run after the web server is started.
*/
public function testPactVerifyConsumer()
{
$config = new VerifierConfig();
$config->getProviderInfo()
->setName('formUrlEncodedProvider') // Providers name to fetch.
->setHost('localhost')
->setPort($this->process->getPort());
$config->getProviderState()
->setStateChangeUrl(new Uri(sprintf('http://localhost:%d/pact-change-state', $this->process->getPort())))
;
$config->getCustomHeaders()
->addHeader('Authorization', 'Bearer 1a2b3c4d5e6f7g8h9i0k');
if ($level = \getenv('PACT_LOGLEVEL')) {
$config->setLogLevel($level);
}

$verifier = new Verifier($config);
$verifier->addFile(__DIR__ . '/../../pacts/formUrlEncodedConsumer-formUrlEncodedProvider.json');

$verifyResult = $verifier->verify();

$this->assertTrue($verifyResult);
}
}
Loading

0 comments on commit 99ea25f

Please sign in to comment.