Issues (3627)

Dispatcher/LegacyEventDispatcherTest.php (5 issues)

1
<?php
2
3
/*
4
 * @copyright   2018 Mautic Contributors. All rights reserved
5
 * @author      Mautic, Inc.
6
 *
7
 * @link        https://mautic.org
8
 *
9
 * @license     GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
10
 */
11
12
namespace Mautic\CampaignBundle\Tests\Executioner\Dispatcher;
13
14
use Doctrine\Common\Collections\ArrayCollection;
15
use Mautic\CampaignBundle\CampaignEvents;
16
use Mautic\CampaignBundle\Entity\Campaign;
17
use Mautic\CampaignBundle\Entity\Event;
18
use Mautic\CampaignBundle\Entity\LeadEventLog;
19
use Mautic\CampaignBundle\Event\CampaignExecutionEvent;
20
use Mautic\CampaignBundle\Event\FailedEvent;
21
use Mautic\CampaignBundle\Event\PendingEvent;
22
use Mautic\CampaignBundle\EventCollector\Accessor\Event\AbstractEventAccessor;
23
use Mautic\CampaignBundle\Executioner\Dispatcher\LegacyEventDispatcher;
24
use Mautic\CampaignBundle\Executioner\Helper\NotificationHelper;
25
use Mautic\CampaignBundle\Executioner\Scheduler\EventScheduler;
26
use Mautic\CoreBundle\Factory\MauticFactory;
27
use Mautic\LeadBundle\Entity\Lead;
28
use Mautic\LeadBundle\Tracker\ContactTracker;
29
use PHPUnit\Framework\MockObject\MockBuilder;
30
use Psr\Log\NullLogger;
31
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
32
33
class LegacyEventDispatcherTest extends \PHPUnit\Framework\TestCase
34
{
35
    /**
36
     * @var MockBuilder|EventDispatcherInterface
37
     */
38
    private $dispatcher;
39
40
    /**
41
     * @var MockBuilder|EventScheduler
42
     */
43
    private $scheduler;
44
45
    /**
46
     * @var MockBuilder|NotificationHelper
47
     */
48
    private $notificationHelper;
49
50
    /**
51
     * @var MockBuilder|MauticFactory
52
     */
53
    private $mauticFactory;
54
55
    /**
56
     * @var MockBuilder|ContactTracker
57
     */
58
    private $contactTracker;
59
60
    protected function setUp(): void
61
    {
62
        $this->dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)
63
            ->disableOriginalConstructor()
64
            ->getMock();
65
66
        $this->scheduler = $this->getMockBuilder(EventScheduler::class)
67
            ->disableOriginalConstructor()
68
            ->getMock();
69
70
        $this->notificationHelper = $this->getMockBuilder(NotificationHelper::class)
71
            ->disableOriginalConstructor()
72
            ->getMock();
73
74
        $this->mauticFactory = $this->getMockBuilder(MauticFactory::class)
75
            ->disableOriginalConstructor()
76
            ->getMock();
77
78
        $this->contactTracker = $this->getMockBuilder(ContactTracker::class)
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getMockBuilder(Ma...onstructor()->getMock() of type PHPUnit\Framework\MockObject\MockObject is incompatible with the declared type Mautic\LeadBundle\Tracke...\MockObject\MockBuilder of property $contactTracker.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
79
            ->disableOriginalConstructor()
80
            ->getMock();
81
    }
82
83
    public function testAllEventsAreFailedWithBadConfig()
84
    {
85
        $config = $this->getMockBuilder(AbstractEventAccessor::class)
86
            ->disableOriginalConstructor()
87
            ->getMock();
88
89
        $config->expects($this->once())
90
            ->method('getConfig')
91
            ->willReturn([]);
92
93
        $logs = new ArrayCollection([new LeadEventLog()]);
94
95
        $pendingEvent = $this->getMockBuilder(PendingEvent::class)
96
            ->disableOriginalConstructor()
97
            ->getMock();
98
        $pendingEvent->expects($this->once())
99
            ->method('failAll');
100
101
        $this->getLegacyEventDispatcher()->dispatchCustomEvent($config, $logs, false, $pendingEvent, $this->mauticFactory);
102
    }
103
104
    public function testPrimayLegacyEventsAreProcessed()
105
    {
106
        $config = $this->getMockBuilder(AbstractEventAccessor::class)
107
            ->disableOriginalConstructor()
108
            ->getMock();
109
110
        $config->expects($this->exactly(2))
111
            ->method('getConfig')
112
            ->willReturn(['eventName' => 'something']);
113
114
        $event    = new Event();
115
        $campaign = new Campaign();
116
        $event->setCampaign($campaign);
117
        $leadEventLog = new LeadEventLog();
118
        $leadEventLog->setEvent($event);
119
        $leadEventLog->setLead(new Lead());
120
        $logs = new ArrayCollection([$leadEventLog]);
121
122
        $pendingEvent = $this->getMockBuilder(PendingEvent::class)
123
            ->disableOriginalConstructor()
124
            ->getMock();
125
126
        // BC default is to have pass
127
        $pendingEvent->expects($this->once())
128
            ->method('pass');
129
130
        $this->contactTracker->expects($this->exactly(2))
0 ignored issues
show
The method expects() does not exist on Mautic\LeadBundle\Tracker\ContactTracker. ( Ignorable by Annotation )

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

130
        $this->contactTracker->/** @scrutinizer ignore-call */ 
131
                               expects($this->exactly(2))

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
The method expects() does not exist on PHPUnit\Framework\MockObject\MockBuilder. ( Ignorable by Annotation )

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

130
        $this->contactTracker->/** @scrutinizer ignore-call */ 
131
                               expects($this->exactly(2))

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
131
            ->method('setSystemContact');
132
133
        // Legacy custom event should dispatch
134
        $this->dispatcher->expects($this->at(0))
135
            ->method('dispatch')
136
            ->with('something', $this->isInstanceOf(CampaignExecutionEvent::class));
137
138
        // Legacy execution event should dispatch
139
        $this->dispatcher->expects($this->at(1))
140
            ->method('dispatch')
141
            ->with(CampaignEvents::ON_EVENT_EXECUTION, $this->isInstanceOf(CampaignExecutionEvent::class));
142
143
        $this->getLegacyEventDispatcher()->dispatchCustomEvent($config, $logs, false, $pendingEvent);
144
    }
145
146
    public function testPrimaryCallbackIsProcessed()
147
    {
148
        $config = $this->getMockBuilder(AbstractEventAccessor::class)
149
            ->disableOriginalConstructor()
150
            ->getMock();
151
152
        $config->expects($this->exactly(2))
153
            ->method('getConfig')
154
            ->willReturn(['callback' => [self::class, 'bogusCallback']]);
155
156
        $event    = new Event();
157
        $campaign = new Campaign();
158
        $event->setCampaign($campaign);
159
        $leadEventLog = new LeadEventLog();
160
        $leadEventLog->setEvent($event);
161
        $leadEventLog->setLead(new Lead());
162
        $logs = new ArrayCollection([$leadEventLog]);
163
164
        $pendingEvent = $this->getMockBuilder(PendingEvent::class)
165
            ->disableOriginalConstructor()
166
            ->getMock();
167
168
        // BC default is to have pass
169
        $pendingEvent->expects($this->once())
170
            ->method('pass');
171
172
        $this->contactTracker->expects($this->exactly(2))
173
            ->method('setSystemContact');
174
175
        // Legacy execution event should dispatch
176
        $this->dispatcher->expects($this->at(0))
177
            ->method('dispatch')
178
            ->with(CampaignEvents::ON_EVENT_EXECUTION, $this->isInstanceOf(CampaignExecutionEvent::class));
179
180
        $this->getLegacyEventDispatcher()->dispatchCustomEvent($config, $logs, false, $pendingEvent);
181
    }
182
183
    public function testArrayResultAppendedToMetadata()
184
    {
185
        $config = $this->getMockBuilder(AbstractEventAccessor::class)
186
            ->disableOriginalConstructor()
187
            ->getMock();
188
189
        $config->expects($this->exactly(2))
190
            ->method('getConfig')
191
            ->willReturn(['eventName' => 'something']);
192
193
        $event    = new Event();
194
        $campaign = new Campaign();
195
        $event->setCampaign($campaign);
196
        $leadEventLog = new LeadEventLog();
197
        $leadEventLog->setEvent($event);
198
        $leadEventLog->setLead(new Lead());
199
        $leadEventLog->setMetadata(['bar' => 'foo']);
200
201
        $logs = new ArrayCollection([$leadEventLog]);
202
203
        $pendingEvent = $this->getMockBuilder(PendingEvent::class)
204
            ->disableOriginalConstructor()
205
            ->getMock();
206
207
        // BC default is to have pass
208
        $pendingEvent->expects($this->once())
209
            ->method('pass');
210
211
        $this->contactTracker->expects($this->exactly(2))
212
            ->method('setSystemContact');
213
214
        // Legacy custom event should dispatch
215
        $this->dispatcher->expects($this->at(0))
216
            ->method('dispatch')
217
            ->with('something', $this->isInstanceOf(CampaignExecutionEvent::class))
218
            ->willReturnCallback(function ($eventName, CampaignExecutionEvent $event) {
219
                $event->setResult(['foo' => 'bar']);
220
            });
221
222
        $this->getLegacyEventDispatcher()->dispatchCustomEvent($config, $logs, false, $pendingEvent);
223
224
        $this->assertEquals(['bar' => 'foo', 'foo' => 'bar'], $leadEventLog->getMetadata());
225
    }
226
227
    public function testFailedResultAsFalseIsProcessed()
228
    {
229
        $config = $this->getMockBuilder(AbstractEventAccessor::class)
230
            ->disableOriginalConstructor()
231
            ->getMock();
232
233
        $config->expects($this->exactly(2))
234
            ->method('getConfig')
235
            ->willReturn(['eventName' => 'something']);
236
237
        $lead     = new Lead();
238
        $event    = new Event();
239
        $campaign = new Campaign();
240
        $event->setCampaign($campaign);
241
        $leadEventLog = new LeadEventLog();
242
        $leadEventLog->setEvent($event);
243
        $leadEventLog->setLead($lead);
244
        $leadEventLog->setMetadata(['bar' => 'foo']);
245
246
        $logs = new ArrayCollection([$leadEventLog]);
247
248
        $pendingEvent = $this->getMockBuilder(PendingEvent::class)
249
            ->disableOriginalConstructor()
250
            ->getMock();
251
252
        // Should fail because we're returning false
253
        $pendingEvent->expects($this->once())
254
            ->method('fail');
255
256
        $this->contactTracker->expects($this->exactly(2))
257
            ->method('setSystemContact');
258
259
        // Legacy custom event should dispatch
260
        $this->dispatcher->expects($this->at(0))
261
            ->method('dispatch')
262
            ->with('something', $this->isInstanceOf(CampaignExecutionEvent::class))
263
            ->willReturnCallback(function ($eventName, CampaignExecutionEvent $event) {
264
                $event->setResult(false);
265
            });
266
267
        $this->dispatcher->expects($this->at(2))
268
            ->method('dispatch')
269
            ->with(CampaignEvents::ON_EVENT_FAILED, $this->isInstanceOf(FailedEvent::class));
270
271
        $this->scheduler->expects($this->once())
272
            ->method('rescheduleFailures');
273
274
        $this->notificationHelper->expects($this->once())
275
            ->method('notifyOfFailure')
276
            ->with($lead, $event);
277
278
        $this->getLegacyEventDispatcher()->dispatchCustomEvent($config, $logs, false, $pendingEvent);
279
    }
280
281
    public function testFailedResultAsArrayIsProcessed()
282
    {
283
        $config = $this->getMockBuilder(AbstractEventAccessor::class)
284
            ->disableOriginalConstructor()
285
            ->getMock();
286
287
        $config->expects($this->exactly(2))
288
            ->method('getConfig')
289
            ->willReturn(['eventName' => 'something']);
290
291
        $event    = new Event();
292
        $campaign = new Campaign();
293
        $event->setCampaign($campaign);
294
        $leadEventLog = new LeadEventLog();
295
        $leadEventLog->setEvent($event);
296
        $leadEventLog->setLead(new Lead());
297
298
        $logs = new ArrayCollection([$leadEventLog]);
299
300
        $pendingEvent = $this->getMockBuilder(PendingEvent::class)
301
            ->disableOriginalConstructor()
302
            ->getMock();
303
304
        // Should fail because we're returning false
305
        $pendingEvent->expects($this->once())
306
            ->method('fail');
307
308
        $this->contactTracker->expects($this->exactly(2))
309
            ->method('setSystemContact');
310
311
        // Legacy custom event should dispatch
312
        $this->dispatcher->expects($this->at(0))
313
            ->method('dispatch')
314
            ->with('something', $this->isInstanceOf(CampaignExecutionEvent::class))
315
            ->willReturnCallback(function ($eventName, CampaignExecutionEvent $event) {
316
                $event->setResult(['result' => false, 'foo' => 'bar']);
317
            });
318
319
        $this->dispatcher->expects($this->at(2))
320
            ->method('dispatch')
321
            ->with(CampaignEvents::ON_EVENT_FAILED, $this->isInstanceOf(FailedEvent::class));
322
323
        $this->scheduler->expects($this->once())
324
            ->method('rescheduleFailures');
325
326
        $this->getLegacyEventDispatcher()->dispatchCustomEvent($config, $logs, false, $pendingEvent);
327
    }
328
329
    public function testPassWithErrorIsHandled()
330
    {
331
        $config = $this->getMockBuilder(AbstractEventAccessor::class)
332
            ->disableOriginalConstructor()
333
            ->getMock();
334
335
        $config->expects($this->exactly(2))
336
            ->method('getConfig')
337
            ->willReturn(['eventName' => 'something']);
338
339
        $event    = new Event();
340
        $campaign = new Campaign();
341
        $event->setCampaign($campaign);
342
        $leadEventLog = new LeadEventLog();
343
        $leadEventLog->setEvent($event);
344
        $leadEventLog->setLead(new Lead());
345
        $leadEventLog->setMetadata(['bar' => 'foo']);
346
347
        $logs = new ArrayCollection([$leadEventLog]);
348
349
        $pendingEvent = $this->getMockBuilder(PendingEvent::class)
350
            ->disableOriginalConstructor()
351
            ->getMock();
352
353
        // Should pass but with an error logged
354
        $pendingEvent->expects($this->once())
355
            ->method('passWithError');
356
357
        $this->contactTracker->expects($this->exactly(2))
358
            ->method('setSystemContact');
359
360
        // Legacy custom event should dispatch
361
        $this->dispatcher->expects($this->at(0))
362
            ->method('dispatch')
363
            ->with('something', $this->isInstanceOf(CampaignExecutionEvent::class))
364
            ->willReturnCallback(function ($eventName, CampaignExecutionEvent $event) {
365
                $event->setResult(['failed' => 1, 'reason' => 'because']);
366
            });
367
368
        $this->scheduler->expects($this->never())
369
            ->method('rescheduleFailure');
370
371
        $this->getLegacyEventDispatcher()->dispatchCustomEvent($config, $logs, false, $pendingEvent);
372
    }
373
374
    public function testLogIsPassed()
375
    {
376
        $config = $this->getMockBuilder(AbstractEventAccessor::class)
377
            ->disableOriginalConstructor()
378
            ->getMock();
379
380
        $config->expects($this->exactly(2))
381
            ->method('getConfig')
382
            ->willReturn(['eventName' => 'something']);
383
384
        $event    = new Event();
385
        $campaign = new Campaign();
386
        $event->setCampaign($campaign);
387
        $leadEventLog = new LeadEventLog();
388
        $leadEventLog->setEvent($event);
389
        $leadEventLog->setLead(new Lead());
390
        $leadEventLog->setMetadata(['bar' => 'foo']);
391
392
        $logs = new ArrayCollection([$leadEventLog]);
393
394
        $pendingEvent = $this->getMockBuilder(PendingEvent::class)
395
            ->disableOriginalConstructor()
396
            ->getMock();
397
398
        // Should fail because we're returning false
399
        $pendingEvent->expects($this->once())
400
            ->method('pass');
401
402
        $this->contactTracker->expects($this->exactly(2))
403
            ->method('setSystemContact');
404
405
        // Should pass
406
        $this->dispatcher->expects($this->at(0))
407
            ->method('dispatch')
408
            ->with('something', $this->isInstanceOf(CampaignExecutionEvent::class))
409
            ->willReturnCallback(function ($eventName, CampaignExecutionEvent $event) {
410
                $event->setResult(true);
411
            });
412
413
        $this->scheduler->expects($this->never())
414
            ->method('rescheduleFailure');
415
416
        $this->getLegacyEventDispatcher()->dispatchCustomEvent($config, $logs, false, $pendingEvent);
417
    }
418
419
    public function testLegacyEventDispatchedForConvertedBatchActions()
420
    {
421
        $config = $this->getMockBuilder(AbstractEventAccessor::class)
422
            ->disableOriginalConstructor()
423
            ->getMock();
424
425
        $config->expects($this->exactly(1))
426
            ->method('getConfig')
427
            ->willReturn(['eventName' => 'something']);
428
429
        $event    = new Event();
430
        $campaign = new Campaign();
431
        $event->setCampaign($campaign);
432
        $leadEventLog = new LeadEventLog();
433
        $leadEventLog->setEvent($event);
434
        $leadEventLog->setLead(new Lead());
435
        $leadEventLog->setMetadata(['bar' => 'foo']);
436
437
        $logs = new ArrayCollection([$leadEventLog]);
438
439
        $pendingEvent = $this->getMockBuilder(PendingEvent::class)
440
            ->disableOriginalConstructor()
441
            ->getMock();
442
443
        // Should never be called
444
        $pendingEvent->expects($this->never())
445
            ->method('pass');
446
447
        $this->contactTracker->expects($this->exactly(2))
448
            ->method('setSystemContact');
449
450
        $this->dispatcher->expects($this->at(0))
451
            ->method('dispatch')
452
            ->with('something', $this->isInstanceOf(CampaignExecutionEvent::class))
453
            ->willReturnCallback(function ($eventName, CampaignExecutionEvent $event) {
454
                $event->setResult(true);
455
            });
456
457
        $this->getLegacyEventDispatcher()->dispatchCustomEvent($config, $logs, true, $pendingEvent);
458
    }
459
460
    /**
461
     * @return LegacyEventDispatcher
462
     */
463
    private function getLegacyEventDispatcher()
464
    {
465
        return new LegacyEventDispatcher(
466
            $this->dispatcher,
467
            $this->scheduler,
468
            new NullLogger(),
469
            $this->notificationHelper,
470
            $this->mauticFactory,
0 ignored issues
show
It seems like $this->mauticFactory can also be of type PHPUnit\Framework\MockObject\MockBuilder; however, parameter $factory of Mautic\CampaignBundle\Ex...spatcher::__construct() does only seem to accept Mautic\CoreBundle\Factory\MauticFactory, maybe add an additional type check? ( Ignorable by Annotation )

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

470
            /** @scrutinizer ignore-type */ $this->mauticFactory,
Loading history...
471
            $this->contactTracker
0 ignored issues
show
It seems like $this->contactTracker can also be of type PHPUnit\Framework\MockObject\MockBuilder; however, parameter $contactTracker of Mautic\CampaignBundle\Ex...spatcher::__construct() does only seem to accept Mautic\LeadBundle\Tracker\ContactTracker, maybe add an additional type check? ( Ignorable by Annotation )

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

471
            /** @scrutinizer ignore-type */ $this->contactTracker
Loading history...
472
        );
473
    }
474
475
    public static function bogusCallback()
476
    {
477
        return true;
478
    }
479
}
480