Proyectos de Subversion Moodle

Rev

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