[Messenger] Add StackInterface, allowing to unstack the call stack

This commit is contained in:
Nicolas Grekas 2018-10-18 13:31:58 +02:00
parent 5ae0e8910f
commit 2bc7d11ad3
21 changed files with 231 additions and 155 deletions

View File

@ -15,6 +15,7 @@ use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
/**
* Wraps all handlers in a single doctrine transaction.
@ -35,7 +36,7 @@ class DoctrineTransactionMiddleware implements MiddlewareInterface
/**
* {@inheritdoc}
*/
public function handle(Envelope $envelope, callable $next): void
public function handle(Envelope $envelope, StackInterface $stack): void
{
$entityManager = $this->managerRegistry->getManager($this->entityManagerName);
@ -45,7 +46,7 @@ class DoctrineTransactionMiddleware implements MiddlewareInterface
$entityManager->getConnection()->beginTransaction();
try {
$next($envelope);
$stack->next()->handle($envelope, $stack);
$entityManager->flush();
$entityManager->getConnection()->commit();
} catch (\Throwable $exception) {

View File

@ -7,7 +7,7 @@ CHANGELOG
* The component is not experimental anymore
* All the changes below are BC BREAKS
* `MessageBusInterface::dispatch()` and `MiddlewareInterface::handle()` now return `void`
* `MiddlewareInterface::handle()` now require an `Envelope` as first argument
* `MiddlewareInterface::handle()` now require an `Envelope` as first argument and a `StackInterface` as second
* `EnvelopeAwareInterface` has been removed
* The signature of `Amqp*` classes changed to take a `Connection` as a first argument and an optional
`Serializer` as a second argument.
@ -16,7 +16,6 @@ CHANGELOG
Instead, it accepts the sender instance itself instead of its identifier in the container.
* `MessageSubscriberInterface::getHandledMessages()` return value has changed. The value of an array item
needs to be an associative array or the method name.
* `ValidationMiddleware::handle()` and `SendMessageMiddleware::handle()` now require an `Envelope` object
* `StampInterface` replaces `EnvelopeItemInterface` and doesn't extend `Serializable` anymore
* The `ConsumeMessagesCommand` class now takes an instance of `Psr\Container\ContainerInterface`
as first constructor argument

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Messenger;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackMiddleware;
/**
* @author Samuel Roze <samuel.roze@gmail.com>
@ -64,14 +65,8 @@ class MessageBus implements MessageBusInterface
if (!$middlewareIterator->valid()) {
return;
}
$next = static function (Envelope $envelope) use ($middlewareIterator, &$next) {
$middlewareIterator->next();
$stack = new StackMiddleware($middlewareIterator);
if ($middlewareIterator->valid()) {
$middlewareIterator->current()->handle($envelope, $next);
}
};
$middlewareIterator->current()->handle($message instanceof Envelope ? $message : new Envelope($message), $next);
$middlewareIterator->current()->handle($message instanceof Envelope ? $message : new Envelope($message), $stack);
}
}

View File

@ -35,12 +35,12 @@ class ActivationMiddleware implements MiddlewareInterface
/**
* {@inheritdoc}
*/
public function handle(Envelope $envelope, callable $next): void
public function handle(Envelope $envelope, StackInterface $stack): void
{
if (\is_callable($this->activated) ? ($this->activated)($envelope) : $this->activated) {
$this->inner->handle($envelope, $next);
$this->inner->handle($envelope, $stack);
} else {
$next($envelope);
$stack->next()->handle($envelope, $stack);
}
}
}

View File

@ -34,11 +34,11 @@ class HandleMessageMiddleware implements MiddlewareInterface
*
* @throws NoHandlerForMessageException When no handler is found and $allowNoHandlers is false
*/
public function handle(Envelope $envelope, callable $next): void
public function handle(Envelope $envelope, StackInterface $stack): void
{
if (null !== $handler = $this->messageHandlerLocator->getHandler($envelope)) {
$handler($envelope->getMessage());
$next($envelope);
$stack->next()->handle($envelope, $stack);
} elseif (!$this->allowNoHandlers) {
throw new NoHandlerForMessageException(sprintf('No handler for message "%s".', \get_class($envelope->getMessage())));
}

View File

@ -29,7 +29,7 @@ class LoggingMiddleware implements MiddlewareInterface
/**
* {@inheritdoc}
*/
public function handle(Envelope $envelope, callable $next): void
public function handle(Envelope $envelope, StackInterface $stack): void
{
$message = $envelope->getMessage();
$context = array(
@ -39,7 +39,7 @@ class LoggingMiddleware implements MiddlewareInterface
$this->logger->debug('Starting handling message {name}', $context);
try {
$next($envelope);
$stack->next()->handle($envelope, $stack);
} catch (\Throwable $e) {
$context['exception'] = $e;
$this->logger->warning('An exception occurred while handling message {name}', $context);

View File

@ -18,16 +18,5 @@ use Symfony\Component\Messenger\Envelope;
*/
interface MiddlewareInterface
{
/**
* @param callable|NextInterface $next
*/
public function handle(Envelope $envelope, callable $next): void;
}
/**
* @internal
*/
interface NextInterface
{
public function __invoke(Envelope $envelope): void;
public function handle(Envelope $envelope, StackInterface $stack): void;
}

View File

@ -34,11 +34,11 @@ class SendMessageMiddleware implements MiddlewareInterface
/**
* {@inheritdoc}
*/
public function handle(Envelope $envelope, callable $next): void
public function handle(Envelope $envelope, StackInterface $stack): void
{
if ($envelope->get(ReceivedStamp::class)) {
// It's a received message. Do not send it back:
$next($envelope);
$stack->next()->handle($envelope, $stack);
return;
}
@ -54,6 +54,6 @@ class SendMessageMiddleware implements MiddlewareInterface
}
}
$next($envelope);
$stack->next()->handle($envelope, $stack);
}
}

View File

@ -0,0 +1,23 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Messenger\Middleware;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
interface StackInterface
{
/**
* Returns the next middleware to process a message.
*/
public function next(): MiddlewareInterface;
}

View File

@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Messenger\Middleware;
use Symfony\Component\Messenger\Envelope;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class StackMiddleware implements MiddlewareInterface, StackInterface
{
private $middlewareIterator;
public function __construct(\Iterator $middlewareIterator = null)
{
$this->middlewareIterator = $middlewareIterator;
}
public function next(): MiddlewareInterface
{
if (null === $iterator = $this->middlewareIterator) {
return $this;
}
$iterator->next();
if (!$iterator->valid()) {
$this->middlewareIterator = null;
return $this;
}
return $iterator->current();
}
public function handle(Envelope $envelope, StackInterface $stack): void
{
// no-op: this is the last null middleware
}
}

View File

@ -37,7 +37,7 @@ class TraceableMiddleware implements MiddlewareInterface
/**
* {@inheritdoc}
*/
public function handle(Envelope $envelope, callable $next): void
public function handle(Envelope $envelope, StackInterface $stack): void
{
$class = \get_class($this->inner);
$eventName = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
@ -49,11 +49,7 @@ class TraceableMiddleware implements MiddlewareInterface
$this->stopwatch->start($eventName, $this->eventCategory);
try {
$this->inner->handle($envelope, function (Envelope $envelope) use ($next, $eventName) {
$this->stopwatch->stop($eventName);
$next($envelope);
$this->stopwatch->start($eventName, $this->eventCategory);
});
$this->inner->handle($envelope, new TraceableInnerMiddleware($stack, $this->stopwatch, $eventName, $this->eventCategory));
} finally {
if ($this->stopwatch->isStarted($eventName)) {
$this->stopwatch->stop($eventName);
@ -61,3 +57,44 @@ class TraceableMiddleware implements MiddlewareInterface
}
}
}
/**
* @internal
*/
class TraceableInnerMiddleware implements MiddlewareInterface, StackInterface
{
private $stack;
private $stopwatch;
private $eventName;
private $eventCategory;
public function __construct(StackInterface $stack, Stopwatch $stopwatch, string $eventName, string $eventCategory)
{
$this->stack = $stack;
$this->stopwatch = $stopwatch;
$this->eventName = $eventName;
$this->eventCategory = $eventCategory;
}
/**
* {@inheritdoc}
*/
public function handle(Envelope $envelope, StackInterface $stack): void
{
$this->stopwatch->stop($this->eventName);
if ($this === $stack) {
$this->stack->next()->handle($envelope, $this->stack);
} else {
$stack->next()->handle($envelope, $stack);
}
$this->stopwatch->start($this->eventName, $this->eventCategory);
}
/**
* {@inheritdoc}
*/
public function next(): MiddlewareInterface
{
return $this;
}
}

View File

@ -31,7 +31,7 @@ class ValidationMiddleware implements MiddlewareInterface
/**
* {@inheritdoc}
*/
public function handle(Envelope $envelope, callable $next): void
public function handle(Envelope $envelope, StackInterface $stack): void
{
$message = $envelope->getMessage();
$groups = null;
@ -45,6 +45,6 @@ class ValidationMiddleware implements MiddlewareInterface
throw new ValidationFailedException($message, $violations);
}
$next($envelope);
$stack->next()->handle($envelope, $stack);
}
}

