Passed
Pull Request — 1.x (#6)
by Kevin
02:07
created

InteractsWithMessengerTest::bootKernel()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
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 Symfony\Component\Messenger\Stamp\DelayStamp;
10
use Zenstruck\Messenger\Test\InteractsWithMessenger;
11
use Zenstruck\Messenger\Test\TestEnvelope;
12
use Zenstruck\Messenger\Test\Tests\Fixture\Messenger\MessageA;
13
use Zenstruck\Messenger\Test\Tests\Fixture\Messenger\MessageAHandler;
14
use Zenstruck\Messenger\Test\Tests\Fixture\Messenger\MessageB;
15
use Zenstruck\Messenger\Test\Tests\Fixture\Messenger\MessageBHandler;
16
use Zenstruck\Messenger\Test\Tests\Fixture\Messenger\MessageC;
17
use Zenstruck\Messenger\Test\Tests\Fixture\NoBundleKernel;
18
19
/**
20
 * @author Kevin Bond <[email protected]>
21
 */
22
final class InteractsWithMessengerTest extends WebTestCase
23
{
24
    use InteractsWithMessenger;
25
26
    /**
27
     * @test
28
     */
29
    public function can_interact_with_queue(): void
30
    {
31
        self::bootKernel();
32
33
        $this->messenger()->queue()->assertEmpty();
34
        $this->assertEmpty(self::$container->get(MessageAHandler::class)->messages);
35
        $this->assertEmpty(self::$container->get(MessageBHandler::class)->messages);
36
37
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
38
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
39
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
40
41
        $this->messenger()->queue()->assertCount(3);
42
        $this->messenger()->queue()->assertContains(MessageA::class);
43
        $this->messenger()->queue()->assertContains(MessageA::class, 2);
44
        $this->messenger()->queue()->assertContains(MessageB::class);
45
        $this->messenger()->queue()->assertContains(MessageB::class, 1);
46
        $this->messenger()->queue()->assertNotContains(MessageC::class);
47
        $this->assertEmpty(self::$container->get(MessageAHandler::class)->messages);
48
        $this->assertEmpty(self::$container->get(MessageBHandler::class)->messages);
49
50
        $this->messenger()->process(2);
51
52
        $this->messenger()->queue()->assertCount(1);
53
        $this->messenger()->queue()->assertContains(MessageA::class, 1);
54
        $this->messenger()->queue()->assertNotContains(MessageB::class);
55
        $this->assertCount(1, self::$container->get(MessageAHandler::class)->messages);
56
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
57
58
        $this->messenger()->process();
59
60
        $this->messenger()->queue()->assertEmpty();
61
        $this->messenger()->queue()->assertNotContains(MessageA::class);
62
        $this->messenger()->queue()->assertNotContains(MessageB::class);
63
        $this->assertCount(2, self::$container->get(MessageAHandler::class)->messages);
64
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
65
    }
66
67
    /**
68
     * @test
69
     */
70
    public function can_disable_intercept(): void
71
    {
72
        self::bootKernel();
73
74
        $this->messenger()->unblock();
75
76
        $this->messenger()->queue()->assertEmpty();
77
        $this->messenger()->acknowledged()->assertEmpty();
78
        $this->messenger()->sent()->assertEmpty();
79
80
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
81
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
82
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
83
84
        $this->messenger()->queue()->assertEmpty();
85
        $this->messenger()->queue()->assertNotContains(MessageA::class);
86
        $this->messenger()->sent()->assertCount(3);
87
        $this->messenger()->sent()->assertContains(MessageA::class, 2);
88
        $this->messenger()->sent()->assertContains(MessageB::class, 1);
89
        $this->messenger()->acknowledged()->assertCount(3);
90
        $this->messenger()->acknowledged()->assertContains(MessageA::class, 2);
91
        $this->messenger()->acknowledged()->assertContains(MessageB::class, 1);
92
        $this->assertCount(2, self::$container->get(MessageAHandler::class)->messages);
93
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
94
    }
95
96
    /**
97
     * @test
98
     */
99
    public function disabling_intercept_with_items_on_queue_processes_all(): void
100
    {
101
        self::bootKernel();
102
103
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
104
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
105
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
106
107
        $this->messenger()->queue()->assertCount(3);
108
109
        $this->messenger()->process();
110
111
        $this->messenger()->queue()->assertEmpty();
112
        $this->assertCount(2, self::$container->get(MessageAHandler::class)->messages);
113
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
114
    }
115
116
    /**
117
     * @test
118
     */
119
    public function can_access_envelope_collection_items_via_first(): void
120
    {
121
        self::bootKernel();
122
123
        self::$container->get(MessageBusInterface::class)->dispatch($m1 = new MessageA());
124
        self::$container->get(MessageBusInterface::class)->dispatch($m2 = new MessageB());
125
        self::$container->get(MessageBusInterface::class)->dispatch($m3 = new MessageA(true));
126
127
        $this->messenger()->queue()->assertCount(3);
128
129
        $this->assertSame($m1, $this->messenger()->queue()->first()->getMessage());
0 ignored issues
show
Bug introduced by
The method getMessage() does not exist on Zenstruck\Messenger\Test\TestEnvelope. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

129
        $this->assertSame($m1, $this->messenger()->queue()->first()->/** @scrutinizer ignore-call */ getMessage());
Loading history...
130
        $this->assertSame($m2, $this->messenger()->queue()->first(MessageB::class)->getMessage());
131
        $this->assertSame($m3, $this->messenger()->queue()->first(fn(Envelope $e) => $e->getMessage()->fail)->getMessage());
132
        $this->assertSame($m3, $this->messenger()->queue()->first(fn($e) => $e->getMessage()->fail)->getMessage());
133
        $this->assertSame($m3, $this->messenger()->queue()->first(fn(MessageA $m) => $m->fail)->getMessage());
134
    }
135
136
    /**
137
     * @test
138
     */
139
    public function envelope_collection_first_throws_exception_if_no_match(): void
140
    {
141
        self::bootKernel();
142
143
        $this->expectException(\RuntimeException::class);
144
145
        $this->messenger()->queue()->first();
146
    }
147
148
    /**
149
     * @test
150
     */
151
    public function can_make_stamp_assertions_on_test_envelope(): void
152
    {
153
        self::bootKernel();
154
155
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA(), [new DelayStamp(1000)]);
156
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
157
158
        $this->messenger()->queue()->first()->assertHasStamp(DelayStamp::class);
159
        $this->messenger()->queue()->first(MessageB::class)->assertNotHasStamp(DelayStamp::class);
160
    }
161
162
    /**
163
     * @test
164
     */
165
    public function cannot_access_queue_if_none_registered(): void
166
    {
167
        self::bootKernel(['environment' => 'test']);
168
169
        $this->expectException(\LogicException::class);
170
        $this->expectExceptionMessage('No transports registered');
171
172
        $this->messenger();
173
    }
174
175
    /**
176
     * @test
177
     */
178
    public function accessing_transport_boots_kernel_if_not_yet_booted(): void
179
    {
180
        $this->messenger()->queue()->assertEmpty();
181
    }
182
183
    /**
184
     * @test
185
     */
186
    public function can_interact_with_multiple_queues(): void
187
    {
188
        self::bootKernel(['environment' => 'multi_transport']);
189
190
        $this->messenger('async1')->queue()->assertEmpty();
191
        $this->messenger('async2')->queue()->assertEmpty();
192
        $this->assertEmpty(self::$container->get(MessageAHandler::class)->messages);
193
        $this->assertEmpty(self::$container->get(MessageBHandler::class)->messages);
194
195
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
196
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
197
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
198
199
        $this->messenger('async1')->queue()->assertCount(2);
200
        $this->messenger('async2')->queue()->assertEmpty();
201
        $this->messenger('async1')->queue()->assertContains(MessageA::class);
202
        $this->messenger('async1')->queue()->assertContains(MessageA::class, 2);
203
        $this->messenger('async2')->queue()->assertNotContains(MessageB::class);
204
        $this->assertEmpty(self::$container->get(MessageAHandler::class)->messages);
205
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
206
207
        $this->messenger('async1')->process(1);
208
        $this->messenger('async2')->process(1);
209
210
        $this->messenger('async1')->queue()->assertCount(1);
211
        $this->messenger('async1')->queue()->assertContains(MessageA::class, 1);
212
        $this->messenger('async2')->queue()->assertNotContains(MessageB::class);
213
        $this->assertCount(1, self::$container->get(MessageAHandler::class)->messages);
214
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
215
216
        $this->messenger('async1')->process();
217
        $this->messenger('async2')->process();
218
219
        $this->messenger('async1')->queue()->assertEmpty();
220
        $this->messenger('async2')->queue()->assertEmpty();
221
        $this->assertCount(2, self::$container->get(MessageAHandler::class)->messages);
222
        $this->assertCount(1, self::$container->get(MessageBHandler::class)->messages);
223
    }
224
225
    /**
226
     * @test
227
     */
228
    public function can_enable_intercept(): void
229
    {
230
        self::bootKernel(['environment' => 'multi_transport']);
231
232
        $this->messenger('async2')->intercept();
233
234
        $this->messenger('async2')->queue()->assertEmpty();
235
        $this->assertEmpty(self::$container->get(MessageBHandler::class)->messages);
236
237
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
238
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB());
239
240
        $this->messenger('async2')->queue()->assertCount(2);
241
    }
