Skip to content

Commit 3f3acb0

Browse files
authored
Add a writer that dispatch in a bus each item as message (#64)
* Replace MessageBusInterface mocks with test dummies * Add an item writer that will dispatch in a bus each written item as a message * Add DispatchEachItemAsMessageWriter in main doc * Remove phpspec/prophecy-phpunit dev dependency from packages that are no longer using it
1 parent 9460b82 commit 3f3acb0

9 files changed

+153
-39
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ composer require yokai/batch-symfony-messenger
2525
This package provides:
2626

2727
- a [job launcher](docs/job-launcher.md) that uses messages to launch jobs
28+
- a [writer](docs/dispatch-each-item-writer.md) that will write each item as a message
2829

2930

3031
## Contribution

composer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
}
2222
},
2323
"require-dev": {
24-
"phpspec/prophecy-phpunit": "^2.0",
2524
"phpunit/phpunit": "^9.5"
2625
},
2726
"autoload-dev": {

docs/dispatch-each-item-writer.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
todo \Yokai\Batch\Bridge\Symfony\Messenger\Writer\DispatchEachItemAsMessageWriter
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yokai\Batch\Bridge\Symfony\Messenger\Writer;
6+
7+
use Symfony\Component\Messenger\MessageBusInterface;
8+
use Yokai\Batch\Exception\UnexpectedValueException;
9+
use Yokai\Batch\Job\Item\ItemWriterInterface;
10+
use Yokai\Batch\Job\JobExecutionAwareInterface;
11+
use Yokai\Batch\Job\JobExecutionAwareTrait;
12+
13+
/**
14+
* This {@see ItemWriterInterface} will consider each written item to be a message.
15+
* Every item will be sent individually to a {@see MessageBusInterface}.
16+
*/
17+
final class DispatchEachItemAsMessageWriter implements ItemWriterInterface, JobExecutionAwareInterface
18+
{
19+
use JobExecutionAwareTrait;
20+
21+
public function __construct(
22+
private MessageBusInterface $messageBus,
23+
) {
24+
}
25+
26+
public function write(iterable $items): void
27+
{
28+
foreach ($items as $item) {
29+
if (!\is_object($item)) {
30+
throw UnexpectedValueException::type('object', $item);
31+
}
32+
$this->messageBus->dispatch($item);
33+
}
34+
}
35+
}

tests/DispatchMessageJobLauncherTest.php

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,25 @@
55
namespace Yokai\Batch\Tests\Bridge\Symfony\Messenger;
66

77
use PHPUnit\Framework\TestCase;
8-
use Prophecy\Argument;
9-
use Prophecy\PhpUnit\ProphecyTrait;
10-
use Symfony\Component\Messenger\Envelope;
118
use Symfony\Component\Messenger\Exception\TransportException;
12-
use Symfony\Component\Messenger\MessageBusInterface;
139
use Yokai\Batch\BatchStatus;
1410
use Yokai\Batch\Bridge\Symfony\Messenger\DispatchMessageJobLauncher;
1511
use Yokai\Batch\Bridge\Symfony\Messenger\LaunchJobMessage;
1612
use Yokai\Batch\Factory\JobExecutionFactory;
1713
use Yokai\Batch\Factory\UniqidJobExecutionIdGenerator;
1814
use Yokai\Batch\Test\Factory\SequenceJobExecutionIdGenerator;
1915
use Yokai\Batch\Test\Storage\InMemoryJobExecutionStorage;
16+
use Yokai\Batch\Tests\Bridge\Symfony\Messenger\Dummy\BufferingMessageBus;
17+
use Yokai\Batch\Tests\Bridge\Symfony\Messenger\Dummy\FailingMessageBus;
2018

2119
final class DispatchMessageJobLauncherTest extends TestCase
2220
{
23-
use ProphecyTrait;
24-
2521
public function testLaunch(): void
2622
{
27-
$messageBus = $this->prophesize(MessageBusInterface::class);
28-
$messageAssertions = Argument::that(
29-
static function ($message): bool {
30-
return $message instanceof LaunchJobMessage
31-
&& $message->getJobName() === 'testing'
32-
&& $message->getConfiguration() === ['_id' => '123456789', 'foo' => ['bar']];
33-
}
34-
);
35-
$messageBus->dispatch($messageAssertions)
36-
->shouldBeCalled()
37-
->willReturn(new Envelope(new LaunchJobMessage('unused')));
38-
3923
$jobLauncher = new DispatchMessageJobLauncher(
4024
new JobExecutionFactory(new UniqidJobExecutionIdGenerator()),
4125
$storage = new InMemoryJobExecutionStorage(),
42-
$messageBus->reveal()
26+
$messageBus = new BufferingMessageBus()
4327
);
4428

4529
$jobExecutionFromLauncher = $jobLauncher->launch('testing', ['_id' => '123456789', 'foo' => ['bar']]);
@@ -51,26 +35,15 @@ static function ($message): bool {
5135
self::assertSame('123456789', $jobExecutionFromStorage->getId());
5236
self::assertSame(BatchStatus::PENDING, $jobExecutionFromStorage->getStatus()->getValue());
5337
self::assertSame(['bar'], $jobExecutionFromStorage->getParameters()->get('foo'));
38+
self::assertJobWasTriggered($messageBus, 'testing', ['_id' => '123456789', 'foo' => ['bar']]);
5439
}
5540

5641
public function testLaunchWithNoId(): void
5742
{
58-
$messageBus = $this->prophesize(MessageBusInterface::class);
59-
$messageAssertions = Argument::that(
60-
static function ($message): bool {
61-
return $message instanceof LaunchJobMessage
62-
&& $message->getJobName() === 'testing'
63-
&& $message->getConfiguration() === ['_id' => '123456789'];
64-
}
65-
);
66-
$messageBus->dispatch($messageAssertions)
67-
->shouldBeCalled()
68-
->willReturn(new Envelope(new LaunchJobMessage('unused')));
69-
7043
$jobLauncher = new DispatchMessageJobLauncher(
7144
new JobExecutionFactory(new SequenceJobExecutionIdGenerator(['123456789'])),
7245
$storage = new InMemoryJobExecutionStorage(),
73-
$messageBus->reveal()
46+
$messageBus = new BufferingMessageBus()
7447
);
7548

7649
$jobExecutionFromLauncher = $jobLauncher->launch('testing');
@@ -81,19 +54,15 @@ static function ($message): bool {
8154
self::assertSame('testing', $jobExecutionFromStorage->getJobName());
8255
self::assertSame('123456789', $jobExecutionFromStorage->getId());
8356
self::assertSame(BatchStatus::PENDING, $jobExecutionFromStorage->getStatus()->getValue());
57+
self::assertJobWasTriggered($messageBus, 'testing', ['_id' => '123456789']);
8458
}
8559

8660
public function testLaunchAndMessengerFail(): void
8761
{
88-
$messageBus = $this->prophesize(MessageBusInterface::class);
89-
$messageBus->dispatch(Argument::any())
90-
->shouldBeCalled()
91-
->willThrow(new TransportException('This is a test'));
92-
9362
$jobLauncher = new DispatchMessageJobLauncher(
9463
new JobExecutionFactory(new UniqidJobExecutionIdGenerator()),
9564
$storage = new InMemoryJobExecutionStorage(),
96-
$messageBus->reveal()
65+
new FailingMessageBus(new TransportException('This is a test'))
9766
);
9867

9968
$jobExecutionFromLauncher = $jobLauncher->launch('testing');
@@ -108,4 +77,14 @@ public function testLaunchAndMessengerFail(): void
10877
self::assertSame(TransportException::class, $failure->getClass());
10978
self::assertSame('This is a test', $failure->getMessage());
11079
}
80+
81+
private static function assertJobWasTriggered(BufferingMessageBus $bus, string $jobName, array $config): void
82+
{
83+
$messages = $bus->getMessages();
84+
self::assertCount(1, $messages);
85+
$message = $messages[0];
86+
self::assertInstanceOf(LaunchJobMessage::class, $message);
87+
self::assertSame($jobName, $message->getJobName());
88+
self::assertSame($config, $message->getConfiguration());
89+
}
11190
}

tests/Dummy/BufferingMessageBus.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yokai\Batch\Tests\Bridge\Symfony\Messenger\Dummy;
6+
7+
use Symfony\Component\Messenger\Envelope;
8+
use Symfony\Component\Messenger\MessageBusInterface;
9+
10+
final class BufferingMessageBus implements MessageBusInterface
11+
{
12+
/**
13+
* @var Envelope[]
14+
*/
15+
private array $envelopes = [];
16+
17+
public function dispatch(object $message, array $stamps = []): Envelope
18+
{
19+
$this->envelopes[] = $envelope = new Envelope($message, $stamps);
20+
21+
return $envelope;
22+
}
23+
24+
/**
25+
* @return object[]
26+
*/
27+
public function getMessages(): array
28+
{
29+
return \array_map(fn (Envelope $envelope) => $envelope->getMessage(), $this->envelopes);
30+
}
31+
32+
/**
33+
* @return Envelope[]
34+
*/
35+
public function getEnvelopes(): array
36+
{
37+
return $this->envelopes;
38+
}
39+
}

tests/Dummy/DummyMessage.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yokai\Batch\Tests\Bridge\Symfony\Messenger\Dummy;
6+
7+
final class DummyMessage
8+
{
9+
}

tests/Dummy/FailingMessageBus.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yokai\Batch\Tests\Bridge\Symfony\Messenger\Dummy;
6+
7+
use Symfony\Component\Messenger\Envelope;
8+
use Symfony\Component\Messenger\Exception\ExceptionInterface;
9+
use Symfony\Component\Messenger\MessageBusInterface;
10+
11+
final class FailingMessageBus implements MessageBusInterface
12+
{
13+
public function __construct(
14+
private ExceptionInterface $exception,
15+
) {
16+
}
17+
18+
public function dispatch(object $message, array $stamps = []): Envelope
19+
{
20+
throw $this->exception;
21+
}
22+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yokai\Batch\Tests\Bridge\Symfony\Messenger\Writer;
6+
7+
use Yokai\Batch\Bridge\Symfony\Messenger\Writer\DispatchEachItemAsMessageWriter;
8+
use PHPUnit\Framework\TestCase;
9+
use Yokai\Batch\Exception\UnexpectedValueException;
10+
use Yokai\Batch\Tests\Bridge\Symfony\Messenger\Dummy\BufferingMessageBus;
11+
use Yokai\Batch\Tests\Bridge\Symfony\Messenger\Dummy\DummyMessage;
12+
13+
class DispatchEachItemAsMessageWriterTest extends TestCase
14+
{
15+
public function test(): void
16+
{
17+
$writer = new DispatchEachItemAsMessageWriter($messageBus = new BufferingMessageBus());
18+
$writer->write([$message1 = new DummyMessage(), $message2 = new DummyMessage()]);
19+
self::assertSame([$message1, $message2], $messageBus->getMessages());
20+
}
21+
22+
public function testInvalidItemType(): void
23+
{
24+
$this->expectException(UnexpectedValueException::class);
25+
$this->expectExceptionMessage('Expecting argument to be object, but got int.');
26+
$writer = new DispatchEachItemAsMessageWriter(new BufferingMessageBus());
27+
$writer->write([1]);
28+
}
29+
}

0 commit comments

Comments
 (0)