Passed
Push — 1.x ( 140de4...9f554c )
by Kevin
01:24
created

cannot_access_queue_if_kernel_not_booted()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Zenstruck\Messenger\Test\Tests;
4
5
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
6
use Symfony\Component\HttpKernel\KernelInterface;
7
use Symfony\Component\Messenger\Envelope;
8
use Symfony\Component\Messenger\MessageBusInterface;
9
use Zenstruck\Messenger\Test\InteractsWithMessenger;
10
use Zenstruck\Messenger\Test\Tests\Fixture\Messenger\MessageA;
11
use Zenstruck\Messenger\Test\Tests\Fixture\Messenger\MessageAHandler;
12
use Zenstruck\Messenger\Test\Tests\Fixture\Messenger\MessageB;
13
use Zenstruck\Messenger\Test\Tests\Fixture\Messenger\MessageBHandler;
14
use Zenstruck\Messenger\Test\Tests\Fixture\Messenger\MessageC;
15
use Zenstruck\Messenger\Test\Tests\Fixture\NoBundleKernel;
16
17
/**
18
 * @author Kevin Bond <[email protected]>
19
 */
20
final class InteractsWithMessengerTest extends WebTestCase
21
{
22
    use InteractsWithMessenger;
23
24
    /**
25
     * @test
26
     */
27
    public function can_interact_with_queue(): void
28
    {
29
        self::bootKernel();
30
31
        $this->transport()->queue()->assertEmpty();
32
        $this->assertEmpty(self::$container->get(MessageAHandler::class)->messages);
33
        $this->assertEmpty(self::$container->get(MessageBHandler::class)->messages);
34
35
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
36
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
37
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
38
39
        $this->transport()->queue()->assertCount(3);
40
        $this->transport()->queue()->assertContains(MessageA::class);
41
        $this->transport()->queue()->assertContains(MessageA::class, 2);
42
        $this->transport()->queue()->assertContains(MessageB::class);
43
        $this->transport()->queue()->assertContains(MessageB::class, 1);
44
        $this->transport()->queue()->assertNotContains(MessageC::class);
45
        $this->assertEmpty(self::$container->get(MessageAHandler::class)->messages);
46
        $this->assertEmpty(self::$container->get(MessageBHandler::class)->messages);
47
48
        $this->transport()->process(2);
49
50
        $this->transport()->queue()->assertCount(1);
51
        $this->transport()->queue()->assertContains(MessageA::class, 1);
52
        $this->transport()->queue()->assertNotContains(MessageB::class);
53
        $this->assertCount(1, self::$container->get(MessageAHandler::class)->messages);
54
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
55
56
        $this->transport()->process();
57
58
        $this->transport()->queue()->assertEmpty();
59
        $this->transport()->queue()->assertNotContains(MessageA::class);
60
        $this->transport()->queue()->assertNotContains(MessageB::class);
61
        $this->assertCount(2, self::$container->get(MessageAHandler::class)->messages);
62
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
63
    }
64
65
    /**
66
     * @test
67
     */
68
    public function can_disable_intercept(): void
69
    {
70
        self::bootKernel();
71
72
        $this->transport()->unblock();
73
74
        $this->transport()->queue()->assertEmpty();
75
        $this->transport()->acknowledged()->assertEmpty();
76
        $this->transport()->sent()->assertEmpty();
77
78
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
79
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
80
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
81
82
        $this->transport()->queue()->assertEmpty();
83
        $this->transport()->queue()->assertNotContains(MessageA::class);
84
        $this->transport()->sent()->assertCount(3);
85
        $this->transport()->sent()->assertContains(MessageA::class, 2);
86
        $this->transport()->sent()->assertContains(MessageB::class, 1);
87
        $this->transport()->acknowledged()->assertCount(3);
88
        $this->transport()->acknowledged()->assertContains(MessageA::class, 2);
89
        $this->transport()->acknowledged()->assertContains(MessageB::class, 1);
90
        $this->assertCount(2, self::$container->get(MessageAHandler::class)->messages);
91
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
92
    }
93
94
    /**
95
     * @test
96
     */
97
    public function disabling_intercept_with_items_on_queue_processes_all(): void
98
    {
99
        self::bootKernel();
100
101
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
102
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
103
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
104
105
        $this->transport()->queue()->assertCount(3);
106
107
        $this->transport()->process();
108
109
        $this->transport()->queue()->assertEmpty();
110
        $this->assertCount(2, self::$container->get(MessageAHandler::class)->messages);
111
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
112
    }
113
114
    /**
115
     * @test
116
     */
117
    public function cannot_access_queue_if_none_registered(): void
118
    {
119
        self::bootKernel(['environment' => 'test']);
120
121
        $this->expectException(\LogicException::class);
122
        $this->expectExceptionMessage('No transports registered');
123
124
        $this->transport();
125
    }
126
127
    /**
128
     * @test
129
     */
130
    public function accessing_transport_boots_kernel_if_not_yet_booted(): void
131
    {
132
        $this->transport()->queue()->assertEmpty();
133
    }
134
135
    /**
136
     * @test
137
     */
138
    public function can_interact_with_multiple_queues(): void
139
    {
140
        self::bootKernel(['environment' => 'multi_transport']);
141
142
        $this->transport('async1')->queue()->assertEmpty();
143
        $this->transport('async2')->queue()->assertEmpty();
144
        $this->assertEmpty(self::$container->get(MessageAHandler::class)->messages);
145
        $this->assertEmpty(self::$container->get(MessageBHandler::class)->messages);
146
147
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
148
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
149
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
150
151
        $this->transport('async1')->queue()->assertCount(2);
152
        $this->transport('async2')->queue()->assertEmpty();
153
        $this->transport('async1')->queue()->assertContains(MessageA::class);
154
        $this->transport('async1')->queue()->assertContains(MessageA::class, 2);
155
        $this->transport('async2')->queue()->assertNotContains(MessageB::class);
156
        $this->assertEmpty(self::$container->get(MessageAHandler::class)->messages);
157
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
158
159
        $this->transport('async1')->process(1);
160
        $this->transport('async2')->process(1);
161
162
        $this->transport('async1')->queue()->assertCount(1);
163
        $this->transport('async1')->queue()->assertContains(MessageA::class, 1);
164
        $this->transport('async2')->queue()->assertNotContains(MessageB::class);
165
        $this->assertCount(1, self::$container->get(MessageAHandler::class)->messages);
166
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
167
168
        $this->transport('async1')->process();
169
        $this->transport('async2')->process();
170
171
        $this->transport('async1')->queue()->assertEmpty();
172
        $this->transport('async2')->queue()->assertEmpty();
173
        $this->assertCount(2, self::$container->get(MessageAHandler::class)->messages);
174
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
175
    }
176
177
    /**
178
     * @test
179
     */
180
    public function can_enable_intercept(): void
181
    {
182
        self::bootKernel(['environment' => 'multi_transport']);
183
184
        $this->transport('async2')->intercept();
185
186
        $this->transport('async2')->queue()->assertEmpty();
187
        $this->assertEmpty(self::$container->get(MessageBHandler::class)->messages);
188
189
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
190
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
191
192
        $this->transport('async2')->queue()->assertCount(2);
193
    }
194
195
    /**
196
     * @test
197
     */
198
    public function cannot_access_queue_that_does_not_exist(): void
199
    {
200
        self::bootKernel(['environment' => 'multi_transport']);
201
202
        $this->expectException(\InvalidArgumentException::class);
203
        $this->expectExceptionMessage('"invalid" not registered');
204
205
        $this->transport('invalid');
206
    }
207
208
    /**
209
     * @test
210
     */
211
    public function cannot_access_queue_that_is_not_test_transport(): void
212
    {
213
        self::bootKernel(['environment' => 'multi_transport']);
214
215
        $this->expectException(\LogicException::class);
216
        $this->expectExceptionMessage('Transport "async3" needs to be set to "test://" in your test config to use this feature.');
217
218
        $this->transport('async3');
219
    }
220
221
    /**
222
     * @test
223
     */
224
    public function queue_name_is_required_if_using_multiple_transports(): void
225
    {
226
        self::bootKernel(['environment' => 'multi_transport']);
227
228
        $this->expectException(\LogicException::class);
229
        $this->expectExceptionMessage('Multiple transports are registered (async1, async2, async3), you must specify a name.');
230
231
        $this->transport();
232
    }
233
234
    /**
235
     * @test
236
     */
237
    public function can_access_message_objects_on_queue(): void
238
    {
239
        self::bootKernel();
240
241
        self::$container->get(MessageBusInterface::class)->dispatch($m1 = new MessageA());
242
        self::$container->get(MessageBusInterface::class)->dispatch($m2 = new MessageB());
243
        self::$container->get(MessageBusInterface::class)->dispatch($m3 = new MessageA());
244
245
        $this->assertSame([$m1, $m2, $m3], $this->transport()->queue()->messages());
246
        $this->assertSame([$m1, $m3], $this->transport()->queue()->messages(MessageA::class));
247
        $this->assertSame([$m2], $this->transport()->queue()->messages(MessageB::class));
248
    }
249
250
    /**
251
     * @test
252
     */
253
    public function can_access_envelopes_on_queue(): void
254
    {
255
        self::bootKernel();
256
257
        self::$container->get(MessageBusInterface::class)->dispatch($m1 = new MessageA());
258
        self::$container->get(MessageBusInterface::class)->dispatch($m2 = new MessageB());
259
        self::$container->get(MessageBusInterface::class)->dispatch($m3 = new MessageA());
260
261
        $messages = \array_map(fn(Envelope $envelope) => $envelope->getMessage(), \iterator_to_array($this->transport()->queue()));
262
263
        $this->assertSame([$m1, $m2, $m3], $messages);
264
    }
265
266
    /**
267
     * @test
268
     */
269
    public function can_access_sent_acknowledged_and_rejected(): void
270
    {
271
        self::bootKernel();
272
273
        self::$container->get(MessageBusInterface::class)->dispatch($m1 = new MessageA(true));
274
        self::$container->get(MessageBusInterface::class)->dispatch($m2 = new MessageB());
275
276
        $this->assertCount(2, $this->transport()->queue());
277
        $this->assertCount(2, $this->transport()->sent());
278
        $this->assertCount(0, $this->transport()->acknowledged());
279
        $this->assertCount(0, $this->transport()->rejected());
280
281
        $this->transport()->process();
282
283
        $this->assertCount(0, $this->transport()->queue());
284
        $this->assertCount(2, $this->transport()->sent());
285
        $this->assertCount(1, $this->transport()->acknowledged());
286
        $this->assertCount(1, $this->transport()->rejected());
287
    }
288
289
    /**
290
     * @test
291
     */
292
    public function cannot_access_queue_if_bundle_not_enabled(): void
293
    {
294
        self::$class = NoBundleKernel::class;
295
        self::bootKernel(['environment' => 'no_bundle']);
296
        self::$class = null;
297
298
        $this->expectException(\LogicException::class);
299
        $this->expectExceptionMessage('Cannot access transport - is ZenstruckMessengerTestBundle enabled in your test environment?');
300
301
        $this->transport();
302
    }
303
304
    /**
305
     * @test
306
     */
307
    public function can_configure_throwing_exceptions(): void
308
    {
309
        self::bootKernel();
310
311
        $this->transport()->throwExceptions();
312
313
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA(true));
314
315
        $this->expectException(\RuntimeException::class);
316
        $this->expectExceptionMessage('handling failed...');
317
318
        $this->transport()->process();
319
    }
