Completed
Push — master ( 8deccf...0fd7bd )
by
unknown
03:42 queued 02:08
created

tests/BatchedProcessorTest.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace SilverStripe\FullTextSearch\Tests;
4
5
use SilverStripe\CMS\Model\SiteTree;
6
use SilverStripe\Core\Config\Config;
7
use SilverStripe\Core\Injector\Injector;
8
use SilverStripe\Dev\SapphireTest;
9
use SilverStripe\FullTextSearch\Search\FullTextSearch;
10
use SilverStripe\FullTextSearch\Tests\BatchedProcessorTest\BatchedProcessor_QueuedJobService;
11
use SilverStripe\FullTextSearch\Tests\BatchedProcessorTest\BatchedProcessorTest_Index;
12
use SilverStripe\FullTextSearch\Tests\BatchedProcessorTest\BatchedProcessorTest_Object;
13
use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateCommitJobProcessor;
14
use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateQueuedJobProcessor;
15
use SilverStripe\FullTextSearch\Search\Processors\SearchUpdateBatchedProcessor;
16
use SilverStripe\FullTextSearch\Search\Updaters\SearchUpdater;
17
use SilverStripe\FullTextSearch\Search\Variants\SearchVariantVersioned;
18
use SilverStripe\ORM\FieldType\DBDatetime;
19
use SilverStripe\Versioned\Versioned;
20
use Symbiote\QueuedJobs\Services\QueuedJob;
21
use Symbiote\QueuedJobs\Services\QueuedJobService;
22
23
/**
24
 * Tests {@see SearchUpdateQueuedJobProcessor}
25
 */
26
class BatchedProcessorTest extends SapphireTest
27
{
28
    protected $oldProcessor;
29
30
    protected static $extra_dataobjects = array(
31
        BatchedProcessorTest_Object::class
32
    );
33
34
    protected static $illegal_extensions = [
35
        SiteTree::class => [
36
            SiteTreeSubsites::class,
37
        ],
38
    ];
39
40
    public static function setUpBeforeClass()
41
    {
42
        // Disable illegal extensions if skipping this test
43
        if (class_exists(Subsite::class) || !interface_exists(QueuedJob::class)) {
44
            static::$illegal_extensions = [];
45
        }
46
        parent::setUpBeforeClass();
47
    }
48
49
    protected function setUp()
50
    {
51
        parent::setUp();
52
53
        if (!interface_exists(QueuedJob::class)) {
54
            $this->markTestSkipped("These tests need the QueuedJobs module installed to run");
55
        }
56
57
        if (class_exists(Subsite::class)) {
58
            $this->markTestSkipped(get_class() . ' skipped when running with subsites');
59
        }
60
61
        DBDatetime::set_mock_now('2015-05-07 06:00:00');
62
63
        Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_size', 5);
64
        Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 0);
65
        Config::modify()->set(SearchUpdateCommitJobProcessor::class, 'cooldown', 600);
66
67
        Versioned::set_stage(Versioned::DRAFT);
68
69
        Injector::inst()->registerService(new BatchedProcessor_QueuedJobService(), QueuedJobService::class);
70
71
        FullTextSearch::force_index_list(BatchedProcessorTest_Index::class);
72
73
        SearchUpdateCommitJobProcessor::$dirty_indexes = array();
74
        SearchUpdateCommitJobProcessor::$has_run = false;
75
76
        $this->oldProcessor = SearchUpdater::$processor;
77
        SearchUpdater::$processor = new SearchUpdateQueuedJobProcessor();
78
    }
79
80
    public function tearDown()
81
    {
82
        if ($this->oldProcessor) {
83
            SearchUpdater::$processor = $this->oldProcessor;
84
        }
85
        FullTextSearch::force_index_list();
86
        parent::tearDown();
87
    }
88
89
    /**
90
     * @return SearchUpdateQueuedJobProcessor
91
     */
92
    protected function generateDirtyIds()
93
    {
94
        $processor = SearchUpdater::$processor;
95
        for ($id = 1; $id <= 42; $id++) {
96
            // Save to db
97
            $object = new BatchedProcessorTest_Object();
98
            $object->TestText = 'Object ' . $id;
99
            $object->write();
100
            // Add to index manually
101
            $processor->addDirtyIDs(
102
                BatchedProcessorTest_Object::class,
103
                array(array(
104
                    'id' => $id,
105
                    'state' => array(SearchVariantVersioned::class => 'Stage')
106
                )),
107
                BatchedProcessorTest_Index::class
108
            );
109
        }
110
        $processor->batchData();
111
        return $processor;
112
    }
113
114
    /**
115
     * Tests that large jobs are broken up into a suitable number of batches
116
     */
117
    public function testBatching()
