Proyectos de Subversion Moodle

Rev

Rev 11 | | Comparar con el anterior | Ultima modificación | Ver Log |

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