320
321
    /**
322
     * @test
323
     */
324
    public function can_configure_throwing_exceptions_with_intercept_disabled(): void
325
    {
326
        self::bootKernel();
327
328
        $this->transport()->throwExceptions()->unblock();
329
330
        $this->expectException(\RuntimeException::class);
331
        $this->expectExceptionMessage('handling failed...');
332
333
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA(true));
334
    }
335
336
    /**
337
     * @test
338
     */
339
    public function can_disable_exception_catching_in_transport_config(): void
340
    {
341
        self::bootKernel(['environment' => 'multi_transport']);
342
343
        $this->expectException(\RuntimeException::class);
344
        $this->expectExceptionMessage('handling failed...');
345
346
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB(true));
347
    }
348
349
    /**
350
     * @test
351
     */
352
    public function can_re_enable_exception_catching_if_disabled_in_transport_config(): void
353
    {
354
        self::bootKernel(['environment' => 'multi_transport']);
355
356
        $this->transport('async2')->catchExceptions();
357
358
        $this->transport('async2')->rejected()->assertEmpty();
359
360
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB(true));
361
362
        $this->transport('async2')->rejected()->assertCount(1);
363
    }
364
365
    /**
366
     * @test
367
     */
368
    public function transport_data_is_persisted_between_requests_and_kernel_shutdown(): void