242
243
    /**
244
     * @test
245
     */
246
    public function cannot_access_queue_that_does_not_exist(): void
247
    {
248
        self::bootKernel(['environment' => 'multi_transport']);
249
250
        $this->expectException(\InvalidArgumentException::class);
251
        $this->expectExceptionMessage('"invalid" not registered');
252
253
        $this->messenger('invalid');
254
    }
255
256
    /**
257
     * @test
258
     */
259
    public function cannot_access_queue_that_is_not_test_transport(): void
260
    {
261
        self::bootKernel(['environment' => 'multi_transport']);
262
263
        $this->expectException(\LogicException::class);
264
        $this->expectExceptionMessage('Transport "async3" needs to be set to "test://" in your test config to use this feature.');
265
266
        $this->messenger('async3');
267
    }
268
269
    /**
270
     * @test
271
     */
272
    public function queue_name_is_required_if_using_multiple_transports(): void
273
    {
274
        self::bootKernel(['environment' => 'multi_transport']);
275
276
        $this->expectException(\LogicException::class);
277
        $this->expectExceptionMessage('Multiple transports are registered (async1, async2, async3), you must specify a name.');
278
279
        $this->messenger();
280
    }
281
282
    /**
283
     * @test
284
     */
285
    public function can_access_message_objects_on_queue(): void
