Completed
Pull Request — master (#35)
by
unknown
04:28
created

QueuedTasksTableTest::setUp()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author [email protected]
4
 * @license http://www.opensource.org/licenses/mit-license.php The MIT License
5
 * @link http://github.com/MSeven/cakephp_queue
6
 */
7
namespace Queue\Test\TestCase\Model\Table;
8
9
use Cake\Datasource\ConnectionManager;
10
use Cake\I18n\FrozenTime;
11
use Cake\I18n\Time;
12
use Cake\ORM\TableRegistry;
13
use Cake\TestSuite\TestCase;
14
use Queue\Model\Table\QueuedTasksTable;
15
16
/**
17
 * Queue\Model\Table\QueuedTasksTable Test Case
18
 */
19
class QueuedTasksTableTest extends TestCase
20
{
21
22
    /**
23
     *
24
     * @var \Queue\Model\Table\QueuedTasksTable
25
     */
26
    protected $QueuedTasks;
27
28
    /**
29
     * Fixtures
30
     *
31
     * @var array
32
     */
33
    public $fixtures = [
34
        'plugin.Queue.QueuedTasks'
35
    ];
36
37
    /**
38
     * setUp method
39
     *
40
     * @return void
41
     */
42
    public function setUp()
43
    {
44
        parent::setUp();
45
        $config = TableRegistry::getTableLocator()->exists('QueuedTasks') ? [] : [
46
            'className' => QueuedTasksTable::class
47
        ];
48
        $this->QueuedTasks = TableRegistry::getTableLocator()->get('QueuedTasks', $config);
49
    }
50
51
    /**
52
     * Basic Instance test
53
     *
54
     * @return void
55
     */
56
    public function testQueueInstance()
57
    {
58
        $this->assertInstanceOf(QueuedTasksTable::class, $this->QueuedTasks);
59
    }
60
61
    /**
62
     * Test the basic create and length evaluation functions.
63
     *
64
     * @return void
65
     */
66
    public function testCreateAndCount()
67
    {
68
        // at first, the queue should contain 0 items.
69
        $this->assertSame(0, $this->QueuedTasks->getLength());
70
71
        // create a job
72
        $this->assertTrue((bool)$this->QueuedTasks->createJob('test1', [
73
            'some' => 'random',
74
            'test' => 'data'
75
        ]));
76
77
        // test if queue Length is 1 now.
78
        $this->assertSame(1, $this->QueuedTasks->getLength());
79
80
        // create some more jobs
81
        $this->assertTrue((bool)$this->QueuedTasks->createJob('test2', [
82
            'some' => 'random',
83
            'test' => 'data2'
84
        ]));
85
        $this->assertTrue((bool)$this->QueuedTasks->createJob('test2', [
86
            'some' => 'random',
87
            'test' => 'data3'
88
        ]));
89
        $this->assertTrue((bool)$this->QueuedTasks->createJob('test3', [
90
            'some' => 'random',
91
            'test' => 'data4'
92
        ]));
93
94
        // overall queueLength shpould now be 4
95
        $this->assertSame(4, $this->QueuedTasks->getLength());
96
97
        // there should be 1 task of type 'test1', one of type 'test3' and 2 of type 'test2'
98
        $this->assertSame(1, $this->QueuedTasks->getLength('test1'));
99
        $this->assertSame(2, $this->QueuedTasks->getLength('test2'));
100
        $this->assertSame(1, $this->QueuedTasks->getLength('test3'));
101
    }
102
103
    /**
104
     * Test the basic create and fetch functions.
105
     *
106
     * @return void
107
     */
108
    public function testCreateAndFetch()
109
    {
110
        $this->_needsConnection();
111
112
        // $capabilities is a list of tasks the worker can run.
113
        $capabilities = [
114
            'task1' => [
115
                'name' => 'task1',
116
                'timeout' => 100,
117
                'retries' => 2
118
            ]
119
        ];
120
        $testData = [
121
            'x1' => 'y1',
122
            'x2' => 'y2',
123
            'x3' => 'y3',
124
            'x4' => 'y4'
125
        ];
126
127
        // start off empty.
128
        $this->assertSame([], $this->QueuedTasks->find()
129
            ->toArray());
130
        // at first, the queue should contain 0 items.
131
        $this->assertSame(0, $this->QueuedTasks->getLength());
132
        // there are no jobs, so we cant fetch any.
133
        $this->assertNull($this->QueuedTasks->requestJob($capabilities));
134
        // insert one job.
135
        $this->assertTrue((bool)$this->QueuedTasks->createJob('task1', $testData));
136
137
        // fetch and check the first job.
138
        $job = $this->QueuedTasks->requestJob($capabilities);
139
        $this->assertSame(1, $job->id);
140
        $this->assertSame('task1', $job->task);
141
        $this->assertSame(0, $job->failed_count);
142
        $this->assertNull($job->completed);
143
        $this->assertSame($testData, unserialize($job->data));
144
145
        // after this job has been fetched, it may not be reassigned.
146
        $result = $this->QueuedTasks->requestJob($capabilities);
147
        $this->assertNull($result);
148
149
        // queue length is still 1 since the first job did not finish.
150
        $this->assertSame(1, $this->QueuedTasks->getLength());
151
152
        // Now mark Task1 as done
153
        $this->assertTrue($this->QueuedTasks->markJobDone($job));
0 ignored issues
show
Bug introduced by
It seems like $job can also be of type null; however, parameter $task of Queue\Model\Table\QueuedTasksTable::markJobDone() does only seem to accept Queue\Model\Entity\QueuedTask, 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

153
        $this->assertTrue($this->QueuedTasks->markJobDone(/** @scrutinizer ignore-type */ $job));
Loading history...
154
155
        // Should be 0 again.
156
        $this->assertSame(0, $this->QueuedTasks->getLength());
157
    }
158
159
    /**
160
     * Test the delivery of jobs in sequence, skipping fetched but not completed tasks.
161
     *
162
     * @return void
163
     */
164
    public function testSequence()
165
    {
166
        $this->_needsConnection();
167
168
        // $capabilities is a list of tasks the worker can run.
169
        $capabilities = [
170
            'task1' => [
171
                'name' => 'task1',
172
                'timeout' => 100,
173
                'retries' => 2
174
            ]
175
        ];
176
        // at first, the queue should contain 0 items.
177
        $this->assertSame(0, $this->QueuedTasks->getLength());
178
        // create some more jobs
179
        foreach (range(0, 9) as $num) {
180
            $this->assertTrue((bool)$this->QueuedTasks->createJob('task1', [
181
                'tasknum' => $num
182
            ]));
183
        }
184
        // 10 jobs in the queue.
185
        $this->assertSame(10, $this->QueuedTasks->getLength());
186
187
        // jobs should be fetched in the original sequence.
188
        $array = [];
189
        foreach (range(0, 4) as $num) {
190
            $array[$num] = $this->QueuedTasks->requestJob($capabilities);
191
            $jobData = unserialize($array[$num]['data']);
192
            $this->assertSame($num, $jobData['tasknum']);
193
        }
194
        // now mark them as done
195
        foreach (range(0, 4) as $num) {
196
            $this->assertTrue($this->QueuedTasks->markJobDone($array[$num]));
197
            $this->assertSame(9 - $num, $this->QueuedTasks->getLength());
198
        }
199
200
        // jobs should be fetched in the original sequence.
201
        foreach (range(5, 9) as $num) {
202
            $job = $this->QueuedTasks->requestJob($capabilities);
203
            $jobData = unserialize($job->data);
204
            $this->assertSame($num, $jobData['tasknum']);
205
            $this->assertTrue($this->QueuedTasks->markJobDone($job));
0 ignored issues
show
Bug introduced by
It seems like $job can also be of type null; however, parameter $task of Queue\Model\Table\QueuedTasksTable::markJobDone() does only seem to accept Queue\Model\Entity\QueuedTask, 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

205
            $this->assertTrue($this->QueuedTasks->markJobDone(/** @scrutinizer ignore-type */ $job));
Loading history...
206
            $this->assertSame(9 - $num, $this->QueuedTasks->getLength());
207
        }
208
    }
209
210
    /**
211
     * Test creating Jobs to run close to a specified time, and strtotime parsing.
212
     * Using toUnixString() function to convert Time object to timestamp, instead of strtotime
213
     *
214
     * @return null
215
     */
216
    public function testNotBefore()
217
    {
218
        $this->assertTrue((bool)$this->QueuedTasks->createJob('task1', null, '+ 1 Min'));
219
        $this->assertTrue((bool)$this->QueuedTasks->createJob('task1', null, '+ 1 Day'));
220
        $this->assertTrue((bool)$this->QueuedTasks->createJob('task1', null, '2009-07-01 12:00:00'));
221
        $data = $this->QueuedTasks->find('all')->toArray();
222
        $this->assertWithinRange((new Time('+ 1 Min'))->toUnixString(), $data[0]['not_before']->toUnixString(), 60);
0 ignored issues
show
Bug introduced by
new Cake\I18n\Time('+ 1 Min')->toUnixString() of type string is incompatible with the type double expected by parameter $expected of Cake\TestSuite\TestCase::assertWithinRange(). ( Ignorable by Annotation )

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

222
        $this->assertWithinRange(/** @scrutinizer ignore-type */ (new Time('+ 1 Min'))->toUnixString(), $data[0]['not_before']->toUnixString(), 60);
Loading history...
223
        $this->assertWithinRange((new Time('+ 1 Day'))->toUnixString(), $data[1]['not_before']->toUnixString(), 60);
224
        $this->assertWithinRange((new Time('2009-07-01 12:00:00'))->toUnixString(), $data[2]['not_before']->toUnixString(), 60);
225
    }
226
227
    /**
228
     * Test Job reordering depending on 'notBefore' field.
229
     * Jobs with an expired not_before field should be executed before any other job without specific timing info.
230
     *
231
     * @return void
232
     */
233
    public function testNotBeforeOrder()
234
    {
235
        $this->_needsConnection();
236
237
        $capabilities = [
238
            'task1' => [
239
                'name' => 'task1',
240
                'timeout' => 100,
241
                'retries' => 2
242
            ],
243
            'dummytask' => [
244
                'name' => 'dummytask',
245
                'timeout' => 100,
246
                'retries' => 2
247
            ]
248
        ];
249
        $this->assertTrue((bool)$this->QueuedTasks->createJob('dummytask'));
250
        $this->assertTrue((bool)$this->QueuedTasks->createJob('dummytask'));
251
        // create a task with it's execution target some seconds in the past, so it should jump to the top of the testCreateAndFetchlist.
252
        $this->assertTrue((bool)$this->QueuedTasks->createJob('task1', [
253
            'three'
254
        ], '- 3 Seconds'));
255
        $this->assertTrue((bool)$this->QueuedTasks->createJob('task1', [
256
            'two'
257
        ], '- 5 Seconds'));
258
        $this->assertTrue((bool)$this->QueuedTasks->createJob('task1', [
259
            'one'
260
        ], '- 7 Seconds'));
261
262
        // when using requestJob, the jobs we just created should be delivered in this order, NOT the order in which they where created.
263
        $expected = [
264
            [
265
                'name' => 'task1',
266
                'data' => [
267
                    'one'
268
                ]
269
            ],
270
            [
271
                'name' => 'task1',
272
                'data' => [
273
                    'two'
274
                ]
275
            ],
276
            [
277
                'name' => 'task1',
278
                'data' => [
279
                    'three'
280
                ]
281
            ],
282
            [
283
                'name' => 'dummytask',
284
                'data' => null
285
            ],
286
            [
287
                'name' => 'dummytask',
288
                'data' => null
289
            ]
290
        ];
291
292
        foreach ($expected as $item) {
293
            $tmp = $this->QueuedTasks->requestJob($capabilities);
294
295
            $this->assertSame($item['name'], $tmp['task']);
296
            $this->assertEquals($item['data'], unserialize($tmp['data']));
297
        }
298
    }
299
300
    /**
301
     * Helper method for skipping tests that need a real connection.
302
     *
303
     * @return void
304
     */
305
    protected function _needsConnection()
306
    {
307
        $config = ConnectionManager::getConfig('test');
308
        $this->skipIf(strpos($config['driver'], 'Mysql') === false, 'Only Mysql is working yet for this.');
309
    }
310
}
311