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_privacy;
18
 
19
use core_privacy\local\request\writer;
20
use core_privacy\local\request\approved_contextlist;
21
 
22
defined('MOODLE_INTERNAL') || die();
23
global $CFG;
24
require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_null_provider.php');
25
require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_provider.php');
26
require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_plugin_subplugin_provider.php');
27
require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_mod_with_user_data_provider.php');
28
require_once($CFG->dirroot . '/privacy/tests/fixtures/provider_a.php');
29
require_once($CFG->dirroot . '/privacy/tests/fixtures/provider_throwing_exception.php');
30
 
31
/**
32
 * Privacy manager unit tests.
33
 *
34
 * @copyright   2018 Jake Dallimore <jrhdallimore@gmail.com>
35
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36
 * @coversDefaultClass \core_privacy\manager
37
 */
1441 ariadna 38
final class manager_test extends \advanced_testcase {
1 efrain 39
    /**
40
     * Test tearDown.
41
     */
42
    public function tearDown(): void {
43
        \core_privacy\local\request\writer::reset();
1441 ariadna 44
        parent::tearDown();
1 efrain 45
    }
46
 
47
    /**
48
     * Helper to spoof the results of the internal function get_components_list, allowing mock components to be tested.
49
     *
50
     * @param array $componentnames and array of component names to include as valid core components.
51
     * @return PHPUnit_Framework_MockObject_MockObject
52
     */
53
    protected function get_mock_manager_with_core_components($componentnames) {
54
        $mock = $this->getMockBuilder(\core_privacy\manager::class)
55
            ->onlyMethods(['get_component_list'])
56
            ->getMock();
57
        $mock->expects($this->any())
58
            ->method('get_component_list')
59
            ->will($this->returnValue($componentnames));
60
        return $mock;
61
    }
62
 
63
    /**
64
     * Test collection of metadata for components implementing a metadata provider.
65
     *
66
     * @covers ::get_metadata_for_components
67
     */
11 efrain 68
    public function test_get_metadata_for_components(): void {
1 efrain 69
        // Get a mock manager, in which the core components list is mocked to include all mock plugins.
70
        // testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).
71
        $mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);
72
 
73
        // Core providers and shared providers both implement the metadata provider.
74
        $collectionarray = $mockman->get_metadata_for_components();
75
        $this->assertArrayHasKey('mod_testcomponent', $collectionarray);
76
        $collection = $collectionarray['mod_testcomponent'];
77
        $this->assertInstanceOf(\core_privacy\local\metadata\collection::class, $collection);
78
        $this->assertArrayHasKey('mod_testcomponent3', $collectionarray);
79
        $collection = $collectionarray['mod_testcomponent3'];
80
        $this->assertInstanceOf(\core_privacy\local\metadata\collection::class, $collection);
81
 
82
        // Component which implements just the local\metadata\null_provider. Metadata is not provided.
83
        $this->assertArrayNotHasKey('mod_testcomponent2', $collectionarray);
84
    }
85
 
86
    /**
87
     * Test that get_contexts_for_userid() only returns contextlist collections for core providers.
88
     *
89
     * @covers ::get_contexts_for_userid
90
     */
11 efrain 91
    public function test_get_contexts_for_userid(): void {
1 efrain 92
        // Get a mock manager, in which the core components list is mocked to include all mock plugins.
93
        // testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).
94
        $mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);
95
 
96
        // Get the contextlist_collection.
97
        $contextlistcollection = $mockman->get_contexts_for_userid(10);
98
        $this->assertInstanceOf(\core_privacy\local\request\contextlist_collection::class, $contextlistcollection);
99
 
100
        ob_flush();
101
 
102
        // Verify we have a contextlist for the component in the collection.
103
        $this->assertInstanceOf(\core_privacy\local\request\contextlist::class,
104
                                $contextlistcollection->get_contextlist_for_component('mod_testcomponent'));
105
 
106
        // Verify we don't have a contextlist for the shared provider in the collection.