286
    {
287
        self::bootKernel();
288
289
        self::$container->get(MessageBusInterface::class)->dispatch($m1 = new MessageA());
290
        self::$container->get(MessageBusInterface::class)->dispatch($m2 = new MessageB());
291
        self::$container->get(MessageBusInterface::class)->dispatch($m3 = new MessageA());
292
293
        $this->assertSame([$m1, $m2, $m3], $this->messenger()->queue()->messages());
294
        $this->assertSame([$m1, $m3], $this->messenger()->queue()->messages(MessageA::class));
295
        $this->assertSame([$m2], $this->messenger()->queue()->messages(MessageB::class));
296
    }
297
298
    /**
299
     * @test
300
     */
301
    public function can_access_envelopes_on_envelope_collection(): void
302
    {
303
        self::bootKernel();
304
305
        self::$container->get(MessageBusInterface::class)->dispatch($m1 = new MessageA());
306
        self::$container->get(MessageBusInterface::class)->dispatch($m2 = new MessageB());
307
        self::$container->get(MessageBusInterface::class)->dispatch($m3 = new MessageA());
308
309
        $messages = \array_map(fn(TestEnvelope $envelope) => $envelope->getMessage(), $this->messenger()->queue()->all());
310
        $messagesFromIterator = \array_map(fn(TestEnvelope $envelope) => $envelope->getMessage(), \iterator_to_array($this->messenger()->queue()));
311
312
        $this->assertSame([$m1, $m2, $m3], $messages);
313
        $this->assertSame([$m1, $m2, $m3], $messagesFromIterator);
314
    }
315
316
    /**
317
     * @test
318
     */
319
    public function can_access_sent_acknowledged_and_rejected(): void
320
    {
321
        self::bootKernel();
322
323
        self::$container->get(MessageBusInterface::class)->dispatch($m1 = new MessageA(true));
324
        self::$container->get(MessageBusInterface::class)->dispatch($m2 = new MessageB());
325
326
        $this->assertCount(2, $this->messenger()->queue());
327
        $this->assertCount(2, $this->messenger()->sent());
328
        $this->assertCount(0, $this->messenger()->acknowledged());
329
        $this->assertCount(0, $this->messenger()->rejected());
330
331
        $this->messenger()->process();
332
333
        $this->assertCount(0, $this->messenger()->queue());
334
        $this->assertCount(2, $this->messenger()->sent());
335
        $this->assertCount(1, $this->messenger()->acknowledged());
336
        $this->assertCount(1, $this->messenger()->rejected());
337
    }