118
    {
119
        $index = singleton(BatchedProcessorTest_Index::class);
120
        $index->reset();
121
        $processor = $this->generateDirtyIds();
122
123
        // Check initial state
124
        $data = $processor->getJobData();
125
        $this->assertEquals(9, $data->totalSteps);
126
        $this->assertEquals(0, $data->currentStep);
127
        $this->assertEmpty($data->isComplete);
128
        $this->assertEquals(0, count($index->getAdded()));
129
130
        // Advance state
131
        for ($pass = 1; $pass <= 8; $pass++) {
132
            $processor->process();
133
            $data = $processor->getJobData();
134
            $this->assertEquals($pass, $data->currentStep);
135
            $this->assertEquals($pass * 5, count($index->getAdded()));
136
        }
137
138
        // Last run should have two hanging items
139
        $processor->process();
140
        $data = $processor->getJobData();
141
        $this->assertEquals(9, $data->currentStep);
142
        $this->assertEquals(42, count($index->getAdded()));
143
        $this->assertTrue($data->isComplete);
144
145
        // Check any additional queued jobs
146
        $processor->afterComplete();
147
        $service = singleton(QueuedJobService::class);
148
        $jobs = $service->getJobs();
149
        $this->assertEquals(1, count($jobs));
150
        $this->assertInstanceOf(SearchUpdateCommitJobProcessor::class, $jobs[0]['job']);
151
    }
152
153
    /**
154
     * Test creation of multiple commit jobs
155
     */
156
    public function testMultipleCommits()
157
    {
158
        $index = singleton(BatchedProcessorTest_Index::class);
159
        $index->reset();
160
161
        // Test that running a commit immediately after submitting to the indexes
162
        // correctly commits
163
        $first = SearchUpdateCommitJobProcessor::queue();
164
        $second = SearchUpdateCommitJobProcessor::queue();
165
166
        $this->assertFalse($index->getIsCommitted());
167
168
        // First process will cause the commit
169
        $this->assertFalse($first->jobFinished());
170
        $first->process();
171
        $allMessages = $first->getMessages();
172
        $this->assertTrue($index->getIsCommitted());
173
        $this->assertTrue($first->jobFinished());
174
        $this->assertStringEndsWith('All indexes committed', $allMessages[2]);
175
176
        // Executing the subsequent processor should not re-trigger a commit
177
        $index->reset();
178
        $this->assertFalse($second->jobFinished());
179
        $second->process();
180
        $allMessages = $second->getMessages();
181
        $this->assertFalse($index->getIsCommitted());
182
        $this->assertTrue($second->jobFinished());
183
        $this->assertStringEndsWith('Indexing already completed this request: Discarding this job', $allMessages[0]);
184
185
        // Given that a third job is created, and the indexes are dirtied, attempting to run this job
186
        // should result in a delay
187
        $index->reset();
188
        $third = SearchUpdateCommitJobProcessor::queue();
189
        $this->assertFalse($third->jobFinished());
190
        $third->process();
191
        $this->assertTrue($third->jobFinished());
192
        $allMessages = $third->getMessages();
193
        $this->assertStringEndsWith(
194
            'Indexing already run this request, but incomplete. Re-scheduling for 2015-05-07 06:10:00',
195
            $allMessages[0]
196
        );
197
    }
198
199
200
    /**
201
     * Tests that the batch_soft_cap setting is properly respected
202
     */
203
    public function testSoftCap()
204
    {
205
        $index = singleton(BatchedProcessorTest_Index::class);
206
        $index->reset();
207
        $processor = $this->generateDirtyIds();
208
209
        // Test that increasing the soft cap to 2 will reduce the number of batches
210
        Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 2);
211
        $processor->batchData();
212
        $data = $processor->getJobData();
213
        //Debug::dump($data);die;
0 ignored issues
show
Unused Code Comprehensibility introduced by
78% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
214
        $this->assertEquals(8, $data->totalSteps);
215
216
        // A soft cap of 1 should not fit in the hanging two items
217
        Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 1);
218
        $processor->batchData();
219
        $data = $processor->getJobData();
220
        $this->assertEquals(9, $data->totalSteps);
221
222
        // Extra large soft cap should fit both items
223
        Config::modify()->set(SearchUpdateBatchedProcessor::class, 'batch_soft_cap', 4);
224
        $processor->batchData();
225
        $data = $processor->getJobData();
226
        $this->assertEquals(8, $data->totalSteps);
227
228
        // Process all data and ensure that all are processed adequately
229
        for ($pass = 1; $pass <= 8; $pass++) {
230
            $processor->process();
231
        }
232
        $data = $processor->getJobData();
233
        $this->assertEquals(8, $data->currentStep);
234
        $this->assertEquals(42, count($index->getAdded()));
235
        $this->assertTrue($data->isComplete);
236
    }
237
}
238