Rev 1 | Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>.namespace core_privacy;use core_privacy\local\request\writer;use core_privacy\local\request\approved_contextlist;defined('MOODLE_INTERNAL') || die();global $CFG;require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_null_provider.php');require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_provider.php');require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_plugin_subplugin_provider.php');require_once($CFG->dirroot . '/privacy/tests/fixtures/mock_mod_with_user_data_provider.php');require_once($CFG->dirroot . '/privacy/tests/fixtures/provider_a.php');require_once($CFG->dirroot . '/privacy/tests/fixtures/provider_throwing_exception.php');/*** Privacy manager unit tests.** @copyright 2018 Jake Dallimore <jrhdallimore@gmail.com>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later* @coversDefaultClass \core_privacy\manager*/class manager_test extends \advanced_testcase {/*** Test tearDown.*/public function tearDown(): void {\core_privacy\local\request\writer::reset();}/*** Helper to spoof the results of the internal function get_components_list, allowing mock components to be tested.** @param array $componentnames and array of component names to include as valid core components.* @return PHPUnit_Framework_MockObject_MockObject*/protected function get_mock_manager_with_core_components($componentnames) {$mock = $this->getMockBuilder(\core_privacy\manager::class)->onlyMethods(['get_component_list'])->getMock();$mock->expects($this->any())->method('get_component_list')->will($this->returnValue($componentnames));return $mock;}/*** Test collection of metadata for components implementing a metadata provider.** @covers ::get_metadata_for_components*/public function test_get_metadata_for_components(): void {// Get a mock manager, in which the core components list is mocked to include all mock plugins.// testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).$mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);// Core providers and shared providers both implement the metadata provider.$collectionarray = $mockman->get_metadata_for_components();$this->assertArrayHasKey('mod_testcomponent', $collectionarray);$collection = $collectionarray['mod_testcomponent'];$this->assertInstanceOf(\core_privacy\local\metadata\collection::class, $collection);$this->assertArrayHasKey('mod_testcomponent3', $collectionarray);$collection = $collectionarray['mod_testcomponent3'];$this->assertInstanceOf(\core_privacy\local\metadata\collection::class, $collection);// Component which implements just the local\metadata\null_provider. Metadata is not provided.$this->assertArrayNotHasKey('mod_testcomponent2', $collectionarray);}/*** Test that get_contexts_for_userid() only returns contextlist collections for core providers.** @covers ::get_contexts_for_userid*/public function test_get_contexts_for_userid(): void {// Get a mock manager, in which the core components list is mocked to include all mock plugins.// testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).$mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);// Get the contextlist_collection.$contextlistcollection = $mockman->get_contexts_for_userid(10);$this->assertInstanceOf(\core_privacy\local\request\contextlist_collection::class, $contextlistcollection);ob_flush();// Verify we have a contextlist for the component in the collection.$this->assertInstanceOf(\core_privacy\local\request\contextlist::class,$contextlistcollection->get_contextlist_for_component('mod_testcomponent'));// Verify we don't have a contextlist for the shared provider in the collection.$this->assertNull($contextlistcollection->get_contextlist_for_component('mod_testcomponent3'));// Verify we don't have a contextlist for the component which does not store user data.$this->assertEmpty($contextlistcollection->get_contextlist_for_component('mod_testcomponent2'));}/*** Test verifying the output of component_is_compliant.** @covers ::component_is_compliant*/public function test_component_is_compliant(): void {// Get a mock manager, in which the core components list is mocked to include all mock plugins.// testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).$mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);// A core_provider plugin implementing all required interfaces (local\metadata\provider, local\request\plugin_provider).$this->assertTrue($mockman->component_is_compliant('mod_testcomponent'));// A component implementing just the \core_privacy\local\metadata\null_provider is compliant.$this->assertTrue($mockman->component_is_compliant('mod_testcomponent2'));// A shared provider plugin implementing all required interfaces (local\metadata\provider, local\request\plugin\subplugin_provider)// is compliant.$this->assertTrue($mockman->component_is_compliant('mod_testcomponent3'));// A component implementing none of the providers.$this->assertFalse($mockman->component_is_compliant('tool_thisisnotarealtool123'));}/*** Provider for component_is_compliant tests.** @return array*/public function component_is_compliant_provider() {return ['An empty subsystem' => ['core_countries',true,],'A real subsystem' => ['core_privacy',true,],];}/*** Test verifying the output of component_is_compliant with specified* components.** @dataProvider component_is_compliant_provider* @param string $component* @param boolean $expected* @covers ::component_is_compliant*/public function test_component_is_compliant_examples($component, $expected): void {$manager = new \core_privacy\manager();$this->assertEquals($expected, $manager->component_is_compliant($component));}/*** Test verifying only approved contextlists can be used with the export_user_data method.** @covers ::export_user_data*/public function test_export_user_data(): void {// Get a mock manager, in which the core components list is mocked to include all mock plugins.// testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).$mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3', 'mod_testcomponent4']);// Get the non-approved contextlists.$contextlistcollection = $mockman->get_contexts_for_userid(10);// Create an approved contextlist.$approvedcontextlistcollection = new \core_privacy\local\request\contextlist_collection(10);foreach ($contextlistcollection->get_contextlists() as $contextlist) {$approvedcontextlist = new approved_contextlist(new \stdClass(), $contextlist->get_component(),$contextlist->get_contextids());$approvedcontextlistcollection->add_contextlist($approvedcontextlist);}// Verify the mocked return from the writer, meaning the manager method exited normally.$this->assertEquals('mock_path', $mockman->export_user_data($approvedcontextlistcollection));// Verify that a user preference was exported for 'mod_testcomponent4'.$prefs = writer::with_context(\context_system::instance())->get_user_preferences('mod_testcomponent4');$this->assertNotEmpty($prefs);$this->assertNotEmpty($prefs->mykey);$this->assertEquals('myvalue', $prefs->mykey->value);$this->assertEquals('mydescription', $prefs->mykey->description);// Verify an exception is thrown if trying to pass in a collection of non-approved_contextlist items.$this->expectException(\moodle_exception::class);$mockman->export_user_data($contextlistcollection);}/*** Test verifying only approved contextlists can be used with the delete_data_for_user method.** @covers ::delete_data_for_user*/public function test_delete_data_for_user(): void {$this->resetAfterTest();// Get a mock manager, in which the core components list is mocked to include all mock plugins.// testcomponent is a core provider, testcomponent2 is a null provider, testcomponent3 is subplugin provider (non core).$mockman = $this->get_mock_manager_with_core_components(['mod_testcomponent', 'mod_testcomponent2', 'mod_testcomponent3']);// Get the non-approved contextlists.$user = \core_user::get_user_by_username('admin');$contextlistcollection = $mockman->get_contexts_for_userid($user->id);// Create an approved contextlist.$approvedcontextlistcollection = new \core_privacy\local\request\contextlist_collection($user->id);foreach ($contextlistcollection->get_contextlists() as $contextlist) {$approvedcontextlist = new approved_contextlist($user, $contextlist->get_component(),$contextlist->get_contextids());$approvedcontextlistcollection->add_contextlist($approvedcontextlist);}// Verify null, as the method has no return type and exits normally. Mainly checking we don't see any exception.$this->assertNull($mockman->delete_data_for_user($approvedcontextlistcollection));// Verify an exception is thrown if trying to pass in a collection of non-approved_contextlist items.$this->expectException(\moodle_exception::class);$mockman->delete_data_for_user($contextlistcollection);}/*** Ensure that all installed plugins can provide metadata.** This really just checks that all providers can be safely autoloaded.** @covers ::get_metadata_for_components*/public function test_installed_plugins(): void {$manager = new \core_privacy\manager();$metadata = $manager->get_metadata_for_components();$this->assertNotEmpty($metadata);}/*** Test that the reason for the null provider is returned.** @covers ::get_null_provider_reason*/public function test_get_null_provider_reason(): void {$manager = new \core_privacy\manager();// Null providers return the reason string.$this->assertEquals('testcomponent2 null provider reason', $manager->get_null_provider_reason('mod_testcomponent2'));// Throw an exception if the wrong type of provider is given.$this->expectException(\coding_exception::class);$string = $manager->get_null_provider_reason('mod_testcomponent');}/*** Test that manager::plugintype_class_callback() can be executed.** @covers ::plugintype_class_callback*/public function test_plugintype_class_callback(): void {\core_privacy\manager::plugintype_class_callback('doesnotexist', 'unusable', 'foo', ['bar']);}/*** Test that manager::component_class_callback() can be executed.** @covers ::component_class_callback*/public function test_component_class_callback(): void {\core_privacy\manager::component_class_callback('foo_bar', 'unusable', 'foo', ['bar']);}/*** Test the manager::is_empty_subsystem function.** @dataProvider is_empty_subsystem_provider* @param string $component* @param bool $expected* @covers ::is_empty_subsystem*/public function test_is_empty_subsystem($component, $expected): void {$this->assertEquals($expected, \core_privacy\manager::is_empty_subsystem($component));}/*** Test cases for the is_empty_subsystem function.** @return array*/public function is_empty_subsystem_provider() {return ['A subsystem which has no directory' => ['core_langconfig',true,],'A subsystem with a directory' => ['core_portfolio',false,],'A plugin' => ['mod_forum',false,],'A plugintype' => ['mod',false,],'An unprefixed subsystem with no directory' => ['langconfig',false,],];}/*** Test that get_contexts_for_userid() with a failing item.** @covers ::get_contexts_for_userid*/public function test_get_contexts_for_userid_with_failing(): void {// Get a mock manager, in which the core components list is mocked to include all mock plugins.// testcomponent is a core provider, testcomponent2 isa null provider, testcomponent3 is subplugin provider (non core).$mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);$observer = $this->getMockBuilder(\core_privacy\manager_observer::class)->onlyMethods(['handle_component_failure'])->getMock();$mockman->set_observer($observer);$observer->expects($this->once())->method('handle_component_failure')->with($this->isInstanceOf(\coding_exception::class),$this->identicalTo('mod_component_broken'),$this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),$this->identicalTo('get_contexts_for_userid'),$this->anything());// Get the contextlist_collection.$contextlistcollection = $mockman->get_contexts_for_userid(10);$this->assertDebuggingCalled();$this->assertInstanceOf(\core_privacy\local\request\contextlist_collection::class, $contextlistcollection);$this->assertCount(1, $contextlistcollection);// The component which completed shoudl have returned a contextlist.$this->assertInstanceOf(\core_privacy\local\request\contextlist::class,$contextlistcollection->get_contextlist_for_component('mod_component_a'));$this->assertEmpty($contextlistcollection->get_contextlist_for_component('mod_component_broken'));}/*** Test that export_user_data() with a failing item.** @covers ::export_user_data*/public function test_export_user_data_with_failing(): void {$user = \core_user::get_user_by_username('admin');$mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);$context = \context_system::instance();$contextid = $context->id;$observer = $this->getMockBuilder(\core_privacy\manager_observer::class)->onlyMethods(['handle_component_failure'])->getMock();$mockman->set_observer($observer);$observer->expects($this->once())->method('handle_component_failure')->with($this->isInstanceOf(\coding_exception::class),$this->identicalTo('mod_component_broken'),$this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),$this->identicalTo('export_user_data'),$this->anything());$collection = new \core_privacy\local\request\contextlist_collection(10);$collection->add_contextlist(new approved_contextlist($user, 'mod_component_broken', [$contextid]));$collection->add_contextlist(new approved_contextlist($user, 'mod_component_a', [$contextid]));// Get the contextlist_collection.$mockman->export_user_data($collection);$this->assertDebuggingCalled();}/*** Test that delete_data_for_user() with a failing item.** @covers ::delete_data_for_user*/public function test_delete_data_for_user_with_failing(): void {$user = \core_user::get_user_by_username('admin');$mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);$context = \context_system::instance();$contextid = $context->id;$observer = $this->getMockBuilder(\core_privacy\manager_observer::class)->onlyMethods(['handle_component_failure'])->getMock();$mockman->set_observer($observer);$observer->expects($this->once())->method('handle_component_failure')->with($this->isInstanceOf(\coding_exception::class),$this->identicalTo('mod_component_broken'),$this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),$this->identicalTo('delete_data_for_user'),$this->anything());$collection = new \core_privacy\local\request\contextlist_collection(10);$collection->add_contextlist(new approved_contextlist($user, 'mod_component_broken', [$contextid]));$collection->add_contextlist(new approved_contextlist($user, 'mod_component_a', [$contextid]));// Get the contextlist_collection.$mockman->delete_data_for_user($collection);$this->assertDebuggingCalled();}/*** Test that delete_data_for_all_users_in_context() with a failing item.** @covers ::delete_data_for_all_users_in_context*/public function test_delete_data_for_all_users_in_context_with_failing(): void {$user = \core_user::get_user_by_username('admin');$mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);$context = \context_system::instance();$observer = $this->getMockBuilder(\core_privacy\manager_observer::class)->onlyMethods(['handle_component_failure'])->getMock();$mockman->set_observer($observer);$observer->expects($this->once())->method('handle_component_failure')->with($this->isInstanceOf(\coding_exception::class),$this->identicalTo('mod_component_broken'),$this->identicalTo(\core_privacy\local\request\core_user_data_provider::class),$this->identicalTo('delete_data_for_all_users_in_context'),$this->anything());// Get the contextlist_collection.$mockman->delete_data_for_all_users_in_context($context);$this->assertDebuggingCalled();}/*** Test that get_metadata_for_components() with a failing item.** @covers ::get_metadata_for_components*/public function test_get_metadata_for_components_with_failing(): void {$user = \core_user::get_user_by_username('admin');$mockman = $this->get_mock_manager_with_core_components(['mod_component_broken', 'mod_component_a']);$context = \context_system::instance();$observer = $this->getMockBuilder(\core_privacy\manager_observer::class)->onlyMethods(['handle_component_failure'])->getMock();$mockman->set_observer($observer);$observer->expects($this->once())->method('handle_component_failure')->with($this->isInstanceOf(\coding_exception::class),$this->identicalTo('mod_component_broken'),$this->identicalTo(\core_privacy\local\metadata\provider::class),$this->identicalTo('get_metadata'),$this->anything());// Get the contextlist_collection.$metadata = $mockman->get_metadata_for_components();$this->assertDebuggingCalled();$this->assertIsArray($metadata);$this->assertCount(1, $metadata);}}