From 7ee934b52e3258af2a73632173b4f8777afcc7ee Mon Sep 17 00:00:00 2001 From: tienvx Date: Tue, 29 Aug 2023 23:25:29 +0700 Subject: [PATCH 1/3] chore: add xml example --- composer.json | 9 +- example/xml/consumer/phpunit.xml | 11 ++ .../src/Service/HttpClientService.php | 28 ++++ .../tests/Service/HttpClientServiceTest.php | 94 ++++++++++++++ .../xml/pacts/xmlConsumer-xmlProvider.json | 122 ++++++++++++++++++ example/xml/provider/phpunit.xml | 11 ++ example/xml/provider/public/index.php | 53 ++++++++ example/xml/provider/tests/PactVerifyTest.php | 66 ++++++++++ 8 files changed, 392 insertions(+), 2 deletions(-) create mode 100644 example/xml/consumer/phpunit.xml create mode 100644 example/xml/consumer/src/Service/HttpClientService.php create mode 100644 example/xml/consumer/tests/Service/HttpClientServiceTest.php create mode 100644 example/xml/pacts/xmlConsumer-xmlProvider.json create mode 100644 example/xml/provider/phpunit.xml create mode 100644 example/xml/provider/public/index.php create mode 100644 example/xml/provider/tests/PactVerifyTest.php diff --git a/composer.json b/composer.json index e558f0384..59ac76a80 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,8 @@ "friendsofphp/php-cs-fixer": "^3.0", "php-amqplib/php-amqplib": "^3.0", "phpstan/phpstan": "^1.9", - "phpunit/phpunit": ">=8.5.23 <10" + "phpunit/phpunit": ">=8.5.23 <10", + "tienvx/pact-php-xml": "dev-main" }, "autoload": { "psr-4": { @@ -53,7 +54,11 @@ "BinaryConsumer\\": "example/binary/consumer/src", "BinaryConsumer\\Tests\\": "example/binary/consumer/tests", "BinaryProvider\\": "example/binary/provider/src", - "BinaryProvider\\Tests\\": "example/binary/provider/tests" + "BinaryProvider\\Tests\\": "example/binary/provider/tests", + "XmlConsumer\\": "example/xml/consumer/src", + "XmlConsumer\\Tests\\": "example/xml/consumer/tests", + "XmlProvider\\": "example/xml/provider/src", + "XmlProvider\\Tests\\": "example/xml/provider/tests" } }, "scripts": { diff --git a/example/xml/consumer/phpunit.xml b/example/xml/consumer/phpunit.xml new file mode 100644 index 000000000..62a9eb007 --- /dev/null +++ b/example/xml/consumer/phpunit.xml @@ -0,0 +1,11 @@ + + + + + ./tests + + + + + + diff --git a/example/xml/consumer/src/Service/HttpClientService.php b/example/xml/consumer/src/Service/HttpClientService.php new file mode 100644 index 000000000..a2193e03a --- /dev/null +++ b/example/xml/consumer/src/Service/HttpClientService.php @@ -0,0 +1,28 @@ +httpClient = new Client(); + $this->baseUri = $baseUri; + } + + public function getMovies(): string + { + $response = $this->httpClient->get(new Uri("{$this->baseUri}/movies"), [ + 'headers' => ['Accept' => 'text/xml; charset=UTF8'] + ]); + + return $response->getBody(); + } +} diff --git a/example/xml/consumer/tests/Service/HttpClientServiceTest.php b/example/xml/consumer/tests/Service/HttpClientServiceTest.php new file mode 100644 index 000000000..8e33abf97 --- /dev/null +++ b/example/xml/consumer/tests/Service/HttpClientServiceTest.php @@ -0,0 +1,94 @@ +setMethod('GET') + ->setPath('/movies') + ->addHeader('Accept', 'text/xml; charset=UTF8'); + + $xmlBuilder = new XmlBuilder('1.0', 'UTF-8'); + $xmlBuilder + ->start('movies') + ->eachLike('movie') + ->start('title') + ->contentLike('PHP: Behind the Parser') + ->end() + ->start('characters') + ->eachLike('character', [], new Options(examples: 2)) + ->start('name') + ->contentLike('Ms. Coder') + ->end() + ->start('actor') + ->contentLike('Onlivia Actora') + ->end() + ->end() + ->end() + ->start('plot') + ->contentLike( + <<end() + ->start('great-lines') + ->eachLike('line') + ->contentLike('PHP solves all my web problems') + ->end() + ->end() + ->start('rating', ['type' => 'thumbs']) + ->contentLike(7) + ->end() + ->start('rating', ['type' => 'stars']) + ->contentLike(5) + ->end() + ->end() + ->end(); + + $response = new ProviderResponse(); + $response + ->setStatus(200) + ->addHeader('Content-Type', 'text/xml') + ->setBody( + json_encode($xmlBuilder->getArray()) + ); + + $config = new MockServerConfig(); + $config + ->setConsumer('xmlConsumer') + ->setProvider('xmlProvider') + ->setPactDir(__DIR__.'/../../../pacts'); + if ($logLevel = \getenv('PACT_LOGLEVEL')) { + $config->setLogLevel($logLevel); + } + $builder = new InteractionBuilder($config); + $builder + ->given('Movies exist') + ->uponReceiving('A get request to /movies') + ->with($request) + ->willRespondWith($response); + + $service = new HttpClientService($config->getBaseUri()); + $moviesResult = new \SimpleXMLElement($service->getMovies()); + $verifyResult = $builder->verify(); + + $this->assertTrue($verifyResult); + $this->assertCount(1, $moviesResult); + } +} diff --git a/example/xml/pacts/xmlConsumer-xmlProvider.json b/example/xml/pacts/xmlConsumer-xmlProvider.json new file mode 100644 index 000000000..8ead9538c --- /dev/null +++ b/example/xml/pacts/xmlConsumer-xmlProvider.json @@ -0,0 +1,122 @@ +{ + "consumer": { + "name": "xmlConsumer" + }, + "interactions": [ + { + "description": "A get request to /movies", + "providerStates": [ + { + "name": "Movies exist" + } + ], + "request": { + "headers": { + "Accept": "text/xml; charset=UTF8" + }, + "method": "GET", + "path": "/movies" + }, + "response": { + "body": "PHP: Behind the ParserMs. CoderOnlivia ActoraSo, this language. It's like, a programming language. Or is it a\nscripting language? All is revealed in this thrilling horror spoof\nof a documentary.PHP solves all my web problems75", + "headers": { + "Content-Type": "text/xml" + }, + "matchingRules": { + "body": { + "$.movies.movie": { + "combine": "AND", + "matchers": [ + { + "match": "type" + } + ] + }, + "$.movies.movie.characters.character": { + "combine": "AND", + "matchers": [ + { + "match": "type" + } + ] + }, + "$.movies.movie.characters.character.actor.#text": { + "combine": "AND", + "matchers": [ + { + "match": "type" + } + ] + }, + "$.movies.movie.characters.character.name.#text": { + "combine": "AND", + "matchers": [ + { + "match": "type" + } + ] + }, + "$.movies.movie.great-lines.line": { + "combine": "AND", + "matchers": [ + { + "match": "type" + } + ] + }, + "$.movies.movie.great-lines.line.#text": { + "combine": "AND", + "matchers": [ + { + "match": "type" + } + ] + }, + "$.movies.movie.plot.#text": { + "combine": "AND", + "matchers": [ + { + "match": "type" + } + ] + }, + "$.movies.movie.rating.#text": { + "combine": "AND", + "matchers": [ + { + "match": "type" + }, + { + "match": "type" + } + ] + }, + "$.movies.movie.title.#text": { + "combine": "AND", + "matchers": [ + { + "match": "type" + } + ] + } + }, + "header": {} + }, + "status": 200 + } + } + ], + "metadata": { + "pactRust": { + "ffi": "0.4.7", + "mockserver": "1.2.3", + "models": "1.1.9" + }, + "pactSpecification": { + "version": "3.0.0" + } + }, + "provider": { + "name": "xmlProvider" + } +} \ No newline at end of file diff --git a/example/xml/provider/phpunit.xml b/example/xml/provider/phpunit.xml new file mode 100644 index 000000000..62a9eb007 --- /dev/null +++ b/example/xml/provider/phpunit.xml @@ -0,0 +1,11 @@ + + + + + ./tests + + + + + + diff --git a/example/xml/provider/public/index.php b/example/xml/provider/public/index.php new file mode 100644 index 000000000..458ec3e1b --- /dev/null +++ b/example/xml/provider/public/index.php @@ -0,0 +1,53 @@ +createXMLArray() + ->start('movies') + ->start('movie') + ->add('title', 'PHP: Behind the Parser') + ->start('characters') + ->start('character') + ->add('name', 'Ms. Coder') + ->add('actor', 'Onlivia Actora') + ->end() + ->start('character') + ->add('name', 'Mr. Coder') + ->add('actor', 'El ActÓr') + ->end() + ->end() + ->add('plot', <<start('great-lines') + ->add('line', 'PHP solves all my web problems') + ->end() + ->add('rating', 7, ['type' => 'thumbs']) + ->add('rating', 5, ['type' => 'stars']) + ->end() + ->end(); + +$app = AppFactory::create(); + +$app->get('/movies', function (Request $request, Response $response) use ($xmlBuilder) { + $response->getBody()->write($xmlBuilder->getXml()); + + return $response->withHeader('Content-Type', 'text/xml'); +}); + +$app->post('/pact-change-state', function (Request $request, Response $response) { + return $response; +}); + +$app->run(); diff --git a/example/xml/provider/tests/PactVerifyTest.php b/example/xml/provider/tests/PactVerifyTest.php new file mode 100644 index 000000000..82a64982d --- /dev/null +++ b/example/xml/provider/tests/PactVerifyTest.php @@ -0,0 +1,66 @@ +process = new Process(['php', '-S', '127.0.0.1:7202', '-t', __DIR__ . '/../public/']); + + $this->process->start(); + $this->process->waitUntil(function (): bool { + $fp = @fsockopen('127.0.0.1', 7202); + $isOpen = is_resource($fp); + if ($isOpen) { + fclose($fp); + } + + return $isOpen; + }); + } + + /** + * Stop the web server process once complete. + */ + 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('xmlProvider') // Providers name to fetch. + ->setHost('localhost') + ->setPort(7202); + $config->getProviderState() + ->setStateChangeUrl(new Uri('http://localhost:7202/pact-change-state')) + ; + if ($level = \getenv('PACT_LOGLEVEL')) { + $config->setLogLevel($level); + } + + $verifier = new Verifier($config); + $verifier->addFile(__DIR__ . '/../../pacts/xmlConsumer-xmlProvider.json'); + + $verifyResult = $verifier->verify(); + + $this->assertTrue($verifyResult); + } +} From 7ac364b2f0f32890e5e781700d2a47bc9402cdad Mon Sep 17 00:00:00 2001 From: "tien.xuan.vo" Date: Fri, 22 Sep 2023 08:54:44 +0700 Subject: [PATCH 2/3] Use Functional Options pattern --- .../tests/Service/HttpClientServiceTest.php | 105 ++++++++++++------ .../xml/pacts/xmlConsumer-xmlProvider.json | 15 ++- example/xml/provider/public/index.php | 63 +++++------ 3 files changed, 107 insertions(+), 76 deletions(-) diff --git a/example/xml/consumer/tests/Service/HttpClientServiceTest.php b/example/xml/consumer/tests/Service/HttpClientServiceTest.php index 8e33abf97..853eb11e6 100644 --- a/example/xml/consumer/tests/Service/HttpClientServiceTest.php +++ b/example/xml/consumer/tests/Service/HttpClientServiceTest.php @@ -23,43 +23,74 @@ public function testGetMovies() $xmlBuilder = new XmlBuilder('1.0', 'UTF-8'); $xmlBuilder - ->start('movies') - ->eachLike('movie') - ->start('title') - ->contentLike('PHP: Behind the Parser') - ->end() - ->start('characters') - ->eachLike('character', [], new Options(examples: 2)) - ->start('name') - ->contentLike('Ms. Coder') - ->end() - ->start('actor') - ->contentLike('Onlivia Actora') - ->end() - ->end() - ->end() - ->start('plot') - ->contentLike( - <<end() - ->start('great-lines') - ->eachLike('line') - ->contentLike('PHP solves all my web problems') - ->end() - ->end() - ->start('rating', ['type' => 'thumbs']) - ->contentLike(7) - ->end() - ->start('rating', ['type' => 'stars']) - ->contentLike(5) - ->end() - ->end() - ->end(); + ->root( + $xmlBuilder->name('movies'), + $xmlBuilder->add( + $xmlBuilder->eachLike(), + $xmlBuilder->name('movie'), + $xmlBuilder->add( + $xmlBuilder->name('title'), + $xmlBuilder->text( + $xmlBuilder->contentLike('PHP: Behind the Parser'), + ), + ), + $xmlBuilder->add( + $xmlBuilder->name('characters'), + $xmlBuilder->add( + $xmlBuilder->eachLike(examples: 2), + $xmlBuilder->name('character'), + $xmlBuilder->add( + $xmlBuilder->name('name'), + $xmlBuilder->text( + $xmlBuilder->contentLike('Ms. Coder'), + ), + ), + $xmlBuilder->add( + $xmlBuilder->name('actor'), + $xmlBuilder->text( + $xmlBuilder->contentLike('Onlivia Actora'), + ), + ), + ), + ), + $xmlBuilder->add( + $xmlBuilder->name('plot'), + $xmlBuilder->text( + $xmlBuilder->contentLike( + <<add( + $xmlBuilder->name('great-lines'), + $xmlBuilder->add( + $xmlBuilder->eachLike(), + $xmlBuilder->name('line'), + $xmlBuilder->text( + $xmlBuilder->contentLike('PHP solves all my web problems'), + ), + ), + ), + $xmlBuilder->add( + $xmlBuilder->name('rating'), + $xmlBuilder->attribute('type', 'thumbs'), + $xmlBuilder->text( + $xmlBuilder->contentLike(7), + ), + ), + $xmlBuilder->add( + $xmlBuilder->name('rating'), + $xmlBuilder->attribute('type', 'stars'), + $xmlBuilder->text( + $xmlBuilder->contentLike(5), + ), + ), + ), + ); $response = new ProviderResponse(); $response diff --git a/example/xml/pacts/xmlConsumer-xmlProvider.json b/example/xml/pacts/xmlConsumer-xmlProvider.json index 8ead9538c..a8e4a8e97 100644 --- a/example/xml/pacts/xmlConsumer-xmlProvider.json +++ b/example/xml/pacts/xmlConsumer-xmlProvider.json @@ -28,7 +28,8 @@ "combine": "AND", "matchers": [ { - "match": "type" + "match": "type", + "min": 1 } ] }, @@ -36,7 +37,8 @@ "combine": "AND", "matchers": [ { - "match": "type" + "match": "type", + "min": 1 } ] }, @@ -60,7 +62,8 @@ "combine": "AND", "matchers": [ { - "match": "type" + "match": "type", + "min": 1 } ] }, @@ -108,9 +111,9 @@ ], "metadata": { "pactRust": { - "ffi": "0.4.7", - "mockserver": "1.2.3", - "models": "1.1.9" + "ffi": "0.4.8", + "mockserver": "1.2.4", + "models": "1.1.11" }, "pactSpecification": { "version": "3.0.0" diff --git a/example/xml/provider/public/index.php b/example/xml/provider/public/index.php index 458ec3e1b..c48aec963 100644 --- a/example/xml/provider/public/index.php +++ b/example/xml/provider/public/index.php @@ -1,47 +1,44 @@ createXMLArray() - ->start('movies') - ->start('movie') - ->add('title', 'PHP: Behind the Parser') - ->start('characters') - ->start('character') - ->add('name', 'Ms. Coder') - ->add('actor', 'Onlivia Actora') - ->end() - ->start('character') - ->add('name', 'Mr. Coder') - ->add('actor', 'El ActÓr') - ->end() - ->end() - ->add('plot', <<get('/movies', function (Request $request, Response $response) { + $response->getBody()->write( + << + + + PHP: Behind the Parser + + + Ms. Coder + Onlivia Actora + + + Mr. Coder + El ActÓr + + + So, this language. It's like, a programming language. Or is it a scripting language? All is revealed in this thrilling horror spoof of a documentary. - PLOT) - ->start('great-lines') - ->add('line', 'PHP solves all my web problems') - ->end() - ->add('rating', 7, ['type' => 'thumbs']) - ->add('rating', 5, ['type' => 'stars']) - ->end() - ->end(); - -$app = AppFactory::create(); - -$app->get('/movies', function (Request $request, Response $response) use ($xmlBuilder) { - $response->getBody()->write($xmlBuilder->getXml()); + + + PHP solves all my web problems + + 7 + 5 + + + XML + ); return $response->withHeader('Content-Type', 'text/xml'); }); From fc01b6b0291c693215388e5dcab5cc20cabc9e14 Mon Sep 17 00:00:00 2001 From: Yousaf Nabi Date: Thu, 12 Oct 2023 16:56:44 +0100 Subject: [PATCH 3/3] chore: missing comma in gh merge --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e703fc0dc..8a329e551 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ "php-amqplib/php-amqplib": "^3.0", "phpstan/phpstan": "^1.9", "phpunit/phpunit": ">=8.5.23 <10", - "tienvx/pact-php-xml": "dev-main" + "tienvx/pact-php-xml": "dev-main", "guzzlehttp/guzzle": "^7.8" }, "autoload": {