338
339
    /**
340
     * @test
341
     */
342
    public function cannot_access_queue_if_bundle_not_enabled(): void
343
    {
344
        self::$class = NoBundleKernel::class;
345
        self::bootKernel(['environment' => 'no_bundle']);
346
        self::$class = null;
347
348
        $this->expectException(\LogicException::class);
349
        $this->expectExceptionMessage('Cannot access transport - is ZenstruckMessengerTestBundle enabled in your test environment?');
350
351
        $this->messenger();
352
    }
353
354
    /**
355
     * @test
356
     */
357
    public function can_configure_throwing_exceptions(): void
358
    {
359
        self::bootKernel();
360
361
        $this->messenger()->throwExceptions();
362
363
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA(true));
364
365
        $this->expectException(\RuntimeException::class);
366
        $this->expectExceptionMessage('handling failed...');
367
368
        $this->messenger()->process();
369
    }
370
371
    /**
372
     * @test
373
     */
374
    public function can_configure_throwing_exceptions_with_intercept_disabled(): void
375
    {
376
        self::bootKernel();
377
378
        $this->messenger()->throwExceptions()->unblock();
379
380
        $this->expectException(\RuntimeException::class);
381
        $this->expectExceptionMessage('handling failed...');
382
383
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA(true));
384
    }
385
386
    /**
387
     * @test
388
     */
389
    public function can_disable_exception_catching_in_transport_config(): void
390
    {
391
        self::bootKernel(['environment' => 'multi_transport']);
392
393
        $this->expectException(\RuntimeException::class);
394
        $this->expectExceptionMessage('handling failed...');
395
396
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB(true));
397
    }
398
399
    /**
400
     * @test
401
     */
402
    public function can_re_enable_exception_catching_if_disabled_in_transport_config(): void
403
    {
404
        self::bootKernel(['environment' => 'multi_transport']);
405
406
        $this->messenger('async2')->catchExceptions();
407
408
        $this->messenger('async2')->rejected()->assertEmpty();
409
410
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageB(true));
411
412
        $this->messenger('async2')->rejected()->assertCount(1);
413
    }
414
415
    /**
416
     * @test
417
     */
418
    public function transport_data_is_persisted_between_requests_and_kernel_shutdown(): void
419
    {
420
        self::bootKernel();
421
422
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
423
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA(true));
424
425
        $this->messenger()->queue()->assertCount(2);
426
427
        self::ensureKernelShutdown();
428
        self::bootKernel();
429
430
        $this->messenger()->queue()->assertCount(2);
431
432
        $this->messenger()->process();
433
434
        self::ensureKernelShutdown();
435
        self::bootKernel();
436
437
        $this->messenger()->queue()->assertEmpty();
438
        $this->messenger()->sent()->assertCount(2);
439
        $this->messenger()->acknowledged()->assertCount(1);
440
        $this->messenger()->rejected()->assertCount(1);
441
442
        self::ensureKernelShutdown();
443
444
        $client = self::createClient();
445
446
        $client->request('GET', '/dispatch');
447
448
        $this->messenger()->queue()->assertCount(1);
449
        $this->messenger()->sent()->assertCount(3);
450
        $this->messenger()->acknowledged()->assertCount(1);
451
        $this->messenger()->rejected()->assertCount(1);
452
453
        $client->request('GET', '/dispatch');
454
455
        $this->messenger()->queue()->assertCount(2);
456
        $this->messenger()->sent()->assertCount(4);
457
        $this->messenger()->acknowledged()->assertCount(1);
458
        $this->messenger()->rejected()->assertCount(1);
459
    }
460
461
    /**
462
     * @test
463
     */
464
    public function can_reset_transport_data(): void
465
    {
466
        self::bootKernel();
467
468
        self::$container->get(MessageBusInterface::class)->dispatch(new MessageA());
469
470
        $this->messenger()->queue()->assertNotEmpty();
471
472
        $this->resetTransports();
473
474
        $this->messenger()->queue()->assertEmpty();
475
    }
476
477
    protected static function bootKernel(array $options = []): KernelInterface
478
    {
479
        return parent::bootKernel(\array_merge(['environment' => 'single_transport'], $options));
480
    }
481
}
482