Completed
Push — master ( 010450...4100f7 )
by
unknown
36:49
created

MongoQueueTest::testMarkJobAsReserved()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 15
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\Job\JobContractInterface;
11
use SfCod\QueueBundle\Queue\MongoQueue;
12
13
/**
14
 * Class MongoQueueTest
15
 *
16
 * @author Virchenko Maksim <[email protected]>
17
 *
18
 * @package SfCod\QueueBundle\Tests\Queue
19
 */
20
class MongoQueueTest extends TestCase
21
{
22
    /**
23
     * Test pushing into database
24
     */
25
    public function testPush()
26
    {
27
        $collection = uniqid('collection_');
28
        $jobName = uniqid('job_');
29
        $data = range(1, 10);
30
31
        $database = new MockDatabase();
32
33
        $mongoQueue = $this->mockMongoQueue($database, $collection);
34
35
        $mongoQueue->push($jobName, $data);
36
37
        $this->assertEquals(1, $database->selectCollection($collection)->count());
38
39
        $job = $database->selectCollection($collection)->findOne();
40
41
        $payload = json_decode($job->payload, true);
42
        $this->assertEquals($jobName, $payload['job']);
43
        $this->assertEquals($data, $payload['data']);
44
    }
45
46
    /**
47
     * Test pop from queue
48
     */
49
    public function testPop()
50
    {
51
        $collection = uniqid('collection_');
52
        $jobName = uniqid('job_');
53
        $data = range(1, 10);
54
55
        $database = new MockDatabase();
56
57
        $mongoQueue = $this->mockMongoQueue($database, $collection);
58
59
        $mongoQueue->push($jobName, $data);
60
61
        $job = $mongoQueue->pop();
62
        $this->assertEquals($jobName, $job->getName());
63
        $this->assertEquals($data, $job->payload()['data']);
64
    }
65
66
    /**
67
     * Test if job exists
68
     */
69
    public function testExists()
70
    {
71
        $collection = uniqid('collection_');
72
        $jobName = uniqid('job_');
73
        $data = range(1, 10);
74
75
        $database = new MockDatabase();
76
77
        $mongoQueue = $this->mockMongoQueue($database, $collection);
78
79
        $mongoQueue->push($jobName, $data);
80
81
        $this->assertTrue($mongoQueue->exists($jobName, $data));
82
    }
83
84
    /**
85
     * Test pushing into database
86
     */
87
    public function testPushOn()
88
    {
89
        $collection = uniqid('collection_');
90
        $jobName = uniqid('job_');
91
        $data = range(1, 10);
92
93
        $database = new MockDatabase();
94
95
        $mongoQueue = $this->mockMongoQueue($database, $collection);
96
97
        $mongoQueue->pushOn('default', $jobName, $data);
98
99
        $this->assertEquals(1, $database->selectCollection($collection)->count());
100
101
        $job = $database->selectCollection($collection)->findOne();
102
103
        $payload = json_decode($job->payload, true);
104
        $this->assertEquals($jobName, $payload['job']);
105
        $this->assertEquals($data, $payload['data']);
106
    }
107
108
    /**
109
     * Test pushing into database
110
     */
111
    public function testPushRaw()
112
    {
113
        $collection = uniqid('collection_');
114
        $jobName = uniqid('job_');
115
        $data = range(1, 10);
116
117
        $database = new MockDatabase();
118
119
        $mongoQueue = $this->mockMongoQueue($database, $collection);
120
121
        $mongoQueue->pushRaw(json_encode(['job' => $jobName, 'data' => $data]));
122
123
        $count = $database->selectCollection($collection)->count();
124
        $this->assertEquals(1, $count);
125
126
        $job = $database->selectCollection($collection)->findOne();
127
128
        $payload = json_decode($job->payload, true);
129
        $this->assertEquals($jobName, $payload['job']);
130
        $this->assertEquals($data, $payload['data']);
131
    }
132
133
    /**
134
     * Test pushing job for later
135
     */
136
    public function testLater()
137
    {
138
        $collection = uniqid('collection_');
139
        $jobName = uniqid('job_');
140
        $data = range(1, 10);
141
        $delay = rand(60, 3600);
142
143
        $database = new MockDatabase();
144
145
        $mongoQueue = $this->mockMongoQueue($database, $collection);
146
147
        $mongoQueue->later($delay, $jobName, $data);
148
149
        $job = $database->selectCollection($collection)->findOne();
150
151
        $payload = json_decode($job->payload, true);
152
        $this->assertEquals($jobName, $payload['job']);
153
        $this->assertEquals($data, $payload['data']);
154
155
        $this->assertGreaterThan(time() + $delay - 10, $job->available_at);
156
    }
157
158
    /**
159
     * Test pushing bulk
160
     */
161
    public function testBulk()
162
    {
163
        $collection = uniqid('collection_');
164
        $jobName = uniqid('job_');
165
        $data = range(1, 10);
166
        $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...
167
168
        $database = new MockDatabase();
169
170
        $mongoQueue = $this->mockMongoQueue($database, $collection);
171
172
        for ($i = 0; $i < 10; ++$i) {
173
            $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...
174
        }
175
176
        $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...
177
178
        $count = $database->selectCollection($collection)->count();
179
180
        $this->assertEquals(10, $count);
181
    }
182
183
    /**
184
     * Test release
185
     */
186
    public function testRelease()
187
    {
188
        $collection = uniqid('collection_');
189
        $jobName = uniqid('job_');
190
        $data = range(1, 10);
191
192
        $database = new MockDatabase();
193
194
        $mongoQueue = $this->mockMongoQueue($database, $collection);
195
196
        $mongoQueue->push($jobName, $data);
197
198
        $job = $database->selectCollection($collection)->findOne();
199
200
        $database->selectCollection($collection)->deleteMany([]);
201
202
        $mongoQueue->release($job->queue, $job, 0);
0 ignored issues
show
Documentation introduced by
$job is of type array|object, but the function expects a object<stdClass>.

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...
203
204
        $count = $database->selectCollection($collection)->count();
205
206
        $this->assertEquals(1, $count);
207
    }
208
209
    /**
210
     * Test getting job by id
211
     */
212
    public function testGetJobById()
213
    {
214
        $collection = uniqid('collection_');
215
        $jobName = uniqid('job_');
216
        $data = range(1, 10);
217
218
        $database = new MockDatabase();
219
220
        $mongoQueue = $this->mockMongoQueue($database, $collection);
221
222
        $mongoQueue->push($jobName, $data);
223
224
        $job = $database->selectCollection($collection)->findOne();
225
226
        $jobContract = $mongoQueue->getJobById($job->_id);
227
228
        $this->assertInstanceOf(JobContractInterface::class, $jobContract);
229
        $this->assertEquals($jobContract->getName(), $jobName);
230
    }
231
232
    /**
233
     * Test deleting reserved
234
     */
235
    public function testDeleteReserved()
236
    {
237
        $collection = uniqid('collection_');
238
        $jobName = uniqid('job_');
239
        $data = range(1, 10);
240
241
        $database = new MockDatabase();
242
243
        $mongoQueue = $this->mockMongoQueue($database, $collection);
244
245
        $mongoQueue->push($jobName, $data);
246
247
        $count = $database->selectCollection($collection)->count();
248
249
        $this->assertEquals(1, $count);
250
251
        $job = $database->selectCollection($collection)->findOne();
252
        $result = $mongoQueue->deleteReserved($job->queue, $job->_id);
253
254
        $this->assertTrue($result);
255
256
        $count = $database->selectCollection($collection)->count();
257
258
        $this->assertEquals(0, $count);
259
    }
260
261
    /**
262
     * Test expire queue
263
     */
264
    public function testExpire()
265
    {
266
        $collection = uniqid('collection_');
267
        $expire = rand(1, 99999);
268
269
        $database = new MockDatabase();
270
271
        $mongoQueue = $this->mockMongoQueue($database, $collection);
272
273
        $mongoQueue->setExpire($expire);
274
275
        $this->assertEquals($expire, $mongoQueue->getExpire());
276
    }
277
278
    /**
279
     * Test queue's size
280
     */
281
    public function testSize()
282
    {
283
        $collection = uniqid('collection_');
284
        $jobName = uniqid('job_');
285
        $data = range(1, 10);
286
287
        $database = new MockDatabase();
288
289
        $mongoQueue = $this->mockMongoQueue($database, $collection);
290
291
        for ($i = 0; $i < 10; ++$i) {
292
            $mongoQueue->push($jobName, $data);
293
        }
294
295
        $job = $database->selectCollection($collection)->findOne();
296
297
        $count = $database->selectCollection($collection)->count();
298
299
        $this->assertEquals($count, $mongoQueue->size());
300
        $this->assertEquals($count, $mongoQueue->size($job->queue));
301
    }
302
303
    /**
304
     * Test can run job
305
     */
306
    public function testCanRunJob()
307
    {
308
        $collection = uniqid('collection_');
309
        $jobName = uniqid('job_');
310
        $data = range(1, 10);
311
312
        $database = new MockDatabase();
313
314
        $mongoQueue = $this->mockMongoQueue($database, $collection);
315
316
        $mongoQueue->push($jobName, $data);
317
318
        $job = $database->selectCollection($collection)->findOne();
319
320
        /** @var JobContractInterface $jobContract */
321
        $jobContract = $mongoQueue->getJobById($job->_id);
322
323
        $canRun = $mongoQueue->canRunJob($jobContract);
324
325
        $this->assertTrue($canRun);
326
    }
327
328
    /**
329
     * Test mark job as reserved
330
     */
331
    public function testMarkJobAsReserved()
332
    {
333
        $collection = uniqid('collection_');
334
        $jobName = uniqid('job_');
335
        $data = range(1, 10);
336
337
        $database = new MockDatabase();
338
339
        $mongoQueue = $this->mockMongoQueue($database, $collection);
340
341
        $mongoQueue->push($jobName, $data);
342
343
        $job = $database->selectCollection($collection)->findOne();
344
        $attempts = $job->attempts;
345
346
        /** @var JobContractInterface $jobContract */
347
        $jobContract = $mongoQueue->getJobById($job->_id);
348
349
        $mongoQueue->markJobAsReserved($jobContract);
350
351
        $reservedJob = $database->selectCollection($collection)->findOne();
352
353
        $this->assertTrue((bool)$reservedJob->reserved);
354
        $this->assertGreaterThan($attempts, $reservedJob->attempts);
355
        $this->assertNotNull($reservedJob->reserved_at);
356
    }
357
358
    /**
359
     * Mock mongo queue
360
     *
361
     * @param Database $database
362
     * @param string $collection
363
     *
364
     * @return MongoQueue
365
     */
366
    private function mockMongoQueue(Database $database, string $collection): MongoQueue
367
    {
368
        $jobResolver = $this->createMock(JobResolverInterface::class);
369
        $mongo = $this->createMock(MongoDriverInterface::class);
370
        $mongo
371
            ->expects($this->any())
372
            ->method('getDatabase')
373
            ->will($this->returnValue($database));
374
375
        $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...
376
377
        return $mongoQueue;
378
    }
379
}
380