Completed
Pull Request — master (#125)
by
unknown
02:05
created

TestQueuedJob   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 46
Duplicated Lines 36.96 %

Coupling/Cohesion

Components 2
Dependencies 1

Importance

Changes 0
Metric Value
wmc 7
lcom 2
cbo 1
dl 17
loc 46
rs 10
c 0
b 0
f 0

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
use SilverStripe\Dev\SapphireTest;
4
use SilverStripe\Core\Config\Config;
5
use SilverStripe\ORM\DataObject;
6
use SilverStripe\QueuedJobs\DataObjects\QueuedJobDescriptor;
7
use SilverStripe\QueuedJobs\Services\QueuedJob;
8
use SilverStripe\QueuedJobs\Tests\QueuedJobsTest\TestQueuedJob;
9
use SilverStripe\QueuedJobs\Tests\QueuedJobsTest\TestQJService;
10
11
/**
12
 *
13
 *
14
 * @author Marcus Nyeholt <[email protected]>
15
 */
16
class QueuedJobsTest extends SapphireTest
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
17
{
18
    /**
19
     * We need the DB for this test
20
     *
21
     * @var bool
22
     */
23
    protected $usesDatabase = true;
24
25
    /**
26
     * {@inheritDoc}
27
     */
28
    public function setUp()
29
    {
30
        parent::setUp();
31
32
        Config::nest();
33
        // Two restarts are allowed per job
34
        Config::modify()->set('SilverStripe\\QueuedJobs\\Services\\QueuedJobService', 'stall_threshold', 2);
35
    }
36
37
    /**
38
     * {@inheritDoc}
39
     */
40
    public function tearDown()
41
    {
42
        Config::unnest();
43
        parent::tearDown();
44
    }
45
46
    /**
47
     * @return QueuedJobService
48
     */
49
    protected function getService()
50
    {
51
        return singleton(TestQJService::class);
52
    }
53
54
    public function testQueueJob()
55
    {
56
        $svc = $this->getService();
57
58
        // lets create a new job and add it tio the queue
59
        $job = new TestQueuedJob();
60
        $jobId = $svc->queueJob($job);
61
        $list = $svc->getJobList();
62
63
        $this->assertEquals(1, $list->count());
64
65
        $myJob = null;
66
        foreach ($list as $job) {
67
            if ($job->Implementation == TestQueuedJob::class) {
68
                $myJob = $job;
69
                break;
70
            }
71
        }
72
73
        $this->assertNotNull($myJob);
74
        $this->assertTrue($jobId > 0);
75
        $this->assertEquals(TestQueuedJob::class, $myJob->Implementation);
76
        $this->assertNotNull($myJob->SavedJobData);
77
    }
78
79
    public function testJobRunAs()
80
    {
81
        $svc = $this->getService();
82
        $list = $svc->getJobList();
83
        foreach ($list as $job) {
84
            $job->delete();
85
        }
86
87
        $this->logInWithPermission('DUMMY');
88
89
        // lets create a new job and add it tio the queue
90
        $job = new TestQueuedJob();
91
        $job->runningAs = "DUMMY";
0 ignored issues
show
Documentation introduced by
The property runningAs does not exist on object<SilverStripe\Queu...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...
92
        $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...
93
        $list = $svc->getJobList();
94
95
        $myJob = $list->First();
96
97
        $this->assertEquals("[email protected]", $myJob->RunAs()->Email);
98
    }
99
100
    public function testQueueSignature()
101
    {
102
        $svc = $this->getService();
103
104
        // lets create a new job and add it tio the queue
105
        $job = new TestQueuedJob();
106
        $jobId = $svc->queueJob($job);
107
108
        $newJob = new TestQueuedJob();
109
        $newId = $svc->queueJob($newJob);
110
111
        $this->assertEquals($jobId, $newId);
112
113
        // now try another, but with different params
114
        $newJob = new TestQueuedJob();
115
        $newJob->randomParam = 'stuff';
0 ignored issues
show
Documentation introduced by
The property randomParam does not exist on object<SilverStripe\Queu...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...
116
        $newId = $svc->queueJob($newJob);
117
118
        $this->assertNotEquals($jobId, $newId);
119
    }
120
121
    public function testProcessJob()
122
    {
123
        $job = new TestQueuedJob();
124
        $job->setup();
125
        $job->process();
126
        // we should now have some  data
127
        $data = $job->getJobData();
128
        $this->assertNotNull($data->messages);
129
        $this->assertFalse($data->isComplete);
130
131
        $jd = $data->jobData;
132
        $this->assertTrue(isset($jd->times));
133
        $this->assertEquals(1, count($jd->times));
134
135
        // now take the 'saved' data and try restoring the job
136
    }
137
138
    public function testResumeJob()
139
    {
140
        $job = new TestQueuedJob();
141
        $job->setup();
142
        $job->process();
143
        // we should now have some  data
144
        $data = $job->getJobData();
145
146
        // so create a new job and restore it from this data
147
148
        $job = new TestQueuedJob();
149
        $job->setup();
150
151
        $job->setJobData($data->totalSteps, $data->currentStep, $data->isComplete, $data->jobData, $data->messages);
152
        $job->process();
153
154
        $data = $job->getJobData();
155
        $this->assertFalse($data->isComplete);
156
        $jd = $data->jobData;
157
        $this->assertTrue(isset($jd->times));
158
        $this->assertEquals(2, count($jd->times));
159
    }
160
161
    public function testInitialiseJob()
162
    {
163
        // okay, lets test it out on the actual service
164
        $svc = $this->getService();
165
        // lets create a new job and add it to the queue
166
        $job = new TestQueuedJob();
167
        $id = $svc->queueJob($job);
168
169
        $descriptor = DataObject::get_by_id('SilverStripe\\QueuedJobs\\DataObjects\\QueuedJobDescriptor', $id);
170
171
        $job = $svc->testInit($descriptor);
172
        $this->assertInstanceOf(TestQueuedJob::class, $job, 'Job has been triggered');
173
174
        $descriptor = DataObject::get_by_id('SilverStripe\\QueuedJobs\\DataObjects\\QueuedJobDescriptor', $id);
175
176
        $this->assertEquals(QueuedJob::STATUS_INIT, $descriptor->JobStatus);
177
    }
178
179
    public function testStartJob()
180
    {
181
        // okay, lets test it out on the actual service
182
        $svc = $this->getService();
183
        // lets create a new job and add it to the queue
184
185
        $this->logInWithPermission('DUMMYUSER');
186
187
        $job = new TestQueuedJob();
188
        $job->testingStartJob = true;
0 ignored issues
show
Documentation introduced by
The property testingStartJob does not exist on object<SilverStripe\Queu...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...
189
        $id = $svc->queueJob($job);
190
191
        $this->logInWithPermission('ADMIN');
192
193
        $result = $svc->runJob($id);
194
        $this->assertTrue($result);
195
196
        // we want to make sure that the current user is the runas user of the job
197
        $descriptor = DataObject::get_by_id('SilverStripe\\QueuedJobs\\DataObjects\\QueuedJobDescriptor', $id);
198
        $this->assertEquals('Complete', $descriptor->JobStatus);
199
    }
200
201
    public function testImmediateQueuedJob()
202
    {
203
        // okay, lets test it out on the actual service
204
        $svc = $this->getService();
205
        // lets create a new job and add it to the queue
206
207
        $job = new TestQueuedJob(QueuedJob::IMMEDIATE);
208
        $job->firstJob = true;
0 ignored issues
show
Documentation introduced by
The property firstJob does not exist on object<SilverStripe\Queu...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
        $job = new TestQueuedJob(QueuedJob::IMMEDIATE);
212
        $job->secondJob = true;
0 ignored issues
show
Documentation introduced by
The property secondJob does not exist on object<SilverStripe\Queu...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...
213
        $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...
214
215
        $jobs = $svc->getJobList(QueuedJob::IMMEDIATE);
216
        $this->assertEquals(2, $jobs->count());
217
218
        // now fake a shutdown
219
        $svc->onShutdown();
220
221
        $jobs = $svc->getJobList(QueuedJob::IMMEDIATE);
222
        $this->assertInstanceOf('SilverStripe\\ORM\\DataList', $jobs);
223
        $this->assertEquals(0, $jobs->count());
224
    }
225
226
    public function testNextJob()
227
    {
228
        $svc = $this->getService();
229
        $list = $svc->getJobList();
230
231
        foreach ($list as $job) {
232
            $job->delete();
233
        }
234
235
        $list = $svc->getJobList();
236
        $this->assertEquals(0, $list->count());
237
238
        $job = new TestQueuedJob();
239
        $id1 = $svc->queueJob($job);
240
241
        $job = new TestQueuedJob();
242
        // to get around the signature checks
243
        $job->randomParam = 'me';
0 ignored issues
show
Documentation introduced by
The property randomParam does not exist on object<SilverStripe\Queu...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
        $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...
245
246
        $job = new TestQueuedJob();
247
        // to get around the signature checks
248
        $job->randomParam = 'mo';
0 ignored issues
show
Documentation introduced by
The property randomParam does not exist on object<SilverStripe\Queu...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...
249
        $id3 = $svc->queueJob($job);
250
251
        $this->assertEquals(2, $id3 - $id1);
252
253
        $list = $svc->getJobList();
254
        $this->assertEquals(3, $list->count());
255
256
        // okay, lets get the first one and initialise it, then make sure that a subsequent init attempt fails
257
        $job = $svc->getNextPendingJob();
258
259
        $this->assertEquals($id1, $job->ID);
260
        $svc->testInit($job);
261
262
        // now try and get another, it should be === false
263
        $next = $svc->getNextPendingJob();
264
265
        $this->assertFalse($next);
266
    }
267
268
    /**
269
     * Verify that broken jobs are correctly verified for health and restarted as necessary
270
     *
271
     * Order of checkJobHealth() and getNextPendingJob() is important
272
     *
273
     * Execution of this job is broken into several "loops", each of which represents one invocation
274
     * of ProcessJobQueueTask
275
     */
276
    public function testJobHealthCheck()
277
    {
278
        // Create a job and add it to the queue
279
        $svc = $this->getService();
280
        $logger = $svc->getLogger();
281
        $job = new TestQueuedJob(QueuedJob::IMMEDIATE);
282
        $job->firstJob = true;
0 ignored issues
show
Documentation introduced by
The property firstJob does not exist on object<SilverStripe\Queu...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...
283
        $id = $svc->queueJob($job);
284
        $descriptor = QueuedJobDescriptor::get()->byID($id);
285
286
        // Verify initial state is new and LastProcessedCount is not marked yet
287
        $this->assertEquals(QueuedJob::STATUS_NEW, $descriptor->JobStatus);
288
        $this->assertEquals(0, $descriptor->StepsProcessed);
289
        $this->assertEquals(-1, $descriptor->LastProcessedCount);
290
        $this->assertEquals(0, $descriptor->ResumeCounts);
291
292
        // Loop 1 - Pick up new job and attempt to run it
293
        // Job health should not attempt to cleanup unstarted jobs
294
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
295
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
296
297
        // Ensure that this is the next job ready to go
298
        $descriptor = QueuedJobDescriptor::get()->byID($id);
299
        $this->assertEquals($nextJob->ID, $descriptor->ID);
300
        $this->assertEquals(QueuedJob::STATUS_NEW, $descriptor->JobStatus);
301
        $this->assertEquals(0, $descriptor->StepsProcessed);
302
        $this->assertEquals(-1, $descriptor->LastProcessedCount);
303
        $this->assertEquals(0, $descriptor->ResumeCounts);
304
305
        // Run 1 - Start the job (no work is done)
306
        $descriptor->JobStatus = QueuedJob::STATUS_INIT;
307
        $descriptor->write();
308
309
        // Assume that something bad happens at this point, the process dies during execution, and
310
        // the task is re-initiated somewhere down the track
311
312
        // Loop 2 - Detect broken job, and mark it for future checking.
313
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
314
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
315
316
        // Note that we don't immediately try to restart it until StepsProcessed = LastProcessedCount
317
        $descriptor = QueuedJobDescriptor::get()->byID($id);
318
        $this->assertFalse($nextJob); // Don't run it this round please!
319
        $this->assertEquals(QueuedJob::STATUS_INIT, $descriptor->JobStatus);
320
        $this->assertEquals(0, $descriptor->StepsProcessed);
321
        $this->assertEquals(0, $descriptor->LastProcessedCount);
322
        $this->assertEquals(0, $descriptor->ResumeCounts);
323
324
        // Loop 3 - We've previously marked this job as broken, so restart it this round
325
        // If no more work has been done on the job at this point, assume that we are able to
326
        // restart it
327
        $logger->clear();
328
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
329
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
330
331
        // This job is resumed and exeuction is attempted this round
332
        $descriptor = QueuedJobDescriptor::get()->byID($id);
333
        $this->assertEquals($nextJob->ID, $descriptor->ID);
334
        $this->assertEquals(QueuedJob::STATUS_WAIT, $descriptor->JobStatus);
335
        $this->assertEquals(0, $descriptor->StepsProcessed);
336
        $this->assertEquals(0, $descriptor->LastProcessedCount);
337
        $this->assertEquals(1, $descriptor->ResumeCounts);
338
        $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());
339
340
        // Run 2 - First restart (work is done)
341
        $descriptor->JobStatus = QueuedJob::STATUS_RUN;
342
        $descriptor->StepsProcessed++; // Essentially delays the next restart by 1 loop
343
        $descriptor->write();
344
345
        // Once again, at this point, assume the job fails and crashes
346
347
        // Loop 4 - Assuming a job has LastProcessedCount < StepsProcessed we are in the same
348
        // situation as step 2.
349
        // Because the last time the loop ran, StepsProcessed was incremented,
350
        // this indicates that it's likely that another task could be working on this job, so
351
        // don't run this.
352
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
353
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
354
355
        $descriptor = QueuedJobDescriptor::get()->byID($id);
356
        $this->assertFalse($nextJob); // Don't run jobs we aren't sure should be restarted
357
        $this->assertEquals(QueuedJob::STATUS_RUN, $descriptor->JobStatus);
358
        $this->assertEquals(1, $descriptor->StepsProcessed);
359
        $this->assertEquals(1, $descriptor->LastProcessedCount);
360
        $this->assertEquals(1, $descriptor->ResumeCounts);
361
362
        // Loop 5 - Job is again found to not have been restarted since last iteration, so perform second
363
        // restart. The job should be attempted to run this loop
364
        $logger->clear();
365
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
366
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
367
368
        // This job is resumed and exeuction is attempted this round
369
        $descriptor = QueuedJobDescriptor::get()->byID($id);
370
        $this->assertEquals($nextJob->ID, $descriptor->ID);
371
        $this->assertEquals(QueuedJob::STATUS_WAIT, $descriptor->JobStatus);
372
        $this->assertEquals(1, $descriptor->StepsProcessed);
373
        $this->assertEquals(1, $descriptor->LastProcessedCount);
374
        $this->assertEquals(2, $descriptor->ResumeCounts);
375
        $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());
376
377
        // Run 3 - Second and last restart (no work is done)
378
        $descriptor->JobStatus = QueuedJob::STATUS_RUN;
379
        $descriptor->write();
380
381
        // Loop 6 - As no progress has been made since loop 3, we can mark this as dead
382
        $logger->clear();
383
        $svc->checkJobHealth(QueuedJob::IMMEDIATE);
384
        $nextJob = $svc->getNextPendingJob(QueuedJob::IMMEDIATE);
385
386
        // Since no StepsProcessed has been done, don't wait another loop to mark this as dead
387
        $descriptor = QueuedJobDescriptor::get()->byID($id);
388
        $this->assertEquals(QueuedJob::STATUS_PAUSED, $descriptor->JobStatus);
389
        $this->assertEmpty($nextJob);
390
        $this->assertContains('A job named A Test job appears to have stalled. It has been paused, please login to check it', $logger->getMessages());
391
    }
392
}
393