View File

@ -29,6 +29,7 @@ use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
use Symfony\Component\Messenger\Tests\Fixtures\DummyCommand;
use Symfony\Component\Messenger\Tests\Fixtures\DummyCommandHandler;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
@ -846,8 +847,8 @@ class HandlerOnUndefinedBus implements MessageSubscriberInterface
class UselessMiddleware implements MiddlewareInterface
{
public function handle(Envelope $message, callable $next): void
public function handle(Envelope $message, StackInterface $stack): void
{
$next($message);
$stack->next()->handle($message, $stack);
}
}

View File

@ -48,8 +48,8 @@ class MessageBusTest extends TestCase
$firstMiddleware->expects($this->once())
->method('handle')
->with($envelope, $this->anything())
->will($this->returnCallback(function ($envelope, $next) {
$next($envelope);
->will($this->returnCallback(function ($envelope, $stack) {
$stack->next()->handle($envelope, $stack);
}));
$secondMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();
@ -76,16 +76,16 @@ class MessageBusTest extends TestCase
$firstMiddleware->expects($this->once())
->method('handle')
->with($envelope, $this->anything())
->will($this->returnCallback(function ($envelope, $next) {
$next($envelope->with(new AnEnvelopeStamp()));
->will($this->returnCallback(function ($envelope, $stack) {
$stack->next()->handle($envelope->with(new AnEnvelopeStamp()), $stack);
}));
$secondMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();
$secondMiddleware->expects($this->once())
->method('handle')
->with($envelopeWithAnotherStamp, $this->anything())
->will($this->returnCallback(function ($envelope, $next) {
$next($envelope);
->will($this->returnCallback(function ($envelope, $stack) {
$stack->next()->handle($envelope, $stack);
}));
$thirdMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();
@ -115,8 +115,8 @@ class MessageBusTest extends TestCase
$firstMiddleware->expects($this->once())
->method('handle')
->with($envelope, $this->anything())
->will($this->returnCallback(function ($message, $next) use ($expectedEnvelope) {
$next($expectedEnvelope);
->will($this->returnCallback(function ($envelope, $stack) use ($expectedEnvelope) {
$stack->next()->handle($expectedEnvelope, $stack);
}));
$secondMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();

View File

@ -11,31 +11,31 @@
namespace Symfony\Component\Messenger\Tests\Middleware;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Middleware\ActivationMiddleware;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
/**
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*/
class ActivationMiddlewareTest extends TestCase
class ActivationMiddlewareTest extends MiddlewareTestCase
{
public function testExecuteMiddlewareOnActivated()
{
$message = new DummyMessage('Hello');
$envelope = new Envelope($message);
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$next->expects($this->never())->method('__invoke');
$stack = $this->createMock(StackInterface::class);
$stack->expects($this->never())->method('next');
$middleware = $this->createMock(MiddlewareInterface::class);
$middleware->expects($this->once())->method('handle')->with($envelope, $next);
$middleware->expects($this->once())->method('handle')->with($envelope, $stack);
$decorator = new ActivationMiddleware($middleware, true);
$decorator->handle($envelope, $next);
$decorator->handle($envelope, $stack);
}
public function testExecuteMiddlewareOnActivatedWithCallable()
@ -46,15 +46,15 @@ class ActivationMiddlewareTest extends TestCase
$activated = $this->createPartialMock(\stdClass::class, array('__invoke'));
$activated->expects($this->once())->method('__invoke')->with($envelope)->willReturn(true);
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$next->expects($this->never())->method('__invoke');
$stack = $this->createMock(StackInterface::class);
$stack->expects($this->never())->method('next');
$middleware = $this->createMock(MiddlewareInterface::class);
$middleware->expects($this->once())->method('handle')->with($envelope, $next);
$middleware->expects($this->once())->method('handle')->with($envelope, $stack);
$decorator = new ActivationMiddleware($middleware, $activated);
$decorator->handle($envelope, $next);
$decorator->handle($envelope, $stack);
}
public function testExecuteMiddlewareOnDeactivated()
@ -62,14 +62,11 @@ class ActivationMiddlewareTest extends TestCase
$message = new DummyMessage('Hello');
$envelope = new Envelope($message);
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$next->expects($this->once())->method('__invoke')->with($envelope);
$middleware = $this->createMock(MiddlewareInterface::class);
$middleware->expects($this->never())->method('handle');
$decorator = new ActivationMiddleware($middleware, false);
$decorator->handle($envelope, $next);
$decorator->handle($envelope, $this->getStackMock());
}
}

View File

@ -11,13 +11,13 @@
namespace Symfony\Component\Messenger\Tests\Middleware;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Handler\Locator\HandlerLocator;
use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware;
use Symfony\Component\Messenger\Middleware\StackMiddleware;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
class HandleMessageMiddlewareTest extends TestCase
class HandleMessageMiddlewareTest extends MiddlewareTestCase
{
public function testItCallsTheHandlerAndNextMiddleware()
{
@ -26,16 +26,13 @@ class HandleMessageMiddlewareTest extends TestCase
$handler = $this->createPartialMock(\stdClass::class, array('__invoke'));
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$middleware = new HandleMessageMiddleware(new HandlerLocator(array(
DummyMessage::class => $handler,
)));
$handler->expects($this->once())->method('__invoke')->with($message);
$next->expects($this->once())->method('__invoke')->with($envelope);
$middleware->handle($envelope, $next);
$middleware->handle($envelope, $this->getStackMock());
}
/**
@ -46,13 +43,13 @@ class HandleMessageMiddlewareTest extends TestCase
{
$middleware = new HandleMessageMiddleware(new HandlerLocator(array()));
$middleware->handle(new Envelope(new DummyMessage('Hey')), function () {});
$middleware->handle(new Envelope(new DummyMessage('Hey')), new StackMiddleware());
}
public function testAllowNoHandlers()
{
$middleware = new HandleMessageMiddleware(new HandlerLocator(array()), true);
$this->assertNull($middleware->handle(new Envelope(new DummyMessage('Hey')), function () {}));
$this->assertNull($middleware->handle(new Envelope(new DummyMessage('Hey')), new StackMiddleware()));
}
}

View File

@ -11,13 +11,13 @@
namespace Symfony\Component\Messenger\Tests\Middleware;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Middleware\LoggingMiddleware;
use Symfony\Component\Messenger\Middleware\StackInterface;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
class LoggingMiddlewareTest extends TestCase
class LoggingMiddlewareTest extends MiddlewareTestCase
{
public function testDebugLogAndNextMiddleware()
{
@ -29,14 +29,8 @@ class LoggingMiddlewareTest extends TestCase
->expects($this->exactly(2))
->method('debug')
;
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$next
->expects($this->once())
->method('__invoke')
->with($envelope)
;
(new LoggingMiddleware($logger))->handle($envelope, $next);
(new LoggingMiddleware($logger))->handle($envelope, $this->getStackMock());
}
/**
@ -56,14 +50,13 @@ class LoggingMiddlewareTest extends TestCase
->expects($this->once())
->method('warning')
;
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$next
$stack = $this->createMock(StackInterface::class);
$stack
->expects($this->once())
->method('__invoke')
->with($envelope)
->method('next')
->willThrowException(new \Exception())
;
(new LoggingMiddleware($logger))->handle($envelope, $next);
(new LoggingMiddleware($logger))->handle($envelope, $stack);
}
}

View File

@ -0,0 +1,37 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Messenger\Tests\Middleware;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
abstract class MiddlewareTestCase extends TestCase
{
protected function getStackMock(bool $nextIsCalled = true)
{
$nextMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock();
$nextMiddleware
->expects($nextIsCalled ? $this->once() : $this->never())
->method('handle')
;
$stack = $this->createMock(StackInterface::class);
$stack
->expects($nextIsCalled ? $this->once() : $this->never())
->method('next')
->willReturn($nextMiddleware)
;
return $stack;
}
}

View File

@ -11,8 +11,8 @@
namespace Symfony\Component\Messenger\Tests\Middleware;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\SendMessageMiddleware;
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
use Symfony\Component\Messenger\Tests\Fixtures\ChildDummyMessage;
@ -21,35 +21,31 @@ use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageInterface;
use Symfony\Component\Messenger\Transport\Sender\Locator\SenderLocatorInterface;
use Symfony\Component\Messenger\Transport\Sender\SenderInterface;
class SendMessageMiddlewareTest extends TestCase
class SendMessageMiddlewareTest extends MiddlewareTestCase
{
public function testItSendsTheMessageToAssignedSender()
{
$message = new DummyMessage('Hey');
$envelope = new Envelope($message);
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender));
$sender->expects($this->once())->method('send')->with($envelope);
$next->expects($this->never())->method($this->anything());
$middleware->handle($envelope, $next);
$middleware->handle($envelope, $this->getStackMock(false));
}
public function testItSendsTheMessageToAssignedSenderWithPreWrappedMessage()
{
$envelope = new Envelope(new DummyMessage('Hey'));
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender));
$sender->expects($this->once())->method('send')->with($envelope);
$next->expects($this->never())->method($this->anything());
$middleware->handle($envelope, $next);
$middleware->handle($envelope, $this->getStackMock(false));
}
public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageClass()
@ -57,16 +53,14 @@ class SendMessageMiddlewareTest extends TestCase
$message = new DummyMessage('Hey');
$envelope = new Envelope($message);
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array(
DummyMessage::class => true,
));
$sender->expects($this->once())->method('send')->with($envelope);
$next->expects($this->once())->method($this->anything());
$middleware->handle($envelope, $next);
$middleware->handle($envelope, $this->getStackMock());
}
public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageParentClass()
@ -74,16 +68,14 @@ class SendMessageMiddlewareTest extends TestCase
$message = new ChildDummyMessage('Hey');
$envelope = new Envelope($message);
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array(
DummyMessage::class => true,
));
$sender->expects($this->once())->method('send')->with($envelope);
$next->expects($this->once())->method($this->anything());
$middleware->handle($envelope, $next);
$middleware->handle($envelope, $this->getStackMock());
}
public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageInterface()
@ -91,16 +83,14 @@ class SendMessageMiddlewareTest extends TestCase
$message = new DummyMessage('Hey');
$envelope = new Envelope($message);
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array(
DummyMessageInterface::class => true,
));
$sender->expects($this->once())->method('send')->with($envelope);
$next->expects($this->once())->method($this->anything());
$middleware->handle($envelope, $next);
$middleware->handle($envelope, $this->getStackMock());
}
public function testItAlsoCallsTheNextMiddlewareBasedOnWildcard()
@ -108,29 +98,25 @@ class SendMessageMiddlewareTest extends TestCase
$message = new DummyMessage('Hey');
$envelope = new Envelope($message);
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender), array(
'*' => true,
));
$sender->expects($this->once())->method('send')->with($envelope);
$next->expects($this->once())->method($this->anything());
$middleware->handle($envelope, $next);
$middleware->handle($envelope, $this->getStackMock());
}
public function testItCallsTheNextMiddlewareWhenNoSenderForThisMessage()
{
$message = new DummyMessage('Hey');
$envelope = new Envelope($message);
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$middleware = new SendMessageMiddleware(new InMemorySenderLocator(null));
$handler = $this->getMockBuilder(MiddlewareInterface::class)->getMock();
$next->expects($this->once())->method($this->anything());
$middleware->handle($envelope, $next);
$middleware->handle($envelope, $this->getStackMock());
}
public function testItSkipsReceivedMessages()
@ -138,14 +124,12 @@ class SendMessageMiddlewareTest extends TestCase
$envelope = (new Envelope(new DummyMessage('Hey')))->with(new ReceivedStamp());
$sender = $this->getMockBuilder(SenderInterface::class)->getMock();
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$middleware = new SendMessageMiddleware(new InMemorySenderLocator($sender));
$sender->expects($this->never())->method('send');
$next->expects($this->once())->method('__invoke')->with($envelope);
$middleware->handle($envelope, $next);
$middleware->handle($envelope, $this->getStackMock());
}
}

View File

@ -11,9 +11,9 @@
namespace Symfony\Component\Messenger\Tests\Middleware;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
use Symfony\Component\Messenger\Middleware\TraceableMiddleware;
use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
use Symfony\Component\Stopwatch\Stopwatch;
@ -21,7 +21,7 @@ use Symfony\Component\Stopwatch\Stopwatch;
/**
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
*/
class TraceableMiddlewareTest extends TestCase
class TraceableMiddlewareTest extends MiddlewareTestCase
{
public function testHandle()
{
@ -32,18 +32,11 @@ class TraceableMiddlewareTest extends TestCase
$middleware->expects($this->once())
->method('handle')
->with($envelope, $this->anything())
->will($this->returnCallback(function ($envelope, callable $next) {
$next($envelope);
->will($this->returnCallback(function ($envelope, StackInterface $stack) {
$stack->next()->handle($envelope, $stack);
}))
;
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$next
->expects($this->once())
->method('__invoke')
->with($envelope)
;
$stopwatch = $this->createMock(Stopwatch::class);
$stopwatch->expects($this->once())->method('isStarted')->willReturn(true);
$stopwatch->expects($this->exactly(2))
@ -57,7 +50,7 @@ class TraceableMiddlewareTest extends TestCase
$traced = new TraceableMiddleware($middleware, $stopwatch, $busId);
$traced->handle($envelope, $next);
$traced->handle($envelope, $this->getStackMock());
}
/**
@ -73,15 +66,15 @@ class TraceableMiddlewareTest extends TestCase
$middleware->expects($this->once())
->method('handle')
->with($envelope, $this->anything())
->will($this->returnCallback(function ($envelope, callable $next) {
$next($envelope);
->will($this->returnCallback(function ($envelope, StackInterface $stack) {
$stack->next()->handle($envelope, $stack);
}))
;
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$next
$stack = $this->createMock(StackInterface::class);
$stack
->expects($this->once())
->method('__invoke')
->method('next')
->willThrowException(new \RuntimeException('Foo exception from next callable'))
;
@ -98,6 +91,6 @@ class TraceableMiddlewareTest extends TestCase
;
$traced = new TraceableMiddleware($middleware, $stopwatch, $busId);
$traced->handle($envelope, $next);
$traced->handle($envelope, $stack);
}
}

View File

@ -11,7 +11,6 @@
namespace Symfony\Component\Messenger\Tests\Middleware;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Middleware\ValidationMiddleware;
use Symfony\Component\Messenger\Stamp\ValidationStamp;
@ -19,7 +18,7 @@ use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage;
use Symfony\Component\Validator\ConstraintViolationListInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
class ValidationMiddlewareTest extends TestCase
class ValidationMiddlewareTest extends MiddlewareTestCase
{
public function testValidateAndNextMiddleware()
{
@ -33,14 +32,8 @@ class ValidationMiddlewareTest extends TestCase
->with($message)
->willReturn($this->createMock(ConstraintViolationListInterface::class))
;
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$next
->expects($this->once())
->method('__invoke')
->with($envelope)
;
(new ValidationMiddleware($validator))->handle($envelope, $next);
(new ValidationMiddleware($validator))->handle($envelope, $this->getStackMock());
}
public function testValidateWithStampAndNextMiddleware()
@ -54,14 +47,8 @@ class ValidationMiddlewareTest extends TestCase
->with($message, null, $groups)
->willReturn($this->createMock(ConstraintViolationListInterface::class))
;
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$next
->expects($this->once())
->method('__invoke')
->with($envelope)
;
(new ValidationMiddleware($validator))->handle($envelope, $next);
(new ValidationMiddleware($validator))->handle($envelope, $this->getStackMock());
}
/**
@ -86,12 +73,7 @@ class ValidationMiddlewareTest extends TestCase
->with($message)
->willReturn($violationList)
;
$next = $this->createPartialMock(\stdClass::class, array('__invoke'));
$next
->expects($this->never())
->method('__invoke')
;
(new ValidationMiddleware($validator))->handle($envelope, $next);
(new ValidationMiddleware($validator))->handle($envelope, $this->getStackMock(false));
}
}