MDL-68909 h5p: move temporary editor files to draft area
[moodle.git] / h5p / tests / h5p_file_storage_test.php
CommitLineData
9ea303e7
AG
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 * Testing the H5P H5PFileStorage interface implementation.
19 *
20 * @package core_h5p
21 * @category test
22 * @copyright 2019 Victor Deniz <victor@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26namespace core_h5p\local\tests;
27
28use core_h5p\file_storage;
08fda3e0 29use core_h5p\local\library\autoloader;
d3ee08db 30use core_h5p\helper;
9ea303e7 31use file_archive;
6da050d7
VDF
32use moodle_exception;
33use ReflectionMethod;
9ea303e7
AG
34use zip_archive;
35
36defined('MOODLE_INTERNAL') || die();
37
38/**
39 * Test class covering the H5PFileStorage interface implementation.
40 *
41 * @package core_h5p
42 * @copyright 2019 Victor Deniz <victor@moodle.com>
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
d68be5b2 44 * @runTestsInSeparateProcesses
9ea303e7
AG
45 */
46class h5p_file_storage_testcase extends \advanced_testcase {
47
48 /** @var \core_h5p\file_storage H5P file storage instance */
49 protected $h5p_file_storage;
50 /** @var \file_storage Core Moodle file_storage associated to the H5P file_storage */
51 protected $h5p_fs_fs;
52 /** @var \context Moodle context of the H5P file_storage */
53 protected $h5p_fs_context;
54 /** @var string Path to temp directory */
55 protected $h5p_tempath;
56 /** @var \core_h5p_generator H5P generator instance */
57 protected $h5p_generator;
58 /** @var array $files an array used in the cache tests. */
59 protected $files = ['scripts' => [], 'styles' => []];
60 /** @var int $libraryid an id for the library. */
61 protected $libraryid = 1;
62
63 protected function setUp() {
64 parent::setUp();
65 $this->resetAfterTest(true);
66
ca7de4b6
SA
67 autoloader::register();
68
9ea303e7
AG
69 // Fetch generator.
70 $generator = \testing_util::get_data_generator();
71 $this->h5p_generator = $generator->get_plugin_generator('core_h5p');
72
73 // Create file_storage_instance and create H5P temp directory.
74 $this->h5p_file_storage = new file_storage();
75 $this->h5p_tempath = $this->h5p_file_storage->getTmpPath();
76 check_dir_exists($this->h5p_tempath);
77
78 // Get value of protected properties.
79 $h5p_fs_rc = new \ReflectionClass(file_storage::class);
80 $h5p_file_storage_context = $h5p_fs_rc->getProperty('context');
81 $h5p_file_storage_context->setAccessible(true);
82 $this->h5p_fs_context = $h5p_file_storage_context->getValue($this->h5p_file_storage);
83
84 $h5p_file_storage_fs = $h5p_fs_rc->getProperty('fs');
85 $h5p_file_storage_fs->setAccessible(true);
86 $this->h5p_fs_fs = $h5p_file_storage_fs->getValue($this->h5p_file_storage);
87 }
88
89 /**
90 * Test that given the main directory of a library that all files are saved
91 * into the file system.
92 */
93 public function test_saveLibrary(): void {
94
95 $machinename = 'TestLib';
96 $majorversion = 1;
97 $minorversion = 0;
98 [$lib, $files] = $this->h5p_generator->create_library($this->h5p_tempath, $this->libraryid, $machinename, $majorversion,
99 $minorversion);
100
101 // Now run the API call.
102 $this->h5p_file_storage->saveLibrary($lib);
103
104 // Check that files are in the Moodle file system.
105 $file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
106 file_storage::LIBRARY_FILEAREA, '1', "/{$machinename}-{$majorversion}.{$minorversion}/", 'library.json');
107 $filepath = "/{$machinename}-{$majorversion}.{$minorversion}/";
108 $this->assertEquals($filepath, $file->get_filepath());
109
110 $file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
111 file_storage::LIBRARY_FILEAREA, '1', "/{$machinename}-{$majorversion}.{$minorversion}/scripts/", 'testlib.min.js');
112 $jsfilepath = "{$filepath}scripts/";
113 $this->assertEquals($jsfilepath, $file->get_filepath());
114
115 $file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
116 file_storage::LIBRARY_FILEAREA, '1', "/{$machinename}-{$majorversion}.{$minorversion}/styles/", 'testlib.min.css');
117 $cssfilepath = "{$filepath}styles/";
118 $this->assertEquals($cssfilepath, $file->get_filepath());
119 }
120
121 /**
122 * Test that a content file can be saved.
123 */
124 public function test_saveContent(): void {
125
126 $source = $this->h5p_tempath . '/' . 'content.json';
127 $this->h5p_generator->create_file($source);
128
129 $this->h5p_file_storage->saveContent($this->h5p_tempath, ['id' => 5]);
130
131 $file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
132 file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');
133 $this->assertEquals(file_storage::CONTENT_FILEAREA, $file->get_filearea());
134 $this->assertEquals('content.json', $file->get_filename());
135 $this->assertEquals(5, $file->get_itemid());
136 }
137
138 /**
139 * Test that content files located on the file system can be deleted.
140 */
141 public function test_deleteContent(): void {
142
143 $source = $this->h5p_tempath . '/' . 'content.json';
144 $this->h5p_generator->create_file($source);
145
146 $this->h5p_file_storage->saveContent($this->h5p_tempath, ['id' => 5]);
147
148 $file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
149 file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');
150 $this->assertEquals('content.json', $file->get_filename());
151
152 // Now to delete the record.
153 $this->h5p_file_storage->deleteContent(['id' => 5]);
154 $file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
155 file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');
156 $this->assertFalse($file);
157 }
158
159 /**
160 * Test that returning a temp path returns what is expected by the h5p library.
161 */
162 public function test_getTmpPath(): void {
163
164 $temparray = explode('/', $this->h5p_tempath);
165 $h5pdirectory = array_pop($temparray);
166 $this->assertTrue(stripos($h5pdirectory, 'h5p-') === 0);
167 }
168
169 /**
170 * Test that the content files can be exported to a specified location.
171 */
172 public function test_exportContent(): void {
173
174 // Create a file to store.
175 $source = $this->h5p_tempath . '/' . 'content.json';
176 $this->h5p_generator->create_file($source);
177
178 $this->h5p_file_storage->saveContent($this->h5p_tempath, ['id' => 5]);
179
180 $file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
181 file_storage::CONTENT_FILEAREA, '5', '/', 'content.json');
182 $this->assertEquals('content.json', $file->get_filename());
183
184 // Now export it.
185 $destinationdirectory = $this->h5p_tempath . '/' . 'testdir';
186 check_dir_exists($destinationdirectory);
187
188 $this->h5p_file_storage->exportContent(5, $destinationdirectory);
189 // Check that there is a file now in that directory.
190 $contents = scandir($destinationdirectory);
191 $value = array_search('content.json', $contents);
192 $this->assertEquals('content.json', $contents[$value]);
193 }
194
195 /**
196 * Test that libraries on the file system can be exported to a specified location.
197 */
198 public function test_exportLibrary(): void {
199
200 $machinename = 'TestLib';
201 $majorversion = 1;
202 $minorversion = 0;
203 [$lib, $files] = $this->h5p_generator->create_library($this->h5p_tempath, $this->libraryid, $machinename, $majorversion,
204 $minorversion);
205
206 // Now run the API call.
207 $this->h5p_file_storage->saveLibrary($lib);
208
209 $destinationdirectory = $this->h5p_tempath . '/' . 'testdir';
210 check_dir_exists($destinationdirectory);
211
212 $this->h5p_file_storage->exportLibrary($lib, $destinationdirectory);
213
214 $filepath = "/{$machinename}-{$majorversion}.{$minorversion}/";
215 // There should be at least three items here (but could be more with . and ..).
216 $this->assertFileExists($destinationdirectory . $filepath . 'library.json');
217 $this->assertFileExists($destinationdirectory . $filepath . 'scripts/' . 'testlib.min.js');
218 $this->assertFileExists($destinationdirectory . $filepath . 'styles/' . 'testlib.min.css');
219 }
220
221 /**
222 * Test that an export file can be saved into the file system.
223 */
224 public function test_saveExport(): void {
225
226 $filename = 'someexportedfile.h5p';
227 $source = $this->h5p_tempath . '/' . $filename;
228 $this->h5p_generator->create_file($source);
229
230 $this->h5p_file_storage->saveExport($source, $filename);
231
232 // Check out if the file is there.
233 $file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
234 file_storage::EXPORT_FILEAREA, '0', '/', $filename);
235 $this->assertEquals(file_storage::EXPORT_FILEAREA, $file->get_filearea());
236 }
237
238 /**
239 * Test that an exort file can be deleted from the file system.
240 * @return [type] [description]
241 */
242 public function test_deleteExport(): void {
243
244 $filename = 'someexportedfile.h5p';
245 $source = $this->h5p_tempath . '/' . $filename;
246 $this->h5p_generator->create_file($source);
247
248 $this->h5p_file_storage->saveExport($source, $filename);
249
250 // Check out if the file is there.
251 $file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
252 file_storage::EXPORT_FILEAREA, '0', '/', $filename);
253 $this->assertEquals(file_storage::EXPORT_FILEAREA, $file->get_filearea());
254
255 // Time to delete.
256 $this->h5p_file_storage->deleteExport($filename);
257
258 // Check out if the file is there.
259 $file = $this->h5p_fs_fs->get_file ($this->h5p_fs_context->id, file_storage::COMPONENT,
260 file_storage::EXPORT_FILEAREA, '0', '/', $filename);
261 $this->assertFalse($file);
262 }
263
264 /**
265 * Test to check if an export file already exists on the file system.
266 */
267 public function test_hasExport(): void {
268
269 $filename = 'someexportedfile.h5p';
270 $source = $this->h5p_tempath . '/' . $filename;
271 $this->h5p_generator->create_file($source);
272
273 // Check that it doesn't exist in the file system.
274 $this->assertFalse($this->h5p_file_storage->hasExport($filename));
275
276 $this->h5p_file_storage->saveExport($source, $filename);
277 // Now it should be present.
278 $this->assertTrue($this->h5p_file_storage->hasExport($filename));
279 }
280
281 /**
282 * Test that all the library files for an H5P activity can be concatenated into "cache" files. One for js and another for css.
283 */
284 public function test_cacheAssets(): void {
285
286 $basedirectory = $this->h5p_tempath . '/' . 'test-1.0';
287
288 $machinename = 'TestLib';
289 $majorversion = 1;
290 $minorversion = 0;
291 [$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
292 $minorversion);
293 array_push($this->files['scripts'], ...$libfiles['scripts']);
294 array_push($this->files['styles'], ...$libfiles['styles']);
295
296 // Now run the API call.
297 $this->h5p_file_storage->saveLibrary($lib);
298
299 // Second library.
300 $basedirectory = $this->h5p_tempath . '/' . 'supertest-2.4';
301
302 $this->libraryid++;
303 $machinename = 'SuperTest';
304 $majorversion = 2;
305 $minorversion = 4;
306 [$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
307 $minorversion);
308 array_push($this->files['scripts'], ...$libfiles['scripts']);
309 array_push($this->files['styles'], ...$libfiles['styles']);
310
311 $this->h5p_file_storage->saveLibrary($lib);
312
313 $this->assertCount(2, $this->files['scripts']);
314 $this->assertCount(2, $this->files['styles']);
315
316 $key = 'testhashkey';
317
318 $this->h5p_file_storage->cacheAssets($this->files, $key);
319 $this->assertCount(1, $this->files['scripts']);
320 $this->assertCount(1, $this->files['styles']);
321
322
323 $expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.js';
324 $this->assertEquals($expectedfile, $this->files['scripts'][0]->path);
325 $expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.css';
326 $this->assertEquals($expectedfile, $this->files['styles'][0]->path);
327 }
328
329 /**
330 * Test that cached files can be retrieved via a key.
331 */
332 public function test_getCachedAssets() {
333
334 $basedirectory = $this->h5p_tempath . '/' . 'test-1.0';
335
336 $machinename = 'TestLib';
337 $majorversion = 1;
338 $minorversion = 0;
339 [$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
340 $minorversion);
341 array_push($this->files['scripts'], ...$libfiles['scripts']);
342 array_push($this->files['styles'], ...$libfiles['styles']);
343
344 // Now run the API call.
345 $this->h5p_file_storage->saveLibrary($lib);
346
347 // Second library.
348 $basedirectory = $this->h5p_tempath . '/' . 'supertest-2.4';
349
350 $this->libraryid++;
351 $machinename = 'SuperTest';
352 $majorversion = 2;
353 $minorversion = 4;
354 [$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
355 $minorversion);
356 array_push($this->files['scripts'], ...$libfiles['scripts']);
357 array_push($this->files['styles'], ...$libfiles['styles']);
358
359 $this->h5p_file_storage->saveLibrary($lib);
360
361 $this->assertCount(2, $this->files['scripts']);
362 $this->assertCount(2, $this->files['styles']);
363
364 $key = 'testhashkey';
365
366 $this->h5p_file_storage->cacheAssets($this->files, $key);
367
368 $testarray = $this->h5p_file_storage->getCachedAssets($key);
369 $this->assertCount(1, $testarray['scripts']);
370 $this->assertCount(1, $testarray['styles']);
371 $expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.js';
372 $this->assertEquals($expectedfile, $testarray['scripts'][0]->path);
373 $expectedfile = '/' . file_storage::CACHED_ASSETS_FILEAREA . '/' . $key . '.css';
374 $this->assertEquals($expectedfile, $testarray['styles'][0]->path);
375 }
376
377 /**
378 * Test that cache files in the files system can be removed.
379 */
380 public function test_deleteCachedAssets(): void {
381 $basedirectory = $this->h5p_tempath . '/' . 'test-1.0';
382
383 $machinename = 'TestLib';
384 $majorversion = 1;
385 $minorversion = 0;
386 [$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
387 $minorversion);
388 array_push($this->files['scripts'], ...$libfiles['scripts']);
389 array_push($this->files['styles'], ...$libfiles['styles']);
390
391 // Now run the API call.
392 $this->h5p_file_storage->saveLibrary($lib);
393
394 // Second library.
395 $basedirectory = $this->h5p_tempath . '/' . 'supertest-2.4';
396
397 $this->libraryid++;
398 $machinename = 'SuperTest';
399 $majorversion = 2;
400 $minorversion = 4;
401 [$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
402 $minorversion);
403 array_push($this->files['scripts'], ...$libfiles['scripts']);
404 array_push($this->files['styles'], ...$libfiles['styles']);
405
406 $this->h5p_file_storage->saveLibrary($lib);
407
408 $this->assertCount(2, $this->files['scripts']);
409 $this->assertCount(2, $this->files['styles']);
410
411 $key = 'testhashkey';
412
413 $this->h5p_file_storage->cacheAssets($this->files, $key);
414
415 $testarray = $this->h5p_file_storage->getCachedAssets($key);
416 $this->assertCount(1, $testarray['scripts']);
417 $this->assertCount(1, $testarray['styles']);
418
419 // Time to delete.
420 $this->h5p_file_storage->deleteCachedAssets([$key]);
421 $testarray = $this->h5p_file_storage->getCachedAssets($key);
422 $this->assertNull($testarray);
423 }
424
425 /**
426 * Retrieve content from a file given a specific path.
427 */
428 public function test_getContent() {
429 $basedirectory = $this->h5p_tempath . '/' . 'test-1.0';
430
431 $machinename = 'TestLib';
432 $majorversion = 1;
433 $minorversion = 0;
434 [$lib, $libfiles] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
435 $minorversion);
436 array_push($this->files['scripts'], ...$libfiles['scripts']);
437 array_push($this->files['styles'], ...$libfiles['styles']);
438
439 // Now run the API call.
440 $this->h5p_file_storage->saveLibrary($lib);
441
442 $content = $this->h5p_file_storage->getContent($this->files['scripts'][0]->path);
443 // The file content is created based on the file system path (\core_h5p_generator::create_file).
444 $expectedcontent = hash("md5", $basedirectory. '/' . 'scripts' . '/' . 'testlib.min.js');
445
446 $this->assertEquals($expectedcontent, $content);
447 }
448
449 /**
450 * Test that an upgrade script can be found on the file system.
451 */
452 public function test_getUpgradeScript() {
453 // Upload an upgrade file.
454 $machinename = 'TestLib';
455 $majorversion = 3;
456 $minorversion = 1;
457 $filepath = '/' . "{$machinename}-{$majorversion}.{$minorversion}" . '/';
458 $fs = get_file_storage();
459 $filerecord = [
460 'contextid' => \context_system::instance()->id,
461 'component' => file_storage::COMPONENT,
462 'filearea' => file_storage::LIBRARY_FILEAREA,
463 'itemid' => 15,
464 'filepath' => $filepath,
465 'filename' => 'upgrade.js'
466 ];
467 $filestorage = new file_storage();
468 $fs->create_file_from_string($filerecord, 'test string info');
47627abe 469 $expectedfilepath = '/' . file_storage::LIBRARY_FILEAREA . $filepath . 'upgrade.js';
9ea303e7
AG
470 $this->assertEquals($expectedfilepath, $filestorage->getUpgradeScript($machinename, $majorversion, $minorversion));
471 $this->assertNull($filestorage->getUpgradeScript($machinename, $majorversion, 7));
472 }
473
474 /**
475 * Test that information from a source can be saved to the specified path.
476 * The zip file has the following contents
477 * - h5ptest
478 * |- content
479 * | |- content.json
480 * |- testFont
481 * | |- testfont.min.css
482 * |- testJavaScript
483 * | |- testscript.min.js
484 * |- h5p.json
485 */
486 public function test_saveFileFromZip() {
487
488 $ziparchive = new zip_archive();
489 $path = __DIR__ . '/fixtures/h5ptest.zip';
490 $result = $ziparchive->open($path, file_archive::OPEN);
491
492 $files = $ziparchive->list_files();
493 foreach ($files as $file) {
494 if (!$file->is_directory) {
495 $stream = $ziparchive->get_stream($file->index);
47627abe 496 $items = explode('/', $file->pathname);
9ea303e7 497 array_shift($items);
47627abe 498 $path = implode('/', $items);
9ea303e7
AG
499 $this->h5p_file_storage->saveFileFromZip($this->h5p_tempath, $path, $stream);
500 $filestocheck[] = $path;
501 }
502 }
503 $ziparchive->close();
504
505 foreach ($filestocheck as $filetocheck) {
506 $pathtocheck = $this->h5p_tempath .'/'. $filetocheck;
507 $this->assertFileExists($pathtocheck);
508 }
509 }
510
511 /**
512 * Test that a library is fully deleted from the file system
513 */
514 public function test_delete_library() {
515
516 $basedirectory = $this->h5p_tempath . '/' . 'test-1.0';
517
518 $machinename = 'TestLib';
519 $majorversion = 1;
520 $minorversion = 0;
521 [$lib, $files] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
522 $minorversion);
523
524 // Now run the API call.
525 $this->h5p_file_storage->saveLibrary($lib);
526
527 // Save a second library to ensure we aren't deleting all libraries, but just the one specified.
528 $basedirectory = $this->h5p_tempath . '/' . 'awesomelib-2.1';
529
530 $this->libraryid++;
531 $machinename = 'AwesomeLib';
532 $majorversion = 2;
533 $minorversion = 1;
534 [$lib2, $files2] = $this->h5p_generator->create_library($basedirectory, $this->libraryid, $machinename, $majorversion,
535 $minorversion);
536
537 // Now run the API call.
538 $this->h5p_file_storage->saveLibrary($lib2);
539
540 $files = $this->h5p_fs_fs->get_area_files($this->h5p_fs_context->id, file_storage::COMPONENT,
541 file_storage::LIBRARY_FILEAREA);
542 $this->assertCount(14, $files);
543
544 $this->h5p_file_storage->delete_library($lib);
545
546 // Let's look at the records.
547 $files = $this->h5p_fs_fs->get_area_files($this->h5p_fs_context->id, file_storage::COMPONENT,
548 file_storage::LIBRARY_FILEAREA);
549 $this->assertCount(7, $files);
550
551 // Check that the db count is still the same after setting the libraryId to false.
552 $lib['libraryId'] = false;
553 $this->h5p_file_storage->delete_library($lib);
554
555 $files = $this->h5p_fs_fs->get_area_files($this->h5p_fs_context->id, file_storage::COMPONENT,
556 file_storage::LIBRARY_FILEAREA);
557 $this->assertCount(7, $files);
558 }
d3ee08db
AA
559
560 /**
561 * Test get_icon_url() function behaviour.
562 *
563 * @dataProvider get_icon_url_provider
564 * @param string $filename The name of the H5P file to load.
565 * @param bool $expected Whether the icon should exist or not.
566 */
567 public function test_get_icon_url(string $filename, bool $expected): void {
568 global $DB;
569
570 $this->resetAfterTest();
571 $factory = new \core_h5p\factory();
572
573 $admin = get_admin();
574
575 // Prepare a valid .H5P file.
576 $path = __DIR__ . '/fixtures/'.$filename;
577
578 // Libraries can be updated when the file has been created by admin, even when the current user is not the admin.
579 $this->setUser($admin);
580 $file = helper::create_fake_stored_file_from_path($path, (int)$admin->id);
581 $factory->get_framework()->set_file($file);
582 $config = (object)[
583 'frame' => 1,
584 'export' => 1,
585 'embed' => 0,
586 'copyright' => 0,
587 ];
588
589 $h5pid = helper::save_h5p($factory, $file, $config);
590 $h5p = $DB->get_record('h5p', ['id' => $h5pid]);
591 $h5plib = $DB->get_record('h5p_libraries', ['id' => $h5p->mainlibraryid]);
592 $iconurl = $this->h5p_file_storage->get_icon_url(
593 $h5plib->id,
594 $h5plib->machinename,
595 $h5plib->majorversion,
596 $h5plib->minorversion
597 );
598 if ($expected) {
599 $this->assertContains(file_storage::ICON_FILENAME, $iconurl);
600 } else {
601 $this->assertFalse($iconurl);
602 }
603 }
604
605 /**
606 * Data provider for test_get_icon_url().
607 *
608 * @return array
609 */
610 public function get_icon_url_provider(): array {
611 return [
612 'Icon included' => [
613 'filltheblanks.h5p',
614 true,
615 ],
616 'Icon not included' => [
617 'greeting-card-887.h5p',
618 false,
619 ],
620 ];
621 }
6da050d7
VDF
622
623 /**
624 * Test the private method get_file, a wrapper for getting an H5P content file.
625 */
626 public function test_get_file(): void {
627
67a11150 628 $this->setAdminUser();
6da050d7
VDF
629 $file = 'img/fake.png';
630 $h5pcontentid = 3;
631
632 // Add a file to a H5P content.
633 $this->h5p_generator->create_content_file($file, file_storage::CONTENT_FILEAREA, $h5pcontentid);
634
635 // Set get_file method accessibility.
636 $method = new ReflectionMethod(file_storage::class, 'get_file');
637 $method->setAccessible(true);
638
639 $contentfile = $method->invoke(new file_storage(), file_storage::CONTENT_FILEAREA, $h5pcontentid, $file);
640
641 // Check that it returns an instance of store_file.
642 $this->assertInstanceOf('stored_file', $contentfile);
643
644 // Add a file to editor.
67a11150 645 $this->h5p_generator->create_content_file($file, 'draft', $h5pcontentid);
6da050d7 646
67a11150 647 $editorfile = $method->invoke(new file_storage(), 'draft', $h5pcontentid, $file);
6da050d7
VDF
648
649 // Check that it returns an instance of store_file.
650 $this->assertInstanceOf('stored_file', $editorfile);
651 }
652
653 /**
654 * Test that a single file is added to Moodle files.
655 */
656 public function test_move_file(): void {
657
658 // Create temp folder.
659 $tempfolder = make_request_directory(false);
660
661 // Create H5P content folder.
662 $filepath = '/img/';
663 $filename = 'fake.png';
664 $h5pcontentfolder = $tempfolder . '/fakeH5Pcontent/content' . $filepath;
665 if (!check_dir_exists($h5pcontentfolder, true, true)) {
666 throw new moodle_exception('error_creating_temp_dir', 'error', $h5pcontentfolder);
667 }
668
669 $file = $h5pcontentfolder . $filename;
670 touch($file);
671
672 $h5pcontentid = 3;
673
674 // Check the file doesn't exist in Moodle files.
675 $this->assertFalse($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,
676 file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));
677
678 // Set get_file method accessibility.
679 $method = new ReflectionMethod(file_storage::class, 'move_file');
680 $method->setAccessible(true);
681
682 $method->invoke(new file_storage(), $file, $h5pcontentid);
683
684 // Check the file exist in Moodle files.
685 $this->assertTrue($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,
686 file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));
687 }
688
689 /**
690 * Test that a file is copied from another H5P content or the H5P editor.
691 *
692 * @return void
693 */
694 public function test_cloneContentFile(): void {
695
67a11150
SA
696 $admin = get_admin();
697 $usercontext = \context_user::instance($admin->id);
698 $this->setUser($admin);
6da050d7
VDF
699 // Upload a file to the editor.
700 $file = 'images/fake.jpg';
701 $filepath = '/'.dirname($file).'/';
702 $filename = basename($file);
703
704 $content = 'abcd';
705
706 $filerecord = array(
67a11150
SA
707 'contextid' => $usercontext->id,
708 'component' => 'user',
709 'filearea' => 'draft',
6da050d7
VDF
710 'itemid' => 0,
711 'filepath' => $filepath,
712 'filename' => $filename,
713 );
714
715 $this->h5p_fs_fs->create_file_from_string($filerecord, $content);
716
717 // Target H5P content, where the file will be cloned.
718 $targetcontent = new \stdClass();
719 $targetcontent->id = 999;
720
721 // Check the file doesn't exists before cloning.
722 $this->assertFalse($this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,
723 file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));
724
725 // Copy file from the editor.
726 $this->h5p_file_storage->cloneContentFile($file, 'editor', $targetcontent);
727
728 // Check the file exists after cloning.
729 $this->assertInstanceOf(\stored_file::class, $this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,
730 file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));
731
732 // Simulate that an H5P content, with id $sourcecontentid, has a file.
733 $file = 'images/fake2.jpg';
734 $filepath = '/'.dirname($file).'/';
735 $filename = basename($file);
736
737 $sourcecontentid = 111;
67a11150
SA
738 $filerecord['contextid'] = $this->h5p_fs_context->id;
739 $filerecord['component'] = file_storage::COMPONENT;
740 $filerecord['filearea'] = file_storage::CONTENT_FILEAREA;
6da050d7
VDF
741 $filerecord['itemid'] = $sourcecontentid;
742 $filerecord['filepath'] = $filepath;
743 $filerecord['filename'] = $filename;
744
745 $this->h5p_fs_fs->create_file_from_string($filerecord, $content);
746
747 // Check the file doesn't exists before cloning.
748 $this->assertFalse($this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,
749 file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));
750
751 // Copy file from another H5P content.
752 $this->h5p_file_storage->cloneContentFile($file, $sourcecontentid, $targetcontent);
753
754 // Check the file exists after cloning.
755 $this->assertInstanceOf(\stored_file::class, $this->h5p_fs_fs->get_file($this->h5p_fs_context->id, file_storage::COMPONENT,
756 file_storage::CONTENT_FILEAREA, $targetcontent->id, $filepath, $filename));
757 }
758
759 /**
760 * Test that a given file exists in an H5P content.
761 *
762 * @return void
763 */
764 public function test_getContentFile(): void {
765
766 $file = 'img/fake.png';
767 $contentid = 3;
768
769 // Add a file to a H5P content.
770 $this->h5p_generator->create_content_file($file, file_storage::CONTENT_FILEAREA, $contentid);
771
772 // Get an existing file id.
773 $fileid = $this->h5p_file_storage->getContentFile($file, $contentid);
774 $this->assertNotNull($fileid);
775
776 // Try to get a nonexistent file.
777 $fileid = $this->h5p_file_storage->getContentFile($file, 5);
778 $this->assertNull($fileid);
779 }
780
781 /**
782 * Tests that the content folder of an H5P content is imported in the Moodle filesystem.
783 */
784 public function test_moveContentDiretory(): void {
785 global $DB;
786
787 // Create temp folder.
788 $tempfolder = make_request_directory(false);
789
790 // Create H5P content folder.
791 $h5pcontentfolder = $tempfolder . '/fakeH5Pcontent';
792 $contentfolder = $h5pcontentfolder . '/content';
793 if (!check_dir_exists($contentfolder, true, true)) {
794 throw new moodle_exception('error_creating_temp_dir', 'error', $contentfolder);
795 }
796
797 // Add content.json file.
798 touch($contentfolder . 'content.json');
799
800 // Create several folders and files inside content folder.
801 $filesexpected = array();
802 $numfolders = random_int(2, 5);
803 for ($numfolder = 1; $numfolder < $numfolders; $numfolder++) {
804 $foldername = '/folder' . $numfolder;
805 $newfolder = $contentfolder . $foldername;
806 if (!check_dir_exists($newfolder, true, true)) {
807 throw new moodle_exception('error_creating_temp_dir', 'error', $newfolder);
808 }
809 $numfiles = random_int(2, 5);
810 for ($numfile = 1; $numfile < $numfiles; $numfile++) {
811 $filename = '/file' . $numfile . '.ext';
812 touch($newfolder . $filename);
813 $filesexpected[] = $foldername . $filename;
814 }
815 }
816
817 $targeth5pcontentid = 111;
818 $this->h5p_file_storage->moveContentDirectory($h5pcontentfolder, $targeth5pcontentid);
819
820 // Get database records.
821 $sql = "SELECT concat(filepath, filename)
822 FROM {files}
823 WHERE filearea = :filearea AND itemid = :itemid AND component = :component AND filename != '.'";
824 $params = [
825 'component' => file_storage::COMPONENT,
826 'filearea' => file_storage::CONTENT_FILEAREA,
827 'itemid' => $targeth5pcontentid
828 ];
829 $filesdb = $DB->get_fieldset_sql($sql, $params);
830 sort($filesdb);
831
832 // Check that created files match with database records.
833 $this->assertEquals($filesexpected, $filesdb);
834 }
835
836 /**
837 * Test that an H5P content file is removed.
838 */
839 public function test_removeContentFile(): void {
840
841 $file = 'img/fake.png';
842 $filepath = '/' . dirname($file) . '/';
843 $filename = basename($file);
844 $h5pcontentid = 3;
845
846 // Add a file to a H5P content.
847 $this->h5p_generator->create_content_file($file, file_storage::CONTENT_FILEAREA, $h5pcontentid);
848
849 // Check the file exists.
850 $this->assertTrue($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,
851 file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));
852
853 $this->h5p_file_storage->removeContentFile($file, $h5pcontentid);
854
855 // Check the file doesn't exists.
856 $this->assertFalse($this->h5p_fs_fs->file_exists($this->h5p_fs_context->id, file_storage::COMPONENT,
857 file_storage::CONTENT_FILEAREA, $h5pcontentid, $filepath, $filename));
858 }
08fda3e0 859}