Skip to content

Commit 594601c

Browse files
committed
Add Beanstalkd Messenger bridge
0 parents  commit 594601c

19 files changed

+1220
-0
lines changed

.gitattributes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/Tests export-ignore
2+
/phpunit.xml.dist export-ignore
3+
/.gitignore export-ignore

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.lock
3+
phpunit.xml

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CHANGELOG
2+
=========
3+
4+
5.2.0
5+
-----
6+
7+
* Introduced the Beanstalkd bridge.

LICENSE

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2018-2020 Fabien Potencier
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Beanstalkd Messenger
2+
====================
3+
4+
Provides Beanstalkd integration for Symfony Messenger.
5+
6+
Full DSN with options: `beanstalkd://<ip>:<port>?tube_name=<name>&timeout=<timeoutInSeconds>&ttr=<ttrInSeconds>`
7+
8+
Resources
9+
---------
10+
11+
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
12+
* [Report issues](https://github.com/symfony/symfony/issues) and
13+
[send Pull Requests](https://github.com/symfony/symfony/pulls)
14+
in the [main Symfony repository](https://github.com/symfony/symfony)

Tests/Fixtures/DummyMessage.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Symfony\Component\Messenger\Bridge\Beanstalkd\Tests\Fixtures;
4+
5+
class DummyMessage
6+
{
7+
private $message;
8+
9+
public function __construct(string $message)
10+
{
11+
$this->message = $message;
12+
}
13+
14+
public function getMessage(): string
15+
{
16+
return $this->message;
17+
}
18+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Messenger\Bridge\Beanstalkd\Tests\Transport;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Tests\Fixtures\DummyMessage;
16+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\BeanstalkdReceivedStamp;
17+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\BeanstalkdReceiver;
18+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\Connection;
19+
use Symfony\Component\Messenger\Exception\MessageDecodingFailedException;
20+
use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer;
21+
use Symfony\Component\Messenger\Transport\Serialization\Serializer;
22+
use Symfony\Component\Serializer as SerializerComponent;
23+
use Symfony\Component\Serializer\Encoder\JsonEncoder;
24+
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
25+
26+
final class BeanstalkdReceiverTest extends TestCase
27+
{
28+
public function testItReturnsTheDecodedMessageToTheHandler()
29+
{
30+
$serializer = $this->createSerializer();
31+
32+
$tube = 'foo bar';
33+
34+
$beanstalkdEnvelope = $this->createBeanstalkdEnvelope();
35+
$connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock();
36+
$connection->expects($this->once())->method('get')->willReturn($beanstalkdEnvelope);
37+
$connection->expects($this->once())->method('getTube')->willReturn($tube);
38+
39+
$receiver = new BeanstalkdReceiver($connection, $serializer);
40+
$actualEnvelopes = $receiver->get();
41+
$this->assertCount(1, $actualEnvelopes);
42+
$this->assertEquals(new DummyMessage('Hi'), $actualEnvelopes[0]->getMessage());
43+
44+
/** @var BeanstalkdReceivedStamp $receivedStamp */
45+
$receivedStamp = $actualEnvelopes[0]->last(BeanstalkdReceivedStamp::class);
46+
47+
$this->assertInstanceOf(BeanstalkdReceivedStamp::class, $receivedStamp);
48+
$this->assertSame('1', $receivedStamp->getId());
49+
$this->assertSame($tube, $receivedStamp->getTube());
50+
}
51+
52+
public function testItReturnsEmptyArrayIfThereAreNoMessages()
53+
{
54+
$serializer = $this->createSerializer();
55+
56+
$connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock();
57+
$connection->expects($this->once())->method('get')->willReturn(null);
58+
59+
$receiver = new BeanstalkdReceiver($connection, $serializer);
60+
$actualEnvelopes = $receiver->get();
61+
$this->assertIsArray($actualEnvelopes);
62+
$this->assertCount(0, $actualEnvelopes);
63+
}
64+
65+
public function testItRejectTheMessageIfThereIsAMessageDecodingFailedException()
66+
{
67+
$this->expectException(MessageDecodingFailedException::class);
68+
69+
$serializer = $this->createMock(PhpSerializer::class);
70+
$serializer->expects($this->once())->method('decode')->willThrowException(new MessageDecodingFailedException());
71+
72+
$beanstalkdEnvelope = $this->createBeanstalkdEnvelope();
73+
$connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock();
74+
$connection->expects($this->once())->method('get')->willReturn($beanstalkdEnvelope);
75+
$connection->expects($this->once())->method('reject');
76+
77+
$receiver = new BeanstalkdReceiver($connection, $serializer);
78+
$receiver->get();
79+
}
80+
81+
private function createBeanstalkdEnvelope(): array
82+
{
83+
return [
84+
'id' => '1',
85+
'body' => '{"message": "Hi"}',
86+
'headers' => [
87+
'type' => DummyMessage::class,
88+
],
89+
];
90+
}
91+
92+
private function createSerializer(): Serializer
93+
{
94+
$serializer = new Serializer(
95+
new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()])
96+
);
97+
98+
return $serializer;
99+
}
100+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Messenger\Bridge\Beanstalkd\Tests\Transport;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Tests\Fixtures\DummyMessage;
16+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\BeanstalkdSender;
17+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\Connection;
18+
use Symfony\Component\Messenger\Envelope;
19+
use Symfony\Component\Messenger\Stamp\DelayStamp;
20+
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
21+
22+
final class BeanstalkdSenderTest extends TestCase
23+
{
24+
public function testSend()
25+
{
26+
$envelope = new Envelope(new DummyMessage('Oy'));
27+
$encoded = ['body' => '...', 'headers' => ['type' => DummyMessage::class]];
28+
29+
$connection = $this->getMockBuilder(Connection::class)
30+
->disableOriginalConstructor()
31+
->getMock();
32+
$connection->expects($this->once())->method('send')->with($encoded['body'], $encoded['headers'], 0);
33+
34+
$serializer = $this->getMockBuilder(SerializerInterface::class)->getMock();
35+
$serializer->method('encode')->with($envelope)->willReturnOnConsecutiveCalls($encoded);
36+
37+
$sender = new BeanstalkdSender($connection, $serializer);
38+
$sender->send($envelope);
39+
}
40+
41+
public function testSendWithDelay()
42+
{
43+
$envelope = (new Envelope(new DummyMessage('Oy')))->with(new DelayStamp(500));
44+
$encoded = ['body' => '...', 'headers' => ['type' => DummyMessage::class]];
45+
46+
$connection = $this->createMock(Connection::class);
47+
$connection->expects($this->once())->method('send')->with($encoded['body'], $encoded['headers'], 500);
48+
49+
$serializer = $this->createMock(SerializerInterface::class);
50+
$serializer->method('encode')->with($envelope)->willReturnOnConsecutiveCalls($encoded);
51+
52+
$sender = new BeanstalkdSender($connection, $serializer);
53+
$sender->send($envelope);
54+
}
55+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Messenger\Bridge\Beanstalkd\Tests\Transport;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\BeanstalkdTransport;
16+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\BeanstalkdTransportFactory;
17+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\Connection;
18+
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
19+
20+
final class BeanstalkdTransportFactoryTest extends TestCase
21+
{
22+
public function testSupports()
23+
{
24+
$factory = new BeanstalkdTransportFactory();
25+
26+
$this->assertTrue($factory->supports('beanstalkd://127.0.0.1', []));
27+
$this->assertFalse($factory->supports('doctrine://127.0.0.1', []));
28+
}
29+
30+
public function testCreateTransport()
31+
{
32+
$factory = new BeanstalkdTransportFactory();
33+
$serializer = $this->createMock(SerializerInterface::class);
34+
35+
$this->assertEquals(
36+
new BeanstalkdTransport(Connection::fromDsn('beanstalkd://127.0.0.1'), $serializer),
37+
$factory->createTransport('beanstalkd://127.0.0.1', [], $serializer)
38+
);
39+
}
40+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Messenger\Bridge\Beanstalkd\Tests\Transport;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Tests\Fixtures\DummyMessage;
16+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\BeanstalkdTransport;
17+
use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\Connection;
18+
use Symfony\Component\Messenger\Envelope;
19+
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
20+
use Symfony\Component\Messenger\Transport\TransportInterface;
21+
22+
final class BeanstalkdTransportTest extends TestCase
23+
{
24+
public function testItIsATransport()
25+
{
26+
$transport = $this->getTransport();
27+
28+
$this->assertInstanceOf(TransportInterface::class, $transport);
29+
}
30+
31+
public function testReceivesMessages()
32+
{
33+
$transport = $this->getTransport(
34+
$serializer = $this->createMock(SerializerInterface::class),
35+
$connection = $this->createMock(Connection::class)
36+
);
37+
38+
$decodedMessage = new DummyMessage('Decoded.');
39+
40+
$beanstalkdEnvelope = [
41+
'id' => '5',
42+
'body' => 'body',
43+
'headers' => ['my' => 'header'],
44+
];
45+
46+
$serializer->method('decode')->with(['body' => 'body', 'headers' => ['my' => 'header']])->willReturn(new Envelope($decodedMessage));
47+
$connection->method('get')->willReturn($beanstalkdEnvelope);
48+
49+
$envelopes = $transport->get();
50+
$this->assertSame($decodedMessage, $envelopes[0]->getMessage());
51+
}
52+
53+
private function getTransport(SerializerInterface $serializer = null, Connection $connection = null): BeanstalkdTransport
54+
{
55+
$serializer = $serializer ?: $this->createMock(SerializerInterface::class);
56+
$connection = $connection ?: $this->createMock(Connection::class);
57+
58+
return new BeanstalkdTransport($connection, $serializer);
59+
}
60+
}

0 commit comments

Comments
 (0)