MDL-32149 add backup tests and dropping of extra tables
[moodle.git] / backup / converter / moodle1 / tests / lib_test.php
CommitLineData
dbf5a447
PS
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/>.
16
17/**
18 * Unit tests for the moodle1 converter
19 *
20 * @package core_backup
21 * @subpackage backup-convert
22 * @category phpunit
23 * @copyright 2011 Mark Nielsen <mark@moodlerooms.com>
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 */
26
27defined('MOODLE_INTERNAL') || die();
28
29global $CFG;
30require_once($CFG->dirroot . '/backup/converter/moodle1/lib.php');
31
32
33class moodle1_converter_test extends advanced_testcase {
34
35 /** @var string the name of the directory containing the unpacked Moodle 1.9 backup */
36 protected $tempdir;
37
38 public function setUp() {
39 global $CFG;
40
41 $this->tempdir = convert_helper::generate_id('simpletest');
42 check_dir_exists("$CFG->tempdir/backup/$this->tempdir/course_files/sub1");
43 check_dir_exists("$CFG->tempdir/backup/$this->tempdir/moddata/unittest/4/7");
44 copy(
45 "$CFG->dirroot/backup/converter/moodle1/simpletest/files/moodle.xml",
46 "$CFG->tempdir/backup/$this->tempdir/moodle.xml"
47 );
48 copy(
49 "$CFG->dirroot/backup/converter/moodle1/simpletest/files/icon.gif",
50 "$CFG->tempdir/backup/$this->tempdir/course_files/file1.gif"
51 );
52 copy(
53 "$CFG->dirroot/backup/converter/moodle1/simpletest/files/icon.gif",
54 "$CFG->tempdir/backup/$this->tempdir/course_files/sub1/file2.gif"
55 );
56 copy(
57 "$CFG->dirroot/backup/converter/moodle1/simpletest/files/icon.gif",
58 "$CFG->tempdir/backup/$this->tempdir/moddata/unittest/4/file1.gif"
59 );
60 copy(
61 "$CFG->dirroot/backup/converter/moodle1/simpletest/files/icon.gif",
62 "$CFG->tempdir/backup/$this->tempdir/moddata/unittest/4/icon.gif"
63 );
64 copy(
65 "$CFG->dirroot/backup/converter/moodle1/simpletest/files/icon.gif",
66 "$CFG->tempdir/backup/$this->tempdir/moddata/unittest/4/7/icon.gif"
67 );
68 }
69
70 public function tearDown() {
71 global $CFG;
72 if (empty($CFG->keeptempdirectoriesonbackup)) {
73 fulldelete("$CFG->tempdir/backup/$this->tempdir");
74 }
75 }
76
77 public function test_detect_format() {
78 $detected = moodle1_converter::detect_format($this->tempdir);
79 $this->assertEquals(backup::FORMAT_MOODLE1, $detected);
80 }
81
82 public function test_convert_factory() {
83 $converter = convert_factory::get_converter('moodle1', $this->tempdir);
84 $this->assertInstanceOf('moodle1_converter', $converter);
85 }
86
87 public function test_stash_storage_not_created() {
88 $converter = convert_factory::get_converter('moodle1', $this->tempdir);
89 $this->setExpectedException('moodle1_convert_storage_exception');
90 $converter->set_stash('tempinfo', 12);
91 }
92
93 public function test_stash_requiring_empty_stash() {
94 $this->resetAfterTest(true);
95 $converter = convert_factory::get_converter('moodle1', $this->tempdir);
96 $converter->create_stash_storage();
97 $converter->set_stash('tempinfo', 12);
98 $this->setExpectedException('moodle1_convert_empty_storage_exception');
99 try {
100 $converter->get_stash('anothertempinfo');
101
102 } catch (moodle1_convert_empty_storage_exception $e) {
103 // we must drop the storage here so we are able to re-create it in the next test
104 $converter->drop_stash_storage();
105 throw new moodle1_convert_empty_storage_exception('rethrowing');
106 }
107 }
108
109 public function test_stash_storage() {
110 $this->resetAfterTest(true);
111 $converter = convert_factory::get_converter('moodle1', $this->tempdir);
112 $converter->create_stash_storage();
113
114 // no implicit stashes
115 $stashes = $converter->get_stash_names();
116 $this->assertEquals(gettype($stashes), 'array');
117 $this->assertTrue(empty($stashes));
118
119 // test stashes without itemid
120 $converter->set_stash('tempinfo1', 12);
121 $converter->set_stash('tempinfo2', array('a' => 2, 'b' => 3));
122 $stashes = $converter->get_stash_names();
123 $this->assertEquals('array', gettype($stashes));
124 $this->assertEquals(2, count($stashes));
125 $this->assertTrue(in_array('tempinfo1', $stashes));
126 $this->assertTrue(in_array('tempinfo2', $stashes));
127 $this->assertEquals(12, $converter->get_stash('tempinfo1'));
128 $this->assertEquals(array('a' => 2, 'b' => 3), $converter->get_stash('tempinfo2'));
129
130 // overwriting a stashed value is allowed
131 $converter->set_stash('tempinfo1', '13');
132 $this->assertNotSame(13, $converter->get_stash('tempinfo1'));
133 $this->assertSame('13', $converter->get_stash('tempinfo1'));
134
135 // repeated reading is allowed
136 $this->assertEquals('13', $converter->get_stash('tempinfo1'));
137
138 // storing empty array
139 $converter->set_stash('empty_array_stash', array());
140 $restored = $converter->get_stash('empty_array_stash');
141 //$this->assertEquals(gettype($restored), 'array'); // todo return null now, this needs MDL-27713 to be fixed, then uncomment
142 $this->assertTrue(empty($restored));
143
144 // test stashes with itemid
145 $converter->set_stash('tempinfo', 'Hello', 1);
146 $converter->set_stash('tempinfo', 'World', 2);
147 $this->assertSame('Hello', $converter->get_stash('tempinfo', 1));
148 $this->assertSame('World', $converter->get_stash('tempinfo', 2));
149
150 // test get_stash_itemids()
151 $ids = $converter->get_stash_itemids('course_fileref');
152 $this->assertEquals(gettype($ids), 'array');
153 $this->assertTrue(empty($ids));
154
155 $converter->set_stash('course_fileref', null, 34);
156 $converter->set_stash('course_fileref', null, 52);
157 $ids = $converter->get_stash_itemids('course_fileref');
158 $this->assertEquals(2, count($ids));
159 $this->assertTrue(in_array(34, $ids));
160 $this->assertTrue(in_array(52, $ids));
161
162 $converter->drop_stash_storage();
163 }
164
165 public function test_get_stash_or_default() {
166 $this->resetAfterTest(true);
167 $converter = convert_factory::get_converter('moodle1', $this->tempdir);
168 $converter->create_stash_storage();
169
170 $this->assertTrue(is_null($converter->get_stash_or_default('stashname')));
171 $this->assertTrue(is_null($converter->get_stash_or_default('stashname', 7)));
172 $this->assertTrue('default' === $converter->get_stash_or_default('stashname', 0, 'default'));
173 $this->assertTrue(array('foo', 'bar') === $converter->get_stash_or_default('stashname', 42, array('foo', 'bar')));
174
175 //$converter->set_stash('stashname', 0);
176 //$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
177
178 //$converter->set_stash('stashname', '');
179 //$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
180
181 //$converter->set_stash('stashname', array());
182 //$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
183
184 $converter->set_stash('stashname', 42);
185 $this->assertTrue(42 === $converter->get_stash_or_default('stashname'));
186 $this->assertTrue(is_null($converter->get_stash_or_default('stashname', 1)));
187 $this->assertTrue(42 === $converter->get_stash_or_default('stashname', 0, 61));
188
189 $converter->set_stash('stashname', array(42 => (object)array('id' => 42)), 18);
190 $stashed = $converter->get_stash_or_default('stashname', 18, 1984);
191 $this->assertEquals(gettype($stashed), 'array');
192 $this->assertTrue(is_object($stashed[42]));
193 $this->assertTrue($stashed[42]->id === 42);
194
195 $converter->drop_stash_storage();
196 }
197
198 public function test_get_contextid() {
199 $this->resetAfterTest(true);
200
201 $converter = convert_factory::get_converter('moodle1', $this->tempdir);
202
203 // stash storage must be created in advance
204 $converter->create_stash_storage();
205
206 // ids are generated on the first call
207 $id1 = $converter->get_contextid(CONTEXT_BLOCK, 10);
208 $id2 = $converter->get_contextid(CONTEXT_BLOCK, 11);
209 $id3 = $converter->get_contextid(CONTEXT_MODULE, 10);
210
211 $this->assertNotEquals($id1, $id2);
212 $this->assertNotEquals($id1, $id3);
213 $this->assertNotEquals($id2, $id3);
214
215 // and then re-used if called with the same params
216 $this->assertEquals($id1, $converter->get_contextid(CONTEXT_BLOCK, 10));
217 $this->assertEquals($id2, $converter->get_contextid(CONTEXT_BLOCK, 11));
218 $this->assertEquals($id3, $converter->get_contextid(CONTEXT_MODULE, 10));
219
220 // for system and course level, the instance is irrelevant
221 // as we need only one system and one course
222 $id1 = $converter->get_contextid(CONTEXT_COURSE);
223 $id2 = $converter->get_contextid(CONTEXT_COURSE, 10);
224 $id3 = $converter->get_contextid(CONTEXT_COURSE, 14);
225
226 $this->assertEquals($id1, $id2);
227 $this->assertEquals($id1, $id3);
228
229 $id1 = $converter->get_contextid(CONTEXT_SYSTEM);
230 $id2 = $converter->get_contextid(CONTEXT_SYSTEM, 11);
231 $id3 = $converter->get_contextid(CONTEXT_SYSTEM, 15);
232
233 $this->assertEquals($id1, $id2);
234 $this->assertEquals($id1, $id3);
235
236 $converter->drop_stash_storage();
237 }
238
239 public function test_get_nextid() {
240 $this->resetAfterTest(true);
241
242 $converter = convert_factory::get_converter('moodle1', $this->tempdir);
243
244 $id1 = $converter->get_nextid();
245 $id2 = $converter->get_nextid();
246 $id3 = $converter->get_nextid();
247
248 $this->assertTrue(0 < $id1);
249 $this->assertTrue($id1 < $id2);
250 $this->assertTrue($id2 < $id3);
251 }
252
253 public function test_migrate_file() {
254 $this->resetAfterTest(true);
255
256 // set-up the file manager
257 $converter = convert_factory::get_converter('moodle1', $this->tempdir);
258 $converter->create_stash_storage();
259 $contextid = $converter->get_contextid(CONTEXT_MODULE, 32);
260 $fileman = $converter->get_file_manager($contextid, 'mod_unittest', 'testarea');
261 // this fileman has not converted anything yet
262 $fileids = $fileman->get_fileids();
263 $this->assertEquals(gettype($fileids), 'array');
264 $this->assertEquals(0, count($fileids));
265 // try to migrate a non-existing directory
266 $returned = $fileman->migrate_directory('not/existing/directory');
267 $this->assertEquals(gettype($returned), 'array');
268 $this->assertEquals(0, count($returned));
269 $fileids = $fileman->get_fileids();
270 $this->assertEquals(gettype($fileids), 'array');
271 $this->assertEquals(0, count($fileids));
272 // migrate a single file
273 $fileman->itemid = 4;
274 $fileman->migrate_file('moddata/unittest/4/icon.gif');
275 $this->assertTrue(is_file($converter->get_workdir_path().'/files/4e/4ea114b0558f53e3af8dd9afc0e0810a95c2a724'));
276 // get the file id
277 $fileids = $fileman->get_fileids();
278 $this->assertEquals(gettype($fileids), 'array');
279 $this->assertEquals(1, count($fileids));
280 // migrate another single file into another file area
281 $fileman->filearea = 'anotherarea';
282 $fileman->itemid = 7;
283 $fileman->migrate_file('moddata/unittest/4/7/icon.gif', '/', 'renamed.gif');
284 // get the file records
285 $filerecordids = $converter->get_stash_itemids('files');
286 foreach ($filerecordids as $filerecordid) {
287 $filerecord = $converter->get_stash('files', $filerecordid);
288 $this->assertEquals('4ea114b0558f53e3af8dd9afc0e0810a95c2a724', $filerecord['contenthash']);
289 $this->assertEquals($contextid, $filerecord['contextid']);
290 $this->assertEquals('mod_unittest', $filerecord['component']);
291 if ($filerecord['filearea'] === 'testarea') {
292 $this->assertEquals(4, $filerecord['itemid']);
293 $this->assertEquals('icon.gif', $filerecord['filename']);
294 }
295 }
296 // explicitly clear the list of migrated files
297 $this->assertTrue(count($fileman->get_fileids()) > 0);
298 $fileman->reset_fileids();
299 $this->assertTrue(count($fileman->get_fileids()) == 0);
300 $converter->drop_stash_storage();
301 }
302
303 public function test_convert_path() {
304 $path = new convert_path('foo_bar', '/ROOT/THINGS/FOO/BAR');
305 $this->assertEquals('foo_bar', $path->get_name());
306 $this->assertEquals('/ROOT/THINGS/FOO/BAR', $path->get_path());
307 $this->assertEquals('process_foo_bar', $path->get_processing_method());
308 $this->assertEquals('on_foo_bar_start', $path->get_start_method());
309 $this->assertEquals('on_foo_bar_end', $path->get_end_method());
310 }
311
312 public function test_convert_path_implicit_recipes() {
313 $path = new convert_path('foo_bar', '/ROOT/THINGS/FOO/BAR');
314 $data = array(
315 'ID' => 76,
316 'ELOY' => 'stronk7',
317 'MARTIN' => 'moodler',
318 'EMPTY' => null,
319 );
320 // apply default recipes (converting keys to lowercase)
321 $data = $path->apply_recipes($data);
322 $this->assertEquals(4, count($data));
323 $this->assertEquals(76, $data['id']);
324 $this->assertEquals('stronk7', $data['eloy']);
325 $this->assertEquals('moodler', $data['martin']);
326 $this->assertSame(null, $data['empty']);
327 }
328
329 public function test_convert_path_explicit_recipes() {
330 $path = new convert_path(
331 'foo_bar', '/ROOT/THINGS/FOO/BAR',
332 array(
333 'newfields' => array(
334 'david' => 'mudrd8mz',
335 'petr' => 'skodak',
336 ),
337 'renamefields' => array(
338 'empty' => 'nothing',
339 ),
340 'dropfields' => array(
341 'id'
342 ),
343 )
344 );
345 $data = array(
346 'ID' => 76,
347 'ELOY' => 'stronk7',
348 'MARTIN' => 'moodler',
349 'EMPTY' => null,
350 );
351 $data = $path->apply_recipes($data);
352
353 $this->assertEquals(5, count($data));
354 $this->assertFalse(array_key_exists('id', $data));
355 $this->assertEquals('stronk7', $data['eloy']);
356 $this->assertEquals('moodler', $data['martin']);
357 $this->assertEquals('mudrd8mz', $data['david']);
358 $this->assertEquals('skodak', $data['petr']);
359 $this->assertSame(null, $data['nothing']);
360 }
361
362 public function test_grouped_data_on_nongrouped_convert_path() {
363 // prepare some grouped data
364 $data = array(
365 'ID' => 77,
366 'NAME' => 'Pale lagers',
367 'BEERS' => array(
368 array(
369 'BEER' => array(
370 'ID' => 67,
371 'NAME' => 'Pilsner Urquell',
372 )
373 ),
374 array(
375 'BEER' => array(
376 'ID' => 34,
377 'NAME' => 'Heineken',
378 )
379 ),
380 )
381 );
382
383 // declare a non-grouped path
384 $path = new convert_path('beer_style', '/ROOT/BEER_STYLES/BEER_STYLE');
385
386 // an attempt to apply recipes throws exception because we do not expect grouped data
387 $this->setExpectedException('convert_path_exception');
388 $data = $path->apply_recipes($data);
389 }
390
391 public function test_grouped_convert_path_with_recipes() {
392 // prepare some grouped data
393 $data = array(
394 'ID' => 77,
395 'NAME' => 'Pale lagers',
396 'BEERS' => array(
397 array(
398 'BEER' => array(
399 'ID' => 67,
400 'NAME' => 'Pilsner Urquell',
401 )
402 ),
403 array(
404 'BEER' => array(
405 'ID' => 34,
406 'NAME' => 'Heineken',
407 )
408 ),
409 )
410 );
411
412 // implict recipes work for grouped data if the path is declared as grouped
413 $path = new convert_path('beer_style', '/ROOT/BEER_STYLES/BEER_STYLE', array(), true);
414 $data = $path->apply_recipes($data);
415 $this->assertEquals('Heineken', $data['beers'][1]['beer']['name']);
416
417 // an attempt to provide explicit recipes on grouped elements throws exception
418 $this->setExpectedException('convert_path_exception');
419 $path = new convert_path(
420 'beer_style', '/ROOT/BEER_STYLES/BEER_STYLE',
421 array(
422 'renamefields' => array(
423 'name' => 'beername', // note this is confusing recipe because the 'name' is used for both
424 // beer-style name ('Pale lagers') and beer name ('Pilsner Urquell')
425 )
426 ), true);
427 }
428
429 public function test_referenced_course_files() {
430
431 $text = 'This is a text containing links to file.php
432as it is parsed from the backup file. <br /><br /><img border="0" width="110" vspace="0" hspace="0" height="92" title="News" alt="News" src="$@FILEPHP@$$@SLASH@$pics$@SLASH@$news.gif" /><a href="$@FILEPHP@$$@SLASH@$pics$@SLASH@$news.gif$@FORCEDOWNLOAD@$">download image</a><br />
433 <br /><a href=\'$@FILEPHP@$$@SLASH@$MANUAL.DOC$@FORCEDOWNLOAD@$\'>download manual</a><br />';
434
435 $files = moodle1_converter::find_referenced_files($text);
436 $this->assertEquals(gettype($files), 'array');
437 $this->assertEquals(2, count($files));
438 $this->assertTrue(in_array('/pics/news.gif', $files));
439 $this->assertTrue(in_array('/MANUAL.DOC', $files));
440
441 $text = moodle1_converter::rewrite_filephp_usage($text, array('/pics/news.gif', '/another/file/notused.txt'), $files);
442 $this->assertEquals($text, 'This is a text containing links to file.php
443as it is parsed from the backup file. <br /><br /><img border="0" width="110" vspace="0" hspace="0" height="92" title="News" alt="News" src="@@PLUGINFILE@@/pics/news.gif" /><a href="@@PLUGINFILE@@/pics/news.gif?forcedownload=1">download image</a><br />
444 <br /><a href=\'$@FILEPHP@$$@SLASH@$MANUAL.DOC$@FORCEDOWNLOAD@$\'>download manual</a><br />');
445 }
446
447 public function test_question_bank_conversion() {
448 global $CFG;
449
450 $this->resetAfterTest(true);
451
452 copy(
453 "$CFG->dirroot/backup/converter/moodle1/simpletest/files/questions.xml",
454 "$CFG->tempdir/backup/$this->tempdir/moodle.xml"
455 );
456 $converter = convert_factory::get_converter('moodle1', $this->tempdir);
457 $converter->convert();
458 }
459
460 public function test_convert_run_convert() {
461 $this->resetAfterTest(true);
462 $converter = convert_factory::get_converter('moodle1', $this->tempdir);
463 $converter->convert();
464 }
465
466 public function test_inforef_manager() {
467 $converter = convert_factory::get_converter('moodle1', $this->tempdir);
468 $inforef = $converter->get_inforef_manager('unittest');
469 $inforef->add_ref('file', 45);
470 $inforef->add_refs('file', array(46, 47));
471 // todo test the write_refs() via some dummy xml_writer
472 $this->setExpectedException('coding_exception');
473 $inforef->add_ref('unknown_referenced_item_name', 76);
474 }
475}