107
        $this->assertNull($contextlistcollection->get_contextlist_for_component('mod_testcomponent3'));
108
 
109
        // Verify we don't have a contextlist for the component which does not store user data.
110
        $this->assertEmpty($contextlistcollection->get_contextlist_for_component('mod_testcomponent2'));
111
    }
112
 
113
    /**
114
     * Test verifying the output of component_is_compliant.
115
     *
116
     * @covers ::component_is_compliant
117
     */
11 efrain 118
    public function test_component_is_compliant(): void {
1 efrain 119
        // Get a mock manager, in which the core components list is mocked to include all mock plugins.
120
        // testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).
121
        $mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);
122
 
123
        // A core_provider plugin implementing all required interfaces (local\metadata\provider, local\request\plugin_provider).
124
        $this->assertTrue($mockman->component_is_compliant('mod_testcomponent'));
125
 
126
        // A component implementing just the \core_privacy\local\metadata\null_provider is compliant.
127
        $this->assertTrue($mockman->component_is_compliant('mod_testcomponent2'));
128
 
129
        // A shared provider plugin implementing all required interfaces (local\metadata\provider, local\request\plugin\subplugin_provider)
130
        // is compliant.
131
        $this->assertTrue($mockman->component_is_compliant('mod_testcomponent3'));
132
 
133
        // A component implementing none of the providers.
134
        $this->assertFalse($mockman->component_is_compliant('tool_thisisnotarealtool123'));
135
    }
136
 
137
    /**
138
     * Provider for component_is_compliant tests.
139
     *
140
     * @return  array
141
     */
1441 ariadna 142
    public static function component_is_compliant_provider(): array {
1 efrain 143
        return [
144
            'An empty subsystem' => [
145
                'core_countries',
146
                true,
147
            ],
148
            'A real subsystem' => [
149
                'core_privacy',
150
                true,
151
            ],
152
        ];
153
    }
154
 
155
    /**
156
     * Test verifying the output of component_is_compliant with specified
157
     * components.
158
     *
159
     * @dataProvider    component_is_compliant_provider
160
     * @param   string  $component
161
     * @param   boolean $expected
162
     * @covers ::component_is_compliant
163
     */
11 efrain 164
    public function test_component_is_compliant_examples($component, $expected): void {
1 efrain 165
        $manager = new \core_privacy\manager();
166
 
167
        $this->assertEquals($expected, $manager->component_is_compliant($component));
168
    }
169
 
170
    /**
171
     *  Test verifying only approved contextlists can be used with the export_user_data method.
172
     *
173
     * @covers ::export_user_data
174
     */
11 efrain 175
    public function test_export_user_data(): void {
1 efrain 176
        // Get a mock manager, in which the core components list is mocked to include all mock plugins.
177
        // testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).
178
        $mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3', 'mod_testcomponent4']);
179
 
180
        // Get the non-approved contextlists.
181
        $contextlistcollection = $mockman->get_contexts_for_userid(10);
182
 
183
        // Create an approved contextlist.
184
        $approvedcontextlistcollection = new \core_privacy\local\request\contextlist_collection(10);
185
        foreach ($contextlistcollection->get_contextlists() as $contextlist) {
186
            $approvedcontextlist = new approved_contextlist(new \stdClass(), $contextlist->get_component(),
187
                $contextlist->get_contextids());
188
            $approvedcontextlistcollection->add_contextlist($approvedcontextlist);
189
        }
190
        // Verify the mocked return from the writer, meaning the manager method exited normally.
191
        $this->assertEquals('mock_path', $mockman->export_user_data($approvedcontextlistcollection));
192
 
193
        // Verify that a user preference was exported for 'mod_testcomponent4'.
194
        $prefs = writer::with_context(\context_system::instance())->get_user_preferences('mod_testcomponent4');
195
        $this->assertNotEmpty($prefs);
196
        $this->assertNotEmpty($prefs->mykey);
197
        $this->assertEquals('myvalue', $prefs->mykey->value);
198
        $this->assertEquals('mydescription', $prefs->mykey->description);
199
 
200
        // Verify an exception is thrown if trying to pass in a collection of non-approved_contextlist items.
201
        $this->expectException(\moodle_exception::class);
202
        $mockman->export_user_data($contextlistcollection);
203
    }
