Skip to content

Commit

Permalink
Use Rust FFI: Message Consumer
Browse files Browse the repository at this point in the history
  • Loading branch information
tienvx committed May 10, 2023
1 parent 3a3afda commit aa4b14e
Show file tree
Hide file tree
Showing 16 changed files with 362 additions and 158 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,9 @@ $consumerMessage = new ExampleMessageConsumer();
$callback = [$consumerMessage, 'ProcessSong'];
$builder->setCallback($callback);

$builder->verify();
$verifyResult = $builder->verify();

$this->assertTrue($verifyResult);
```


Expand Down
4 changes: 2 additions & 2 deletions example/src/MessageConsumer/ExampleMessageConsumer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@

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";

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";
Expand Down
32 changes: 5 additions & 27 deletions example/tests/MessageConsumer/ExampleMessageConsumerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

namespace MessageConsumer;

require_once __DIR__ . '/../../src/MessageConsumer/ExampleMessageConsumer.php';

use Exception;
use PhpPact\Consumer\MessageBuilder;
use PhpPact\Config\PactConfigInterface;
Expand All @@ -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
*/
Expand All @@ -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);
Expand All @@ -63,11 +49,9 @@ public function testProcessText()
$callback = [$consumerMessage, 'ProcessText'];
$builder->setCallback($callback);

$hasException = false;

$builder->verify();
$verifyResult = $builder->verify();

$this->assertTrue(true, 'Expects to reach this true statement by running verify()');
$this->assertTrue($verifyResult);
}

/**
Expand All @@ -93,14 +77,8 @@ public function testProcessSong()
$callback = [$consumerMessage, 'ProcessSong'];
$builder->setCallback($callback);

$hasException = false;

try {
$builder->verify();
} catch (Exception $e) {
$hasException = true;
}
$verifyResult = $builder->verify();

$this->assertFalse($hasException, 'Expects verification to pass without exceptions being thrown');
$this->assertTrue($verifyResult);
}
}
59 changes: 59 additions & 0 deletions src/PhpPact/Consumer/AbstractMessageBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

namespace PhpPact\Consumer;

use PhpPact\Consumer\Model\Message;

abstract class AbstractMessageBuilder implements BuilderInterface
{
protected Message $message;

public function __construct()
{
$this->message = new Message();
}

/**
* @param string $name what is given to the request
* @param array<string, string> $params for that request
* @param bool $overwrite clear pass states completely and start this array
*/
public function given(string $name, array $params = [], bool $overwrite = false): self
{
$this->message->setProviderState($name, $params, $overwrite);

return $this;
}

/**
* @param string $description what is received when the request is made
*/
public function expectsToReceive(string $description): self
{
$this->message->setDescription($description);

return $this;
}

/**
* @param array<string, string> $metadata what is the additional metadata of the message
*/
public function withMetadata(array $metadata): self
{
$this->message->setMetadata($metadata);

return $this;
}

/**
* Make the http request to the Mock Service to register the message. Content is required.
*
* @param mixed $contents required to be in the message
*/
public function withContent(mixed $contents): self
{
$this->message->setContents($contents);

return $this;
}
}
37 changes: 37 additions & 0 deletions src/PhpPact/Consumer/Driver/Interaction/MessageDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace PhpPact\Consumer\Driver\Interaction;

use PhpPact\Consumer\Driver\Pact\PactDriverInterface;
use PhpPact\Consumer\Model\Message;
use PhpPact\Consumer\Registry\Interaction\MessageRegistryInterface;
use PhpPact\FFI\ClientInterface;

class MessageDriver implements MessageDriverInterface
{
public function __construct(
private ClientInterface $client,
private PactDriverInterface $pactDriver,
private MessageRegistryInterface $messageRegistry
) {
}

public function reify(): string
{
return $this->client->call('pactffi_message_reify', $this->messageRegistry->getId());
}

public function writePactAndCleanUp(): bool
{
$this->pactDriver->writePact();
$this->pactDriver->cleanUp();

return true;
}

public function registerMessage(Message $message): void
{
$this->pactDriver->setUp();
$this->messageRegistry->registerMessage($message);
}
}
14 changes: 14 additions & 0 deletions src/PhpPact/Consumer/Driver/Interaction/MessageDriverInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace PhpPact\Consumer\Driver\Interaction;

use PhpPact\Consumer\Model\Message;

interface MessageDriverInterface
{
public function registerMessage(Message $message): void;

public function reify(): string;

public function writePactAndCleanUp(): bool;
}
24 changes: 24 additions & 0 deletions src/PhpPact/Consumer/Factory/MessageDriverFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace PhpPact\Consumer\Factory;

use PhpPact\Consumer\Driver\Interaction\MessageDriver;
use PhpPact\Consumer\Driver\Interaction\MessageDriverInterface;
use PhpPact\Consumer\Driver\Pact\PactDriver;
use PhpPact\Config\PactConfigInterface;
use PhpPact\Consumer\Registry\Interaction\MessageRegistry;
use PhpPact\Consumer\Registry\Pact\PactRegistry;
use PhpPact\FFI\Client;

class MessageDriverFactory
{
public static function create(PactConfigInterface $config): MessageDriverInterface
{
$client = new Client();
$pactRegistry = new PactRegistry($client);
$pactDriver = new PactDriver($client, $config, $pactRegistry);
$messageRegistry = new MessageRegistry($client, $pactRegistry);

return new MessageDriver($client, $pactDriver, $messageRegistry);
}
}
87 changes: 13 additions & 74 deletions src/PhpPact/Consumer/MessageBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,26 @@

namespace PhpPact\Consumer;

use PhpPact\Consumer\Model\Message;
use PhpPact\Consumer\Driver\Interaction\MessageDriverInterface;
use PhpPact\Config\PactConfigInterface;
use PhpPact\Standalone\PactMessage\PactMessage;
use PhpPact\Consumer\Factory\MessageDriverFactory;

/**
* Build a message and send it to the Ruby Standalone Mock Service
*/
class MessageBuilder implements BuilderInterface
class MessageBuilder extends AbstractMessageBuilder
{
protected PactMessage $pactMessage;

protected PactConfigInterface $config;
protected MessageDriverInterface $driver;

/**
* @var array<mixed, callable>
*/
protected array $callback;

private Message $message;

public function __construct(PactConfigInterface $config)
public function __construct(PactConfigInterface|MessageDriverInterface $driver)
{
$this->config = $config;
$this->message = new Message();
$this->pactMessage = new PactMessage();
parent::__construct();
$this->driver = $driver instanceof MessageDriverInterface ? $driver : MessageDriverFactory::create($driver);
}

/**
Expand All @@ -45,56 +40,14 @@ public function setCallback(callable $callback, ?string $description = null): se
return $this;
}

/**
* @param string $name what is given to the request
* @param array<string, string> $params for that request
* @param bool $overwrite clear pass states completely and start this array
*/
public function given(string $name, array $params = [], bool $overwrite = false): self
{
$this->message->setProviderState($name, $params, $overwrite);

return $this;
}

/**
* @param string $description what is received when the request is made
*/
public function expectsToReceive(string $description): self
{
$this->message->setDescription($description);

return $this;
}

/**
* @param array<string, string> $metadata what is the additional metadata of the message
*/
public function withMetadata(array $metadata): self
{
$this->message->setMetadata($metadata);

return $this;
}

/**
* Make the http request to the Mock Service to register the message. Content is required.
*
* @param mixed $contents required to be in the message
*/
public function withContent($contents): self
{
$this->message->setContents($contents);

return $this;
}

/**
* Run reify to create an example pact from the message (i.e. create messages from matchers)
*/
public function reify(): string
{
return $this->pactMessage->reify($this->message);
$this->driver->registerMessage($this->message);

return $this->driver->reify();
}

/**
Expand All @@ -107,18 +60,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.');
Expand All @@ -133,21 +84,9 @@ public function verify(?string $description = null): bool
\call_user_func($callback, $pactJson);
}

return $this->writePact();
return $this->driver->writePactAndCleanUp();
} catch (\Exception $e) {
return false;
}
}

/**
* 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());
}
}
Loading

0 comments on commit aa4b14e

Please sign in to comment.