Completed
Push — master ( 6d2f87...a1ca3e )
by
unknown
83:38 queued 43:39
created

MongoQueueTest::testRelease()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 27
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 16
nc 1
nop 0
1
<?php
2
3
namespace SfCod\QueueBundle\Tests\Queue;
4
5
use Helmich\MongoMock\MockDatabase;
6
use MongoDB\Database;
7
use PHPUnit\Framework\TestCase;
8
use SfCod\QueueBundle\Base\JobResolverInterface;
9
use SfCod\QueueBundle\Base\MongoDriverInterface;
10
use SfCod\QueueBundle\Entity\Job;
11
use SfCod\QueueBundle\Job\JobContractInterface;
12
use SfCod\QueueBundle\Queue\MongoQueue;
13
14
/**
15
 * Class MongoQueueTest
16
 *
17
 * @author Virchenko Maksim <[email protected]>
18
 *
19
 * @package SfCod\QueueBundle\Tests\Queue
20
 */
21
class MongoQueueTest extends TestCase
22
{
23
    /**
24
     * Test pushing into database
25
     */
26
    public function testPush()
27
    {
28
        $collection = uniqid('collection_');
29
        $jobName = uniqid('job_');
30
        $data = range(1, 10);
31
32
        $database = new MockDatabase();
33
34
        $mongoQueue = $this->mockMongoQueue($database, $collection);
35
36
        $mongoQueue->push($jobName, $data);
37
38
        $this->assertEquals(1, $database->selectCollection($collection)->count());
39
40
        $job = $database->selectCollection($collection)->findOne();
41
42
        $payload = json_decode($job->payload, true);
43
        $this->assertEquals($jobName, $payload['job']);
44
        $this->assertEquals($data, $payload['data']);
45
    }
46
47
    /**
48
     * Test pop from queue
49
     */
50
    public function testPop()
51
    {
52
        $collection = uniqid('collection_');
53
        $jobName = uniqid('job_');
54
        $data = range(1, 10);
55
56
        $database = new MockDatabase();
57
58
        $mongoQueue = $this->mockMongoQueue($database, $collection);
59
60
        $mongoQueue->push($jobName, $data);
61
62
        $job = $mongoQueue->pop();
63
        $this->assertEquals($jobName, $job->getName());
64
        $this->assertEquals($data, $job->payload()['data']);
65
    }
66
67
    /**
68
     * Test if job exists
69
     */
70
    public function testExists()
71
    {
72
        $collection = uniqid('collection_');
73
        $jobName = uniqid('job_');
74
        $data = range(1, 10);
75
76
        $database = new MockDatabase();
77
78
        $mongoQueue = $this->mockMongoQueue($database, $collection);
79
80
        $mongoQueue->push($jobName, $data);
81
82
        $this->assertTrue($mongoQueue->exists($jobName, $data));
83
    }
84
85
    /**
86
     * Test pushing into database
87
     */
88
    public function testPushOn()
89
    {
90
        $collection = uniqid('collection_');
91
        $jobName = uniqid('job_');
92
        $data = range(1, 10);
93
94
        $database = new MockDatabase();
95
96
        $mongoQueue = $this->mockMongoQueue($database, $collection);
97
98
        $mongoQueue->pushOn('default', $jobName, $data);
99
100
        $this->assertEquals(1, $database->selectCollection($collection)->count());
101
102
        $job = $database->selectCollection($collection)->findOne();
103
104
        $payload = json_decode($job->payload, true);
105
        $this->assertEquals($jobName, $payload['job']);
106
        $this->assertEquals($data, $payload['data']);
107
    }
108
109
    /**
110
     * Test pushing into database
111
     */
112
    public function testPushRaw()
113
    {
114
        $collection = uniqid('collection_');
115
        $jobName = uniqid('job_');
116
        $data = range(1, 10);
117
118
        $database = new MockDatabase();
119
120
        $mongoQueue = $this->mockMongoQueue($database, $collection);
121
122
        $mongoQueue->pushRaw(json_encode(['job' => $jobName, 'data' => $data]));
123
124
        $count = $database->selectCollection($collection)->count();
125
        $this->assertEquals(1, $count);
126
127
        $job = $database->selectCollection($collection)->findOne();
128
129
        $payload = json_decode($job->payload, true);
130
        $this->assertEquals($jobName, $payload['job']);
131
        $this->assertEquals($data, $payload['data']);
132
    }
133
134
    /**
135
     * Test pushing job for later
136
     */
137
    public function testLater()
138
    {
139
        $collection = uniqid('collection_');
140
        $jobName = uniqid('job_');
141
        $data = range(1, 10);
142
        $delay = rand(60, 3600);
143
144
        $database = new MockDatabase();
145
146
        $mongoQueue = $this->mockMongoQueue($database, $collection);
147
148
        $mongoQueue->later($delay, $jobName, $data);
149
150
        $job = $database->selectCollection($collection)->findOne();
151
152
        $payload = json_decode($job->payload, true);
153
        $this->assertEquals($jobName, $payload['job']);
154
        $this->assertEquals($data, $payload['data']);
155
156
        $this->assertGreaterThan(time() + $delay - 10, $job->available_at);
157
    }
158
159
    /**
160
     * Test pushing bulk
161
     */
162
    public function testBulk()
163
    {
164
        $collection = uniqid('collection_');
165
        $jobName = uniqid('job_');
166
        $data = range(1, 10);
167
        $delay = rand(60, 3600);
0 ignored issues
show
Unused Code introduced by
$delay is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
168
169
        $database = new MockDatabase();
170
171
        $mongoQueue = $this->mockMongoQueue($database, $collection);
172
173
        for ($i = 0; $i < 10; ++$i) {
174
            $jobs[] = $jobName . $i;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$jobs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $jobs = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
175
        }
176
177
        $mongoQueue->bulk($jobs, $data);
0 ignored issues
show
Bug introduced by
The variable $jobs does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
178
179
        $count = $database->selectCollection($collection)->count();
180
181
        $this->assertEquals(10, $count);
182
    }
183
184
    /**
185
     * Test release
186
     */
187
    public function testRelease()
188
    {
189
        $collection = uniqid('collection_');
190
        $jobName = uniqid('job_');
191
        $data = range(1, 10);
192
193
        $database = new MockDatabase();
194
195
        $mongoQueue = $this->mockMongoQueue($database, $collection);
196
197
        $mongoQueue->push($jobName, $data);
198
199
        $job = $database->selectCollection($collection)->findOne();
200
201
        $database->selectCollection($collection)->deleteMany([]);
202
203
        $jobToRelease = new Job();
204
        $jobToRelease->setId($job->_id);
205
        $jobToRelease->setQueue($job->queue);
206
        $jobToRelease->setAttempts($job->attempts);
207
208
        $mongoQueue->release($jobToRelease, 0);
209
210
        $count = $database->selectCollection($collection)->count();
211
212
        $this->assertEquals(1, $count);
213
    }
214
215
    /**
216
     * Test getting job by id
217
     */
218
    public function testGetJobById()
219
    {
220
        $collection = uniqid('collection_');
221
        $jobName = uniqid('job_');
222
        $data = range(1, 10);
223
224
        $database = new MockDatabase();
225
226
        $mongoQueue = $this->mockMongoQueue($database, $collection);
227
228
        $mongoQueue->push($jobName, $data);
229
230
        $job = $database->selectCollection($collection)->findOne();
231
232
        $jobContract = $mongoQueue->getJobById($job->_id);
233
234
        $this->assertInstanceOf(JobContractInterface::class, $jobContract);
235
        $this->assertEquals($jobContract->getName(), $jobName);
236
    }
237
238
    /**
239
     * Test deleting reserved
240
     */
241
    public function testDeleteReserved()
242
    {
243
        $collection = uniqid('collection_');
244
        $jobName = uniqid('job_');
245
        $data = range(1, 10);
246
247
        $database = new MockDatabase();
248
249
        $mongoQueue = $this->mockMongoQueue($database, $collection);
250
251
        $mongoQueue->push($jobName, $data);
252
253
        $count = $database->selectCollection($collection)->count();
254
255
        $this->assertEquals(1, $count);
256
257
        $job = $database->selectCollection($collection)->findOne();
258
        $result = $mongoQueue->deleteReserved($job->queue, $job->_id);
259
260
        $this->assertTrue($result);
261
262
        $count = $database->selectCollection($collection)->count();
263
264
        $this->assertEquals(0, $count);
265
    }
266
267
    /**
268
     * Test expire queue
269
     */
270
    public function testExpire()
271
    {
272
        $collection = uniqid('collection_');
273
        $expire = rand(1, 99999);
274
275
        $database = new MockDatabase();
276
277
        $mongoQueue = $this->mockMongoQueue($database, $collection);
278
279
        $mongoQueue->setExpire($expire);
280
281
        $this->assertEquals($expire, $mongoQueue->getExpire());
282
    }
283
284
    /**
285
     * Test queue's size
286
     */
287
    public function testSize()
288
    {
289
        $collection = uniqid('collection_');
290
        $jobName = uniqid('job_');
291
        $data = range(1, 10);
292
293
        $database = new MockDatabase();
294
295
        $mongoQueue = $this->mockMongoQueue($database, $collection);
296
297
        for ($i = 0; $i < 10; ++$i) {
298
            $mongoQueue->push($jobName, $data);
299
        }
300
301
        $job = $database->selectCollection($collection)->findOne();
302
303
        $count = $database->selectCollection($collection)->count();
304
305
        $this->assertEquals($count, $mongoQueue->size());
306
        $this->assertEquals($count, $mongoQueue->size($job->queue));
307
    }
308
309
    /**
310
     * Test can run job
311
     */
312
    public function testCanRunJob()
313
    {
314
        $collection = uniqid('collection_');
315
        $jobName = uniqid('job_');
316
        $data = range(1, 10);
317
318
        $database = new MockDatabase();
319
320
        $mongoQueue = $this->mockMongoQueue($database, $collection);
321
322
        $mongoQueue->push($jobName, $data);
323
324
        $job = $database->selectCollection($collection)->findOne();
325
326
        /** @var JobContractInterface $jobContract */
327
        $jobContract = $mongoQueue->getJobById($job->_id);
328
329
        $canRun = $mongoQueue->canRunJob($jobContract);
330
331
        $this->assertTrue($canRun);
332
    }
333
334
    /**
335
     * Test mark job as reserved
336
     */
337
    public function testMarkJobAsReserved()
338
    {
339
        $collection = uniqid('collection_');
340
        $jobName = uniqid('job_');
341
        $data = range(1, 10);
342
343
        $database = new MockDatabase();
344
345
        $mongoQueue = $this->mockMongoQueue($database, $collection);
346
347
        $mongoQueue->push($jobName, $data);
348
349
        $job = $database->selectCollection($collection)->findOne();
350
        $attempts = $job->attempts;
351
352
        /** @var JobContractInterface $jobContract */
353
        $jobContract = $mongoQueue->getJobById($job->_id);
354
355
        $mongoQueue->markJobAsReserved($jobContract);
356
357
        $reservedJob = $database->selectCollection($collection)->findOne();
358
359
        $this->assertTrue((bool)$reservedJob->reserved);
360
        $this->assertGreaterThan($attempts, $reservedJob->attempts);
361
        $this->assertNotNull($reservedJob->reserved_at);
362
    }
363
364
    /**
365
     * Mock mongo queue
366
     *
367
     * @param Database $database
368
     * @param string $collection
369
     *
370
     * @return MongoQueue
371
     */
372
    private function mockMongoQueue(Database $database, string $collection): MongoQueue
373
    {
374
        $jobResolver = $this->createMock(JobResolverInterface::class);
375
        $mongo = $this->createMock(MongoDriverInterface::class);
376
        $mongo
377
            ->expects($this->any())
378
            ->method('getDatabase')
379
            ->will($this->returnValue($database));
380
381
        $mongoQueue = new MongoQueue($jobResolver, $mongo, $collection);
0 ignored issues
show
Documentation introduced by
$jobResolver is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<SfCod\QueueBundle...e\JobResolverInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Documentation introduced by
$mongo is of type object<PHPUnit\Framework\MockObject\MockObject>, but the function expects a object<SfCod\QueueBundle...e\MongoDriverInterface>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
382
383
        return $mongoQueue;
384
    }
385
}
386