diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 7697056b..b6cd146b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -63,7 +63,7 @@ jobs:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
- extensions: openssl, sockets, curl, zip
+ extensions: openssl, sockets, curl, zip, ffi
php-version: ${{ matrix.php }}
- name: Composer install
diff --git a/README.md b/README.md
index accc88dd..3fb015bd 100644
--- a/README.md
+++ b/README.md
@@ -11,31 +11,39 @@ PHP version of [Pact](https://pact.io). Enables consumer driven contract testing
Table of contents
=================
-* [Versions](#versions)
-* [Specifications](#specifications)
-* [Installation](#installation)
-* [Basic Consumer Usage](#basic-consumer-usage)
- * [Start and Stop the Mock Server](#start-and-stop-the-mock-server)
- * [Create Consumer Unit Test](#create-consumer-unit-test)
- * [Create Mock Request](#create-mock-request)
- * [Create Mock Response](#create-mock-response)
- * [Build the Interaction](#build-the-interaction)
- * [Make the Request](#make-the-request)
- * [Make Assertions](#make-assertions)
-* [Basic Provider Usage](#basic-provider-usage)
- * [Create Unit Tests](#create-unit-test)
- * [Start API](#start-api)
- * [Provider Verification](#provider-verification)
- * [Verify From Pact Broker](#verify-from-pact-broker)
- * [Verify All from Pact Broker](#verify-all-from-pact-broker)
- * [Verify Files by Path](#verify-files-by-path)
-* [Tips](#tips)
- * [Starting API Asynchronously](#starting-api-asynchronously)
- * [Set Up Provider State](#set-up-provider-state)
- * [Examples](#additional-examples)
+- [Pact PHP](#pact-php)
+- [Table of contents](#table-of-contents)
+ - [Versions](#versions)
+ - [Specifications](#specifications)
+ - [Installation](#installation)
+ - [Basic Consumer Usage](#basic-consumer-usage)
+ - [Publish Contracts To Pact Broker](#publish-contracts-to-pact-broker)
+ - [Create Consumer Unit Test](#create-consumer-unit-test)
+ - [Create Mock Request](#create-mock-request)
+ - [Create Mock Response](#create-mock-response)
+ - [Build the Interaction](#build-the-interaction)
+ - [Start the Mock Server](#start-the-mock-server)
+ - [Make the Request](#make-the-request)
+ - [Verify Interactions](#verify-interactions)
+ - [Make Assertions](#make-assertions)
+ - [Basic Provider Usage](#basic-provider-usage)
+ - [Create Unit Test](#create-unit-test)
+ - [Start API](#start-api)
+ - [Provider Verification](#provider-verification)
+ - [Verify From Pact Broker](#verify-from-pact-broker)
+ - [Verify All from Pact Broker](#verify-all-from-pact-broker)
+ - [Verify Files by Path](#verify-files-by-path)
+ - [Tips](#tips)
+ - [Starting API Asynchronously](#starting-api-asynchronously)
+ - [Set Up Provider State](#set-up-provider-state)
+ - [Additional Examples](#additional-examples)
+ - [Message support](#message-support)
+ - [Consumer Side Message Processing](#consumer-side-message-processing)
+ - [Provider Side Message Validation](#provider-side-message-validation)
+ - [Usage for the optional `pact-stub-service`](#usage-for-the-optional-pact-stub-service)
## Versions
-9.X updates internal dependencies and libraries. This results in dropping PHP 7.4
+9.X adds support for pact specification 3.X & 4.X via Pact FFI. This results in dropping PHP 7.4
8.X updates internal dependencies and libraries. This results in dropping PHP 7.3
@@ -52,7 +60,13 @@ If you wish to stick with the 2.X implementation, you can continue to pull from
## Specifications
-The 3.X version is the version of Pact-PHP, not the pact specification version that it supports. Pact-Php 3.X supports [Pact-Specification 2.X](https://github.com/pact-foundation/pact-specification/tree/version-2).
+The 3.X version is the version of Pact-PHP, not the pact specification version that it supports.
+
+Pact-Php 3.X -> 8.X supports [Pact-Specification 2.X](https://github.com/pact-foundation/pact-specification/tree/version-2).
+Pact-Php 9.X supports:
+ * [Pact-Specification 2.X](https://github.com/pact-foundation/pact-specification/tree/version-2)
+ * [Pact-Specification 3.X](https://github.com/pact-foundation/pact-specification/tree/version-3).
+ * [Pact-Specification 4.X](https://github.com/pact-foundation/pact-specification/tree/version-4).
## Installation
@@ -68,39 +82,12 @@ Composer hosts older versions under `mattersight/phppact`, which is abandoned. P
All of the following code will be used exclusively for the Consumer.
-### Start and Stop the Mock Server
+### Publish Contracts To Pact Broker
-This library contains a wrapper for the [Ruby Standalone Mock Service](https://github.com/pact-foundation/pact-mock_service).
+When all tests in test suite are passed, you may want to publish generated contract files to pact broker automatically.
The easiest way to configure this is to use a [PHPUnit Listener](https://phpunit.de/manual/current/en/appendixes.configuration.html#appendixes.configuration.test-listeners). A default listener is included in this project, see [PactTestListener.php](/src/PhpPact/Consumer/Listener/PactTestListener.php). This utilizes environmental variables for configurations. These env variables can either be added to the system or to the phpunit.xml configuration file. Here is an example [phpunit.xml](/example/phpunit.consumer.xml) file configured to use the default. Keep in mind that both the test suite and the arguments array must be the same value.
-Alternatively, you can start and stop as in whatever means you would like by following this example:
-
-```php
-setHost('localhost');
- $config->setPort(7200);
- $config->setConsumer('someConsumer');
- $config->setProvider('someProvider');
- $config->setCors(true);
-
- // Instantiate the mock server object with the config. This can be any
- // instance of MockServerConfigInterface.
- $server = new MockServer($config);
-
- // Create the process.
- $server->start();
-
- // Stop the process.
- $server->stop();
-```
-
### Create Consumer Unit Test
Create a standard PHPUnit test case class and function.
@@ -191,6 +178,14 @@ $builder
->willRespondWith($response); // This has to be last. This is what makes an API request to the Mock Server to set the interaction.
```
+### Start the Mock Server
+
+Mock server need to be started manually
+
+```php
+$builder->createMockServer();
+```
+
### Make the Request
```php
@@ -204,7 +199,7 @@ Verify that all interactions took place that were registered.
This typically should be in each test, that way the test that failed to verify is marked correctly.
```php
-$builder->verify();
+$this->assertTrue($builder->verify());
```
### Make Assertions
diff --git a/UPGRADE-9.0.md b/UPGRADE-9.0.md
new file mode 100644
index 00000000..53672228
--- /dev/null
+++ b/UPGRADE-9.0.md
@@ -0,0 +1,25 @@
+UPGRADE FROM 8.x to 9.0
+=======================
+
+* Interaction Builder
+ * It's now required to call `PhpPact\Consumer\InteractionBuilder::createMockServer` manually
+
+ Example Usage:
+ ```php
+ $builder = new InteractionBuilder($config);
+ $builder
+ ->given('a person exists')
+ ->uponReceiving('a get request to /hello/{name}')
+ ->with($request)
+ ->willRespondWith($response);
+ $builder->createMockServer();
+
+ $apiClient->sendRequest();
+
+ $this->assertTrue($builder->verify());
+ ```
+
+ * These environment variables can be removed:
+ * PACT_CORS
+ * PACT_MOCK_SERVER_HEALTH_CHECK_TIMEOUT
+ * PACT_MOCK_SERVER_HEALTH_CHECK_RETRY_SEC
diff --git a/composer.json b/composer.json
index 6f3aeae7..cfef1684 100644
--- a/composer.json
+++ b/composer.json
@@ -71,7 +71,7 @@
},
"scripts": {
"start-provider": "php -S localhost:58000 -t example/src/Provider/public/",
- "static-code-analysis": "phpstan analyse src/ --level=5",
+ "static-code-analysis": "phpstan analyse src/ --level=5 -c phpstan.neon",
"lint": "php-cs-fixer fix --config .php-cs-fixer.php --dry-run",
"fix": "php-cs-fixer fix --config .php-cs-fixer.php",
"test": "phpunit --debug -c example/phpunit.all.xml"
@@ -87,6 +87,22 @@
},
"url": "https://github.com/pact-foundation/pact-ruby-standalone/releases/download/v{$version}/pact-{$version}-{$os}{$architecture}.{$extension}",
"path": "bin/pact-ruby-standalone"
+ },
+ "pact-ffi-headers": {
+ "version": "0.4.1",
+ "url": "https://github.com/pact-foundation/pact-reference/releases/download/libpact_ffi-v{$version}/pact.h",
+ "path": "bin/pact-ffi-headers/pact.h"
+ },
+ "pact-ffi-lib": {
+ "version": "0.4.1",
+ "variables": {
+ "{$prefix}": "PHP_OS_FAMILY === 'Windows' ? 'pact_ffi' : 'libpact_ffi'",
+ "{$os}": "PHP_OS === 'Darwin' ? 'osx' : strtolower(PHP_OS_FAMILY)",
+ "{$architecture}": "in_array(php_uname('m'), ['arm64', 'aarch64']) ? (PHP_OS === 'Darwin' ? 'aarch64-apple-darwin' : 'aarch64') : 'x86_64'",
+ "{$extension}": "PHP_OS_FAMILY === 'Windows' ? 'dll' : (PHP_OS === 'Darwin' ? 'dylib' : 'so')"
+ },
+ "url": "https://github.com/pact-foundation/pact-reference/releases/download/libpact_ffi-v{$version}/{$prefix}-{$os}-{$architecture}.{$extension}.gz",
+ "path": "bin/pact-ffi-lib/pact.{$extension}"
}
}
},
diff --git a/example/phpunit.all.xml b/example/phpunit.all.xml
index 554c8a46..02a047d5 100644
--- a/example/phpunit.all.xml
+++ b/example/phpunit.all.xml
@@ -36,7 +36,5 @@
-
-
diff --git a/example/phpunit.consumer.xml b/example/phpunit.consumer.xml
index 6e88b251..0e521db3 100644
--- a/example/phpunit.consumer.xml
+++ b/example/phpunit.consumer.xml
@@ -24,7 +24,6 @@
-
diff --git a/example/phpunit.core.xml b/example/phpunit.core.xml
index aefb2d26..57e6e2e4 100644
--- a/example/phpunit.core.xml
+++ b/example/phpunit.core.xml
@@ -24,7 +24,5 @@
-
-
diff --git a/example/src/Consumer/Service/HttpClientService.php b/example/src/Consumer/Service/HttpClientService.php
index 668ba75b..3ae6ad9d 100644
--- a/example/src/Consumer/Service/HttpClientService.php
+++ b/example/src/Consumer/Service/HttpClientService.php
@@ -12,10 +12,10 @@
class HttpClientService
{
/** @var Client */
- private $httpClient;
+ private Client $httpClient;
/** @var string */
- private $baseUri;
+ private string $baseUri;
public function __construct(string $baseUri)
{
diff --git a/example/tests/Consumer/Service/ConsumerServiceGoodbyeTest.php b/example/tests/Consumer/Service/ConsumerServiceGoodbyeTest.php
index e5106f55..bc840bb2 100644
--- a/example/tests/Consumer/Service/ConsumerServiceGoodbyeTest.php
+++ b/example/tests/Consumer/Service/ConsumerServiceGoodbyeTest.php
@@ -37,11 +37,12 @@ public function testGetGoodbyeString()
->uponReceiving('A get request to /goodbye/{name}')
->with($request)
->willRespondWith($response);
+ $builder->createMockServer();
$service = new HttpClientService($config->getBaseUri());
$result = $service->getGoodbyeString('Bob');
- $builder->verify();
+ $this->assertTrue($builder->verify());
$this->assertEquals('Goodbye, Bob', $result);
}
diff --git a/example/tests/Consumer/Service/ConsumerServiceHelloTest.php b/example/tests/Consumer/Service/ConsumerServiceHelloTest.php
index 2a80f394..d23df42c 100644
--- a/example/tests/Consumer/Service/ConsumerServiceHelloTest.php
+++ b/example/tests/Consumer/Service/ConsumerServiceHelloTest.php
@@ -33,7 +33,7 @@ public function testGetHelloString()
->setStatus(200)
->addHeader('Content-Type', 'application/json')
->setBody([
- 'message' => $matcher->term('Hello, Bob', '(Hello, )[A-Za-z]')
+ 'message' => $matcher->term('Hello, Bob', '(Hello, )[A-Za-z]+')
]);
// Create a configuration that reflects the server that was started. You can create a custom MockServerConfigInterface if needed.
@@ -42,12 +42,13 @@ public function testGetHelloString()
$builder
->uponReceiving('A get request to /hello/{name}')
->with($request)
- ->willRespondWith($response); // This has to be last. This is what makes an API request to the Mock Server to set the interaction.
+ ->willRespondWith($response); // This has to be last. This is what makes a FFI call to the Mock Server to set the interaction.
+ $builder->createMockServer();
$service = new HttpClientService($config->getBaseUri()); // Pass in the URL to the Mock Server.
$result = $service->getHelloString('Bob'); // Make the real API request against the Mock Server.
- $builder->verify(); // This will verify that the interactions took place.
+ $this->assertTrue($builder->verify()); // This will verify that the interactions took place.
$this->assertEquals('Hello, Bob', $result); // Make your assertions.
}
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 00000000..e0f2f0e8
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,3 @@
+parameters:
+ excludePaths:
+ - src/PhpPact/Consumer/Model/Pact.php
diff --git a/phpunit.xml b/phpunit.xml
index 35d425c2..af9ebf68 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -26,6 +26,5 @@
-
diff --git a/src/PhpPact/Consumer/BuilderInterface.php b/src/PhpPact/Consumer/BuilderInterface.php
index 0b58c219..406acd26 100644
--- a/src/PhpPact/Consumer/BuilderInterface.php
+++ b/src/PhpPact/Consumer/BuilderInterface.php
@@ -12,11 +12,4 @@ interface BuilderInterface
* Verify that the interactions are valid.
*/
public function verify(): bool;
-
- /**
- * Write the Pact without deleting the interactions.
- *
- * @return bool
- */
- public function writePact(): bool;
}
diff --git a/src/PhpPact/Consumer/Exception/InteractionRequestBodyNotAddedException.php b/src/PhpPact/Consumer/Exception/InteractionRequestBodyNotAddedException.php
new file mode 100644
index 00000000..2f99fd3e
--- /dev/null
+++ b/src/PhpPact/Consumer/Exception/InteractionRequestBodyNotAddedException.php
@@ -0,0 +1,12 @@
+mockServerConfig = new MockServerEnvConfig();
- }
-
- /**
- * @throws AssertionFailedError
- * @throws RuntimeException
- */
- public function executeAfterLastTest(): void
- {
- try {
- $this->getMockServerService()->verifyInteractions();
- } catch (Exception $e) {
- throw new AssertionFailedError('Pact interaction verification failed', 0, $e);
- }
-
- try {
- \file_put_contents($this->getPactFilename(), $this->getPactJson());
- } catch (Exception $e) {
- throw new RuntimeException('Pact contract generation failed', 0, $e);
- }
- }
-
- private function getMockServerService(): MockServerHttpService
- {
- return new MockServerHttpService(
- $this->getClient(),
- $this->mockServerConfig
- );
- }
-
- private function getClient(): ClientInterface
- {
- if (!$this->client) {
- $this->client = new GuzzleClient();
- }
-
- return $this->client;
- }
-
- private function getPactFilename(): string
- {
- return $this->mockServerConfig->getPactDir()
- . DIRECTORY_SEPARATOR
- . $this->mockServerConfig->getConsumer()
- . '-'
- . $this->mockServerConfig->getProvider() . '.json';
- }
-
- private function getPactJson(): string
- {
- $uri = $this->mockServerConfig->getBaseUri()->withPath('/pact');
- $response = $this->getClient()->post(
- $uri,
- [
- 'headers' => [
- 'Content-Type' => 'application/json',
- 'X-Pact-Mock-Service' => true,
- ],
- 'body' => \json_encode([
- 'consumer' => ['name' => $this->mockServerConfig->getConsumer()],
- 'provider' => ['name' => $this->mockServerConfig->getProvider()]
- ])
- ]
- );
-
- return \json_encode(\json_decode($response->getBody()->getContents()));
- }
-}
diff --git a/src/PhpPact/Consumer/InteractionBuilder.php b/src/PhpPact/Consumer/InteractionBuilder.php
index 93ec41d6..55affa48 100644
--- a/src/PhpPact/Consumer/InteractionBuilder.php
+++ b/src/PhpPact/Consumer/InteractionBuilder.php
@@ -4,10 +4,9 @@
use PhpPact\Consumer\Model\ConsumerRequest;
use PhpPact\Consumer\Model\Interaction;
+use PhpPact\Consumer\Model\Pact;
use PhpPact\Consumer\Model\ProviderResponse;
-use PhpPact\Http\GuzzleClient;
use PhpPact\Standalone\MockService\MockServerConfigInterface;
-use PhpPact\Standalone\MockService\Service\MockServerHttpService;
/**
* Build an interaction and send it to the Ruby Standalone Mock Service
@@ -15,13 +14,11 @@
*/
class InteractionBuilder implements BuilderInterface
{
- /** @var MockServerHttpService */
- protected $mockServerHttpService;
-
- /** @var MockServerConfigInterface */
- protected $config;
/** @var Interaction */
- private $interaction;
+ protected Interaction $interaction;
+
+ /** @var Pact */
+ protected Pact $pact;
/**
* InteractionBuilder constructor.
@@ -30,9 +27,8 @@ class InteractionBuilder implements BuilderInterface
*/
public function __construct(MockServerConfigInterface $config)
{
- $this->config = $config;
- $this->mockServerHttpService = new MockServerHttpService(new GuzzleClient(), $config);
$this->interaction = new Interaction();
+ $this->pact = new Pact($config);
}
/**
@@ -72,8 +68,6 @@ public function with(ConsumerRequest $request): self
}
/**
- * Make the http request to the Mock Service to register the interaction.
- *
* @param ProviderResponse $response mock of response received
*
* @return bool returns true on success
@@ -82,7 +76,7 @@ public function willRespondWith(ProviderResponse $response): bool
{
$this->interaction->setResponse($response);
- return $this->mockServerHttpService->registerInteraction($this->interaction);
+ return $this->pact->registerInteraction($this->interaction);
}
/**
@@ -90,31 +84,14 @@ public function willRespondWith(ProviderResponse $response): bool
*/
public function verify(): bool
{
- return $this->mockServerHttpService->verifyInteractions();
- }
-
- /**
- * Writes the file to disk and deletes interactions from mock server.
- */
- public function finalize(): bool
- {
- // Write the pact file to disk.
- $this->mockServerHttpService->getPactJson();
-
- // Delete the interactions.
- $this->mockServerHttpService->deleteAllInteractions();
-
- return true;
+ return $this->pact->verifyInteractions();
}
/**
- * {@inheritdoc}
+ * Create mock server before verifying.
*/
- public function writePact(): bool
+ public function createMockServer(): void
{
- // Write the pact file to disk.
- $this->mockServerHttpService->getPactJson();
-
- return true;
+ $this->pact->createMockServer();
}
}
diff --git a/src/PhpPact/Consumer/Listener/PactTestListener.php b/src/PhpPact/Consumer/Listener/PactTestListener.php
index 5d88ef18..ba0a20d2 100644
--- a/src/PhpPact/Consumer/Listener/PactTestListener.php
+++ b/src/PhpPact/Consumer/Listener/PactTestListener.php
@@ -3,12 +3,10 @@
namespace PhpPact\Consumer\Listener;
use GuzzleHttp\Psr7\Uri;
-use PhpPact\Broker\Service\BrokerHttpClient;
-use PhpPact\Http\GuzzleClient;
use PhpPact\Standalone\Exception\MissingEnvVariableException;
-use PhpPact\Standalone\MockService\MockServer;
+use PhpPact\Standalone\Broker\Broker;
+use PhpPact\Standalone\Broker\BrokerConfig;
use PhpPact\Standalone\MockService\MockServerEnvConfig;
-use PhpPact\Standalone\MockService\Service\MockServerHttpService;
use PHPUnit\Framework\AssertionFailedError;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestListener;
@@ -18,26 +16,25 @@
/**
* PACT listener that can be used with environment variables and easily attached to PHPUnit configuration.
* Class PactTestListener
+ *
+ * @internal
*/
class PactTestListener implements TestListener
{
use TestListenerDefaultImplementation;
- /** @var MockServer */
- private $server;
-
/**
* Name of the test suite configured in your phpunit config.
*
* @var string[]
*/
- private $testSuiteNames;
+ private array $testSuiteNames;
/** @var MockServerEnvConfig */
- private $mockServerConfig;
+ private MockServerEnvConfig $mockServerConfig;
/** @var bool */
- private $failed;
+ private bool $failed = false;
/**
* PactTestListener constructor.
@@ -52,19 +49,6 @@ public function __construct(array $testSuiteNames)
$this->mockServerConfig = new MockServerEnvConfig();
}
- /**
- * @param TestSuite $suite
- *
- * @throws \Exception
- */
- public function startTestSuite(TestSuite $suite): void
- {
- if (\in_array($suite->getName(), $this->testSuiteNames)) {
- $this->server = new MockServer($this->mockServerConfig);
- $this->server->start();
- }
- }
-
public function addError(Test $test, \Throwable $t, float $time): void
{
$this->failed = true;
@@ -83,47 +67,39 @@ public function addFailure(Test $test, AssertionFailedError $e, float $time): vo
public function endTestSuite(TestSuite $suite): void
{
if (\in_array($suite->getName(), $this->testSuiteNames)) {
- try {
- $httpService = new MockServerHttpService(new GuzzleClient(), $this->mockServerConfig);
- $httpService->verifyInteractions();
-
- $json = $httpService->getPactJson();
- } finally {
- $this->server->stop();
- }
-
if ($this->failed === true) {
print 'A unit test has failed. Skipping PACT file upload.';
} elseif (!($pactBrokerUri = \getenv('PACT_BROKER_URI'))) {
print 'PACT_BROKER_URI environment variable was not set. Skipping PACT file upload.';
} elseif (!($consumerVersion = \getenv('PACT_CONSUMER_VERSION'))) {
print 'PACT_CONSUMER_VERSION environment variable was not set. Skipping PACT file upload.';
- } elseif (!($tag = \getenv('PACT_CONSUMER_TAG'))) {
- print 'PACT_CONSUMER_TAG environment variable was not set. Skipping PACT file upload.';
} else {
- $clientConfig = [];
+ $brokerConfig = new BrokerConfig();
+ $brokerConfig->setPacticipant($this->mockServerConfig->getConsumer());
+ $brokerConfig->setPactLocations($this->mockServerConfig->getPactDir());
+ $brokerConfig->setBrokerUri(new Uri($pactBrokerUri));
+ $brokerConfig->setConsumerVersion($consumerVersion);
+ if ($tag = \getenv('PACT_CONSUMER_TAG')) {
+ $brokerConfig->setTag($tag);
+ }
+
if (($user = \getenv('PACT_BROKER_HTTP_AUTH_USER')) &&
($pass = \getenv('PACT_BROKER_HTTP_AUTH_PASS'))
) {
- $clientConfig = [
- 'auth' => [$user, $pass],
- ];
- }
-
- if (($sslVerify = \getenv('PACT_BROKER_SSL_VERIFY'))) {
- $clientConfig['verify'] = $sslVerify !== 'no';
+ $brokerConfig->setBrokerUsername($user);
+ $brokerConfig->setBrokerPassword($pass);
}
- $headers = [];
if ($bearerToken = \getenv('PACT_BROKER_BEARER_TOKEN')) {
- $headers['Authorization'] = 'Bearer ' . $bearerToken;
+ $brokerConfig->setBrokerToken($bearerToken);
}
- $client = new GuzzleClient($clientConfig);
+ if ($branch = \getenv('PACT_CONSUMER_BRANCH')) {
+ $brokerConfig->setBranch($branch);
+ }
- $brokerHttpService = new BrokerHttpClient($client, new Uri($pactBrokerUri), $headers);
- $brokerHttpService->tag($this->mockServerConfig->getConsumer(), $consumerVersion, $tag);
- $brokerHttpService->publishJson($consumerVersion, $json);
+ $broker = new Broker($brokerConfig);
+ $broker->publish();
print 'Pact file has been uploaded to the Broker successfully.';
}
}
diff --git a/src/PhpPact/Consumer/Matcher/Matcher.php b/src/PhpPact/Consumer/Matcher/Matcher.php
index 3317c3d5..e8e9cf42 100644
--- a/src/PhpPact/Consumer/Matcher/Matcher.php
+++ b/src/PhpPact/Consumer/Matcher/Matcher.php
@@ -3,7 +3,9 @@
namespace PhpPact\Consumer\Matcher;
/**
- * Matcher implementation. Builds the Ruby Mock Server specification json for interaction publishing.
+ * Matcher implementation. Builds the Pact FFI specification json for interaction publishing.
+ * @see https://docs.pact.io/implementation_guides/rust/pact_ffi/integrationjson
+ *
* Class Matcher.
*/
class Matcher
@@ -46,8 +48,8 @@ public function like($value): array
}
return [
- 'contents' => $value,
- 'json_class' => 'Pact::SomethingLike',
+ 'value' => $value,
+ 'pact:matcher:type' => 'type',
];
}
@@ -61,14 +63,11 @@ public function like($value): array
*/
public function eachLike($value, int $min = 1): array
{
- $result = [
- 'contents' => $value,
- 'json_class' => 'Pact::ArrayLike',
+ return [
+ 'value' => array_fill(0, $min, $value),
+ 'pact:matcher:type' => 'type',
+ 'min' => $min,
];
-
- $result['min'] = $min;
-
- return $result;
}
/**
@@ -92,15 +91,9 @@ public function term($value, string $pattern): array
}
return [
- 'data' => [
- 'generate' => $value,
- 'matcher' => [
- 'json_class' => 'Regexp',
- 'o' => 0,
- 's' => $pattern,
- ],
- ],
- 'json_class' => 'Pact::Term',
+ 'value' => $value,
+ 'regex' => $pattern,
+ 'pact:matcher:type' => 'regex',
];
}
@@ -114,7 +107,7 @@ public function term($value, string $pattern): array
*
* @return array
*/
- public function regex($value, string $pattern)
+ public function regex($value, string $pattern): array
{
return $this->term($value, $pattern);
}
diff --git a/src/PhpPact/Consumer/Model/AbstractPact.php b/src/PhpPact/Consumer/Model/AbstractPact.php
new file mode 100644
index 00000000..a8abca50
--- /dev/null
+++ b/src/PhpPact/Consumer/Model/AbstractPact.php
@@ -0,0 +1,20 @@
+ffi = FFI::cdef(\file_get_contents(Scripts::getHeader()), Scripts::getLibrary());
+ }
+}
diff --git a/src/PhpPact/Consumer/Model/ConsumerRequest.php b/src/PhpPact/Consumer/Model/ConsumerRequest.php
index b54ce104..f0561145 100644
--- a/src/PhpPact/Consumer/Model/ConsumerRequest.php
+++ b/src/PhpPact/Consumer/Model/ConsumerRequest.php
@@ -11,27 +11,27 @@ class ConsumerRequest implements \JsonSerializable
/**
* @var string
*/
- private $method;
+ private string $method;
/**
- * @var array|string
+ * @var string
*/
- private $path;
+ private string $path;
/**
* @var string[]
*/
- private $headers;
+ private array $headers = [];
/**
- * @var mixed
+ * @var null|string
*/
- private $body;
+ private ?string $body = null;
/**
- * @var string
+ * @var array
*/
- private $query;
+ private array $query = [];
/**
* @return string
@@ -54,9 +54,9 @@ public function setMethod(string $method): self
}
/**
- * @return array|string
+ * @return string
*/
- public function getPath()
+ public function getPath(): string
{
return $this->path;
}
@@ -66,17 +66,17 @@ public function getPath()
*
* @return ConsumerRequest
*/
- public function setPath($path): self
+ public function setPath(array|string $path): self
{
- $this->path = $path;
+ $this->path = is_array($path) ? json_encode($path) : $path;
return $this;
}
/**
- * @return string[]
+ * @return array
*/
- public function getHeaders()
+ public function getHeaders(): array
{
return $this->headers;
}
@@ -88,7 +88,10 @@ public function getHeaders()
*/
public function setHeaders(array $headers): self
{
- $this->headers = $headers;
+ $this->headers = [];
+ foreach ($headers as $header => $value) {
+ $this->addHeader($header, $value);
+ }
return $this;
}
@@ -99,17 +102,17 @@ public function setHeaders(array $headers): self
*
* @return ConsumerRequest
*/
- public function addHeader(string $header, $value): self
+ public function addHeader(string $header, array|string $value): self
{
- $this->headers[$header] = $value;
+ $this->headers[$header] = is_array($value) ? $value : [$value];
return $this;
}
/**
- * @return mixed
+ * @return null|string
*/
- public function getBody()
+ public function getBody(): ?string
{
return $this->body;
}
@@ -119,46 +122,52 @@ public function getBody()
*
* @return ConsumerRequest
*/
- public function setBody($body)
+ public function setBody(mixed $body): self
{
- $this->body = $body;
+ if (\is_string($body)) {
+ $this->body = $body;
+ } elseif (!\is_null($body)) {
+ $this->body = \json_encode($body);
+ $this->addHeader('Content-Type', 'application/json');
+ } else {
+ $this->body = null;
+ }
return $this;
}
/**
- * @return null|string
+ * @return array
*/
- public function getQuery()
+ public function getQuery(): array
{
return $this->query;
}
/**
- * @param string $query
+ * @param array $query
*
* @return ConsumerRequest
*/
- public function setQuery(string $query): self
+ public function setQuery(array $query): self
{
- $this->query = $query;
+ $this->query = [];
+ foreach ($query as $key => $value) {
+ $this->addQueryParameter($key, $value);
+ }
return $this;
}
/**
- * @param string $key
- * @param string $value
+ * @param string $key
+ * @param array|string $value
*
* @return ConsumerRequest
*/
- public function addQueryParameter(string $key, string $value): self
+ public function addQueryParameter(string $key, array|string $value): self
{
- if ($this->query === null) {
- $this->query = "{$key}={$value}";
- } else {
- $this->query = "{$this->query}&{$key}={$value}";
- }
+ $this->query[$key] = is_array($value) ? $value : [$value];
return $this;
}
@@ -166,8 +175,7 @@ public function addQueryParameter(string $key, string $value): self
/**
* {@inheritdoc}
*/
- #[\ReturnTypeWillChange]
- public function jsonSerialize()
+ public function jsonSerialize(): array
{
$results = [];
diff --git a/src/PhpPact/Consumer/Model/Interaction.php b/src/PhpPact/Consumer/Model/Interaction.php
index 06577c06..e7485fea 100644
--- a/src/PhpPact/Consumer/Model/Interaction.php
+++ b/src/PhpPact/Consumer/Model/Interaction.php
@@ -8,25 +8,50 @@
*/
class Interaction implements \JsonSerializable
{
+ /**
+ * @var int
+ */
+ private int $id;
+
/**
* @var string
*/
- private $description;
+ private string $description;
/**
* @var null|string
*/
- private $providerState;
+ private ?string $providerState = null;
/**
* @var ConsumerRequest
*/
- private $request;
+ private ConsumerRequest $request;
/**
* @var ProviderResponse
*/
- private $response;
+ private ProviderResponse $response;
+
+ /**
+ * @return int
+ */
+ public function getId(): int
+ {
+ return $this->id;
+ }
+
+ /**
+ * @param int $id
+ *
+ * @return Interaction
+ */
+ public function setId(int $id): self
+ {
+ $this->id = $id;
+
+ return $this;
+ }
/**
* @return string
@@ -111,8 +136,7 @@ public function setResponse(ProviderResponse $response): self
/**
* {@inheritdoc}
*/
- #[\ReturnTypeWillChange]
- public function jsonSerialize()
+ public function jsonSerialize(): array
{
if ($this->getProviderState()) {
return [
diff --git a/src/PhpPact/Consumer/Model/Pact.php b/src/PhpPact/Consumer/Model/Pact.php
new file mode 100644
index 00000000..997eee43
--- /dev/null
+++ b/src/PhpPact/Consumer/Model/Pact.php
@@ -0,0 +1,189 @@
+initWithLogLevel()
+ ->newPact()
+ ->withSpecification();
+ }
+
+ public function createMockServer(): void
+ {
+ $port = $this->ffi->pactffi_create_mock_server_for_transport(
+ $this->id,
+ $this->config->getHost(),
+ $this->config->getPort(),
+ $this->config->isSecure() ? 'https' : 'http',
+ null
+ );
+
+ if ($port < 0) {
+ $message = match ($port) {
+ -1 => 'An invalid handle was received. Handles should be created with `pactffi_new_pact`',
+ -2 => 'Transport_config is not valid JSON',
+ -3 => 'The mock server could not be started',
+ -4 => 'The method panicked',
+ -5 => 'The address is not valid',
+ };
+ throw new MockServerNotStartedException($message);
+ }
+ $this->config->setPort($port);
+ }
+
+ public function verifyInteractions(): bool
+ {
+ $result = $this->ffi->pactffi_mock_server_matched($this->config->getPort());
+
+ if ($result) {
+ $error = $this->ffi->pactffi_write_pact_file(
+ $this->config->getPort(),
+ $this->config->getPactDir(),
+ $this->config->getPactFileWriteMode() === PactConfigInterface::MODE_OVERWRITE
+ );
+ if ($error) {
+ $message = match ($error) {
+ 1 => 'A general panic was caught',
+ 2 => 'The pact file was not able to be written',
+ 3 => 'A mock server with the provided port was not found',
+ };
+ throw new PactFileNotWroteException($message);
+ }
+ }
+
+ $this->ffi->pactffi_cleanup_mock_server($this->config->getPort());
+ $this->ffi->pactffi_free_pact_handle($this->id);
+
+ return $result;
+ }
+
+ public function registerInteraction(Interaction $interaction): bool
+ {
+ $this
+ ->newInteraction($interaction)
+ ->given($interaction)
+ ->uponReceiving($interaction)
+ ->with($interaction)
+ ->willRespondWith($interaction);
+
+ return true;
+ }
+
+ private function initWithLogLevel(): self
+ {
+ $logLevel = $this->config->getLogLevel();
+ if ($logLevel) {
+ $this->ffi->pactffi_init_with_log_level($logLevel);
+ }
+
+ return $this;
+ }
+
+ private function newPact(): self
+ {
+ $this->id = $this->ffi->pactffi_new_pact($this->config->getConsumer(), $this->config->getProvider());
+
+ return $this;
+ }
+
+ private function withSpecification(): self
+ {
+ $supportedVersions = [
+ '1.0.0' => $this->ffi->PactSpecification_V1,
+ '1.1.0' => $this->ffi->PactSpecification_V1_1,
+ '2.0.0' => $this->ffi->PactSpecification_V2,
+ '3.0.0' => $this->ffi->PactSpecification_V3,
+ '4.0.0' => $this->ffi->PactSpecification_V4,
+ ];
+ $version = $supportedVersions[$this->config->getPactSpecificationVersion()] ?? $this->ffi->PactSpecification_Unknown;
+ $this->ffi->pactffi_with_specification($this->id, $version);
+
+ return $this;
+ }
+
+ private function newInteraction(Interaction $interaction): self
+ {
+ $id = $this->ffi->pactffi_new_interaction($this->id, $interaction->getDescription());
+ $interaction->setId($id);
+
+ return $this;
+ }
+
+ private function given(Interaction $interaction): self
+ {
+ $this->ffi->pactffi_given($interaction->getId(), $interaction->getProviderState());
+
+ return $this;
+ }
+
+ private function uponReceiving(Interaction $interaction): self
+ {
+ $this->ffi->pactffi_upon_receiving($interaction->getId(), $interaction->getDescription());
+
+ return $this;
+ }
+
+ private function with(Interaction $interaction): self
+ {
+ $id = $interaction->getId();
+ $request = $interaction->getRequest();
+ $this->ffi->pactffi_with_request($id, $request->getMethod(), $request->getPath());
+ foreach ($request->getHeaders() as $header => $values) {
+ foreach (array_values($values) as $index => $value) {
+ $this->ffi->pactffi_with_header_v2($id, $this->ffi->InteractionPart_Request, $header, $index, $value);
+ }
+ }
+ foreach ($request->getQuery() as $key => $values) {
+ foreach (array_values($values) as $index => $value) {
+ $this->ffi->pactffi_with_query_parameter_v2($id, $key, $index, $value);
+ }
+ }
+ if (!\is_null($request->getBody())) {
+ $success = $this->ffi->pactffi_with_body($id, $this->ffi->InteractionPart_Request, null, $request->getBody());
+ if (!$success) {
+ throw new InteractionRequestBodyNotAddedException();
+ }
+ }
+
+ return $this;
+ }
+
+ private function willRespondWith(Interaction $interaction): self
+ {
+ $id = $interaction->getId();
+ $response = $interaction->getResponse();
+ $this->ffi->pactffi_response_status($id, $response->getStatus());
+ foreach ($response->getHeaders() as $header => $values) {
+ foreach (array_values($values) as $index => $value) {
+ $this->ffi->pactffi_with_header_v2($id, $this->ffi->InteractionPart_Response, $header, $index, $value);
+ }
+ }
+ if (!\is_null($response->getBody())) {
+ $success = $this->ffi->pactffi_with_body($id, $this->ffi->InteractionPart_Response, null, $response->getBody());
+ if (!$success) {
+ throw new InteractionResponseBodyNotAddedException();
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/src/PhpPact/Consumer/Model/ProviderResponse.php b/src/PhpPact/Consumer/Model/ProviderResponse.php
index d138f555..d3237e40 100644
--- a/src/PhpPact/Consumer/Model/ProviderResponse.php
+++ b/src/PhpPact/Consumer/Model/ProviderResponse.php
@@ -11,17 +11,17 @@ class ProviderResponse implements \JsonSerializable
/**
* @var int
*/
- private $status;
+ private int $status;
/**
- * @var null|string[]
+ * @var string[]
*/
- private $headers;
+ private array $headers = [];
/**
- * @var null|array
+ * @var null|string
*/
- private $body;
+ private ?string $body = null;
/**
* @return int
@@ -44,9 +44,9 @@ public function setStatus(int $status): self
}
/**
- * @return null|string[]
+ * @return string[]
*/
- public function getHeaders()
+ public function getHeaders(): array
{
return $this->headers;
}
@@ -58,7 +58,10 @@ public function getHeaders()
*/
public function setHeaders(array $headers): self
{
- $this->headers = $headers;
+ $this->headers = [];
+ foreach ($headers as $header => $value) {
+ $this->addHeader($header, $value);
+ }
return $this;
}
@@ -69,29 +72,36 @@ public function setHeaders(array $headers): self
*
* @return ProviderResponse
*/
- public function addHeader(string $header, $value): self
+ public function addHeader(string $header, array|string $value): self
{
- $this->headers[$header] = $value;
+ $this->headers[$header] = is_array($value) ? $value : [$value];
return $this;
}
/**
- * @return mixed
+ * @return null|string
*/
- public function getBody()
+ public function getBody(): ?string
{
return $this->body;
}
/**
- * @param iterable $body
+ * @param mixed $body
*
* @return ProviderResponse
*/
- public function setBody($body): self
+ public function setBody(mixed $body): self
{
- $this->body = $body;
+ if (\is_string($body)) {
+ $this->body = $body;
+ } elseif (!\is_null($body)) {
+ $this->body = \json_encode($body);
+ $this->addHeader('Content-Type', 'application/json');
+ } else {
+ $this->body = null;
+ }
return $this;
}
@@ -99,8 +109,7 @@ public function setBody($body): self
/**
* {@inheritdoc}
*/
- #[\ReturnTypeWillChange]
- public function jsonSerialize()
+ public function jsonSerialize(): array
{
$results = [
'status' => $this->getStatus(),
diff --git a/src/PhpPact/Standalone/Broker/Broker.php b/src/PhpPact/Standalone/Broker/Broker.php
index 910706be..2dd0e5b8 100644
--- a/src/PhpPact/Standalone/Broker/Broker.php
+++ b/src/PhpPact/Standalone/Broker/Broker.php
@@ -12,11 +12,11 @@
class Broker
{
/** @var Logger */
- private $logger;
+ private Logger $logger;
/** @var BrokerConfig */
- private $config;
+ private BrokerConfig $config;
/** @var string */
- private $command;
+ private string $command;
public function __construct(BrokerConfig $config)
{
diff --git a/src/PhpPact/Standalone/Broker/BrokerConfig.php b/src/PhpPact/Standalone/Broker/BrokerConfig.php
index e54f668e..8e12ee45 100644
--- a/src/PhpPact/Standalone/Broker/BrokerConfig.php
+++ b/src/PhpPact/Standalone/Broker/BrokerConfig.php
@@ -7,55 +7,55 @@
class BrokerConfig
{
/** @var null|UriInterface */
- private $brokerUri;
+ private ?UriInterface $brokerUri = null;
/** @var null|string */
- private $brokerToken;
+ private ?string $brokerToken = null;
/** @var null|string */
- private $brokerUsername;
+ private ?string $brokerUsername = null;
/** @var null|string */
- private $brokerPassword;
+ private ?string $brokerPassword = null;
/** @var bool */
- private $verbose = false;
+ private bool $verbose = false;
/** @var null|string */
- private $pacticipant;
+ private ?string $pacticipant = null;
/** @var null|string */
- private $request;
+ private ?string $request = null;
/** @var null|string */
- private $header;
+ private ?string $header = null;
/** @var null|string */
- private $data;
+ private ?string $data = null;
/** @var null|string */
- private $user;
+ private ?string $user = null;
/** @var null|string */
- private $consumer;
+ private ?string $consumer = null;
/** @var null|string */
- private $provider;
+ private ?string $provider = null;
/** @var null|string */
- private $description;
+ private ?string $description = null;
/** @var null|string */
- private $uuid;
+ private ?string $uuid = null;
/** @var null|string */
- private $version;
+ private ?string $version = null;
/** @var null|string */
- private $branch = null;
+ private ?string $branch = null;
/** @var null|string */
- private $tag = null;
+ private ?string $tag = null;
/** @var null|string */
- private $name;
+ private ?string $name = null;
/** @var null|string */
- private $repositoryUrl;
+ private ?string $repositoryUrl = null;
/** @var null|string */
- private $url;
+ private ?string $url = null;
/** @var null|string */
- private $consumerVersion;
+ private ?string $consumerVersion = null;
/** @var null|string */
- private $pactLocations;
+ private ?string $pactLocations = null;
/**
* @return null|string
@@ -68,7 +68,7 @@ public function getRepositoryUrl(): ?string
/**
* @param null|string $repositoryUrl
*
- * @return BrokerConfig
+ * @return $this
*/
public function setRepositoryUrl(?string $repositoryUrl): self
{
@@ -88,7 +88,7 @@ public function getUrl(): ?string
/**
* @param null|string $url
*
- * @return BrokerConfig
+ * @return $this
*/
public function setUrl(?string $url): self
{
@@ -108,7 +108,7 @@ public function getVersion(): ?string
/**
* @param null|string $version
*
- * @return BrokerConfig
+ * @return $this
*/
public function setVersion(?string $version): self
{
@@ -128,7 +128,7 @@ public function getBranch(): ?string
/**
* @param null|string $branch
*
- * @return BrokerConfig
+ * @return $this
*/
public function setBranch(?string $branch): self
{
@@ -148,7 +148,7 @@ public function getTag(): ?string
/**
* @param null|string $tag
*
- * @return BrokerConfig
+ * @return $this
*/
public function setTag(?string $tag): self
{
@@ -168,7 +168,7 @@ public function getName(): ?string
/**
* @param null|string $name
*
- * @return BrokerConfig
+ * @return $this
*/
public function setName(?string $name): self
{
@@ -188,7 +188,7 @@ public function getRequest(): ?string
/**
* @param null|string $request
*
- * @return BrokerConfig
+ * @return $this
*/
public function setRequest(?string $request): self
{
@@ -208,7 +208,7 @@ public function getHeader(): ?string
/**
* @param null|string $header
*
- * @return BrokerConfig
+ * @return $this
*/
public function setHeader(?string $header): self
{
@@ -228,7 +228,7 @@ public function getData(): ?string
/**
* @param null|string $data
*
- * @return BrokerConfig
+ * @return $this
*/
public function setData(?string $data): self
{
@@ -248,7 +248,7 @@ public function getUser(): ?string
/**
* @param null|string $user
*
- * @return BrokerConfig
+ * @return $this
*/
public function setUser(?string $user): self
{
@@ -268,7 +268,7 @@ public function getConsumer(): ?string
/**
* @param null|string $consumer
*
- * @return BrokerConfig
+ * @return $this
*/
public function setConsumer(?string $consumer): self
{
@@ -288,7 +288,7 @@ public function getProvider(): ?string
/**
* @param null|string $provider
*
- * @return BrokerConfig
+ * @return $this
*/
public function setProvider(?string $provider): self
{
@@ -308,7 +308,7 @@ public function getDescription(): ?string
/**
* @param null|string $description
*
- * @return BrokerConfig
+ * @return $this
*/
public function setDescription(?string $description): self
{
@@ -328,7 +328,7 @@ public function getUuid(): ?string
/**
* @param null|string $uuid
*
- * @return BrokerConfig
+ * @return $this
*/
public function setUuid(?string $uuid): self
{
@@ -337,11 +337,26 @@ public function setUuid(?string $uuid): self
return $this;
}
- public function isVerbose()
+ /**
+ * @return bool
+ */
+ public function isVerbose(): bool
{
return $this->verbose;
}
+ /**
+ * @param bool $verbose
+ *
+ * @return $this
+ */
+ public function setVerbose(bool $verbose): self
+ {
+ $this->verbose = $verbose;
+
+ return $this;
+ }
+
/**
* @return null|UriInterface
*/
@@ -352,6 +367,8 @@ public function getBrokerUri(): ?UriInterface
/**
* @param null|UriInterface $brokerUri
+ *
+ * @return $this
*/
public function setBrokerUri(?UriInterface $brokerUri): self
{
@@ -370,6 +387,8 @@ public function getBrokerToken(): ?string
/**
* @param null|string $brokerToken
+ *
+ * @return $this
*/
public function setBrokerToken(?string $brokerToken): self
{
@@ -388,6 +407,8 @@ public function getBrokerUsername(): ?string
/**
* @param null|string $brokerUsername
+ *
+ * @return $this
*/
public function setBrokerUsername(?string $brokerUsername): self
{
@@ -406,6 +427,8 @@ public function getBrokerPassword(): ?string
/**
* @param null|string $brokerPassword
+ *
+ * @return $this
*/
public function setBrokerPassword(?string $brokerPassword): self
{
@@ -414,13 +437,18 @@ public function setBrokerPassword(?string $brokerPassword): self
return $this;
}
- public function getPacticipant()
+ /**
+ * @return null|string
+ */
+ public function getPacticipant(): ?string
{
return $this->pacticipant;
}
/**
* @param null|string $pacticipant
+ *
+ * @return $this
*/
public function setPacticipant(?string $pacticipant): self
{
@@ -440,7 +468,7 @@ public function getConsumerVersion(): ?string
/**
* @param null|string $consumerVersion
*
- * @return BrokerConfig
+ * @return $this
*/
public function setConsumerVersion(?string $consumerVersion): self
{
@@ -460,7 +488,7 @@ public function getPactLocations(): ?string
/**
* @param string $locations
*
- * @return BrokerConfig
+ * @return $this
*/
public function setPactLocations(string $locations): self
{
diff --git a/src/PhpPact/Standalone/Exception/HealthCheckFailedException.php b/src/PhpPact/Standalone/Exception/HealthCheckFailedException.php
deleted file mode 100644
index 665ad684..00000000
--- a/src/PhpPact/Standalone/Exception/HealthCheckFailedException.php
+++ /dev/null
@@ -1,17 +0,0 @@
-config = $config;
-
- if (!$httpService) {
- $this->httpService = new MockServerHttpService(new GuzzleClient(), $this->config);
- } else {
- $this->httpService = $httpService;
- }
- }
-
- /**
- * Start the Mock Server. Verify that it is running.
- *
- * @throws Exception
- *
- * @return int process ID of the started Mock Server
- */
- public function start(): int
- {
- $this->processRunner = new ProcessRunner(Scripts::getMockService(), $this->getArguments());
-
- $processId = $this->processRunner->run();
-
- $result = $this->verifyHealthCheck();
- if ($result) {
- $retrySec = $this->config->getHealthCheckRetrySec();
- \sleep($retrySec);
- }
-
- return $processId;
- }
-
- /**
- * Stop the Mock Server process.
- *
- * @return bool Was stopping successful?
- */
- public function stop(): bool
- {
- return $this->processRunner->stop();
- }
-
- /**
- * Build an array of command arguments.
- *
- * @return array
- */
- private function getArguments(): array
- {
- $results = [];
-
- $logLevel = $this->config->getLogLevel();
- $consumer = \escapeshellarg($this->config->getConsumer());
- $provider = \escapeshellarg($this->config->getProvider());
- $pactDir = \escapeshellarg($this->config->getPactDir());
-
- $results[] = 'service';
- $results[] = "--consumer={$consumer}";
- $results[] = "--provider={$provider}";
- $results[] = "--pact-dir={$pactDir}";
- $results[] = "--pact-file-write-mode={$this->config->getPactFileWriteMode()}";
- $results[] = "--host={$this->config->getHost()}";
- $results[] = "--port={$this->config->getPort()}";
-
- if ($logLevel) {
- $results[] = \sprintf('--log-level=%s', \escapeshellarg($logLevel));
- }
-
- if ($this->config->hasCors()) {
- $results[] = '--cors=true';
- }
-
- if ($this->config->getPactSpecificationVersion() !== null) {
- $results[] = "--pact-specification-version={$this->config->getPactSpecificationVersion()}";
- }
-
- if (!empty($this->config->getLog())) {
- $log = \escapeshellarg($this->config->getLog());
- $results[] = \sprintf('--log=%s', $log);
- }
-
- return $results;
- }
-
- /**
- * Make sure the server starts as expected.
- *
- * @throws Exception
- *
- * @return bool
- */
- private function verifyHealthCheck(): bool
- {
- $service = $this->httpService;
-
- // Verify that the service is up.
- $tries = 0;
- $maxTries = $this->config->getHealthCheckTimeout();
- $retrySec = $this->config->getHealthCheckRetrySec();
- do {
- ++$tries;
-
- try {
- return $service->healthCheck();
- } catch (ConnectionException $e) {
- \sleep($retrySec);
- }
- } while ($tries <= $maxTries);
-
- throw new HealthCheckFailedException("Failed to make connection to Mock Server in {$maxTries} attempts.");
- }
-}
diff --git a/src/PhpPact/Standalone/MockService/MockServerConfig.php b/src/PhpPact/Standalone/MockService/MockServerConfig.php
index 3b5c7621..05a03364 100644
--- a/src/PhpPact/Standalone/MockService/MockServerConfig.php
+++ b/src/PhpPact/Standalone/MockService/MockServerConfig.php
@@ -2,98 +2,34 @@
namespace PhpPact\Standalone\MockService;
-use Composer\Semver\VersionParser;
use GuzzleHttp\Psr7\Uri;
-use PhpPact\Standalone\PactConfigInterface;
+use PhpPact\Standalone\PactConfig;
use Psr\Http\Message\UriInterface;
/**
* Configuration defining the default PhpPact Ruby Standalone server.
* Class MockServerConfig.
*/
-class MockServerConfig implements MockServerConfigInterface, PactConfigInterface
+class MockServerConfig extends PactConfig implements MockServerConfigInterface
{
/**
* Host on which to bind the service.
*
* @var string
*/
- private $host = 'localhost';
+ private string $host = 'localhost';
/**
- * Port on which to run the service.
+ * Port on which to run the service. A value of zero will result in the operating system allocating an available port.
*
* @var int
*/
- private $port = 7200;
+ private int $port = 7200;
/**
* @var bool
*/
- private $secure = false;
-
- /**
- * Consumer name.
- *
- * @var string
- */
- private $consumer;
-
- /**
- * Provider name.
- *
- * @var string
- */
- private $provider;
-
- /**
- * Directory to which the pacts will be written.
- *
- * @var string
- */
- private $pactDir;
-
- /**
- * `overwrite` or `merge`. Use `merge` when running multiple mock service
- * instances in parallel for the same consumer/provider pair. Ensure the
- * pact file is deleted before running tests when using this option so that
- * interactions deleted from the code are not maintained in the file.
- *
- * @var string
- */
- private $pactFileWriteMode = 'overwrite';
-
- /**
- * The pact specification version to use when writing the pact. Note that only versions 1 and 2 are currently supported.
- *
- * @var string
- */
- private $pactSpecificationVersion;
-
- /**
- * File to which to log output.
- *
- * @var string
- */
- private $log;
-
- /** @var bool */
- private $cors = false;
-
- /**
- * The max allowed attempts the mock server has to be available in. Otherwise it is considered as sick.
- *
- * @var int
- */
- private $healthCheckTimeout;
-
- /**
- * The seconds between health checks of mock server
- *
- * @var int
- */
- private $healthCheckRetrySec;
- private $logLevel;
+ private bool $secure = false;
/**
* {@inheritdoc}
@@ -106,7 +42,7 @@ public function getHost(): string
/**
* {@inheritdoc}
*/
- public function setHost(string $host): MockServerConfigInterface
+ public function setHost(string $host): self
{
$this->host = $host;
@@ -124,7 +60,7 @@ public function getPort(): int
/**
* {@inheritdoc}
*/
- public function setPort(int $port): MockServerConfigInterface
+ public function setPort(int $port): self
{
$this->port = $port;
@@ -142,7 +78,7 @@ public function isSecure(): bool
/**
* {@inheritdoc}
*/
- public function setSecure(bool $secure): MockServerConfigInterface
+ public function setSecure(bool $secure): self
{
$this->secure = $secure;
@@ -158,214 +94,4 @@ public function getBaseUri(): UriInterface
return new Uri("{$protocol}://{$this->getHost()}:{$this->getPort()}");
}
-
- /**
- * {@inheritdoc}
- */
- public function getConsumer(): string
- {
- return $this->consumer;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setConsumer(string $consumer): PactConfigInterface
- {
- $this->consumer = $consumer;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getProvider(): string
- {
- return $this->provider;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setProvider(string $provider): PactConfigInterface
- {
- $this->provider = $provider;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPactDir()
- {
- if ($this->pactDir === null) {
- return \sys_get_temp_dir();
- }
-
- return $this->pactDir;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setPactDir($pactDir): PactConfigInterface
- {
- if ($pactDir === null) {
- return $this;
- }
-
- if ('\\' !== \DIRECTORY_SEPARATOR) {
- $pactDir = \str_replace('\\', \DIRECTORY_SEPARATOR, $pactDir);
- }
-
- $this->pactDir = $pactDir;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPactFileWriteMode(): string
- {
- return $this->pactFileWriteMode;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setPactFileWriteMode(string $pactFileWriteMode): MockServerConfigInterface
- {
- $options = ['overwrite', 'merge'];
-
- if (!\in_array($pactFileWriteMode, $options)) {
- $implodedOptions = \implode(', ', $options);
-
- throw new \InvalidArgumentException("Invalid PhpPact File Write Mode, value must be one of the following: {$implodedOptions}.");
- }
-
- $this->pactFileWriteMode = $pactFileWriteMode;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPactSpecificationVersion()
- {
- return $this->pactSpecificationVersion;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setPactSpecificationVersion($pactSpecificationVersion): PactConfigInterface
- {
- /*
- * Parse the version but do not assign it. If it is an invalid version, an exception is thrown
- */
- $parser = new VersionParser();
- $parser->normalize($pactSpecificationVersion);
-
- $this->pactSpecificationVersion = $pactSpecificationVersion;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLog()
- {
- return $this->log;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setLog(string $log): PactConfigInterface
- {
- $this->log = $log;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLogLevel()
- {
- return $this->logLevel;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setLogLevel(string $logLevel): PactConfigInterface
- {
- $logLevel = \strtoupper($logLevel);
- if (!\in_array($logLevel, ['DEBUG', 'INFO', 'WARN', 'ERROR'])) {
- throw new \InvalidArgumentException('LogLevel ' . $logLevel . ' not supported.');
- }
- $this->logLevel = $logLevel;
-
- return $this;
- }
-
- public function hasCors(): bool
- {
- return $this->cors;
- }
-
- public function setCors($flag): MockServerConfigInterface
- {
- if ($flag === 'true') {
- $this->cors = true;
- } elseif ($flag === 'false') {
- $this->cors = false;
- } else {
- $this->cors = (bool) $flag;
- }
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setHealthCheckTimeout($timeout): MockServerConfigInterface
- {
- $this->healthCheckTimeout = $timeout;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getHealthCheckTimeout(): int
- {
- return $this->healthCheckTimeout;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setHealthCheckRetrySec($seconds): MockServerConfigInterface
- {
- $this->healthCheckRetrySec = $seconds;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getHealthCheckRetrySec(): int
- {
- return $this->healthCheckRetrySec;
- }
}
diff --git a/src/PhpPact/Standalone/MockService/MockServerConfigInterface.php b/src/PhpPact/Standalone/MockService/MockServerConfigInterface.php
index a1066ab3..fc6eb64c 100644
--- a/src/PhpPact/Standalone/MockService/MockServerConfigInterface.php
+++ b/src/PhpPact/Standalone/MockService/MockServerConfigInterface.php
@@ -2,13 +2,14 @@
namespace PhpPact\Standalone\MockService;
+use PhpPact\Standalone\PactConfigInterface;
use Psr\Http\Message\UriInterface;
/**
* Mock Server configuration interface to allow for simple overrides that are reusable.
* Interface MockServerConfigInterface.
*/
-interface MockServerConfigInterface
+interface MockServerConfigInterface extends PactConfigInterface
{
/**
* @return string the host of the mock service
@@ -50,52 +51,4 @@ public function setSecure(bool $secure): self;
* @return UriInterface
*/
public function getBaseUri(): UriInterface;
-
- /**
- * @return string 'merge' or 'overwrite' merge means that interactions are added and overwrite means that the entire file is overwritten
- */
- public function getPactFileWriteMode(): string;
-
- /**
- * @param string $pactFileWriteMode 'merge' or 'overwrite' merge means that interactions are added and overwrite means that the entire file is overwritten
- *
- * @return MockServerConfigInterface
- */
- public function setPactFileWriteMode(string $pactFileWriteMode): self;
-
- /**
- * @return bool
- */
- public function hasCors(): bool;
-
- /**
- * @param bool|string $flag
- *
- * @return MockServerConfigInterface
- */
- public function setCors($flag): self;
-
- /**
- * @param int $timeout
- *
- * @return MockServerConfigInterface
- */
- public function setHealthCheckTimeout($timeout): self;
-
- /**
- * @return int
- */
- public function getHealthCheckTimeout(): int;
-
- /**
- * @param int $seconds
- *
- * @return MockServerConfigInterface
- */
- public function setHealthCheckRetrySec($seconds): self;
-
- /**
- * @return int
- */
- public function getHealthCheckRetrySec(): int;
}
diff --git a/src/PhpPact/Standalone/MockService/MockServerEnvConfig.php b/src/PhpPact/Standalone/MockService/MockServerEnvConfig.php
index 0edc8251..1f11a8a8 100644
--- a/src/PhpPact/Standalone/MockService/MockServerEnvConfig.php
+++ b/src/PhpPact/Standalone/MockService/MockServerEnvConfig.php
@@ -10,7 +10,7 @@
*/
class MockServerEnvConfig extends MockServerConfig
{
- public const DEFAULT_SPECIFICATION_VERSION = '2.0.0';
+ public const DEFAULT_SPECIFICATION_VERSION = '3.0.0';
/**
* MockServerEnvConfig constructor.
@@ -24,7 +24,6 @@ public function __construct()
$this->setConsumer($this->parseEnv('PACT_CONSUMER_NAME'));
$this->setProvider($this->parseEnv('PACT_PROVIDER_NAME'));
$this->setPactDir($this->parseEnv('PACT_OUTPUT_DIR', false));
- $this->setCors($this->parseEnv('PACT_CORS', false));
if ($logDir = $this->parseEnv('PACT_LOG', false)) {
$this->setLog($logDir);
@@ -34,18 +33,6 @@ public function __construct()
$this->setLogLevel($logLevel);
}
- $timeout = $this->parseEnv('PACT_MOCK_SERVER_HEALTH_CHECK_TIMEOUT', false);
- if (!$timeout) {
- $timeout = 10;
- }
- $this->setHealthCheckTimeout($timeout);
-
- $seconds = $this->parseEnv('PACT_MOCK_SERVER_HEALTH_CHECK_RETRY_SEC', false);
- if (!$seconds) {
- $seconds = 1;
- }
- $this->setHealthCheckRetrySec($seconds);
-
$version = $this->parseEnv('PACT_SPECIFICATION_VERSION', false);
if (!$version) {
$version = static::DEFAULT_SPECIFICATION_VERSION;
@@ -64,7 +51,7 @@ public function __construct()
*
* @return null|string
*/
- private function parseEnv(string $variableName, bool $required = true)
+ private function parseEnv(string $variableName, bool $required = true): ?string
{
$result = null;
diff --git a/src/PhpPact/Standalone/MockService/Service/MockServerHttpService.php b/src/PhpPact/Standalone/MockService/Service/MockServerHttpService.php
deleted file mode 100644
index 2c13e83a..00000000
--- a/src/PhpPact/Standalone/MockService/Service/MockServerHttpService.php
+++ /dev/null
@@ -1,181 +0,0 @@
-client = $client;
- $this->config = $config;
- }
-
- /**
- * {@inheritdoc}
- */
- public function healthCheck(): bool
- {
- $uri = $this->config->getBaseUri()->withPath('/');
-
- try {
- $response = $this->client->get($uri, [
- 'headers' => [
- 'Content-Type' => 'application/json',
- 'X-Pact-Mock-Service' => true,
- ],
- ]);
-
- $body = $response->getBody()->getContents();
-
- if ($response->getStatusCode() !== 200
- || $body !== "Mock service running\n") {
- throw new ConnectionException('Failed to receive a successful response from the Mock Server.');
- }
- } catch (RequestException $e) {
- throw new ConnectionException('Failed to receive a successful response from the Mock Server.', $e);
- } catch (GuzzleConnectionException $e) {
- throw new ConnectionException('Failed to receive a successful response from the Mock Server.', $e);
- }
-
- return true;
- }
-
- /**
- * {@inheritdoc}
- */
- public function deleteAllInteractions(): bool
- {
- $uri = $this->config->getBaseUri()->withPath('/interactions');
-
- $response = $this->client->delete($uri, [
- 'headers' => [
- 'Content-Type' => 'application/json',
- 'X-Pact-Mock-Service' => true,
- ],
- ]);
-
- if ($response->getStatusCode() !== 200) {
- return false;
- }
-
- return true;
- }
-
- /**
- * {@inheritdoc}
- */
- public function registerInteraction(Interaction $interaction): bool
- {
- $uri = $this->config->getBaseUri()->withPath('/interactions');
-
- $body = \json_encode($interaction->jsonSerialize());
-
- $this->client->post($uri, [
- 'headers' => [
- 'Content-Type' => 'application/json',
- 'X-Pact-Mock-Service' => true,
- ],
- 'body' => $body,
- ]);
-
- return true;
- }
-
- /**
- * Separate function for messages, instead of interactions, as I am unsure what to do with the Ruby Standalone at the moment
- *
- * @param Message $message
- *
- * @return bool
- */
- public function registerMessage(Message $message): bool
- {
- $uri = $this->config->getBaseUri()->withPath('/interactions');
-
- $body = \json_encode($message->jsonSerialize());
-
- $this->client->post($uri, [
- 'headers' => [
- 'Content-Type' => 'application/json',
- 'X-Pact-Mock-Service' => true,
- ],
- 'body' => $body,
- ]);
-
- return true;
- }
-
- /**
- * {@inheritdoc}
- */
- public function verifyInteractions(): bool
- {
- $uri = $this->config->getBaseUri()->withPath('/interactions/verification');
-
- $this->client->get($uri, [
- 'headers' => [
- 'Content-Type' => 'application/json',
- 'X-Pact-Mock-Service' => true,
- ],
- ]);
-
- return true;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPactJson(): string
- {
- $uri = $this->config->getBaseUri()->withPath('/pact');
- $response = $this->client->post($uri, [
- 'headers' => [
- 'Content-Type' => 'application/json',
- 'X-Pact-Mock-Service' => true,
- ],
- ]);
-
- return \json_encode(\json_decode($response->getBody()->getContents()));
- }
-
- /**
- * Wrapper for getPactJson to force the Ruby server to write the pact file to disk
- *
- * If the Pact-PHP does not gracefully kill the Ruby Server, it will not write the
- * file to disk. This enables a work around.
- */
- public function writePact(): string
- {
- return $this->getPactJson();
- }
-}
diff --git a/src/PhpPact/Standalone/MockService/Service/MockServerHttpServiceInterface.php b/src/PhpPact/Standalone/MockService/Service/MockServerHttpServiceInterface.php
deleted file mode 100644
index e3bfbe62..00000000
--- a/src/PhpPact/Standalone/MockService/Service/MockServerHttpServiceInterface.php
+++ /dev/null
@@ -1,51 +0,0 @@
-consumer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setConsumer(string $consumer): self
+ {
+ $this->consumer = $consumer;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getProvider(): string
+ {
+ return $this->provider;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setProvider(string $provider): self
+ {
+ $this->provider = $provider;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPactDir(): string
+ {
+ if ($this->pactDir === null) {
+ return \sys_get_temp_dir();
+ }
+
+ return $this->pactDir;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPactDir(?string $pactDir): self
+ {
+ if ($pactDir === null) {
+ return $this;
+ }
+
+ if ('\\' !== \DIRECTORY_SEPARATOR) {
+ $pactDir = \str_replace('\\', \DIRECTORY_SEPARATOR, $pactDir);
+ }
+
+ $this->pactDir = $pactDir;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPactSpecificationVersion(): string
+ {
+ return $this->pactSpecificationVersion;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @throws \UnexpectedValueException
+ */
+ public function setPactSpecificationVersion(string $pactSpecificationVersion): self
+ {
+ /*
+ * Parse the version but do not assign it. If it is an invalid version, an exception is thrown
+ */
+ $parser = new VersionParser();
+ $parser->normalize($pactSpecificationVersion);
+
+ $this->pactSpecificationVersion = $pactSpecificationVersion;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLog(): ?string
+ {
+ return $this->log;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setLog(string $log): self
+ {
+ $this->log = $log;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLogLevel(): ?string
+ {
+ return $this->logLevel;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setLogLevel(string $logLevel): self
+ {
+ $logLevel = \strtoupper($logLevel);
+ if (!\in_array($logLevel, ['DEBUG', 'INFO', 'WARN', 'ERROR'])) {
+ throw new \InvalidArgumentException('LogLevel ' . $logLevel . ' not supported.');
+ }
+ $this->logLevel = $logLevel;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPactFileWriteMode(): string
+ {
+ return $this->pactFileWriteMode;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setPactFileWriteMode(string $pactFileWriteMode): self
+ {
+ $options = [self::MODE_OVERWRITE, self::MODE_MERGE];
+
+ if (!\in_array($pactFileWriteMode, $options)) {
+ $implodedOptions = \implode(', ', $options);
+
+ throw new \InvalidArgumentException("Invalid PhpPact File Write Mode, value must be one of the following: {$implodedOptions}.");
+ }
+
+ $this->pactFileWriteMode = $pactFileWriteMode;
+
+ return $this;
+ }
+}
diff --git a/src/PhpPact/Standalone/PactConfigInterface.php b/src/PhpPact/Standalone/PactConfigInterface.php
index 3369e46e..b1d21344 100644
--- a/src/PhpPact/Standalone/PactConfigInterface.php
+++ b/src/PhpPact/Standalone/PactConfigInterface.php
@@ -8,6 +8,9 @@
*/
interface PactConfigInterface
{
+ public const MODE_OVERWRITE = 'overwrite';
+ public const MODE_MERGE = 'merge';
+
/**
* @return string
*/
@@ -16,7 +19,7 @@ public function getConsumer(): string;
/**
* @param string $consumer consumers name
*
- * @return PactConfigInterface
+ * @return $this
*/
public function setConsumer(string $consumer): self;
@@ -28,50 +31,50 @@ public function getProvider(): string;
/**
* @param string $provider providers name
*
- * @return PactConfigInterface
+ * @return $this
*/
public function setProvider(string $provider): self;
/**
* @return string url to place the pact files when written to disk
*/
- public function getPactDir();
+ public function getPactDir(): string;
/**
* @param null|string $pactDir url to place the pact files when written to disk
*
- * @return PactConfigInterface
+ * @return $this
*/
- public function setPactDir($pactDir): self;
+ public function setPactDir(?string $pactDir): self;
/**
* @return string pact version
*/
- public function getPactSpecificationVersion();
+ public function getPactSpecificationVersion(): string;
/**
* @param string $pactSpecificationVersion pact semver version
*
- * @return PactConfigInterface
+ * @return $this
*/
- public function setPactSpecificationVersion($pactSpecificationVersion): self;
+ public function setPactSpecificationVersion(string $pactSpecificationVersion): self;
/**
- * @return string directory for log output
+ * @return null|string directory for log output
*/
- public function getLog();
+ public function getLog(): ?string;
/**
* @param string $log directory for log output
*
- * @return PactConfigInterface
+ * @return $this
*/
public function setLog(string $log): self;
/**
* @return null|string
*/
- public function getLogLevel();
+ public function getLogLevel(): ?string;
/**
* @param string $logLevel
@@ -79,4 +82,16 @@ public function getLogLevel();
* @return $this
*/
public function setLogLevel(string $logLevel): self;
+
+ /**
+ * @return string 'merge' or 'overwrite' merge means that interactions are added and overwrite means that the entire file is overwritten
+ */
+ public function getPactFileWriteMode(): string;
+
+ /**
+ * @param string $pactFileWriteMode 'merge' or 'overwrite' merge means that interactions are added and overwrite means that the entire file is overwritten
+ *
+ * @return $this
+ */
+ public function setPactFileWriteMode(string $pactFileWriteMode): self;
}
diff --git a/src/PhpPact/Standalone/PactMessage/PactMessageConfig.php b/src/PhpPact/Standalone/PactMessage/PactMessageConfig.php
index 2874e772..3ad3c782 100644
--- a/src/PhpPact/Standalone/PactMessage/PactMessageConfig.php
+++ b/src/PhpPact/Standalone/PactMessage/PactMessageConfig.php
@@ -2,168 +2,12 @@
namespace PhpPact\Standalone\PactMessage;
-use Composer\Semver\VersionParser;
-use PhpPact\Standalone\PactConfigInterface;
+use PhpPact\Standalone\PactConfig;
/**
* Configuration defining the default PhpPact Ruby Standalone server.
- * Class MockServerConfig.
+ * Class PactMessageConfig.
*/
-class PactMessageConfig implements PactConfigInterface
+class PactMessageConfig extends PactConfig
{
- /**
- * Consumer name.
- *
- * @var string
- */
- private $consumer;
-
- /**
- * Provider name.
- *
- * @var string
- */
- private $provider;
-
- /**
- * Directory to which the pacts will be written.
- *
- * @var string
- */
- private $pactDir;
-
- /**
- * The pact specification version to use when writing the pact. Note that only versions 1 and 2 are currently supported.
- *
- * @var string
- */
- private $pactSpecificationVersion;
-
- /**
- * File to which to log output.
- *
- * @var string
- */
- private $log;
-
- /** @var string */
- private $logLevel;
-
- /**
- * {@inheritdoc}
- */
- public function getConsumer(): string
- {
- return $this->consumer;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setConsumer(string $consumer): PactConfigInterface
- {
- $this->consumer = $consumer;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getProvider(): string
- {
- return $this->provider;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setProvider(string $provider): PactConfigInterface
- {
- $this->provider = $provider;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPactDir()
- {
- if ($this->pactDir === null) {
- return \sys_get_temp_dir();
- }
-
- return $this->pactDir;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setPactDir($pactDir): PactConfigInterface
- {
- $this->pactDir = $pactDir;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getPactSpecificationVersion()
- {
- return $this->pactSpecificationVersion;
- }
-
- /**
- * {@inheritdoc}
- *
- * @throws \UnexpectedValueException
- */
- public function setPactSpecificationVersion($pactSpecificationVersion): PactConfigInterface
- {
- /*
- * Parse the version but do not assign it. If it is an invalid version, an exception is thrown
- */
- $parser = new VersionParser();
- $parser->normalize($pactSpecificationVersion);
-
- $this->pactSpecificationVersion = $pactSpecificationVersion;
-
- return $this;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getLog()
- {
- return $this->log;
- }
-
- /**
- * {@inheritdoc}
- */
- public function setLog(string $log): PactConfigInterface
- {
- $this->log = $log;
-
- return $this;
- }
-
- public function getLogLevel()
- {
- return $this->logLevel;
- }
-
- public function setLogLevel(string $logLevel): PactConfigInterface
- {
- $logLevel = \strtoupper($logLevel);
- if (!\in_array($logLevel, ['DEBUG', 'INFO', 'WARN', 'ERROR'])) {
- throw new \InvalidArgumentException('LogLevel ' . $logLevel . ' not supported.');
- }
- $this->logLevel = $logLevel;
-
- return $this;
- }
}
diff --git a/tests/PhpPact/Consumer/InteractionBuilderTest.php b/tests/PhpPact/Consumer/InteractionBuilderTest.php
index 3bdd9a14..33eaa902 100644
--- a/tests/PhpPact/Consumer/InteractionBuilderTest.php
+++ b/tests/PhpPact/Consumer/InteractionBuilderTest.php
@@ -6,39 +6,12 @@
use PhpPact\Consumer\Matcher\Matcher;
use PhpPact\Consumer\Model\ConsumerRequest;
use PhpPact\Consumer\Model\ProviderResponse;
-use PhpPact\Http\GuzzleClient;
use PhpPact\Standalone\Exception\MissingEnvVariableException;
-use PhpPact\Standalone\MockService\MockServer;
use PhpPact\Standalone\MockService\MockServerEnvConfig;
-use PhpPact\Standalone\MockService\Service\MockServerHttpService;
-use PhpPact\Standalone\MockService\Service\MockServerHttpServiceInterface;
use PHPUnit\Framework\TestCase;
class InteractionBuilderTest extends TestCase
{
- /** @var MockServerHttpServiceInterface */
- private $service;
-
- /** @var MockServer */
- private $mockServer;
-
- /**
- * @throws MissingEnvVariableException
- * @throws \Exception
- */
- protected function setUp(): void
- {
- $config = new MockServerEnvConfig();
- $this->mockServer = new MockServer($config);
- $this->mockServer->start();
- $this->service = new MockServerHttpService(new GuzzleClient(), $config);
- }
-
- protected function tearDown(): void
- {
- $this->mockServer->stop();
- }
-
/**
* @throws MissingEnvVariableException
* @throws \Exception
diff --git a/tests/PhpPact/Consumer/Matcher/MatcherTest.php b/tests/PhpPact/Consumer/Matcher/MatcherTest.php
index 789bdf57..b406def8 100644
--- a/tests/PhpPact/Consumer/Matcher/MatcherTest.php
+++ b/tests/PhpPact/Consumer/Matcher/MatcherTest.php
@@ -9,7 +9,7 @@
class MatcherTest extends TestCase
{
/** @var Matcher */
- private $matcher;
+ private Matcher $matcher;
protected function setUp(): void
{
@@ -32,7 +32,7 @@ public function testLike()
{
$json = \json_encode($this->matcher->like(12));
- $this->assertEquals('{"contents":12,"json_class":"Pact::SomethingLike"}', $json);
+ $this->assertEquals('{"value":12,"pact:matcher:type":"type"}', $json);
}
/**
@@ -45,15 +45,17 @@ public function testEachLikeStdClass()
$object->value2 = 2;
$expected = \json_encode([
- 'contents' => [
- 'value1' => [
- 'contents' => 1,
- 'json_class' => 'Pact::SomethingLike',
- ],
- 'value2' => 2,
+ 'value' => [
+ [
+ 'value1' => [
+ 'value' => 1,
+ 'pact:matcher:type' => 'type',
+ ],
+ 'value2' => 2,
+ ]
],
- 'json_class' => 'Pact::ArrayLike',
- 'min' => 1,
+ 'pact:matcher:type' => 'type',
+ 'min' => 1,
]);
$actual = \json_encode($this->matcher->eachLike($object, 1));
@@ -72,15 +74,17 @@ public function testEachLikeArray()
];
$expected = \json_encode([
- 'contents' => [
- 'value1' => [
- 'contents' => 1,
- 'json_class' => 'Pact::SomethingLike',
- ],
- 'value2' => 2,
+ 'value' => [
+ [
+ 'value1' => [
+ 'value' => 1,
+ 'pact:matcher:type' => 'type',
+ ],
+ 'value2' => 2,
+ ]
],
- 'json_class' => 'Pact::ArrayLike',
- 'min' => 1,
+ 'pact:matcher:type' => 'type',
+ 'min' => 1,
]);
$actual = \json_encode($this->matcher->eachLike($object, 1));
@@ -103,15 +107,9 @@ public function testRegexNoMatch()
public function testRegex()
{
$expected = [
- 'data' => [
- 'generate' => 'Games',
- 'matcher' => [
- 'json_class' => 'Regexp',
- 'o' => 0,
- 's' => 'Games|Other',
- ],
- ],
- 'json_class' => 'Pact::Term',
+ 'value' => 'Games',
+ 'regex' => 'Games|Other',
+ 'pact:matcher:type' => 'regex',
];
$actual = $this->matcher->regex('Games', 'Games|Other');
@@ -125,15 +123,9 @@ public function testRegex()
public function testDate()
{
$expected = [
- 'data' => [
- 'generate' => '2010-01-17',
- 'matcher' => [
- 'json_class' => 'Regexp',
- 'o' => 0,
- 's' => '^([\\+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))?)$',
- ],
- ],
- 'json_class' => 'Pact::Term',
+ 'value' => '2010-01-17',
+ 'regex' => '^([\\+-]?\\d{4}(?!\\d{2}\\b))((-?)((0[1-9]|1[0-2])(\\3([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))?)$',
+ 'pact:matcher:type' => 'regex',
];
$actual = $this->matcher->dateISO8601('2010-01-17');
@@ -149,15 +141,9 @@ public function testDate()
public function testTime($time)
{
$expected = [
- 'data' => [
- 'generate' => $time,
- 'matcher' => [
- 'json_class' => 'Regexp',
- 'o' => 0,
- 's' => '^(T\\d\\d:\\d\\d(:\\d\\d)?(\\.\\d+)?([+-][0-2]\\d(?:|:?[0-5]\\d)|Z)?)$',
- ],
- ],
- 'json_class' => 'Pact::Term',
+ 'value' => $time,
+ 'regex' => '^(T\\d\\d:\\d\\d(:\\d\\d)?(\\.\\d+)?([+-][0-2]\\d(?:|:?[0-5]\\d)|Z)?)$',
+ 'pact:matcher:type' => 'regex',
];
$actual = $this->matcher->timeISO8601($time);
@@ -189,15 +175,9 @@ public function dataProviderForTimeTest()
public function testDateTime($dateTime)
{
$expected = [
- 'data' => [
- 'generate' => $dateTime,
- 'matcher' => [
- 'json_class' => 'Regexp',
- 'o' => 0,
- 's' => '^\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d([+-][0-2]\\d(?:|:?[0-5]\\d)|Z)?$',
- ],
- ],
- 'json_class' => 'Pact::Term',
+ 'value' => $dateTime,
+ 'regex' => '^\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d([+-][0-2]\\d(?:|:?[0-5]\\d)|Z)?$',
+ 'pact:matcher:type' => 'regex',
];
$actual = $this->matcher->dateTimeISO8601($dateTime);
@@ -227,15 +207,9 @@ public function dataProviderForDateTimeTest()
public function testDateTimeWithMillis($dateTime)
{
$expected = [
- 'data' => [
- 'generate' => $dateTime,
- 'matcher' => [
- 'json_class' => 'Regexp',
- 'o' => 0,
- 's' => '^\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d{3}([+-][0-2]\\d(?:|:?[0-5]\\d)|Z)?$',
- ],
- ],
- 'json_class' => 'Pact::Term',
+ 'value' => $dateTime,
+ 'regex' => '^\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d{3}([+-][0-2]\\d(?:|:?[0-5]\\d)|Z)?$',
+ 'pact:matcher:type' => 'regex',
];
$actual = $this->matcher->dateTimeWithMillisISO8601($dateTime);
@@ -263,15 +237,9 @@ public function dataProviderForDateTimeWithMillisTest()
public function testTimestampRFC3339()
{
$expected = [
- 'data' => [
- 'generate' => 'Mon, 31 Oct 2016 15:21:41 -0400',
- 'matcher' => [
- 'json_class' => 'Regexp',
- 'o' => 0,
- 's' => '^(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s\\d{2}\\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\s\\d{4}\\s\\d{2}:\\d{2}:\\d{2}\\s(\\+|-)\\d{4}$',
- ],
- ],
- 'json_class' => 'Pact::Term',
+ 'value' => 'Mon, 31 Oct 2016 15:21:41 -0400',
+ 'regex' => '^(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s\\d{2}\\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\\s\\d{4}\\s\\d{2}:\\d{2}:\\d{2}\\s(\\+|-)\\d{4}$',
+ 'pact:matcher:type' => 'regex',
];
$actual = $this->matcher->timestampRFC3339('Mon, 31 Oct 2016 15:21:41 -0400');
@@ -286,7 +254,7 @@ public function testInteger()
{
$json = \json_encode($this->matcher->integer());
- $this->assertEquals('{"contents":13,"json_class":"Pact::SomethingLike"}', $json);
+ $this->assertEquals('{"value":13,"pact:matcher:type":"type"}', $json);
}
/**
@@ -296,7 +264,7 @@ public function testBoolean()
{
$json = \json_encode($this->matcher->boolean());
- $this->assertEquals('{"contents":true,"json_class":"Pact::SomethingLike"}', $json);
+ $this->assertEquals('{"value":true,"pact:matcher:type":"type"}', $json);
}
/**
@@ -306,7 +274,7 @@ public function testDecimal()
{
$json = \json_encode($this->matcher->decimal());
- $this->assertEquals('{"contents":13.01,"json_class":"Pact::SomethingLike"}', $json);
+ $this->assertEquals('{"value":13.01,"pact:matcher:type":"type"}', $json);
}
/**
@@ -315,15 +283,9 @@ public function testDecimal()
public function testHexadecimal()
{
$expected = [
- 'data' => [
- 'generate' => '3F',
- 'matcher' => [
- 'json_class' => 'Regexp',
- 'o' => 0,
- 's' => '^[0-9a-fA-F]+$',
- ],
- ],
- 'json_class' => 'Pact::Term',
+ 'value' => '3F',
+ 'regex' => '^[0-9a-fA-F]+$',
+ 'pact:matcher:type' => 'regex',
];
$this->assertEquals($expected, $this->matcher->hexadecimal());
@@ -335,15 +297,9 @@ public function testHexadecimal()
public function testUuid()
{
$expected = [
- 'data' => [
- 'generate' => 'ce118b6e-d8e1-11e7-9296-cec278b6b50a',
- 'matcher' => [
- 'json_class' => 'Regexp',
- 'o' => 0,
- 's' => '^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$',
- ],
- ],
- 'json_class' => 'Pact::Term',
+ 'value' => 'ce118b6e-d8e1-11e7-9296-cec278b6b50a',
+ 'regex' => '^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$',
+ 'pact:matcher:type' => 'regex',
];
$this->assertEquals($expected, $this->matcher->uuid());
@@ -355,15 +311,9 @@ public function testUuid()
public function testIpv4Address()
{
$expected = [
- 'data' => [
- 'generate' => '127.0.0.13',
- 'matcher' => [
- 'json_class' => 'Regexp',
- 'o' => 0,
- 's' => '^(\\d{1,3}\\.)+\\d{1,3}$',
- ],
- ],
- 'json_class' => 'Pact::Term',
+ 'value' => '127.0.0.13',
+ 'regex' => '^(\\d{1,3}\\.)+\\d{1,3}$',
+ 'pact:matcher:type' => 'regex',
];
$this->assertEquals($expected, $this->matcher->ipv4Address());
@@ -375,15 +325,9 @@ public function testIpv4Address()
public function testIpv6Address()
{
$expected = [
- 'data' => [
- 'generate' => '::ffff:192.0.2.128',
- 'matcher' => [
- 'json_class' => 'Regexp',
- 'o' => 0,
- 's' => '^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$',
- ],
- ],
- 'json_class' => 'Pact::Term',
+ 'value' => '::ffff:192.0.2.128',
+ 'regex' => '^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$',
+ 'pact:matcher:type' => 'regex',
];
$this->assertEquals($expected, $this->matcher->ipv6Address());
diff --git a/tests/PhpPact/Consumer/Model/ConsumerRequestTest.php b/tests/PhpPact/Consumer/Model/ConsumerRequestTest.php
index 4e760bbe..f30aeca7 100644
--- a/tests/PhpPact/Consumer/Model/ConsumerRequestTest.php
+++ b/tests/PhpPact/Consumer/Model/ConsumerRequestTest.php
@@ -15,16 +15,16 @@ public function testSerializing()
->setMethod('PUT')
->setPath('/somepath')
->addHeader('Content-Type', 'application/json')
+ ->addQueryParameter('fruit', ['apple', 'banana'])
->setBody([
'currentCity' => 'Austin',
]);
- $data = \json_decode(\json_encode($model->jsonSerialize()), true);
-
- $this->assertEquals('PUT', $data['method']);
- $this->assertEquals('application/json', $data['headers']['Content-Type']);
- $this->assertEquals('/somepath', $data['path']);
- $this->assertEquals('Austin', $data['body']['currentCity']);
+ $this->assertEquals('PUT', $model->getMethod());
+ $this->assertEquals(['Content-Type' => ['application/json']], $model->getHeaders());
+ $this->assertEquals(['fruit' => ['apple', 'banana']], $model->getQuery());
+ $this->assertEquals('/somepath', $model->getPath());
+ $this->assertEquals('{"currentCity":"Austin"}', $model->getBody());
}
public function testSerializingWhenPathUsingMatcher()
@@ -36,17 +36,15 @@ public function testSerializingWhenPathUsingMatcher()
->setMethod('PATCH')
->setPath($matcher->regex("/somepath/$pathVariable/status", '\/somepath\/[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\/status'))
->addHeader('Content-Type', 'application/json')
+ ->addQueryParameter('food', 'milk')
->setBody([
'status' => 'finished',
]);
- $data = \json_decode(\json_encode($model->jsonSerialize()), true);
-
- $this->assertEquals('PATCH', $data['method']);
- $this->assertEquals('application/json', $data['headers']['Content-Type']);
- $this->assertIsArray($data['path']);
- $this->assertArrayHasKey('data', $data['path']);
- $this->assertArrayHasKey('json_class', $data['path']);
- $this->assertEquals('finished', $data['body']['status']);
+ $this->assertEquals('PATCH', $model->getMethod());
+ $this->assertEquals(['Content-Type' => ['application/json']], $model->getHeaders());
+ $this->assertEquals(['food' => ['milk']], $model->getQuery());
+ $this->assertEquals('{"value":"\/somepath\/474d610b-c6e3-45bd-9f70-529e7ad21df0\/status","regex":"\\\\\\/somepath\\\\\\/[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\\\\\\/status","pact:matcher:type":"regex"}', $model->getPath());
+ $this->assertEquals('{"status":"finished"}', $model->getBody());
}
}
diff --git a/tests/PhpPact/Consumer/Model/ProviderResponseTest.php b/tests/PhpPact/Consumer/Model/ProviderResponseTest.php
index 49e2c7f1..2da664be 100644
--- a/tests/PhpPact/Consumer/Model/ProviderResponseTest.php
+++ b/tests/PhpPact/Consumer/Model/ProviderResponseTest.php
@@ -17,10 +17,8 @@ public function testSerializing()
'currentCity' => 'Austin',
]);
- $data = \json_decode(\json_encode($model->jsonSerialize()), true);
-
- $this->assertEquals(200, $data['status']);
- $this->assertEquals('application/json', $data['headers']['Content-Type']);
- $this->assertEquals('Austin', $data['body']['currentCity']);
+ $this->assertEquals(200, $model->getStatus());
+ $this->assertEquals(['Content-Type' => ['application/json']], $model->getHeaders());
+ $this->assertEquals('{"currentCity":"Austin"}', $model->getBody());
}
}
diff --git a/tests/PhpPact/Standalone/Broker/BrokerConfigTest.php b/tests/PhpPact/Standalone/Broker/BrokerConfigTest.php
index 8a35baf3..2e799e12 100644
--- a/tests/PhpPact/Standalone/Broker/BrokerConfigTest.php
+++ b/tests/PhpPact/Standalone/Broker/BrokerConfigTest.php
@@ -2,42 +2,87 @@
namespace PhpPactTest\Standalone\Broker;
-use PhpPact\Standalone\MockService\MockServerConfig;
+use GuzzleHttp\Psr7\Uri;
+use PhpPact\Standalone\Broker\BrokerConfig;
use PHPUnit\Framework\TestCase;
class BrokerConfigTest extends TestCase
{
public function testSetters()
{
- $host = 'test-host';
- $port = 1234;
- $provider = 'test-provider';
- $consumer = 'test-consumer';
- $pactDir = 'test-pact-dir/';
- $pactFileWriteMode = 'merge';
- $log = 'test-log-dir/';
- $cors = true;
- $pactSpecificationVersion = 2.0;
-
- $subject = (new MockServerConfig())
- ->setHost($host)
- ->setPort($port)
- ->setProvider($provider)
+ $brokerUri = new Uri('http://localhost');
+ $brokerToken = 'abc-123';
+ $brokerUsername = 'user';
+ $brokerPassword = 'pass';
+
+ $verbose = true;
+ $pacticipant = 'a pacticipant';
+
+ $request = 'POST';
+ $header = 'Accept application/json';
+ $data = '{"key": "value"}';
+ $user = 'username:password';
+ $url = 'https://example.org/webhook';
+ $consumer = 'test-consumer';
+ $provider = 'test-provider';
+ $description = 'an example webhook';
+ $uuid = 'd2181b32-8b03-4daf-8cc0-d9168b2f6fac';
+
+ $version = '1.2.3';
+ $branch = 'new-feature';
+ $tag = 'prod';
+
+ $name = 'My Project';
+ $repositoryUrl = 'https://github.com/vendor/my-project';
+
+ $consumerVersion = '1.1.2';
+ $pactLocations = '/path/to/pacts';
+
+ $subject = (new BrokerConfig())
+ ->setBrokerUri($brokerUri)
+ ->setBrokerToken($brokerToken)
+ ->setBrokerUsername($brokerUsername)
+ ->setBrokerPassword($brokerPassword)
+ ->setVerbose($verbose)
+ ->setPacticipant($pacticipant)
+ ->setRequest($request)
+ ->setHeader($header)
+ ->setData($data)
+ ->setUser($user)
+ ->setUrl($url)
->setConsumer($consumer)
- ->setPactDir($pactDir)
- ->setPactFileWriteMode($pactFileWriteMode)
- ->setLog($log)
- ->setPactSpecificationVersion($pactSpecificationVersion)
- ->setCors($cors);
-
- static::assertSame($host, $subject->getHost());
- static::assertSame($port, $subject->getPort());
- static::assertSame($provider, $subject->getProvider());
+ ->setProvider($provider)
+ ->setDescription($description)
+ ->setUuid($uuid)
+ ->setVersion($version)
+ ->setBranch($branch)
+ ->setTag($tag)
+ ->setName($name)
+ ->setRepositoryUrl($repositoryUrl)
+ ->setConsumerVersion($consumerVersion)
+ ->setPactLocations($pactLocations);
+
+ static::assertSame($brokerUri, $subject->getBrokerUri());
+ static::assertSame($brokerToken, $subject->getBrokerToken());
+ static::assertSame($brokerUsername, $subject->getBrokerUsername());
+ static::assertSame($brokerPassword, $subject->getBrokerPassword());
+ static::assertSame($verbose, $subject->isVerbose());
+ static::assertSame($pacticipant, $subject->getPacticipant());
+ static::assertSame($request, $subject->getRequest());
+ static::assertSame($header, $subject->getHeader());
+ static::assertSame($data, $subject->getData());
+ static::assertSame($user, $subject->getUser());
+ static::assertSame($url, $subject->getUrl());
static::assertSame($consumer, $subject->getConsumer());
- static::assertSame($pactDir, $subject->getPactDir());
- static::assertSame($pactFileWriteMode, $subject->getPactFileWriteMode());
- static::assertSame($log, $subject->getLog());
- static::assertSame($pactSpecificationVersion, $subject->getPactSpecificationVersion());
- static::assertSame($cors, $subject->hasCors());
+ static::assertSame($provider, $subject->getProvider());
+ static::assertSame($description, $subject->getDescription());
+ static::assertSame($uuid, $subject->getUuid());
+ static::assertSame($version, $subject->getVersion());
+ static::assertSame($branch, $subject->getBranch());
+ static::assertSame($tag, $subject->getTag());
+ static::assertSame($name, $subject->getName());
+ static::assertSame($repositoryUrl, $subject->getRepositoryUrl());
+ static::assertSame($consumerVersion, $subject->getConsumerVersion());
+ static::assertSame($pactLocations, $subject->getPactLocations());
}
}
diff --git a/tests/PhpPact/Standalone/MockServer/MockServerConfigTest.php b/tests/PhpPact/Standalone/MockServer/MockServerConfigTest.php
index 60dcad2b..419461b5 100644
--- a/tests/PhpPact/Standalone/MockServer/MockServerConfigTest.php
+++ b/tests/PhpPact/Standalone/MockServer/MockServerConfigTest.php
@@ -16,8 +16,7 @@ public function testSetters()
$pactDir = 'test-pact-dir/';
$pactFileWriteMode = 'merge';
$log = 'test-log-dir/';
- $cors = true;
- $pactSpecificationVersion = 2.0;
+ $pactSpecificationVersion = '2.0.0';
$subject = (new MockServerConfig())
->setHost($host)
@@ -27,8 +26,7 @@ public function testSetters()
->setPactDir($pactDir)
->setPactFileWriteMode($pactFileWriteMode)
->setLog($log)
- ->setPactSpecificationVersion($pactSpecificationVersion)
- ->setCors($cors);
+ ->setPactSpecificationVersion($pactSpecificationVersion);
static::assertSame($host, $subject->getHost());
static::assertSame($port, $subject->getPort());
@@ -38,6 +36,5 @@ public function testSetters()
static::assertSame($pactFileWriteMode, $subject->getPactFileWriteMode());
static::assertSame($log, $subject->getLog());
static::assertSame($pactSpecificationVersion, $subject->getPactSpecificationVersion());
- static::assertSame($cors, $subject->hasCors());
}
}
diff --git a/tests/PhpPact/Standalone/MockServer/MockServerTest.php b/tests/PhpPact/Standalone/MockServer/MockServerTest.php
deleted file mode 100644
index 6d356742..00000000
--- a/tests/PhpPact/Standalone/MockServer/MockServerTest.php
+++ /dev/null
@@ -1,68 +0,0 @@
-start();
- $this->assertTrue(\is_int($pid));
- } finally {
- $result = $mockServer->stop();
- $this->assertTrue($result);
- }
- }
-
- /**
- * @throws MissingEnvVariableException
- * @throws \Exception
- */
- public function testStartAndStopWithRecognizedTimeout()
- {
- // the mock server actually takes more than one second to be ready
- // we use this fact to test the timeout
- $orig = \getenv('PACT_MOCK_SERVER_HEALTH_CHECK_TIMEOUT');
- \putenv('PACT_MOCK_SERVER_HEALTH_CHECK_TIMEOUT=1');
-
- $httpService = $this->getMockBuilder(MockServerHttpService::class)
- ->disableOriginalConstructor()
- ->getMock();
-
- $connectionException = $this->getMockBuilder(ConnectionException::class)
- ->disableOriginalConstructor()
- ->getMock();
-
- // take sth lower than the default value
- $httpService->expects($this->atMost(5))
- ->method('healthCheck')
- ->will($this->returnCallback(function () use ($connectionException) {
- throw $connectionException;
- }));
-
- try {
- $mockServer = new MockServer(new MockServerEnvConfig(), $httpService);
- $mockServer->start();
- $this->fail('MockServer should not pass defined health check.');
- } catch (HealthCheckFailedException $e) {
- $this->assertTrue(true);
- } finally {
- $mockServer->stop();
- \putenv('PACT_MOCK_SERVER_HEALTH_CHECK_TIMEOUT=' . $orig);
- }
- }
-}
diff --git a/tests/PhpPact/Standalone/MockServer/Service/MockServerHttpServiceTest.php b/tests/PhpPact/Standalone/MockServer/Service/MockServerHttpServiceTest.php
deleted file mode 100644
index 9f831646..00000000
--- a/tests/PhpPact/Standalone/MockServer/Service/MockServerHttpServiceTest.php
+++ /dev/null
@@ -1,212 +0,0 @@
-config = new MockServerEnvConfig();
- $this->mockServer = new MockServer($this->config);
- $this->mockServer->start();
- $this->service = new MockServerHttpService(new GuzzleClient(), $this->config);
- }
-
- protected function tearDown(): void
- {
- $this->mockServer->stop();
- }
-
- /**
- * @throws ConnectionException
- */
- public function testHealthCheck()
- {
- $result = $this->service->healthCheck();
- $this->assertTrue($result);
- }
-
- public function testRegisterInteraction()
- {
- $request = new ConsumerRequest();
- $request
- ->setPath('/example')
- ->setMethod('GET');
- $response = new ProviderResponse();
- $response->setStatus(200);
-
- $interaction = new Interaction();
- $interaction
- ->setDescription('Fake description')
- ->setProviderState('Fake provider state')
- ->setRequest($request)
- ->setResponse($response);
-
- $result = $this->service->registerInteraction($interaction);
-
- $this->assertTrue($result);
- }
-
- public function testDeleteAllInteractions()
- {
- $result = $this->service->deleteAllInteractions();
- $this->assertTrue($result);
- }
-
- public function testVerifyInteractions()
- {
- $result = $this->service->verifyInteractions();
- $this->assertTrue($result);
- }
-
- public function testVerifyInteractionsFailure()
- {
- $request = new ConsumerRequest();
- $request
- ->setPath('/example')
- ->setMethod('GET');
-
- $response = new ProviderResponse();
- $response->setStatus(200);
-
- $interaction = new Interaction();
- $interaction
- ->setDescription('Some description')
- ->setProviderState('Some state')
- ->setRequest($request)
- ->setResponse($response);
- $this->service->registerInteraction($interaction);
-
- $this->expectException(ServerException::class);
- $result = $this->service->verifyInteractions();
- $this->assertFalse($result);
- }
-
- public function testGetPactJson()
- {
- $result = $this->service->getPactJson();
- $this->assertEquals('{"consumer":{"name":"someConsumer"},"provider":{"name":"someProvider"},"interactions":[],"metadata":{"pactSpecification":{"version":"2.0.0"}}}', $result);
- }
-
- public function testFullGetInteraction()
- {
- $request = new ConsumerRequest();
- $request
- ->setPath('/example')
- ->setMethod('GET')
- ->setQuery('enabled=true')
- ->addQueryParameter('order', 'asc')
- ->addQueryParameter('value', '12')
- ->addHeader('Content-Type', 'application/json');
-
- $expectedResponseBody = [
- 'message' => 'Hello, world!',
- ];
- $response = new ProviderResponse();
- $response
- ->setStatus(200)
- ->setBody($expectedResponseBody)
- ->addHeader('Content-Type', 'application/json');
-
- $interaction = new Interaction();
- $interaction
- ->setDescription('Fake description')
- ->setProviderState('Fake provider state')
- ->setRequest($request)
- ->setResponse($response);
-
- $result = $this->service->registerInteraction($interaction);
-
- $this->assertTrue($result);
-
- $client = new GuzzleClient();
- $uri = $this->config->getBaseUri()->withPath('/example')->withQuery('enabled=true&order=asc&value=12');
- $response = $client->get($uri, [
- 'headers' => [
- 'Content-Type' => 'application/json',
- ],
- ]);
-
- $body = $response->getBody()->getContents();
- $this->assertEquals(\json_encode($expectedResponseBody), $body);
- $this->assertEquals($response->getHeaderLine('Access-Control-Allow-Origin'), '*', 'CORS flag not set properly');
- $this->assertEquals(200, $response->getStatusCode());
- }
-
- /**
- * @throws MissingEnvVariableException
- * @throws \Exception
- */
- public function testMatcherWithMockServer()
- {
- $matcher = new Matcher();
-
- $category = new stdClass();
- $category->name = $matcher->term('Games', '[gbBG]');
-
- $request = new ConsumerRequest();
- $request
- ->setPath('/test')
- ->setMethod('GET');
-
- $response = new ProviderResponse();
- $response
- ->setStatus(200)
- ->addHeader('Content-Type', 'application/json')
- ->setBody([
- 'results' => $matcher->eachLike($category),
- ]);
-
- $config = new MockServerEnvConfig();
- $interaction = new InteractionBuilder($config);
- $interaction
- ->given('Something')
- ->uponReceiving('Stuff')
- ->with($request)
- ->willRespondWith($response);
-
- $client = new GuzzleClient();
- $uri = $this->config->getBaseUri()->withPath('/test');
- $client->get($uri, [
- 'headers' => [
- 'Content-Type' => 'application/json',
- ],
- ]);
-
- $httpClient = new MockServerHttpService(new GuzzleClient(), $config);
-
- $pact = \json_decode($httpClient->getPactJson(), true);
-
- $this->assertArrayHasKey('$.body.results[*].name', $pact['interactions'][0]['response']['matchingRules']);
- }
-}
diff --git a/tests/PhpPact/Standalone/PactConfigTest.php b/tests/PhpPact/Standalone/PactConfigTest.php
new file mode 100644
index 00000000..42db4851
--- /dev/null
+++ b/tests/PhpPact/Standalone/PactConfigTest.php
@@ -0,0 +1,66 @@
+config = new PactConfig();
+ }
+
+ public function testSetters(): void
+ {
+ $provider = 'test-provider';
+ $consumer = 'test-consumer';
+ $pactDir = 'test-pact-dir/';
+ $pactSpecificationVersion = '2.0.0';
+ $log = 'test-log-dir/';
+ $logLevel = 'ERROR';
+ $pactFileWriteMode = 'merge';
+
+ $this->config
+ ->setProvider($provider)
+ ->setConsumer($consumer)
+ ->setPactDir($pactDir)
+ ->setPactSpecificationVersion($pactSpecificationVersion)
+ ->setLog($log)
+ ->setLogLevel($logLevel)
+ ->setPactFileWriteMode($pactFileWriteMode);
+
+ static::assertSame($provider, $this->config->getProvider());
+ static::assertSame($consumer, $this->config->getConsumer());
+ static::assertSame($pactDir, $this->config->getPactDir());
+ static::assertSame($pactSpecificationVersion, $this->config->getPactSpecificationVersion());
+ static::assertSame($log, $this->config->getLog());
+ static::assertSame($logLevel, $this->config->getLogLevel());
+ static::assertSame($pactFileWriteMode, $this->config->getPactFileWriteMode());
+ }
+
+ public function testInvalidPactSpecificationVersion(): void
+ {
+ $this->expectException(\UnexpectedValueException::class);
+ $this->expectExceptionMessage('Invalid version string "invalid"');
+ $this->config->setPactSpecificationVersion('invalid');
+ }
+
+ public function testInvalidLogLevel(): void
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('LogLevel TRACE not supported.');
+ $this->config->setLogLevel('TRACE');
+ }
+
+ public function testInvalidPactFileWriteMode(): void
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage("Invalid PhpPact File Write Mode, value must be one of the following: overwrite, merge.");
+ $this->config->setPactFileWriteMode('APPEND');
+ }
+}