204
 
205
    /**
206
     *  Test verifying only approved contextlists can be used with the delete_data_for_user method.
207
     *
208
     * @covers ::delete_data_for_user
209
     */
11 efrain 210
    public function test_delete_data_for_user(): void {
1 efrain 211
        $this->resetAfterTest();
212
        // Get a mock manager, in which the core components list is mocked to include all mock plugins.
213
        // testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).
214
        $mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);
215
 
216
        // Get the non-approved contextlists.
217
        $user = \core_user::get_user_by_username('admin');
218
        $contextlistcollection = $mockman->get_contexts_for_userid($user->id);
219
 
220
        // Create an approved contextlist.
221
        $approvedcontextlistcollection = new \core_privacy\local\request\contextlist_collection($user->id);
222
        foreach ($contextlistcollection->get_contextlists() as $contextlist) {
223
            $approvedcontextlist = new approved_contextlist($user, $contextlist->get_component(),
224
                $contextlist->get_contextids());
225
            $approvedcontextlistcollection->add_contextlist($approvedcontextlist);
226
        }
227
 
228
        // Verify null, as the method has no return type and exits normally. Mainly checking we don't see any exception.
229
        $this->assertNull($mockman->delete_data_for_user($approvedcontextlistcollection));
230
 
231
        // Verify an exception is thrown if trying to pass in a collection of non-approved_contextlist items.
232
        $this->expectException(\moodle_exception::class);
233
        $mockman->delete_data_for_user($contextlistcollection);
234
    }
235
 
236
    /**
237
     * Ensure that all installed plugins can provide metadata.
238
     *
239
     * This really just checks that all providers can be safely autoloaded.
240
     *
241
     * @covers ::get_metadata_for_components
242
     */
11 efrain 243
    public function test_installed_plugins(): void {
1 efrain 244
        $manager = new \core_privacy\manager();
245
        $metadata = $manager->get_metadata_for_components();
246
        $this->assertNotEmpty($metadata);
247
    }
248
 
249
    /**
250
     * Test that the reason for the null provider is returned.
251
     *
252
     * @covers ::get_null_provider_reason
253
     */
11 efrain 254
    public function test_get_null_provider_reason(): void {
1 efrain 255
        $manager = new \core_privacy\manager();
256
        // Null providers return the reason string.
257
        $this->assertEquals('testcomponent2 null provider reason', $manager->get_null_provider_reason('mod_testcomponent2'));
258
        // Throw an exception if the wrong type of provider is given.
259
        $this->expectException(\coding_exception::class);
260
        $string = $manager->get_null_provider_reason('mod_testcomponent');
261
    }
262
 
263
    /**
264
     * Test that manager::plugintype_class_callback() can be executed.
265
     *
266
     * @covers ::plugintype_class_callback
267
     */
11 efrain 268
    public function test_plugintype_class_callback(): void {
1 efrain 269
        \core_privacy\manager::plugintype_class_callback('doesnotexist', 'unusable', 'foo', ['bar']);
270
    }
271
 
272
    /**
273
     * Test that manager::component_class_callback() can be executed.
274
     *
275
     * @covers ::component_class_callback
276
     */
11 efrain 277
    public function test_component_class_callback(): void {
1 efrain 278
        \core_privacy\manager::component_class_callback('foo_bar', 'unusable', 'foo', ['bar']);
279
    }
280
 
281
    /**
282
     * Test the manager::is_empty_subsystem function.
283
     *
284
     * @dataProvider is_empty_subsystem_provider
285
     * @param   string  $component
286
     * @param   bool    $expected
287
     * @covers ::is_empty_subsystem
288
     */
