Completed
Pull Request — 3.x (#387)
by
unknown
01:53
created

testShouldSetExpectedDelayStrategyToAmqpConnectionFactoryOfInstanceDelayStrategyAware()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 9.552
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\NotificationBundle\Tests\Backend;
15
16
use Enqueue\AmqpLib\AmqpConnectionFactory;
17
use Interop\Amqp\AmqpContext;
18
use PHPUnit\Framework\TestCase;
19
use Sonata\NotificationBundle\Backend\AMQPBackend;
20
use Sonata\NotificationBundle\Backend\AMQPBackendDispatcher;
21
use Sonata\NotificationBundle\Exception\BackendNotFoundException;
22
use Sonata\NotificationBundle\Tests\Mock\AmqpConnectionFactoryDelayStrategyAwareStub;
23
use Sonata\NotificationBundle\Tests\Mock\AmqpConnectionFactoryStub;
24
use Sonata\NotificationBundle\Tests\Mock\AnyDelayStrategyStub;
25
26
class AMQPBackendDispatcherTest extends TestCase
27
{
28
    protected function setUp()
29
    {
30
        if (!class_exists(AmqpConnectionFactory::class)) {
31
            $this->markTestSkipped('enqueue/amqp-lib library is not installed');
32
        }
33
34
        AmqpConnectionFactoryStub::$config = null;
35
        AmqpConnectionFactoryStub::$context = null;
36
    }
37
38
    public function testThrowIfSettingsMissFactoryClassOptionOnGetContext()
39
    {
40
        $dispatcher = new AMQPBackendDispatcher([], [], 'default', []);
41
42
        $this->expectException(\LogicException::class);
43
        $this->expectExceptionMessage('The factory_class option is missing though it is required.');
44
        $dispatcher->getContext();
45
    }
46
47
    public function testThrowIfFactoryClassIsNotRealClass()
48
    {
49
        $dispatcher = new AMQPBackendDispatcher(['factory_class' => 'anInvalidClass'], [], 'default', []);
50
51
        $this->expectException(\LogicException::class);
52
        $this->expectExceptionMessage('The factory_class option "anInvalidClass" has to be valid class that implements "Interop\Amqp\AmqpConnectionFactory"');
53
        $dispatcher->getContext();
54
    }
55
56
    public function testThrowIfFactoryClassIsNotInstanceOfAmqpConnectionFactoryInterface()
57
    {
58
        $dispatcher = new AMQPBackendDispatcher(['factory_class' => \stdClass::class], [], 'default', []);
59
60
        $this->expectException(\LogicException::class);
61
        $this->expectExceptionMessage('The factory_class option "stdClass" has to be valid class that implements "Interop\Amqp\AmqpConnectionFactory"');
62
        $dispatcher->getContext();
63
    }
64
65
    public function testThrowIfDelayStrategyClassIsSetButNotRealClass(): void
66
    {
67
        $dispatcher = new AMQPBackendDispatcher(
68
            [
69
                'host' => 'theHost',
70
                'port' => 'thePort',
71
                'user' => 'theUser',
72
                'pass' => 'thePass',
73
                'vhost' => 'theVhost',
74
                'factory_class' => AmqpConnectionFactoryDelayStrategyAwareStub::class,
75
                'delay_strategy_class' => 'anInvalidClass',
76
            ],
77
            [], 'default',
78
            []
79
        );
80
81
        $this->expectException(\LogicException::class);
82
        $this->expectExceptionMessage('The delay_strategy_class option "anInvalidClass" has to be a valid class that implements "Enqueue\AmqpTools\DelayStrategy"');
83
        $dispatcher->getContext();
84
    }
85
86
    public function testThrowIfDelayStrategyClassIsSetButNotInstanceOfDelayStrategyInterface(): void
87
    {
88
        $dispatcher = new AMQPBackendDispatcher(
89
            [
90
                'host' => 'theHost',
91
                'port' => 'thePort',
92
                'user' => 'theUser',
93
                'pass' => 'thePass',
94
                'vhost' => 'theVhost',
95
                'factory_class' => AmqpConnectionFactoryDelayStrategyAwareStub::class,
96
                'delay_strategy_class' => \stdClass::class,
97
            ],
98
            [], 'default',
99
            []
100
        );
101
102
        $this->expectException(\LogicException::class);
103
        $this->expectExceptionMessage('The delay_strategy_class option "stdClass" has to be a valid class that implements "Enqueue\AmqpTools\DelayStrategy"');
104
        $dispatcher->getContext();
105
    }
106
107
    public function testShouldPassExpectedOptionsToAmqpConnectionFactoryConstructor()
108
    {
109
        $dispatcher = new AMQPBackendDispatcher(
110
            [
111
                'host' => 'theHost',
112
                'port' => 'thePort',
113
                'user' => 'theUser',
114
                'pass' => 'thePass',
115
                'vhost' => 'theVhost',
116
                'factory_class' => AmqpConnectionFactoryStub::class,
117
                'delay_strategy_class' => null,
118
            ],
119
            [],
120
            'default',
121
            []
122
        );
123
124
        $dispatcher->getContext();
125
126
        $this->assertSame([
127
            'host' => 'theHost',
128
            'port' => 'thePort',
129
            'user' => 'theUser',
130
            'pass' => 'thePass',
131
            'vhost' => 'theVhost',
132
        ], AmqpConnectionFactoryStub::$config);
133
    }
134
135
    public function testShouldSetExpectedDelayStrategyToAmqpConnectionFactoryOfInstanceDelayStrategyAware(): void
136
    {
137
        $expectedContext = $this->createMock(AmqpContext::class);
138
139
        $dispatcher = new AMQPBackendDispatcher(
140
            [
141
                'host' => 'aHost',
142
                'port' => 'aPort',
143
                'user' => 'aUser',
144
                'pass' => 'aPass',
145
                'vhost' => 'aVhost',
146
                'factory_class' => AmqpConnectionFactoryDelayStrategyAwareStub::class,
147
                'delay_strategy_class' => AnyDelayStrategyStub::class,
148
            ],
149
            [],
150
            'default',
151
            []
152
        );
153
154
        AmqpConnectionFactoryDelayStrategyAwareStub::$context = $expectedContext;
155
156
        $this->assertSame($expectedContext, $dispatcher->getContext());
157
    }
158
159
    public function testShouldReturnExpectedAmqpContext()
160
    {
161
        $expectedContext = $this->createMock(AmqpContext::class);
162
163
        $dispatcher = new AMQPBackendDispatcher(
164
            [
165
                'host' => 'aHost',
166
                'port' => 'aPort',
167
                'user' => 'aUser',
168
                'pass' => 'aPass',
169
                'vhost' => 'aVhost',
170
                'factory_class' => AmqpConnectionFactoryStub::class,
171
                'delay_strategy_class' => null,
172
            ],
173
            [],
174
            'default',
175
            []
176
        );
177
178
        AmqpConnectionFactoryStub::$context = $expectedContext;
179
180
        $actualContext = $dispatcher->getContext();
181
182
        $this->assertSame($expectedContext, $actualContext);
183
    }
184
185
    public function testQueue()
186
    {
187
        $mock = $this->getMockQueue('foo', 'message.type.foo', $this->once());
188
        $mock2 = $this->getMockQueue('bar', 'message.type.foo', $this->never());
189
        $fooBackend = ['type' => 'message.type.foo', 'backend' => $mock];
190
        $barBackend = ['type' => 'message.type.bar', 'backend' => $mock2];
191
        $backends = [$fooBackend, $barBackend];
192
        $dispatcher = $this->getDispatcher($backends);
193
        $dispatcher->createAndPublish('message.type.foo', []);
194
    }
195
196
    public function testDefaultQueue()
197
    {
198
        $mock = $this->getMockQueue('foo', 'message.type.foo', $this->once());
199
        $fooBackend = ['type' => 'default', 'backend' => $mock];
200
        $dispatcher = $this->getDispatcher([$fooBackend]);
201
        $dispatcher->createAndPublish('some.other.type', []);
202
    }
203
204
    public function testDefaultQueueNotFound()
205
    {
206
        $mock = $this->getMockQueue('foo', 'message.type.foo', $this->never());
207
        $fooBackend = ['type' => 'message.type.foo', 'backend' => $mock];
208
        $dispatcher = $this->getDispatcher([$fooBackend]);
209
210
        $this->expectException(BackendNotFoundException::class);
211
        $dispatcher->createAndPublish('some.other.type', []);
212
    }
213
214
    public function testInvalidQueue()
215
    {
216
        $mock = $this->getMockQueue('foo', 'message.type.bar');
217
        $dispatcher = $this->getDispatcher(
218
            [['type' => 'bar', 'backend' => $mock]],
219
            [['queue' => 'foo', 'routing_key' => 'message.type.bar']]
220
        );
221
222
        $this->expectException(BackendNotFoundException::class);
223
        $dispatcher->createAndPublish('message.type.bar', []);
224
    }
225
226
    public function testAllQueueInitializeOnce()
227
    {
228
        $queues = [
229
            ['queue' => 'foo', 'routing_key' => 'message.type.foo'],
230
            ['queue' => 'bar', 'routing_key' => 'message.type.bar'],
231
            ['queue' => 'baz', 'routing_key' => 'message.type.baz'],
232
        ];
233
234
        $backends = [];
235
236
        foreach ($queues as $queue) {
237
            $mock = $this->getMockQueue($queue['queue'], $queue['routing_key']);
238
            $mock->expects($this->once())
239
                ->method('initialize');
240
            $backends[] = ['type' => $queue['routing_key'], 'backend' => $mock];
241
        }
242
243
        $dispatcher = $this->getDispatcher($backends, $queues);
244
245
        $dispatcher->createAndPublish('message.type.foo', []);
246
        $dispatcher->createAndPublish('message.type.foo', []);
247
    }
248
249
    protected function getMockQueue($queue, $type, $called = null)
250
    {
251
        $methods = ['createAndPublish', 'initialize'];
252
        $args = ['', 'foo', false, 'message.type.foo'];
253
        $mock = $this->getMockBuilder(AMQPBackend::class)
254
                     ->setConstructorArgs($args)
255
                     ->setMethods($methods)
256
                     ->getMock();
257
258
        if (null !== $called) {
259
            $mock->expects($called)
260
                ->method('createAndPublish')
261
            ;
262
        }
263
264
        return $mock;
265
    }
266
267
    protected function getDispatcher(array $backends, array $queues = [['queue' => 'foo', 'routing_key' => 'message.type.foo']])
268
    {
269
        $settings = [
270
                'host' => 'foo',
271
                'port' => 'port',
272
                'user' => 'user',
273
                'pass' => 'pass',
274
                'vhost' => '/',
275
        ];
276
277
        return new AMQPBackendDispatcher($settings, $queues, 'default', $backends);
278
    }
279
}
280