diff --git a/README.md b/README.md index 115e75a93..34602cf62 100644 --- a/README.md +++ b/README.md @@ -372,7 +372,7 @@ $consumerMessage = new ExampleMessageConsumer(); $callback = [$consumerMessage, 'ProcessSong']; $builder->setCallback($callback); -$builder->verify(); +$this->assertTrue($builder->verify()); ``` diff --git a/example/src/MessageConsumer/ExampleMessageConsumer.php b/example/src/MessageConsumer/ExampleMessageConsumer.php index 0a8219440..77851aa69 100644 --- a/example/src/MessageConsumer/ExampleMessageConsumer.php +++ b/example/src/MessageConsumer/ExampleMessageConsumer.php @@ -4,7 +4,7 @@ class ExampleMessageConsumer { - public function ProcessText($message) + public function ProcessText(string $message): object { $obj = \json_decode($message); print ' [x] Processed ' . \print_r($obj->contents->text, true) . "\n"; @@ -12,7 +12,7 @@ public function ProcessText($message) return $obj; } - public function ProcessSong($message) + public function ProcessSong(string $message): object { $obj = \json_decode($message); print ' [x] Processed ' . \print_r($obj->contents->song, true) . "\n"; diff --git a/example/tests/MessageConsumer/ExampleMessageConsumerTest.php b/example/tests/MessageConsumer/ExampleMessageConsumerTest.php index e9bda5d01..569733450 100644 --- a/example/tests/MessageConsumer/ExampleMessageConsumerTest.php +++ b/example/tests/MessageConsumer/ExampleMessageConsumerTest.php @@ -2,8 +2,6 @@ namespace MessageConsumer; -require_once __DIR__ . '/../../src/MessageConsumer/ExampleMessageConsumer.php'; - use Exception; use PhpPact\Consumer\MessageBuilder; use PhpPact\Config\PactConfigInterface; @@ -28,18 +26,6 @@ public static function setUpBeforeClass(): void ->setPactDir(__DIR__ . '/../../output/'); } - public static function tearDownAfterClass(): void - { - parent::tearDownAfterClass(); - - // build out brokerHttpService as your example - /* - $brokerHttpService = new BrokerHttpClient(new GuzzleClient(), new Uri($pactBrokerUri)); - $brokerHttpService->publishJson($json, $consumerVersion); - $brokerHttpService->tag($this->mockServerConfig->getConsumer(), $consumerVersion, $tag); - */ - } - /** * @throws Exception */ @@ -53,7 +39,7 @@ public function testProcessText() $metadata = ['queue'=>'wind cries', 'routing_key'=>'wind cries']; $builder - ->given('a message', ['foo']) + ->given('a message', ['foo' => 'bar']) ->expectsToReceive('an alligator named Mary exists') ->withMetadata($metadata) ->withContent($contents); @@ -63,11 +49,7 @@ public function testProcessText() $callback = [$consumerMessage, 'ProcessText']; $builder->setCallback($callback); - $hasException = false; - - $builder->verify(); - - $this->assertTrue(true, 'Expects to reach this true statement by running verify()'); + $this->assertTrue($builder->verify()); } /** @@ -93,14 +75,6 @@ public function testProcessSong() $callback = [$consumerMessage, 'ProcessSong']; $builder->setCallback($callback); - $hasException = false; - - try { - $builder->verify(); - } catch (Exception $e) { - $hasException = true; - } - - $this->assertFalse($hasException, 'Expects verification to pass without exceptions being thrown'); + $this->assertTrue($builder->verify()); } } diff --git a/src/PhpPact/Consumer/Driver/Interaction/MessageDriver.php b/src/PhpPact/Consumer/Driver/Interaction/MessageDriver.php new file mode 100644 index 000000000..251c1445e --- /dev/null +++ b/src/PhpPact/Consumer/Driver/Interaction/MessageDriver.php @@ -0,0 +1,32 @@ +id = $this->ffi->call('pactffi_new_message_interaction', $this->pactDriver->getId(), $description); + } + + /** + * {@inheritdoc} + */ + public function setMetadata(array $metadata): void + { + foreach ($metadata as $key => $value) { + $this->ffi->call('pactffi_message_with_metadata', $this->id, (string) $key, (string) $value); + } + } + + public function reify(): string + { + return $this->ffi->call('pactffi_message_reify', $this->id); + } + + public function update(): void + { + $this->pactDriver->writePact(); + $this->pactDriver->cleanUp(); + } +} diff --git a/src/PhpPact/Consumer/Driver/Interaction/MessageDriverInterface.php b/src/PhpPact/Consumer/Driver/Interaction/MessageDriverInterface.php new file mode 100644 index 000000000..15525b178 --- /dev/null +++ b/src/PhpPact/Consumer/Driver/Interaction/MessageDriverInterface.php @@ -0,0 +1,15 @@ + $metadata + */ + public function setMetadata(array $metadata): void; + + public function reify(): string; + + public function update(): void; +} diff --git a/src/PhpPact/Consumer/Factory/MessageRegistryFactory.php b/src/PhpPact/Consumer/Factory/MessageRegistryFactory.php new file mode 100644 index 000000000..0430fdce6 --- /dev/null +++ b/src/PhpPact/Consumer/Factory/MessageRegistryFactory.php @@ -0,0 +1,22 @@ +config = $config; - $this->message = new Message(); - $this->pactMessage = new PactMessage(); + $this->registry = $registry instanceof MessageRegistryInterface ? $registry : MessageRegistryFactory::create($registry); + $this->message = new Message(); } /** @@ -82,7 +82,7 @@ public function withMetadata(array $metadata): self * * @param mixed $contents required to be in the message */ - public function withContent($contents): self + public function withContent(mixed $contents): self { $this->message->setContents($contents); @@ -94,7 +94,7 @@ public function withContent($contents): self */ public function reify(): string { - return $this->pactMessage->reify($this->message); + return $this->registry->reify($this->message); } /** @@ -107,18 +107,16 @@ public function verifyMessage(callable $callback, ?string $description = null): { $this->setCallback($callback, $description); - return $this->verify($description); + return $this->verify(); } /** * Verify the use of the pact by calling the callback * It also calls finalize to write the pact * - * @param null|string $description description of the pact and thus callback - * * @throws \Exception if callback is not set */ - public function verify(?string $description = null): bool + public function verify(): bool { if (\count($this->callback) < 1) { throw new \Exception('Callbacks need to exist to run verify.'); @@ -141,13 +139,9 @@ public function verify(?string $description = null): bool /** * Write the Pact without deleting the interactions. - * @throws \JsonException */ public function writePact(): bool { - // you do not want to save the reified json - $pactJson = \json_encode($this->message, JSON_THROW_ON_ERROR); - - return $this->pactMessage->update($pactJson, $this->config->getConsumer(), $this->config->getProvider(), $this->config->getPactDir()); + return $this->registry->update(); } } diff --git a/src/PhpPact/Consumer/Model/Message.php b/src/PhpPact/Consumer/Model/Message.php index af2c047dd..1b8b3a4e1 100644 --- a/src/PhpPact/Consumer/Model/Message.php +++ b/src/PhpPact/Consumer/Model/Message.php @@ -14,7 +14,7 @@ class Message /** * @var array */ - private array $metadata; + private array $metadata = []; private mixed $contents; @@ -43,11 +43,19 @@ public function getMetadata(): array */ public function setMetadata(array $metadata): self { - $this->metadata = $metadata; + $this->metadata = []; + foreach ($metadata as $key => $value) { + $this->setMetadataValue($key, $value); + } return $this; } + private function setMetadataValue(string $key, string $value): void + { + $this->metadata[$key] = $value; + } + public function getContents(): mixed { return $this->contents; diff --git a/src/PhpPact/Consumer/Service/MessageRegistry.php b/src/PhpPact/Consumer/Service/MessageRegistry.php new file mode 100644 index 000000000..e84846312 --- /dev/null +++ b/src/PhpPact/Consumer/Service/MessageRegistry.php @@ -0,0 +1,81 @@ +newInteraction($message) + ->given($message) + ->expectsToReceive($message) + ->withMetadata($message) + ->withContent($message); + } + + private function newInteraction(Message $message): self + { + $this->driver->newInteraction($message->getDescription()); + + return $this; + } + + private function given(Message $message): self + { + $this->driver->setProviderStates($message->getProviderStates()); + + return $this; + } + + private function expectsToReceive(Message $message): self + { + $this->driver->setDescription($message->getDescription()); + + return $this; + } + + private function withMetadata(Message $message): self + { + $this->driver->setMetadata($message->getMetadata()); + + return $this; + } + + private function withContent(Message $message): self + { + if (\is_string($message->getContents())) { + $contents = $message->getContents(); + $contentType = 'text/plain'; + } else { + $contents = \json_encode($message->getContents(), JSON_THROW_ON_ERROR); + $contentType = 'application/json'; + } + + $this->driver->setBody(DriverInterface::REQUEST, $contentType, $contents); + + return $this; + } + + public function reify(Message $message): string + { + $this->registerMessage($message); + + return $this->driver->reify(); + } + + public function update(): bool + { + $this->driver->update(); + + return true; + } +} diff --git a/src/PhpPact/Consumer/Service/MessageRegistryInterface.php b/src/PhpPact/Consumer/Service/MessageRegistryInterface.php new file mode 100644 index 000000000..45dd8f990 --- /dev/null +++ b/src/PhpPact/Consumer/Service/MessageRegistryInterface.php @@ -0,0 +1,12 @@ +runBlocking(); - - $output = $process->getOutput(); - \preg_replace("/\r|\n/", '', $output); - - return $output; - } - - /** - * Update a pact with the given message, or create the pact if it does not exist. The MESSAGE_JSON may be in the legacy Ruby JSON format or the v2+ format. - */ - public function update(string $pactJson, string $consumer, string $provider, string $pactDir): bool - { - $arguments = []; - $arguments[] = 'update'; - $arguments[] = "--consumer={$consumer}"; - $arguments[] = "--provider={$provider}"; - $arguments[] = "--pact-dir={$pactDir}"; - $arguments[] = "'" . $pactJson . "'"; - - $process = new ProcessRunner(Scripts::getPactMessage(), $arguments); - $process->runBlocking(); - - \sleep(1); - - return true; - } -} diff --git a/tests/PhpPact/Consumer/Model/MessageTest.php b/tests/PhpPact/Consumer/Model/MessageTest.php new file mode 100644 index 000000000..165ed8a81 --- /dev/null +++ b/tests/PhpPact/Consumer/Model/MessageTest.php @@ -0,0 +1,34 @@ + 'bar']; + $metadata = ['queue' => 'foo', 'routing_key' => 'bar']; + $contents = 'test'; + + $subject = (new Message()) + ->setDescription($description) + ->addProviderState($providerStateName, $providerStateParams) + ->setMetadata($metadata) + ->setContents($contents); + + static::assertSame($description, $subject->getDescription()); + $providerStates = $subject->getProviderStates(); + static::assertCount(1, $providerStates); + static::assertContainsOnlyInstancesOf(ProviderState::class, $providerStates); + static::assertEquals($providerStateName, $providerStates[0]->getName()); + static::assertEquals($providerStateParams, $providerStates[0]->getParams()); + static::assertSame($metadata, $subject->getMetadata()); + static::assertSame($contents, $subject->getContents()); + } +}