369
    {
370
        self::bootKernel();
371
372
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
373
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA(true));
374
375
        $this->transport()->queue()->assertCount(2);
376
377
        self::ensureKernelShutdown();
378
        self::bootKernel();
379
380
        $this->transport()->queue()->assertCount(2);
381
382
        $this->transport()->process();
383
384
        self::ensureKernelShutdown();
385
        self::bootKernel();
386
387
        $this->transport()->queue()->assertEmpty();
388
        $this->transport()->sent()->assertCount(2);
389
        $this->transport()->acknowledged()->assertCount(1);
390
        $this->transport()->rejected()->assertCount(1);
391
392
        self::ensureKernelShutdown();
393
394
        $client = self::createClient();
395
396
        $client->request('GET', '/dispatch');
397
398
        $this->transport()->queue()->assertCount(1);
399
        $this->transport()->sent()->assertCount(3);
400
        $this->transport()->acknowledged()->assertCount(1);
401
        $this->transport()->rejected()->assertCount(1);
402
403
        $client->request('GET', '/dispatch');
404
405
        $this->transport()->queue()->assertCount(2);
406
        $this->transport()->sent()->assertCount(4);
407
        $this->transport()->acknowledged()->assertCount(1);
408
        $this->transport()->rejected()->assertCount(1);
409
    }
410
411
    /**
412
     * @test
413
     */
414
    public function can_reset_transport_data(): void
415
    {
416
        self::bootKernel();
417
418
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
419
420
        $this->transport()->queue()->assertNotEmpty();
421
422
        $this->resetTransports();
423
424
        $this->transport()->queue()->assertEmpty();
425
    }
426
427
    protected static function bootKernel(array $options = []): KernelInterface
428
    {
429
        return parent::bootKernel(\array_merge(['environment' => 'single_transport'], $options));
430
    }
431
}
432