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

testShouldSetExpectedDelayStrategyToAmqpConnectionFactoryOfInstanceDelayStrategyAware()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 9.52
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()
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 valid class that implements "Enqueue\AmqpTools\DelayStrategy"');
83
        $dispatcher->getContext();
84
    }
85
86
    public function testThrowIfDelayStrategyClassIsSetButNotInstanceOfDelayStrategyInterface()
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 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()
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
        $actualContext = $dispatcher->getContext();
157
158
        $this->assertSame($expectedContext, $actualContext);
159
    }
160
161
    public function testShouldReturnExpectedAmqpContext()
162
    {
163
        $expectedContext = $this->createMock(AmqpContext::class);
164
165
        $dispatcher = new AMQPBackendDispatcher(
166
            [
167
                'host' => 'aHost',
168
                'port' => 'aPort',
169
                'user' => 'aUser',
170
                'pass' => 'aPass',
171
                'vhost' => 'aVhost',
172
                'factory_class' => AmqpConnectionFactoryStub::class,
173
                'delay_strategy_class' => null,
174
            ],
175
            [],
176
            'default',
177
            []
178
        );
179
180
        AmqpConnectionFactoryStub::$context = $expectedContext;
181
182
        $actualContext = $dispatcher->getContext();
183
184
        $this->assertSame($expectedContext, $actualContext);
185
    }
186
187
    public function testQueue()
188
    {
189
        $mock = $this->getMockQueue('foo', 'message.type.foo', $this->once());
190
        $mock2 = $this->getMockQueue('bar', 'message.type.foo', $this->never());
191
        $fooBackend = ['type' => 'message.type.foo', 'backend' => $mock];
192
        $barBackend = ['type' => 'message.type.bar', 'backend' => $mock2];
193
        $backends = [$fooBackend, $barBackend];
194
        $dispatcher = $this->getDispatcher($backends);
195
        $dispatcher->createAndPublish('message.type.foo', []);
196
    }
197
198
    public function testDefaultQueue()
199
    {
200
        $mock = $this->getMockQueue('foo', 'message.type.foo', $this->once());
201
        $fooBackend = ['type' => 'default', 'backend' => $mock];
202
        $dispatcher = $this->getDispatcher([$fooBackend]);
203
        $dispatcher->createAndPublish('some.other.type', []);
204
    }
205
206
    public function testDefaultQueueNotFound()
207
    {
208
        $mock = $this->getMockQueue('foo', 'message.type.foo', $this->never());
209
        $fooBackend = ['type' => 'message.type.foo', 'backend' => $mock];
210
        $dispatcher = $this->getDispatcher([$fooBackend]);
211
212
        $this->expectException(BackendNotFoundException::class);
213
        $dispatcher->createAndPublish('some.other.type', []);
214
    }
215
216
    public function testInvalidQueue()
217
    {
218
        $mock = $this->getMockQueue('foo', 'message.type.bar');
219
        $dispatcher = $this->getDispatcher(
220
            [['type' => 'bar', 'backend' => $mock]],
221
            [['queue' => 'foo', 'routing_key' => 'message.type.bar']]
222
        );
223
224
        $this->expectException(BackendNotFoundException::class);
225
        $dispatcher->createAndPublish('message.type.bar', []);
226
    }
227
228
    public function testAllQueueInitializeOnce()
229
    {
230
        $queues = [
231
            ['queue' => 'foo', 'routing_key' => 'message.type.foo'],
232
            ['queue' => 'bar', 'routing_key' => 'message.type.bar'],
233
            ['queue' => 'baz', 'routing_key' => 'message.type.baz'],
234
        ];
235
236
        $backends = [];
237
238
        foreach ($queues as $queue) {
239
            $mock = $this->getMockQueue($queue['queue'], $queue['routing_key']);
240
            $mock->expects($this->once())
241
                ->method('initialize');
242
            $backends[] = ['type' => $queue['routing_key'], 'backend' => $mock];
243
        }
244
245
        $dispatcher = $this->getDispatcher($backends, $queues);
246
247
        $dispatcher->createAndPublish('message.type.foo', []);
248
        $dispatcher->createAndPublish('message.type.foo', []);
249
    }
250
251
    protected function getMockQueue($queue, $type, $called = null)
252
    {
253
        $methods = ['createAndPublish', 'initialize'];
254
        $args = ['', 'foo', false, 'message.type.foo'];
255
        $mock = $this->getMockBuilder(AMQPBackend::class)
256
                     ->setConstructorArgs($args)
257
                     ->setMethods($methods)
258
                     ->getMock();
259
260
        if (null !== $called) {
261
            $mock->expects($called)
262
                ->method('createAndPublish')
263
            ;
264
        }
265
266
        return $mock;
267
    }
268
269
    protected function getDispatcher(array $backends, array $queues = [['queue' => 'foo', 'routing_key' => 'message.type.foo']])
270
    {
271
        $settings = [
272
                'host' => 'foo',
273
                'port' => 'port',
274
                'user' => 'user',
275
                'pass' => 'pass',
276
                'vhost' => '/',
277
        ];
278
279
        return new AMQPBackendDispatcher($settings, $queues, 'default', $backends);
280
    }
281
}
282