From a378890875b07997d24d479aff1017755d5368cf Mon Sep 17 00:00:00 2001 From: "tien.xuan.vo" Date: Fri, 30 Aug 2024 15:36:22 +0700 Subject: [PATCH 1/2] feat: Allow add custom provider headers --- .../tests/Service/HttpClient.php | 2 +- docs/provider.md | 16 ++++++++ .../InteractionDriverInterface.php | 1 - .../Model/Config/CustomHeaders.php | 39 +++++++++++++++++++ .../Model/Config/CustomHeadersInterface.php | 18 +++++++++ .../ProviderVerifier/Model/VerifierConfig.php | 16 ++++++++ .../Model/VerifierConfigInterface.php | 5 +++ .../Standalone/ProviderVerifier/Verifier.php | 13 +++++++ .../Model/VerifierConfigTest.php | 4 ++ .../ProviderVerifier/VerifierTest.php | 16 ++++++++ 10 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 src/PhpPact/Standalone/ProviderVerifier/Model/Config/CustomHeaders.php create mode 100644 src/PhpPact/Standalone/ProviderVerifier/Model/Config/CustomHeadersInterface.php diff --git a/compatibility-suite/tests/Service/HttpClient.php b/compatibility-suite/tests/Service/HttpClient.php index 4e23d64c..2810b7e4 100644 --- a/compatibility-suite/tests/Service/HttpClient.php +++ b/compatibility-suite/tests/Service/HttpClient.php @@ -41,7 +41,7 @@ private function formatQueryString(array $query): string { $result = []; - foreach($query as $key => $values) { + foreach ($query as $key => $values) { foreach ($values as $value) { $result[] = urlencode($key) . '=' . urlencode($value); } diff --git a/docs/provider.md b/docs/provider.md index 9245a5ae..0fc9ede5 100644 --- a/docs/provider.md +++ b/docs/provider.md @@ -60,6 +60,22 @@ public function testPactVerifyConsumers(): void } ``` +## Add Custom Headers Prior to Verification + +Sometimes you may need to add custom headers to the requests that can't be persisted in a pact file. +e.g. an OAuth bearer token: `Authorization: Bearer 1a2b3c4d5e6f7g8h9i0k` + +```php +$config->getCustomHeaders() + ->addHeader('Authorization', 'Bearer 1a2b3c4d5e6f7g8h9i0k'); +``` + +The requests will have custom headers added before being sent to the Provider API. + +> Note: Custom headers are not the only approach for authentication and authorization. For other approaches, please refer to this [documentation](https://docs.pact.io/provider/handling_auth#4-modify-the-request-to-use-real-credentials). + +> **Important Note:** You should only use this feature for headers that can not be persisted in the pact file. By modifying the request, you are potentially modifying the contract from the consumer tests! + ## Verification Sources There are four ways to verify Pact files. See the examples below. diff --git a/src/PhpPact/Consumer/Driver/Interaction/InteractionDriverInterface.php b/src/PhpPact/Consumer/Driver/Interaction/InteractionDriverInterface.php index 5b592473..4fc5ce3f 100644 --- a/src/PhpPact/Consumer/Driver/Interaction/InteractionDriverInterface.php +++ b/src/PhpPact/Consumer/Driver/Interaction/InteractionDriverInterface.php @@ -3,7 +3,6 @@ namespace PhpPact\Consumer\Driver\Interaction; use PhpPact\Consumer\Model\Interaction; - use PhpPact\Standalone\MockService\Model\VerifyResult; interface InteractionDriverInterface extends DriverInterface diff --git a/src/PhpPact/Standalone/ProviderVerifier/Model/Config/CustomHeaders.php b/src/PhpPact/Standalone/ProviderVerifier/Model/Config/CustomHeaders.php new file mode 100644 index 00000000..c5027869 --- /dev/null +++ b/src/PhpPact/Standalone/ProviderVerifier/Model/Config/CustomHeaders.php @@ -0,0 +1,39 @@ + + */ + private array $headers = []; + + /** + * @param array $headers + */ + public function setHeaders(array $headers): self + { + $this->headers = []; + foreach ($headers as $name => $value) { + $this->addHeader($name, $value); + } + + return $this; + } + + public function addHeader(string $name, string $value): self + { + $this->headers[$name] = $value; + + return $this; + } + + /** + * @return array + */ + public function getHeaders(): array + { + return $this->headers; + } +} diff --git a/src/PhpPact/Standalone/ProviderVerifier/Model/Config/CustomHeadersInterface.php b/src/PhpPact/Standalone/ProviderVerifier/Model/Config/CustomHeadersInterface.php new file mode 100644 index 00000000..723c2de4 --- /dev/null +++ b/src/PhpPact/Standalone/ProviderVerifier/Model/Config/CustomHeadersInterface.php @@ -0,0 +1,18 @@ + $headers + */ + public function setHeaders(array $headers): self; + + public function addHeader(string $name, string $value): self; + + /** + * @return array + */ + public function getHeaders(): array; +} diff --git a/src/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfig.php b/src/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfig.php index 209d9c1b..8167f078 100644 --- a/src/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfig.php +++ b/src/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfig.php @@ -7,6 +7,8 @@ use PhpPact\Standalone\ProviderVerifier\Model\Config\CallingAppInterface; use PhpPact\Standalone\ProviderVerifier\Model\Config\ConsumerFilters; use PhpPact\Standalone\ProviderVerifier\Model\Config\ConsumerFiltersInterface; +use PhpPact\Standalone\ProviderVerifier\Model\Config\CustomHeaders; +use PhpPact\Standalone\ProviderVerifier\Model\Config\CustomHeadersInterface; use PhpPact\Standalone\ProviderVerifier\Model\Config\FilterInfo; use PhpPact\Standalone\ProviderVerifier\Model\Config\FilterInfoInterface; use PhpPact\Standalone\ProviderVerifier\Model\Config\ProviderInfo; @@ -35,6 +37,7 @@ class VerifierConfig implements VerifierConfigInterface private VerificationOptionsInterface $verificationOptions; private ?PublishOptionsInterface $publishOptions = null; private ConsumerFiltersInterface $consumerFilters; + private CustomHeadersInterface $customHeaders; public function __construct() { @@ -44,6 +47,7 @@ public function __construct() $this->providerState = new ProviderState(); $this->verificationOptions = new VerificationOptions(); $this->consumerFilters = new ConsumerFilters(); + $this->customHeaders = new CustomHeaders(); } public function setCallingApp(CallingAppInterface $callingApp): self @@ -162,4 +166,16 @@ public function getVerificationOptions(): VerificationOptionsInterface { return $this->verificationOptions; } + + public function setCustomHeaders(CustomHeadersInterface $customHeaders): self + { + $this->customHeaders = $customHeaders; + + return $this; + } + + public function getCustomHeaders(): CustomHeadersInterface + { + return $this->customHeaders; + } } diff --git a/src/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfigInterface.php b/src/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfigInterface.php index bad14ed8..a2803a66 100644 --- a/src/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfigInterface.php +++ b/src/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfigInterface.php @@ -4,6 +4,7 @@ use PhpPact\Standalone\ProviderVerifier\Model\Config\CallingAppInterface; use PhpPact\Standalone\ProviderVerifier\Model\Config\ConsumerFiltersInterface; +use PhpPact\Standalone\ProviderVerifier\Model\Config\CustomHeadersInterface; use PhpPact\Standalone\ProviderVerifier\Model\Config\FilterInfoInterface; use PhpPact\Standalone\ProviderVerifier\Model\Config\ProviderInfoInterface; use PhpPact\Standalone\ProviderVerifier\Model\Config\ProviderStateInterface; @@ -58,4 +59,8 @@ public function getVerificationOptions(): VerificationOptionsInterface; public function getLogLevel(): ?string; public function setLogLevel(string $logLevel): self; + + public function setCustomHeaders(CustomHeadersInterface $customHeaders): self; + + public function getCustomHeaders(): CustomHeadersInterface; } diff --git a/src/PhpPact/Standalone/ProviderVerifier/Verifier.php b/src/PhpPact/Standalone/ProviderVerifier/Verifier.php index 5d6918a8..d5b132a1 100644 --- a/src/PhpPact/Standalone/ProviderVerifier/Verifier.php +++ b/src/PhpPact/Standalone/ProviderVerifier/Verifier.php @@ -27,6 +27,7 @@ public function __construct(VerifierConfigInterface $config, private ?LoggerInte $this->setVerificationOptions($config); $this->setPublishOptions($config); $this->setConsumerFilters($config); + $this->setCustomHeaders($config); $this->setLogLevel($config); } @@ -125,6 +126,18 @@ private function setConsumerFilters(VerifierConfigInterface $config): void ); } + private function setCustomHeaders(VerifierConfigInterface $config): void + { + foreach ($config->getCustomHeaders()->getHeaders() as $name => $value) { + $this->client->call( + 'pactffi_verifier_add_custom_header', + $this->handle, + $name, + $value + ); + } + } + private function setLogLevel(VerifierConfigInterface $config): void { if ($logLevel = $config->getLogLevel()) { diff --git a/tests/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfigTest.php b/tests/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfigTest.php index c0df7af9..b8b4f8e9 100644 --- a/tests/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfigTest.php +++ b/tests/PhpPact/Standalone/ProviderVerifier/Model/VerifierConfigTest.php @@ -4,6 +4,7 @@ use PhpPact\Standalone\ProviderVerifier\Model\Config\CallingApp; use PhpPact\Standalone\ProviderVerifier\Model\Config\ConsumerFilters; +use PhpPact\Standalone\ProviderVerifier\Model\Config\CustomHeaders; use PhpPact\Standalone\ProviderVerifier\Model\Config\FilterInfo; use PhpPact\Standalone\ProviderVerifier\Model\Config\ProviderInfo; use PhpPact\Standalone\ProviderVerifier\Model\Config\ProviderState; @@ -29,6 +30,7 @@ public function testSetters(): void new ProviderTransport(), new ProviderTransport(), ]; + $customHeaders = new CustomHeaders(); $subject = new VerifierConfig(); $subject->setCallingApp($callingApp); @@ -39,6 +41,7 @@ public function testSetters(): void $subject->setPublishOptions($publishOptions); $subject->setConsumerFilters($consumerFilters); $subject->setProviderTransports($providerTransports); + $subject->setCustomHeaders($customHeaders); $this->assertSame($callingApp, $subject->getCallingApp()); $this->assertSame($providerInfo, $subject->getProviderInfo()); @@ -49,5 +52,6 @@ public function testSetters(): void $this->assertSame($publishOptions, $subject->getPublishOptions()); $this->assertSame($consumerFilters, $subject->getConsumerFilters()); $this->assertSame($providerTransports, $subject->getProviderTransports()); + $this->assertSame($customHeaders, $subject->getCustomHeaders()); } } diff --git a/tests/PhpPact/Standalone/ProviderVerifier/VerifierTest.php b/tests/PhpPact/Standalone/ProviderVerifier/VerifierTest.php index 661f45b6..8584107c 100644 --- a/tests/PhpPact/Standalone/ProviderVerifier/VerifierTest.php +++ b/tests/PhpPact/Standalone/ProviderVerifier/VerifierTest.php @@ -79,6 +79,8 @@ private function setUpCalls(bool $hasProviderTags = true, bool $hasFilterConsume $this->config->setPublishOptions($publishOptions); $this->config->getConsumerFilters() ->setFilterConsumerNames($filterConsumerNames = $hasFilterConsumerNames ? ['http-consumer-1', 'http-consumer-2', 'message-consumer-2'] : []); + $this->config->getCustomHeaders() + ->setHeaders($customHeaders = ['name-1' => 'value-1', 'name-2' => 'value-2']); $this->config->setLogLevel($logLevel = 'info'); $this->calls = [ ['pactffi_verifier_new_for_application', $callingAppName, $callingAppVersion, $this->handle], @@ -104,6 +106,20 @@ private function setUpCalls(bool $hasProviderTags = true, bool $hasFilterConsume $hasFilterConsumerNames ? count($filterConsumerNames) : null, null ], + [ + 'pactffi_verifier_add_custom_header', + $this->handle, + 'name-1', + $customHeaders['name-1'], + null, + ], + [ + 'pactffi_verifier_add_custom_header', + $this->handle, + 'name-2', + $customHeaders['name-2'], + null, + ], ['pactffi_init_with_log_level', strtoupper($logLevel), null], ]; } From 5349c2e989fca241172e725a8f1baba20633f18f Mon Sep 17 00:00:00 2001 From: "tien.xuan.vo" Date: Wed, 4 Sep 2024 11:14:26 +0700 Subject: [PATCH 2/2] docs: Add custom header upgrade in v10 --- UPGRADE-10.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/UPGRADE-10.0.md b/UPGRADE-10.0.md index 1c73212c..abcb1625 100644 --- a/UPGRADE-10.0.md +++ b/UPGRADE-10.0.md @@ -45,6 +45,7 @@ This migrates from a CLI driven process for the Pact Framework, to an FFI proces - `addUrl` - Verify Provider by Pact Url retrieved by Broker (Webhooks) - `addBroker` Verify Provider by dynamically fetched Pacts (Provider change) - `addFile` / `addDir` - Verify Provider by local file or directory + - `$config->addCustomProviderHeader("headerName", "headerValue")` is now available via `$config->getCustomHeaders()->addHeader("headerName", "headerValue")` Example Usage: