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 4, 2023
1 parent ff2120f commit fd71b2f
Show file tree
Hide file tree
Showing 13 changed files with 223 additions and 103 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ $consumerMessage = new ExampleMessageConsumer();
$callback = [$consumerMessage, 'ProcessSong'];
$builder->setCallback($callback);

$builder->verify();
$this->assertTrue($builder->verify());
```


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: 3 additions & 29 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,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());
}

/**
Expand All @@ -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());
}
}
32 changes: 32 additions & 0 deletions src/PhpPact/Consumer/Driver/Interaction/MessageDriver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace PhpPact\Consumer\Driver\Interaction;

class MessageDriver extends AbstractDriver implements MessageDriverInterface
{
public function newInteraction(string $description): void
{
$this->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();
}
}
15 changes: 15 additions & 0 deletions src/PhpPact/Consumer/Driver/Interaction/MessageDriverInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace PhpPact\Consumer\Driver\Interaction;

interface MessageDriverInterface extends DriverInterface
{
/**
* @param array<string, string> $metadata
*/
public function setMetadata(array $metadata): void;

public function reify(): string;

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

namespace PhpPact\Consumer\Factory;

use PhpPact\Consumer\Driver\Interaction\MessageDriver;
use PhpPact\Consumer\Driver\Pact\PactDriver;
use PhpPact\Config\PactConfigInterface;
use PhpPact\Consumer\Service\FFI;
use PhpPact\Consumer\Service\MessageRegistryInterface;
use PhpPact\Consumer\Service\MessageRegistry;

class MessageRegistryFactory
{
public static function create(PactConfigInterface $config): MessageRegistryInterface
{
$ffi = new FFI();
$pactDriver = new PactDriver($ffi, $config);
$messageDriver = new MessageDriver($ffi, $pactDriver);

return new MessageRegistry($messageDriver);
}
}
28 changes: 11 additions & 17 deletions src/PhpPact/Consumer/MessageBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

namespace PhpPact\Consumer;

use PhpPact\Consumer\Factory\MessageRegistryFactory;
use PhpPact\Consumer\Model\Message;
use PhpPact\Config\PactConfigInterface;
use PhpPact\Standalone\PactMessage\PactMessage;
use PhpPact\Consumer\Service\MessageRegistryInterface;

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

protected PactConfigInterface $config;

Expand All @@ -22,11 +23,10 @@ class MessageBuilder implements BuilderInterface

private Message $message;

public function __construct(PactConfigInterface $config)
public function __construct(PactConfigInterface|MessageRegistryInterface $registry)
{
$this->config = $config;
$this->message = new Message();
$this->pactMessage = new PactMessage();
$this->registry = $registry instanceof MessageRegistryInterface ? $registry : MessageRegistryFactory::create($registry);
$this->message = new Message();
}

/**
Expand Down Expand Up @@ -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);

Expand All @@ -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);
}

/**
Expand All @@ -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.');
Expand All @@ -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();
}
}
12 changes: 10 additions & 2 deletions src/PhpPact/Consumer/Model/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Message
/**
* @var array<string, string>
*/
private array $metadata;
private array $metadata = [];

private mixed $contents;

Expand Down Expand Up @@ -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;
Expand Down
81 changes: 81 additions & 0 deletions src/PhpPact/Consumer/Service/MessageRegistry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

namespace PhpPact\Consumer\Service;

use PhpPact\Consumer\Driver\Interaction\DriverInterface;
use PhpPact\Consumer\Driver\Interaction\MessageDriverInterface;
use PhpPact\Consumer\Model\Message;

class MessageRegistry implements MessageRegistryInterface
{
public function __construct(private MessageDriverInterface $driver)
{
}

public function registerMessage(Message $message): void
{
$this
->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;
}
}
12 changes: 12 additions & 0 deletions src/PhpPact/Consumer/Service/MessageRegistryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

namespace PhpPact\Consumer\Service;

use PhpPact\Consumer\Model\Message;

interface MessageRegistryInterface
{
public function reify(Message $pact): string;

public function update(): bool;
}
5 changes: 0 additions & 5 deletions src/PhpPact/Standalone/Installer/Model/Scripts.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ public static function getBroker(): string
return self::$destinationDir . '/bin/pact-ruby-standalone/bin/pact-broker' . self::getSuffix();
}

public static function getPactMessage(): string
{
return self::$destinationDir . '/bin/pact-ruby-standalone/bin/pact-message' . self::getSuffix();
}

private static function getSuffix(): string
{
return (PHP_OS_FAMILY === 'Windows' ? '.bat' : '');
Expand Down
Loading

0 comments on commit fd71b2f

Please sign in to comment.