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.

QueuedJobsTest::testCheckdefaultJobs()   B
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 94

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 94
rs 8.1309
c 0
b 0
f 0
cc 1
nc 1
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Symbiote\QueuedJobs\Tests;
4
5
use SilverStripe\Core\Config\Config;
6
use SilverStripe\ORM\DataList;
7
use SilverStripe\ORM\DataObject;
8
use Symbiote\QueuedJobs\DataObjects\QueuedJobDescriptor;
9
use Symbiote\QueuedJobs\Services\QueuedJob;
10
use Symbiote\QueuedJobs\Services\QueuedJobService;
11
use Symbiote\QueuedJobs\Tests\QueuedJobsTest\TestExceptingJob;
12
use Symbiote\QueuedJobs\Tests\QueuedJobsTest\TestQJService;
13
use Symbiote\QueuedJobs\Tests\QueuedJobsTest\TestQueuedJob;
14
15
/**
16
 * @author Marcus Nyeholt <[email protected]>
17
 */
18
class QueuedJobsTest extends AbstractTest
19
{
20
    /**
21
     * We need the DB for this test
22
     *
23
     * @var bool
24
     */
25
    protected $usesDatabase = true;
26
27
    /**
28
     * {@inheritDoc}
29
     */
30
    protected function setUp()
31
    {
32
        parent::setUp();
33
34
        // Two restarts are allowed per job
35
        Config::modify()->set(QueuedJobService::class, 'stall_threshold', 2);
36
37
        // Allow large memory limit in cases of integration tests
38
        Config::modify()->set(QueuedJobService::class, 'memory_limit', 2 * 1024 * 1024 * 1024);
39
    }
40
41
    /**
42
     * @return TestQJService
43
     */
44
    protected function getService()
45
    {
46
        return singleton(TestQJService::class);
47
    }
48
49
    public function testQueueJob()
50
    {
51
        $svc = $this->getService();
52
53
        // lets create a new job and add it tio the queue
54
        $job = new TestQueuedJob();
55
        $jobId = $svc->queueJob($job);
56
        $list = $svc->getJobList();
57
58
        $this->assertCount(1, $list);
59
60
        $myJob = null;
61
        foreach ($list as $job) {
62
            if ($job->Implementation == TestQueuedJob::class) {
63
                $myJob = $job;
64
                break;
65
            }
66
        }
67
68
        $this->assertNotNull($myJob);
69
        $this->assertGreaterThan(0, $jobId);
70
        $this->assertEquals(TestQueuedJob::class, $myJob->Implementation);
71
        $this->assertNotNull($myJob->SavedJobData);
72
    }
73
74
    public function testJobRunAs()
75
    {
76
        $svc = $this->getService();
77
        $list = $svc->getJobList();
78
        foreach ($list as $job) {
79
            $job->delete();
80
        }
81
82
        $this->logInWithPermission('DUMMY');
83
84
        // lets create a new job and add it tio the queue
85
        $job = new TestQueuedJob();
86
        $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...
87
        $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...
88
        $list = $svc->getJobList();
89
90
        $myJob = $list->First();
91
92
        $this->assertEquals("[email protected]", $myJob->RunAs()->Email);
93
    }
94
95
    public function testQueueSignature()
96
    {
97
        $svc = $this->getService();
98
99
        // lets create a new job and add it tio the queue
100
        $job = new TestQueuedJob();
101
        $jobId = $svc->queueJob($job);
102
103
        $newJob = new TestQueuedJob();
104
        $newId = $svc->queueJob($newJob);
105
106
        $this->assertEquals($jobId, $newId);
107
108
        // now try another, but with different params
109
        $newJob = new TestQueuedJob();
110
        $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...
111
        $newId = $svc->queueJob($newJob);
112
113
        $this->assertNotEquals($jobId, $newId);
114
    }
115
116
    public function testProcessJob()
117
    {
118
        $job = new TestQueuedJob();
119
        $job->setup();
120
        $job->process();
121
        // we should now have some  data
122
        $data = $job->getJobData();
123
        $this->assertNotNull($data->messages);
124
        $this->assertFalse($data->isComplete);
125
126
        $jd = $data->jobData;
127
        $this->assertTrue(isset($jd->times));
128
        $this->assertCount(1, $jd->times);
129
130
        // now take the 'saved' data and try restoring the job
131
    }
132
133
    public function testResumeJob()
134
    {
135
        $job = new TestQueuedJob();
136
        $job->setup();
137
        $job->process();
138
        // we should now have some  data
139
        $data = $job->getJobData();
140
141
        // so create a new job and restore it from this data
142
143
        $job = new TestQueuedJob();
144
        $job->setup();
145
146
        $job->setJobData($data->totalSteps, $data->currentStep, $data->isComplete, $data->jobData, $data->messages);
147
        $job->process();
148
149
        $data = $job->getJobData();
150
        $this->assertFalse($data->isComplete);
151
        $jd = $data->jobData;
152
        $this->assertTrue(isset($jd->times));
153
        $this->assertCount(2, $jd->times);
154
    }
155
156
    public function testInitialiseJob()
157
    {
158
        // okay, lets test it out on the actual service
159
        $svc = $this->getService();
160
        // lets create a new job and add it to the queue
161
        $job = new TestQueuedJob();
162
        $id = $svc->queueJob($job);
163
164
        $descriptor = DataObject::get_by_id(QueuedJobDescriptor::class, $id);
165
166
        $job = $svc->testInit($descriptor);
167
        $this->assertInstanceOf(TestQueuedJob::class, $job, 'Job has been triggered');
168
169
        $descriptor = DataObject::get_by_id(QueuedJobDescriptor::class, $id);
170
171
        $this->assertEquals(QueuedJob::STATUS_INIT, $descriptor->JobStatus);
172
    }
173
174
    public function testStartJob()
175
    {
176
        // okay, lets test it out on the actual service
177
        $svc = $this->getService();
178
        // lets create a new job and add it to the queue
179
180
        $this->logInWithPermission('DUMMYUSER');
181
182
        $job = new TestQueuedJob();
183
        $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...
184
        $id = $svc->queueJob($job);
185
186
        $this->logInWithPermission('ADMIN');
187
188
        $result = $svc->runJob($id);
189
        $this->assertTrue($result);
190
191
        // we want to make sure that the current user is the runas user of the job
192
        $descriptor = DataObject::get_by_id(QueuedJobDescriptor::class, $id);
193
        $this->assertEquals('Complete', $descriptor->JobStatus);
194
    }
195
196
    public function testImmediateQueuedJob()
197
    {
198
        // okay, lets test it out on the actual service
199
        $svc = $this->getService();
200
        // lets create a new job and add it to the queue
201
202
        $job = new TestQueuedJob(QueuedJob::IMMEDIATE);
203
        $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...
204
        $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...
205
206
        $job = new TestQueuedJob(QueuedJob::IMMEDIATE);
207
        $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...
208
        $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...
209
210
        $jobs = $svc->getJobList(QueuedJob::IMMEDIATE);
211
        $this->assertCount(2, $jobs);
212
213
        // now fake a shutdown
214
        $svc->onShutdown();
215
216
        $jobs = $svc->getJobList(QueuedJob::IMMEDIATE);
217
        $this->assertInstanceOf(DataList::class, $jobs);
218
        $this->assertCount(0, $jobs);
219
    }
220
221
    public function testNextJob()
222
    {
223
        $svc = $this->getService();
224
        $list = $svc->getJobList();
225
226
        foreach ($list as $job) {
227
            $job->delete();
228
        }
229
230
        $list = $svc->getJobList();
231
        $this->assertCount(0, $list);
232
233
        $job = new TestQueuedJob();
234
        $id1 = $svc->queueJob($job);
235
236
        $job = new TestQueuedJob();
237
        // to get around the signature checks
238
        $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...
239
        $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...
240
241
        $job = new TestQueuedJob();
242
        // to get around the signature checks
243
        $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...
244
        $id3 = $svc->queueJob($job);
245
246
        $this->assertEquals(2, $id3 - $id1);
247
248
        $list = $svc->getJobList();
249
        $this->assertCount(3, $list);
250
251
        // okay, lets get the first one and initialise it, then make sure that a subsequent init attempt fails
252
        $job = $svc->getNextPendingJob();
253
254
        $this->assertEquals($id1, $job->ID);
255
        $svc->testInit($job);
256
257
        // now try and get another, it should be === false
258
        $next = $svc->getNextPendingJob();
259
260
        $this->assertFalse($next);
261
    }
262
263
    /**
264
     * Verify that broken jobs are correctly verified for health and restarted as necessary
265
     *
266
     * Order of checkJobHealth() and getNextPendingJob() is important
267
     *
268
     * Execution of this job is broken into several "loops", each of which represents one invocation
269
     * of ProcessJobQueueTask
270
     */
271
    public function testJobHealthCheck()
272
    {
273
        // Create a job and add it to the queue
274
        $svc = $this->getService();
275
        $logger = $svc->getLogger();
276
        $job = new TestQueuedJob(QueuedJob::IMMEDIATE);
277
        $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...
278
        $id = $svc->queueJob($job);
279
        $descriptor = QueuedJobDescriptor::get()->byID($id);
280
281
        // Verify initial state is new and LastProcessedCount is not marked yet
282
        $this->assertEquals(QueuedJob::STATUS_NEW, $descriptor->JobStatus);
283
        $this->assertEquals(0, $descriptor->StepsProcessed);
284
        $this->assertEquals(-1, $descriptor->LastProcessedCount);
285
        $this->assertEquals(0, $descriptor->ResumeCounts);
286
287
        // Loop 1 - Pick up new job and attempt to run it
288
        // Job health should not attempt to cleanup unstarted jobs
289
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
290
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
291
292
        // Ensure that this is the next job ready to go
293
        $descriptor = QueuedJobDescriptor::get()->byID($id);
294
        $this->assertEquals($nextJob->ID, $descriptor->ID);
295
        $this->assertEquals(QueuedJob::STATUS_NEW, $descriptor->JobStatus);
296
        $this->assertEquals(0, $descriptor->StepsProcessed);
297
        $this->assertEquals(-1, $descriptor->LastProcessedCount);
298
        $this->assertEquals(0, $descriptor->ResumeCounts);
299
300
        // Run 1 - Start the job (no work is done)
301
        $descriptor->JobStatus = QueuedJob::STATUS_INIT;
302
        $descriptor->write();
303
304
        // Assume that something bad happens at this point, the process dies during execution, and
305
        // the task is re-initiated somewhere down the track
306
307
        // Loop 2 - Detect broken job, and mark it for future checking.
308
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
309
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
310
311
        // Note that we don't immediately try to restart it until StepsProcessed = LastProcessedCount
312
        $descriptor = QueuedJobDescriptor::get()->byID($id);
313
        $this->assertFalse($nextJob); // Don't run it this round please!
314
        $this->assertEquals(QueuedJob::STATUS_INIT, $descriptor->JobStatus);
315
        $this->assertEquals(0, $descriptor->StepsProcessed);
316
        $this->assertEquals(0, $descriptor->LastProcessedCount);
317
        $this->assertEquals(0, $descriptor->ResumeCounts);
318
319
        // Loop 3 - We've previously marked this job as broken, so restart it this round
320
        // If no more work has been done on the job at this point, assume that we are able to
321
        // restart it
322
        $logger->clear();
323
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
324
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
325
326
        // This job is resumed and exeuction is attempted this round
327
        $descriptor = QueuedJobDescriptor::get()->byID($id);
328
        $this->assertEquals($nextJob->ID, $descriptor->ID);
329
        $this->assertEquals(QueuedJob::STATUS_WAIT, $descriptor->JobStatus);
330
        $this->assertEquals(0, $descriptor->StepsProcessed);
331
        $this->assertEquals(0, $descriptor->LastProcessedCount);
332
        $this->assertEquals(1, $descriptor->ResumeCounts);
333
        $this->assertContains(
334
            'A job named A Test job appears to have stalled. It will be stopped and restarted, please login to '
335
            . 'make sure it has continued',
336
            $logger->getMessages()
337
        );
338
339
        // Run 2 - First restart (work is done)
340
        $descriptor->JobStatus = QueuedJob::STATUS_RUN;
341
        $descriptor->StepsProcessed++; // Essentially delays the next restart by 1 loop
342
        $descriptor->write();
343
344
        // Once again, at this point, assume the job fails and crashes
345
346
        // Loop 4 - Assuming a job has LastProcessedCount < StepsProcessed we are in the same
347
        // situation as step 2.
348
        // Because the last time the loop ran, StepsProcessed was incremented,
349
        // this indicates that it's likely that another task could be working on this job, so
350
        // don't run this.
351
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
352
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
353
354
        $descriptor = QueuedJobDescriptor::get()->byID($id);
355
        $this->assertFalse($nextJob); // Don't run jobs we aren't sure should be restarted
356
        $this->assertEquals(QueuedJob::STATUS_RUN, $descriptor->JobStatus);
357
        $this->assertEquals(1, $descriptor->StepsProcessed);
358
        $this->assertEquals(1, $descriptor->LastProcessedCount);
359
        $this->assertEquals(1, $descriptor->ResumeCounts);
360
361
        // Loop 5 - Job is again found to not have been restarted since last iteration, so perform second
362
        // restart. The job should be attempted to run this loop
363
        $logger->clear();
364
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
365
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
366
367
        // This job is resumed and exeuction is attempted this round
368
        $descriptor = QueuedJobDescriptor::get()->byID($id);
369
        $this->assertEquals($nextJob->ID, $descriptor->ID);
370
        $this->assertEquals(QueuedJob::STATUS_WAIT, $descriptor->JobStatus);
371
        $this->assertEquals(1, $descriptor->StepsProcessed);
372
        $this->assertEquals(1, $descriptor->LastProcessedCount);
373
        $this->assertEquals(2, $descriptor->ResumeCounts);
374
        $this->assertContains(
375
            'A job named A Test job appears to have stalled. It will be stopped and restarted, please login '
376
            . 'to make sure it has continued',
377
            $logger->getMessages()
378
        );
379
380
        // Run 3 - Second and last restart (no work is done)
381
        $descriptor->JobStatus = QueuedJob::STATUS_RUN;
382
        $descriptor->write();
383
384
        // Loop 6 - As no progress has been made since loop 3, we can mark this as dead
385
        $logger->clear();
386
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
387
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
388
389
        // Since no StepsProcessed has been done, don't wait another loop to mark this as dead
390
        $descriptor = QueuedJobDescriptor::get()->byID($id);
391
        $this->assertEquals(QueuedJob::STATUS_PAUSED, $descriptor->JobStatus);
392
        $this->assertEmpty($nextJob);
393
        $this->assertContains(
394
            'A job named A Test job appears to have stalled. It has been paused, please login to check it',
395
            $logger->getMessages()
396
        );
397
    }
398
399
    public function testExceptionWithMemoryExhaustion()
400
    {
401
        $svc = $this->getService();
402
        $job = new TestExceptingJob();
403
        $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...
404
        $id = $svc->queueJob($job);
405
        $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...
406
407
        // we want to set the memory limit _really_ low so that our first run triggers
408
        $mem = Config::inst()->get('QueuedJobService', 'memory_limit');
409
        Config::modify()->set(QueuedJobService::class, 'memory_limit', 1);
410
411
        $svc->runJob($id);
412
413
        Config::modify()->set(QueuedJobService::class, 'memory_limit', $mem);
414
415
        $descriptor = QueuedJobDescriptor::get()->byID($id);
416
417
        $this->assertEquals(QueuedJob::STATUS_BROKEN, $descriptor->JobStatus);
418
    }
419
420
    public function testCheckdefaultJobs()
421
    {
422
        // Create a job and add it to the queue
423
        $svc = $this->getService();
424
        $testDefaultJobsArray = array(
425
            'ArbitraryName' => array(
426
                # I'll get restarted and create an alert email
427
                'type' => TestQueuedJob::class,
428
                'filter' => array(
429
                    'JobTitle' => "A Test job"
430
                ),
431
                'recreate' => 1,
432
                'construct' => array(
433
                    'queue' => QueuedJob::QUEUED
434
                ),
435
                'startDateFormat' => 'Y-m-d 02:00:00',
436
                'startTimeString' => 'tomorrow',
437
                'email' => '[email protected]'
438
            ));
439
        $svc->defaultJobs = $testDefaultJobsArray;
440
        $jobConfig = $testDefaultJobsArray['ArbitraryName'];
441
442
        $activeJobs = QueuedJobDescriptor::get()->filter(
443
            'JobStatus',
444
            array(
445
                QueuedJob::STATUS_NEW,
446
                QueuedJob::STATUS_INIT,
447
                QueuedJob::STATUS_RUN,
448
                QueuedJob::STATUS_WAIT,
449
                QueuedJob::STATUS_PAUSED
450
            )
451
        );
452
        //assert no jobs currently active
453
        $this->assertCount(0, $activeJobs);
454
455
        //add a default job to the queue
456
        $svc->checkdefaultJobs();
457
        $this->assertCount(1, $activeJobs);
458
        $descriptor = $activeJobs->filter(array_merge(
459
            array('Implementation' => $jobConfig['type']),
460
            $jobConfig['filter']
461
        ))->first();
462
        // Verify initial state is new
463
        $this->assertEquals(QueuedJob::STATUS_NEW, $descriptor->JobStatus);
464
465
        //update Job to paused
466
        $descriptor->JobStatus = QueuedJob::STATUS_PAUSED;
467
        $descriptor->write();
468
        //check defaults the paused job shoudl be ignored
469
        $svc->checkdefaultJobs();
470
        $this->assertCount(1, $activeJobs);
471
        //assert we now still have 1 of our job (paused)
472
        $this->assertCount(1, QueuedJobDescriptor::get());
473
474
        //update Job to broken
475
        $descriptor->JobStatus = QueuedJob::STATUS_BROKEN;
476
        $descriptor->write();
477
        //check and add job for broken job
478
        $svc->checkdefaultJobs();
479
        $this->assertCount(1, $activeJobs);
480
        //assert we now have 2 of our job (one good one broken)
481
        $this->assertCount(2, QueuedJobDescriptor::get());
482
483
        //test not adding a job when job is there already
484
        $svc->checkdefaultJobs();
485
        $this->assertCount(1, $activeJobs);
486
        //assert we now have 2 of our job (one good one broken)
487
        $this->assertCount(2, QueuedJobDescriptor::get());
488
489
        //test add jobs with various start dates
490
        $job = $activeJobs->first();
491
        date('Y-m-d 02:00:00', strtotime('+1 day'));
492
        $this->assertEquals(date('Y-m-d 02:00:00', strtotime('+1 day')), $job->StartAfter);
493
        //swap start time to midday
494
        $testDefaultJobsArray['ArbitraryName']['startDateFormat'] = 'Y-m-d 12:00:00';
495
        //clean up then add new jobs
496
        $svc->defaultJobs = $testDefaultJobsArray;
497
        $activeJobs->removeAll();
498
        $svc->checkdefaultJobs();
499
        //assert one jobs currently active
500
        $this->assertCount(1, $activeJobs);
501
        $job = $activeJobs->first();
502
        $this->assertEquals(date('Y-m-d 12:00:00', strtotime('+1 day')), $job->StartAfter);
503
        //test alert email
504
        $email = $this->findEmail('[email protected]');
505
        $this->assertNotNull($email);
506
507
        //test broken job config
508
        unset($testDefaultJobsArray['ArbitraryName']['startDateFormat']);
509
        //clean up then add new jobs
510
        $svc->defaultJobs = $testDefaultJobsArray;
511
        $activeJobs->removeAll();
512
        $svc->checkdefaultJobs();
513
    }
514
}
515