11 efrain 289
    public function test_is_empty_subsystem($component, $expected): void {
1 efrain 290
        $this->assertEquals($expected, \core_privacy\manager::is_empty_subsystem($component));
291
    }
292
 
293
    /**
294
     * Test cases for the is_empty_subsystem function.
295
     *
296
     * @return array
297
     */
1441 ariadna 298
    public static function is_empty_subsystem_provider(): array {
1 efrain 299
        return [
300
            'A subsystem which has no directory' => [
301
                'core_langconfig',
302
                true,
303
            ],
304
            'A subsystem with a directory' => [
305
                'core_portfolio',
306
                false,
307
            ],
308
            'A plugin' => [
309
                'mod_forum',
310
                false,
311
            ],
312
            'A plugintype' => [
313
                'mod',
314
                false,
315
            ],
316
            'An unprefixed subsystem with no directory' => [
317
                'langconfig',
318
                false,
319
            ],
320
        ];
321
    }
322
 
323
    /**
324
     * Test that get_contexts_for_userid() with a failing item.
325
     *
326
     * @covers ::get_contexts_for_userid
327
     */
11 efrain 328
    public function test_get_contexts_for_userid_with_failing(): void {
1 efrain 329
        // Get a mock manager, in which the core components list is mocked to include all mock plugins.
330
        // testcomponent is a core provider, testcomponent2 isa null provider, testcomponent3 is subplugin provider (non core).
331
        $mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);
332
 
333
        $observer = $this->getMockBuilder(\core_privacy\manager_observer::class)
334
            ->onlyMethods(['handle_component_failure'])
335
            ->getMock();
336
        $mockman->set_observer($observer);
337
 
338
        $observer->expects($this->once())
339
            ->method('handle_component_failure')
340
            ->with(
341
                $this->isInstanceOf(\coding_exception::class),
342
                $this->identicalTo('mod_component_broken'),
343
                $this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),
344
                $this->identicalTo('get_contexts_for_userid'),
345
                $this->anything()
346
            );
347
 
348
        // Get the contextlist_collection.
349
        $contextlistcollection = $mockman->get_contexts_for_userid(10);
350
        $this->assertDebuggingCalled();
351
        $this->assertInstanceOf(\core_privacy\local\request\contextlist_collection::class, $contextlistcollection);
352
        $this->assertCount(1, $contextlistcollection);
353
 
354
        // The component which completed shoudl have returned a contextlist.
355
        $this->assertInstanceOf(\core_privacy\local\request\contextlist::class,
356
                                $contextlistcollection->get_contextlist_for_component('mod_component_a'));
357
        $this->assertEmpty($contextlistcollection->get_contextlist_for_component('mod_component_broken'));
358
    }
359
 
360
    /**
361
     * Test that export_user_data() with a failing item.
362
     *
363
     * @covers ::export_user_data
364
     */
11 efrain 365
    public function test_export_user_data_with_failing(): void {
1 efrain 366
        $user = \core_user::get_user_by_username('admin');
367
        $mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);
368
        $context = \context_system::instance();
369
        $contextid = $context->id;
370
 
371
        $observer = $this->getMockBuilder(\core_privacy\manager_observer::class)
372
            ->onlyMethods(['handle_component_failure'])
373
            ->getMock();
374
        $mockman->set_observer($observer);
375
 
376
        $observer->expects($this->once())
377
            ->method('handle_component_failure')
378
            ->with(
379
                $this->isInstanceOf(\coding_exception::class),
380
                $this->identicalTo('mod_component_broken'),
381
                $this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),
382
                $this->identicalTo('export_user_data'),
383
                $this->anything()
384
            );
385
 
386
        $collection = new \core_privacy\local\request\contextlist_collection(10);
387
        $collection->add_contextlist(new approved_contextlist($user, 'mod_component_broken', [$contextid]));
388
        $collection->add_contextlist(new approved_contextlist($user, 'mod_component_a', [$contextid]));
389
 
390
        // Get the contextlist_collection.
