3c673f7274ffb33c80d87cb6d7231da150e13dc9
[moodle.git] / backup / util / progress / tests / progress_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Unit tests for the progress classes.
19  *
20  * @package core_backup
21  * @category phpunit
22  * @copyright 2013 The Open University
23  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 // Include all the needed stuff.
29 global $CFG;
30 require_once($CFG->dirroot . '/backup/util/progress/core_backup_progress.class.php');
32 /**
33  * Progress tests.
34  */
35 class backup_progress_testcase extends basic_testcase {
37     /**
38      * Tests for basic use with simple numeric progress.
39      */
40     public function test_basic() {
41         $progress = new core_backup_mock_progress();
43         // Check values of empty progress things.
44         $this->assertFalse($progress->is_in_progress_section());
46         // Start progress counting, check basic values and check that update
47         // gets called.
48         $progress->start_progress('hello', 10);
49         $this->assertTrue($progress->was_update_called());
50         $this->assertTrue($progress->is_in_progress_section());
51         $this->assertEquals('hello', $progress->get_current_description());
53         // Check numeric position and indeterminate count.
54         $this->assert_min_max(0.0, 0.0, $progress);
55         $this->assertEquals(0, $progress->get_progress_count());
57         // Make some progress and check that the time limit gets added.
58         $progress->step_time();
59         $progress->progress(2);
60         $this->assertTrue($progress->was_update_called());
61         $this->assertEquals(120, ini_get('max_execution_time'));
63         // Check the new value.
64         $this->assert_min_max(0.2, 0.2, $progress);
66         // Do another progress run at same time, it should be ignored.
67         $progress->progress(3);
68         $this->assertFalse($progress->was_update_called());
69         $this->assert_min_max(0.2, 0.2, $progress);
71         // End the section. This should cause an update.
72         $progress->end_progress();
73         $this->assertTrue($progress->was_update_called());
75         // Because there are no sections left open, it thinks we finished.
76         $this->assert_min_max(1.0, 1.0, $progress);
78         // There was 1 progress call.
79         $this->assertEquals(1, $progress->get_progress_count());
81         // Clear the time limit, otherwise phpunit complains.
82         set_time_limit(0);
83     }
85     /**
86      * Tests progress that is nested and/or indeterminate.
87      */
88     public function test_nested() {
89         // Outer progress goes from 0 to 10.
90         $progress = new core_backup_mock_progress();
91         $progress->start_progress('hello', 10);
93         // Get up to 4, check position.
94         $progress->step_time();
95         $progress->progress(4);
96         $this->assert_min_max(0.4, 0.4, $progress);
97         $this->assertEquals('hello', $progress->get_current_description());
99         // Now start indeterminate progress.
100         $progress->start_progress('world');
101         $this->assert_min_max(0.4, 0.5, $progress);
102         $this->assertEquals('world', $progress->get_current_description());
104         // Do some indeterminate progress and count it (once per second).
105         $progress->step_time();
106         $progress->progress();
107         $this->assertEquals(2, $progress->get_progress_count());
108         $progress->progress();
109         $this->assertEquals(2, $progress->get_progress_count());
110         $progress->step_time();
111         $progress->progress();
112         $this->assertEquals(3, $progress->get_progress_count());
113         $this->assert_min_max(0.4, 0.5, $progress);
115         // Exit the indeterminate section.
116         $progress->end_progress();
117         $this->assert_min_max(0.5, 0.5, $progress);
119         $progress->step_time();
120         $progress->progress(7);
121         $this->assert_min_max(0.7, 0.7, $progress);
123         // Enter a numbered section (this time with a range of 5).
124         $progress->start_progress('frogs', 5);
125         $this->assert_min_max(0.7, 0.7, $progress);
126         $progress->step_time();
127         $progress->progress(1);
128         $this->assert_min_max(0.72, 0.72, $progress);
129         $progress->step_time();
130         $progress->progress(3);
131         $this->assert_min_max(0.76, 0.76, $progress);
133         // Now enter another indeterminate section.
134         $progress->start_progress('and');
135         $this->assert_min_max(0.76, 0.78, $progress);
137         // Make some progress, should increment indeterminate count.
138         $progress->step_time();
139         $progress->progress();
140         $this->assertEquals(7, $progress->get_progress_count());
142         // Enter numbered section, won't make any difference to values.
143         $progress->start_progress('zombies', 2);
144         $progress->step_time();
145         $progress->progress(1);
146         $this->assert_min_max(0.76, 0.78, $progress);
147         $this->assertEquals(8, $progress->get_progress_count());
149         // Leaving it will make no difference too.
150         $progress->end_progress();
152         // Leaving the indeterminate section will though.
153         $progress->end_progress();
154         $this->assert_min_max(0.78, 0.78, $progress);
156         // Leave the two numbered sections.
157         $progress->end_progress();
158         $this->assert_min_max(0.8, 0.8, $progress);
159         $progress->end_progress();
160         $this->assertFalse($progress->is_in_progress_section());
162         set_time_limit(0);
163     }
165     /**
166      * Tests the feature for 'weighting' nested progress.
167      */
168     public function test_nested_weighted() {
169         $progress = new core_backup_mock_progress();
170         $progress->start_progress('', 10);
172         // First nested child has 2 units of its own and is worth 1 unit.
173         $progress->start_progress('', 2);
174         $progress->step_time();
175         $progress->progress(1);
176         $this->assert_min_max(0.05, 0.05, $progress);
177         $progress->end_progress();
178         $this->assert_min_max(0.1, 0.1, $progress);
180         // Next child has 2 units of its own but is worth 3 units.
181         $progress->start_progress('weighted', 2, 3);
182         $progress->step_time();
183         $progress->progress(1);
184         $this->assert_min_max(0.25, 0.25, $progress);
185         $progress->end_progress();
186         $this->assert_min_max(0.4, 0.4, $progress);
188         // Next indeterminate child is worth 6 units.
189         $progress->start_progress('', core_backup_progress::INDETERMINATE, 6);
190         $progress->step_time();
191         $progress->progress();
192         $this->assert_min_max(0.4, 1.0, $progress);
193         $progress->end_progress();
194         $this->assert_min_max(1.0, 1.0, $progress);
196         set_time_limit(0);
197     }
199     /**
200      * I had some issues with real use in backup/restore, this test is intended
201      * to be similar.
202      */
203     public function test_realistic() {
204         $progress = new core_backup_mock_progress();
205         $progress->start_progress('parent', 100);
206         $progress->start_progress('child', 1);
207         $progress->progress(1);
208         $this->assert_min_max(0.01, 0.01, $progress);
209         $progress->end_progress();
210         $this->assert_min_max(0.01, 0.01, $progress);
212         // Clear the time limit, otherwise phpunit complains.
213         set_time_limit(0);
214     }
216     /**
217      * Tests for any exceptions due to invalid calls.
218      */
219     public function test_exceptions() {
220         $progress = new core_backup_mock_progress();
222         // Check errors when empty.
223         try {
224             $progress->progress();
225             $this->fail();
226         } catch (coding_exception $e) {
227             $this->assertEquals(1, preg_match('~without start_progress~', $e->getMessage()));
228         }
229         try {
230             $progress->end_progress();
231             $this->fail();
232         } catch (coding_exception $e) {
233             $this->assertEquals(1, preg_match('~without start_progress~', $e->getMessage()));
234         }
235         try {
236             $progress->get_current_description();
237             $this->fail();
238         } catch (coding_exception $e) {
239             $this->assertEquals(1, preg_match('~Not inside progress~', $e->getMessage()));
240         }
241         try {
242             $progress->start_progress('', 1, 7);
243             $this->fail();
244         } catch (coding_exception $e) {
245             $this->assertEquals(1, preg_match('~must be 1~', $e->getMessage()));
246         }
248         // Check invalid start (0).
249         try {
250             $progress->start_progress('hello', 0);
251             $this->fail();
252         } catch (coding_exception $e) {
253             $this->assertEquals(1, preg_match('~cannot be zero or negative~', $e->getMessage()));
254         }
256         // Indeterminate when value expected.
257         $progress->start_progress('hello', 10);
258         try {
259             $progress->progress(core_backup_progress::INDETERMINATE);
260             $this->fail();
261         } catch (coding_exception $e) {
262             $this->assertEquals(1, preg_match('~expecting value~', $e->getMessage()));
263         }
265         // Value when indeterminate expected.
266         $progress->start_progress('hello');
267         try {
268             $progress->progress(4);
269             $this->fail();
270         } catch (coding_exception $e) {
271             $this->assertEquals(1, preg_match('~expecting INDETERMINATE~', $e->getMessage()));
272         }
274         // Illegal values.
275         $progress->start_progress('hello', 10);
276         try {
277             $progress->progress(-2);
278             $this->fail();
279         } catch (coding_exception $e) {
280             $this->assertEquals(1, preg_match('~out of range~', $e->getMessage()));
281         }
282         try {
283             $progress->progress(11);
284             $this->fail();
285         } catch (coding_exception $e) {
286             $this->assertEquals(1, preg_match('~out of range~', $e->getMessage()));
287         }
289         // You are allowed two with the same value...
290         $progress->progress(4);
291         $progress->step_time();
292         $progress->progress(4);
293         $progress->step_time();
295         // ...but not to go backwards.
296         try {
297             $progress->progress(3);
298             $this->fail();
299         } catch (coding_exception $e) {
300             $this->assertEquals(1, preg_match('~backwards~', $e->getMessage()));
301         }
303         // When you go forward, you can't go further than there is room.
304         try {
305             $progress->start_progress('', 1, 7);
306             $this->fail();
307         } catch (coding_exception $e) {
308             $this->assertEquals(1, preg_match('~would exceed max~', $e->getMessage()));
309         }
311         // Clear the time limit, otherwise phpunit complains.
312         set_time_limit(0);
313     }
315     /**
316      * Checks the current progress values are as expected.
317      *
318      * @param number $min Expected min progress
319      * @param number $max Expected max progress
320      * @param core_backup_mock_progress $progress
321      */
322     private function assert_min_max($min, $max, core_backup_mock_progress $progress) {
323         $this->assertEquals(array($min, $max),
324                 $progress->get_progress_proportion_range());
325     }
328 /**
329  * Helper class that records when update_progress is called and allows time
330  * stepping.
331  */
332 class core_backup_mock_progress extends core_backup_progress {
333     private $updatecalled = false;
334     private $time = 1;
336     /**
337      * Checks if update was called since the last call to this function.
338      *
339      * @return boolean True if update was called
340      */
341     public function was_update_called() {
342         if ($this->updatecalled) {
343             $this->updatecalled = false;
344             return true;
345         }
346         return false;
347     }
349     /**
350      * Steps the current time by 1 second.
351      */
352     public function step_time() {
353         $this->time++;
354     }
356     protected function update_progress() {
357         $this->updatecalled = true;
358     }
360     protected function get_time() {
361         return $this->time;
362     }