GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( 6956e2...9a55f0 )
by
unknown
02:08
created

QueuedJobsTest::testQueueJob()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 9.536
c 0
b 0
f 0
cc 3
nc 3
nop 0
1
<?php
2
3
namespace Symbiote\QueuedJobs\Tests;
4
5
use SilverStripe\Dev\SapphireTest;
6
use SilverStripe\Core\Config\Config;
7
use SilverStripe\ORM\DataList;
8
use SilverStripe\ORM\DataObject;
9
use Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor;
10
use Symbiote\QueuedJobs\Services\QueuedJob;
11
use Symbiote\QueuedJobs\Services\QueuedJobService;
12
use Symbiote\QueuedJobs\Tests\QueuedJobsTest\TestExceptingJob;
13
use Symbiote\QueuedJobs\Tests\QueuedJobsTest\TestQueuedJob;
14
use Symbiote\QueuedJobs\Tests\QueuedJobsTest\TestQJService;
15
16
/**
17
 * @author Marcus Nyeholt <[email protected]>
18
 */
19
class QueuedJobsTest extends AbstractTest
20
{
21
    /**
22
     * We need the DB for this test
23
     *
24
     * @var bool
25
     */
26
    protected $usesDatabase = true;
27
28
    /**
29
     * {@inheritDoc}
30
     */
31
    protected function setUp()
32
    {
33
        parent::setUp();
34
35
        // Two restarts are allowed per job
36
        Config::modify()->set(QueuedJobService::class, 'stall_threshold', 2);
37
38
        // Allow large memory limit in cases of integration tests
39
        Config::modify()->set(QueuedJobService::class, 'memory_limit', 2 * 1024 * 1024 * 1024);
40
    }
41
42
    /**
43
     * @return TestQJService
44
     */
45
    protected function getService()
46
    {
47
        return singleton(TestQJService::class);
48
    }
49
50
    public function testQueueJob()
51
    {
52
        $svc = $this->getService();
53
54
        // lets create a new job and add it tio the queue
55
        $job = new TestQueuedJob();
56
        $jobId = $svc->queueJob($job);
57
        $list = $svc->getJobList();
58
59
        $this->assertCount(1, $list);
60
61
        $myJob = null;
62
        foreach ($list as $job) {
63
            if ($job->Implementation == TestQueuedJob::class) {
64
                $myJob = $job;
65
                break;
66
            }
67
        }
68
69
        $this->assertNotNull($myJob);
70
        $this->assertGreaterThan(0, $jobId);
71
        $this->assertEquals(TestQueuedJob::class, $myJob->Implementation);
72
        $this->assertNotNull($myJob->SavedJobData);
73
    }
74
75
    public function testJobRunAs()
76
    {
77
        $svc = $this->getService();
78
        $list = $svc->getJobList();
79
        foreach ($list as $job) {
80
            $job->delete();
81
        }
82
83
        $this->logInWithPermission('DUMMY');
84
85
        // lets create a new job and add it tio the queue
86
        $job = new TestQueuedJob();
87
        $job->runningAs = "DUMMY";
0 ignored issues
show
Documentation introduced by
The property runningAs does not exist on object<Symbiote\QueuedJo...JobsTest\TestQueuedJob>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
88
        $jobId = $svc->queueJob($job);
0 ignored issues
show
Unused Code introduced by
$jobId 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...
89
        $list = $svc->getJobList();
90
91
        $myJob = $list->First();
92
93
        $this->assertEquals("[email protected]", $myJob->RunAs()->Email);
94
    }
95
96
    public function testQueueSignature()
97
    {
98
        $svc = $this->getService();
99
100
        // lets create a new job and add it tio the queue
101
        $job = new TestQueuedJob();
102
        $jobId = $svc->queueJob($job);
103
104
        $newJob = new TestQueuedJob();
105
        $newId = $svc->queueJob($newJob);
106
107
        $this->assertEquals($jobId, $newId);
108
109
        // now try another, but with different params
110
        $newJob = new TestQueuedJob();
111
        $newJob->randomParam = 'stuff';
0 ignored issues
show
Documentation introduced by
The property randomParam does not exist on object<Symbiote\QueuedJo...JobsTest\TestQueuedJob>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
112
        $newId = $svc->queueJob($newJob);
113
114
        $this->assertNotEquals($jobId, $newId);
115
    }
116
117
    public function testProcessJob()
118
    {
119
        $job = new TestQueuedJob();
120
        $job->setup();
121
        $job->process();
122
        // we should now have some  data
123
        $data = $job->getJobData();
124
        $this->assertNotNull($data->messages);
125
        $this->assertFalse($data->isComplete);
126
127
        $jd = $data->jobData;
128
        $this->assertTrue(isset($jd->times));
129
        $this->assertCount(1, $jd->times);
130
131
        // now take the 'saved' data and try restoring the job
132
    }
133
134
    public function testResumeJob()
135
    {
136
        $job = new TestQueuedJob();
137
        $job->setup();
138
        $job->process();
139
        // we should now have some  data
140
        $data = $job->getJobData();
141
142
        // so create a new job and restore it from this data
143
144
        $job = new TestQueuedJob();
145
        $job->setup();
146
147
        $job->setJobData($data->totalSteps, $data->currentStep, $data->isComplete, $data->jobData, $data->messages);
148
        $job->process();
149
150
        $data = $job->getJobData();
151
        $this->assertFalse($data->isComplete);
152
        $jd = $data->jobData;
153
        $this->assertTrue(isset($jd->times));
154
        $this->assertCount(2, $jd->times);
155
    }
156
157
    public function testInitialiseJob()
158
    {
159
        // okay, lets test it out on the actual service
160
        $svc = $this->getService();
161
        // lets create a new job and add it to the queue
162
        $job = new TestQueuedJob();
163
        $id = $svc->queueJob($job);
164
165
        $descriptor = DataObject::get_by_id(QueuedJobDescriptor::class, $id);
166
167
        $job = $svc->testInit($descriptor);
168
        $this->assertInstanceOf(TestQueuedJob::class, $job, 'Job has been triggered');
169
170
        $descriptor = DataObject::get_by_id(QueuedJobDescriptor::class, $id);
171
172
        $this->assertEquals(QueuedJob::STATUS_INIT, $descriptor->JobStatus);
173
    }
174
175
    public function testStartJob()
176
    {
177
        // okay, lets test it out on the actual service
178
        $svc = $this->getService();
179
        // lets create a new job and add it to the queue
180
181
        $this->logInWithPermission('DUMMYUSER');
182
183
        $job = new TestQueuedJob();
184
        $job->testingStartJob = true;
0 ignored issues
show
Documentation introduced by
The property testingStartJob does not exist on object<Symbiote\QueuedJo...JobsTest\TestQueuedJob>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
185
        $id = $svc->queueJob($job);
186
187
        $this->logInWithPermission('ADMIN');
188
189
        $result = $svc->runJob($id);
190
        $this->assertTrue($result);
191
192
        // we want to make sure that the current user is the runas user of the job
193
        $descriptor = DataObject::get_by_id(QueuedJobDescriptor::class, $id);
194
        $this->assertEquals('Complete', $descriptor->JobStatus);
195
    }
196
197
    public function testImmediateQueuedJob()
198
    {
199
        // okay, lets test it out on the actual service
200
        $svc = $this->getService();
201
        // lets create a new job and add it to the queue
202
203
        $job = new TestQueuedJob(QueuedJob::IMMEDIATE);
204
        $job->firstJob = true;
0 ignored issues
show
Documentation introduced by
The property firstJob does not exist on object<Symbiote\QueuedJo...JobsTest\TestQueuedJob>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
205
        $id = $svc->queueJob($job);
0 ignored issues
show
Unused Code introduced by
$id 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...
206
207
        $job = new TestQueuedJob(QueuedJob::IMMEDIATE);
208
        $job->secondJob = true;
0 ignored issues
show
Documentation introduced by
The property secondJob does not exist on object<Symbiote\QueuedJo...JobsTest\TestQueuedJob>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
209
        $id = $svc->queueJob($job);
0 ignored issues
show
Unused Code introduced by
$id 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...
210
211
        $jobs = $svc->getJobList(QueuedJob::IMMEDIATE);
212
        $this->assertCount(2, $jobs);
213
214
        // now fake a shutdown
215
        $svc->onShutdown();
216
217
        $jobs = $svc->getJobList(QueuedJob::IMMEDIATE);
218
        $this->assertInstanceOf(DataList::class, $jobs);
219
        $this->assertCount(0, $jobs);
220
    }
221
222
    public function testNextJob()
223
    {
224
        $svc = $this->getService();
225
        $list = $svc->getJobList();
226
227
        foreach ($list as $job) {
228
            $job->delete();
229
        }
230
231
        $list = $svc->getJobList();
232
        $this->assertCount(0, $list);
233
234
        $job = new TestQueuedJob();
235
        $id1 = $svc->queueJob($job);
236
237
        $job = new TestQueuedJob();
238
        // to get around the signature checks
239
        $job->randomParam = 'me';
0 ignored issues
show
Documentation introduced by
The property randomParam does not exist on object<Symbiote\QueuedJo...JobsTest\TestQueuedJob>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
240
        $id2 = $svc->queueJob($job);
0 ignored issues
show
Unused Code introduced by
$id2 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...
241
242
        $job = new TestQueuedJob();
243
        // to get around the signature checks
244
        $job->randomParam = 'mo';
0 ignored issues
show
Documentation introduced by
The property randomParam does not exist on object<Symbiote\QueuedJo...JobsTest\TestQueuedJob>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
245
        $id3 = $svc->queueJob($job);
246
247
        $this->assertEquals(2, $id3 - $id1);
248
249
        $list = $svc->getJobList();
250
        $this->assertCount(3, $list);
251
252
        // okay, lets get the first one and initialise it, then make sure that a subsequent init attempt fails
253
        $job = $svc->getNextPendingJob();
254
255
        $this->assertEquals($id1, $job->ID);
256
        $svc->testInit($job);
257
258
        // now try and get another, it should be === false
259
        $next = $svc->getNextPendingJob();
260
261
        $this->assertFalse($next);
262
    }
263
264
    /**
265
     * Verify that broken jobs are correctly verified for health and restarted as necessary
266
     *
267
     * Order of checkJobHealth() and getNextPendingJob() is important
268
     *
269
     * Execution of this job is broken into several "loops", each of which represents one invocation
270
     * of ProcessJobQueueTask
271
     */
272
    public function testJobHealthCheck()
273
    {
274
        // Create a job and add it to the queue
275
        $svc = $this->getService();
276
        $logger = $svc->getLogger();
277
        $job = new TestQueuedJob(QueuedJob::IMMEDIATE);
278
        $job->firstJob = true;
0 ignored issues
show
Documentation introduced by
The property firstJob does not exist on object<Symbiote\QueuedJo...JobsTest\TestQueuedJob>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
279
        $id = $svc->queueJob($job);
280
        $descriptor = QueuedJobDescriptor::get()->byID($id);
281
282
        // Verify initial state is new and LastProcessedCount is not marked yet
283
        $this->assertEquals(QueuedJob::STATUS_NEW, $descriptor->JobStatus);
284
        $this->assertEquals(0, $descriptor->StepsProcessed);
285
        $this->assertEquals(-1, $descriptor->LastProcessedCount);
286
        $this->assertEquals(0, $descriptor->ResumeCounts);
287
288
        // Loop 1 - Pick up new job and attempt to run it
289
        // Job health should not attempt to cleanup unstarted jobs
290
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
291
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
292
293
        // Ensure that this is the next job ready to go
294
        $descriptor = QueuedJobDescriptor::get()->byID($id);
295
        $this->assertEquals($nextJob->ID, $descriptor->ID);
296
        $this->assertEquals(QueuedJob::STATUS_NEW, $descriptor->JobStatus);
297
        $this->assertEquals(0, $descriptor->StepsProcessed);
298
        $this->assertEquals(-1, $descriptor->LastProcessedCount);
299
        $this->assertEquals(0, $descriptor->ResumeCounts);
300
301
        // Run 1 - Start the job (no work is done)
302
        $descriptor->JobStatus = QueuedJob::STATUS_INIT;
303
        $descriptor->write();
304
305
        // Assume that something bad happens at this point, the process dies during execution, and
306
        // the task is re-initiated somewhere down the track
307
308
        // Loop 2 - Detect broken job, and mark it for future checking.
309
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
310
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
311
312
        // Note that we don't immediately try to restart it until StepsProcessed = LastProcessedCount
313
        $descriptor = QueuedJobDescriptor::get()->byID($id);
314
        $this->assertFalse($nextJob); // Don't run it this round please!
315
        $this->assertEquals(QueuedJob::STATUS_INIT, $descriptor->JobStatus);
316
        $this->assertEquals(0, $descriptor->StepsProcessed);
317
        $this->assertEquals(0, $descriptor->LastProcessedCount);
318
        $this->assertEquals(0, $descriptor->ResumeCounts);
319
320
        // Loop 3 - We've previously marked this job as broken, so restart it this round
321
        // If no more work has been done on the job at this point, assume that we are able to
322
        // restart it
323
        $logger->clear();
324
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
325
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
326
327
        // This job is resumed and exeuction is attempted this round
328
        $descriptor = QueuedJobDescriptor::get()->byID($id);
329
        $this->assertEquals($nextJob->ID, $descriptor->ID);
330
        $this->assertEquals(QueuedJob::STATUS_WAIT, $descriptor->JobStatus);
331
        $this->assertEquals(0, $descriptor->StepsProcessed);
332
        $this->assertEquals(0, $descriptor->LastProcessedCount);
333
        $this->assertEquals(1, $descriptor->ResumeCounts);
334
        $this->assertContains('A job named A Test job appears to have stalled. It will be stopped and restarted, please login to make sure it has continued', $logger->getMessages());
335
336
        // Run 2 - First restart (work is done)
337
        $descriptor->JobStatus = QueuedJob::STATUS_RUN;
338
        $descriptor->StepsProcessed++; // Essentially delays the next restart by 1 loop
339
        $descriptor->write();
340
341
        // Once again, at this point, assume the job fails and crashes
342
343
        // Loop 4 - Assuming a job has LastProcessedCount < StepsProcessed we are in the same
344
        // situation as step 2.
345
        // Because the last time the loop ran, StepsProcessed was incremented,
346
        // this indicates that it's likely that another task could be working on this job, so
347
        // don't run this.
348
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
349
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
350
351
        $descriptor = QueuedJobDescriptor::get()->byID($id);
352
        $this->assertFalse($nextJob); // Don't run jobs we aren't sure should be restarted
353
        $this->assertEquals(QueuedJob::STATUS_RUN, $descriptor->JobStatus);
354
        $this->assertEquals(1, $descriptor->StepsProcessed);
355
        $this->assertEquals(1, $descriptor->LastProcessedCount);
356
        $this->assertEquals(1, $descriptor->ResumeCounts);
357
358
        // Loop 5 - Job is again found to not have been restarted since last iteration, so perform second
359
        // restart. The job should be attempted to run this loop
360
        $logger->clear();
361
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
362
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
363
364
        // This job is resumed and exeuction is attempted this round
365
        $descriptor = QueuedJobDescriptor::get()->byID($id);
366
        $this->assertEquals($nextJob->ID, $descriptor->ID);
367
        $this->assertEquals(QueuedJob::STATUS_WAIT, $descriptor->JobStatus);
368
        $this->assertEquals(1, $descriptor->StepsProcessed);
369
        $this->assertEquals(1, $descriptor->LastProcessedCount);
370
        $this->assertEquals(2, $descriptor->ResumeCounts);
371
        $this->assertContains('A job named A Test job appears to have stalled. It will be stopped and restarted, please login to make sure it has continued', $logger->getMessages());
372
373
        // Run 3 - Second and last restart (no work is done)
374
        $descriptor->JobStatus = QueuedJob::STATUS_RUN;
375
        $descriptor->write();
376
377
        // Loop 6 - As no progress has been made since loop 3, we can mark this as dead
378
        $logger->clear();
379
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
380
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
381
382
        // Since no StepsProcessed has been done, don't wait another loop to mark this as dead
383
        $descriptor = QueuedJobDescriptor::get()->byID($id);
384
        $this->assertEquals(QueuedJob::STATUS_PAUSED, $descriptor->JobStatus);
385
        $this->assertEmpty($nextJob);
386
        $this->assertContains('A job named A Test job appears to have stalled. It has been paused, please login to check it', $logger->getMessages());
387
    }
388
389
    public function testExceptionWithMemoryExhaustion()
390
    {
391
        $svc = $this->getService();
392
        $job = new TestExceptingJob();
393
        $job->firstJob = true;
0 ignored issues
show
Documentation introduced by
The property firstJob does not exist on object<Symbiote\QueuedJo...sTest\TestExceptingJob>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
394
        $id = $svc->queueJob($job);
395
        $descriptor = QueuedJobDescriptor::get()->byID($id);
0 ignored issues
show
Unused Code introduced by
$descriptor 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...
396
397
        // we want to set the memory limit _really_ low so that our first run triggers
398
        $mem = Config::inst()->get('QueuedJobService', 'memory_limit');
399
        Config::modify()->set(QueuedJobService::class, 'memory_limit', 1);
400
401
        $svc->runJob($id);
402
403
        Config::modify()->set(QueuedJobService::class, 'memory_limit', $mem);
404
405
        $descriptor = QueuedJobDescriptor::get()->byID($id);
406
407
        $this->assertEquals(QueuedJob::STATUS_BROKEN, $descriptor->JobStatus);
408
    }
409
410
    public function testCheckdefaultJobs()
411
    {
412
        // Create a job and add it to the queue
413
        $svc = $this->getService();
414
        $testDefaultJobsArray = array(
415
            'ArbitraryName' => array(
416
                # I'll get restarted and create an alert email
417
                'type' => TestQueuedJob::class,
418
                'filter' => array(
419
                    'JobTitle' => "A Test job"
420
                ),
421
                'recreate' => 1,
422
                'construct' => array(
423
                    'queue' => QueuedJob::QUEUED
424
                ),
425
                'startDateFormat' => 'Y-m-d 02:00:00',
426
                'startTimeString' => 'tomorrow',
427
                'email' => '[email protected]'
428
            ));
429
        $svc->defaultJobs = $testDefaultJobsArray;
430
        $jobConfig = $testDefaultJobsArray['ArbitraryName'];
431
432
        $activeJobs = QueuedJobDescriptor::get()->filter(
433
            'JobStatus',
434
            array(
435
                QueuedJob::STATUS_NEW,
436
                QueuedJob::STATUS_INIT,
437
                QueuedJob::STATUS_RUN,
438
                QueuedJob::STATUS_WAIT,
439
                QueuedJob::STATUS_PAUSED
440
            )
441
        );
442
        //assert no jobs currently active
443
        $this->assertCount(0, $activeJobs);
444
445
        //add a default job to the queue
446
        $svc->checkdefaultJobs();
447
        $this->assertCount(1, $activeJobs);
448
        $descriptor = $activeJobs->filter(array_merge(
449
            array('Implementation' => $jobConfig['type']),
450
            $jobConfig['filter']
451
        ))->first();
452
        // Verify initial state is new
453
        $this->assertEquals(QueuedJob::STATUS_NEW, $descriptor->JobStatus);
454
455
        //update Job to paused
456
        $descriptor->JobStatus = QueuedJob::STATUS_PAUSED;
457
        $descriptor->write();
458
        //check defaults the paused job shoudl be ignored
459
        $svc->checkdefaultJobs();
460
        $this->assertCount(1, $activeJobs);
461
        //assert we now still have 1 of our job (paused)
462
        $this->assertCount(1, QueuedJobDescriptor::get());
463
464
        //update Job to broken
465
        $descriptor->JobStatus = QueuedJob::STATUS_BROKEN;
466
        $descriptor->write();
467
        //check and add job for broken job
468
        $svc->checkdefaultJobs();
469
        $this->assertCount(1, $activeJobs);
470
        //assert we now have 2 of our job (one good one broken)
471
        $this->assertCount(2, QueuedJobDescriptor::get());
472
473
        //test not adding a job when job is there already
474
        $svc->checkdefaultJobs();
475
        $this->assertCount(1, $activeJobs);
476
        //assert we now have 2 of our job (one good one broken)
477
        $this->assertCount(2, QueuedJobDescriptor::get());
478
479
        //test add jobs with various start dates
480
        $job = $activeJobs->first();
481
        date('Y-m-d 02:00:00', strtotime('+1 day'));
482
        $this->assertEquals(date('Y-m-d 02:00:00', strtotime('+1 day')), $job->StartAfter);
483
        //swap start time to midday
484
        $testDefaultJobsArray['ArbitraryName']['startDateFormat'] = 'Y-m-d 12:00:00';
485
        //clean up then add new jobs
486
        $svc->defaultJobs = $testDefaultJobsArray;
487
        $activeJobs->removeAll();
488
        $svc->checkdefaultJobs();
489
        //assert one jobs currently active
490
        $this->assertCount(1, $activeJobs);
491
        $job = $activeJobs->first();
492
        $this->assertEquals(date('Y-m-d 12:00:00', strtotime('+1 day')), $job->StartAfter);
493
        //test alert email
494
        $email = $this->findEmail('[email protected]');
495
        $this->assertNotNull($email);
496
497
        //test broken job config
498
        unset($testDefaultJobsArray['ArbitraryName']['startDateFormat']);
499
        //clean up then add new jobs
500
        $svc->defaultJobs = $testDefaultJobsArray;
501
        $activeJobs->removeAll();
502
        $svc->checkdefaultJobs();
503
    }
504
}
505