391
        $mockman->export_user_data($collection);
392
        $this->assertDebuggingCalled();
393
    }
394
 
395
    /**
396
     * Test that delete_data_for_user() with a failing item.
397
     *
398
     * @covers ::delete_data_for_user
399
     */
11 efrain 400
    public function test_delete_data_for_user_with_failing(): void {
1 efrain 401
        $user = \core_user::get_user_by_username('admin');
402
        $mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);
403
        $context = \context_system::instance();
404
        $contextid = $context->id;
405
 
406
        $observer = $this->getMockBuilder(\core_privacy\manager_observer::class)
407
            ->onlyMethods(['handle_component_failure'])
408
            ->getMock();
409
        $mockman->set_observer($observer);
410
 
411
        $observer->expects($this->once())
412
            ->method('handle_component_failure')
413
            ->with(
414
                $this->isInstanceOf(\coding_exception::class),
415
                $this->identicalTo('mod_component_broken'),
416
                $this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),
417
                $this->identicalTo('delete_data_for_user'),
418
                $this->anything()
419
            );
420
 
421
        $collection = new \core_privacy\local\request\contextlist_collection(10);
422
        $collection->add_contextlist(new approved_contextlist($user, 'mod_component_broken', [$contextid]));
423
        $collection->add_contextlist(new approved_contextlist($user, 'mod_component_a', [$contextid]));
424
 
425
        // Get the contextlist_collection.
426
        $mockman->delete_data_for_user($collection);
427
        $this->assertDebuggingCalled();
428
    }
429
 
430
    /**
431
     * Test that delete_data_for_all_users_in_context() with a failing item.
432
     *
433
     * @covers ::delete_data_for_all_users_in_context
434
     */
11 efrain 435
    public function test_delete_data_for_all_users_in_context_with_failing(): void {
1 efrain 436
        $user = \core_user::get_user_by_username('admin');
437
        $mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);
438
        $context = \context_system::instance();
439
 
440
        $observer = $this->getMockBuilder(\core_privacy\manager_observer::class)
441
            ->onlyMethods(['handle_component_failure'])
442
            ->getMock();
443
        $mockman->set_observer($observer);
444
 
445
        $observer->expects($this->once())
446
            ->method('handle_component_failure')
447
            ->with(
448
                $this->isInstanceOf(\coding_exception::class),
449
                $this->identicalTo('mod_component_broken'),
450
                $this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),
451
                $this->identicalTo('delete_data_for_all_users_in_context'),
452
                $this->anything()
453
            );
454
 
455
        // Get the contextlist_collection.
456
        $mockman->delete_data_for_all_users_in_context($context);
457
        $this->assertDebuggingCalled();
458
    }
459
 
460
    /**
461
     * Test that get_metadata_for_components() with a failing item.
462
     *
463
     * @covers ::get_metadata_for_components
464
     */
11 efrain 465
    public function test_get_metadata_for_components_with_failing(): void {
1 efrain 466
        $user = \core_user::get_user_by_username('admin');
467
        $mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);
468
        $context = \context_system::instance();
469
 
470
        $observer = $this->getMockBuilder(\core_privacy\manager_observer::class)
471
            ->onlyMethods(['handle_component_failure'])
472
            ->getMock();
473
        $mockman->set_observer($observer);
474
 
475
        $observer->expects($this->once())
476
            ->method('handle_component_failure')
477
            ->with(
478
                $this->isInstanceOf(\coding_exception::class),
479
                $this->identicalTo('mod_component_broken'),
480
                $this->identicalTo(\core_privacy\local\metadata\provider::class),
481
                $this->identicalTo('get_metadata'),
482
                $this->anything()
483
            );
484
 
485
        // Get the contextlist_collection.
486
        $metadata = $mockman->get_metadata_for_components();
487
        $this->assertDebuggingCalled();
488
 
489
        $this->assertIsArray($metadata);
490
        $this->assertCount(1, $metadata);
491
    }
492
}