From 08248c30a745012fc4a1e7cb24d2c386f14b7085 Mon Sep 17 00:00:00 2001 From: Jun Pataleta Date: Fri, 31 Aug 2018 11:21:08 +0800 Subject: [PATCH] MDL-62554 tool_dataprivacy: Unit tests for new WS/API functions --- admin/tool/dataprivacy/tests/api_test.php | 158 ++++++++++ .../tool/dataprivacy/tests/external_test.php | 275 ++++++++++++++++++ 2 files changed, 433 insertions(+) diff --git a/admin/tool/dataprivacy/tests/api_test.php b/admin/tool/dataprivacy/tests/api_test.php index 9feebcf055b..18915c16a64 100644 --- a/admin/tool/dataprivacy/tests/api_test.php +++ b/admin/tool/dataprivacy/tests/api_test.php @@ -1321,6 +1321,164 @@ class tool_dataprivacy_api_testcase extends advanced_testcase { $this->assertEquals($data->contexts->used, $contextids, '', 0.0, 10, true); } + /** + * Data provider for \tool_dataprivacy_api_testcase::test_set_context_defaults + */ + public function set_context_defaults_provider() { + $contextlevels = [ + [CONTEXT_COURSECAT], + [CONTEXT_COURSE], + [CONTEXT_MODULE], + [CONTEXT_BLOCK], + ]; + $paramsets = [ + [true, true, false, false], // Inherit category and purpose, Not for activity, Don't override. + [true, false, false, false], // Inherit category but not purpose, Not for activity, Don't override. + [false, true, false, false], // Inherit purpose but not category, Not for activity, Don't override. + [false, false, false, false], // Don't inherit both category and purpose, Not for activity, Don't override. + [false, false, false, true], // Don't inherit both category and purpose, Not for activity, Override instances. + ]; + $data = []; + foreach ($contextlevels as $level) { + foreach ($paramsets as $set) { + $data[] = array_merge($level, $set); + } + if ($level == CONTEXT_MODULE) { + // Add a combination where defaults for activity is being set. + $data[] = [CONTEXT_MODULE, false, false, true, false]; + $data[] = [CONTEXT_MODULE, false, false, true, true]; + } + } + return $data; + } + + /** + * Test for \tool_dataprivacy\api::set_context_defaults() + * + * @dataProvider set_context_defaults_provider + * @param int $contextlevel The context level + * @param bool $inheritcategory Whether to set category value as INHERIT. + * @param bool $inheritpurpose Whether to set purpose value as INHERIT. + * @param bool $foractivity Whether to set defaults for an activity. + * @param bool $override Whether to override instances. + */ + public function test_set_context_defaults($contextlevel, $inheritcategory, $inheritpurpose, $foractivity, $override) { + $this->setAdminUser(); + + $generator = $this->getDataGenerator(); + + // Generate course cat, course, block, assignment, forum instances. + $coursecat = $generator->create_category(); + $course = $generator->create_course(['category' => $coursecat->id]); + $block = $generator->create_block('online_users'); + $assign = $generator->create_module('assign', ['course' => $course->id]); + $forum = $generator->create_module('forum', ['course' => $course->id]); + + $coursecatcontext = context_coursecat::instance($coursecat->id); + $coursecontext = context_course::instance($course->id); + $blockcontext = context_block::instance($block->id); + + list($course, $assigncm) = get_course_and_cm_from_instance($assign->id, 'assign'); + list($course, $forumcm) = get_course_and_cm_from_instance($forum->id, 'forum'); + $assigncontext = context_module::instance($assigncm->id); + $forumcontext = context_module::instance($forumcm->id); + + // Generate purposes and categories. + $category1 = api::create_category((object)['name' => 'Test category 1']); + $category2 = api::create_category((object)['name' => 'Test category 2']); + $purpose1 = api::create_purpose((object)[ + 'name' => 'Test purpose 1', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' + ]); + $purpose2 = api::create_purpose((object)[ + 'name' => 'Test purpose 2', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' + ]); + + // Assign purposes and categories to contexts. + $coursecatctxinstance = api::set_context_instance((object) [ + 'contextid' => $coursecatcontext->id, + 'purposeid' => $purpose1->get('id'), + 'categoryid' => $category1->get('id'), + ]); + $coursectxinstance = api::set_context_instance((object) [ + 'contextid' => $coursecontext->id, + 'purposeid' => $purpose1->get('id'), + 'categoryid' => $category1->get('id'), + ]); + $blockctxinstance = api::set_context_instance((object) [ + 'contextid' => $blockcontext->id, + 'purposeid' => $purpose1->get('id'), + 'categoryid' => $category1->get('id'), + ]); + $assignctxinstance = api::set_context_instance((object) [ + 'contextid' => $assigncontext->id, + 'purposeid' => $purpose1->get('id'), + 'categoryid' => $category1->get('id'), + ]); + $forumctxinstance = api::set_context_instance((object) [ + 'contextid' => $forumcontext->id, + 'purposeid' => $purpose1->get('id'), + 'categoryid' => $category1->get('id'), + ]); + + $categoryid = $inheritcategory ? context_instance::INHERIT : $category2->get('id'); + $purposeid = $inheritpurpose ? context_instance::INHERIT : $purpose2->get('id'); + $activity = ''; + if ($contextlevel == CONTEXT_MODULE && $foractivity) { + $activity = 'assign'; + } + $result = api::set_context_defaults($contextlevel, $categoryid, $purposeid, $activity, $override); + $this->assertTrue($result); + + $targetctxinstance = false; + switch ($contextlevel) { + case CONTEXT_COURSECAT: + $targetctxinstance = $coursecatctxinstance; + break; + case CONTEXT_COURSE: + $targetctxinstance = $coursectxinstance; + break; + case CONTEXT_MODULE: + $targetctxinstance = $assignctxinstance; + break; + case CONTEXT_BLOCK: + $targetctxinstance = $blockctxinstance; + break; + } + $this->assertNotFalse($targetctxinstance); + + // Check the context instances. + $instanceexists = context_instance::record_exists($targetctxinstance->get('id')); + if ($override) { + // If overridden, context instances on this context level would have been deleted. + $this->assertFalse($instanceexists); + + // Check forum context instance. + $forumctxexists = context_instance::record_exists($forumctxinstance->get('id')); + if ($contextlevel != CONTEXT_MODULE || $foractivity) { + // The forum context instance won't be affected in this test if: + // - The overridden defaults are not for context modules. + // - Only the defaults for assign have been set. + $this->assertTrue($forumctxexists); + } else { + // If we're overriding for the whole course module context level, + // then this forum context instance will be deleted as well. + $this->assertFalse($forumctxexists); + } + } else { + // Otherwise, the context instance record remains. + $this->assertTrue($instanceexists); + } + + // Check defaults. + list($defaultpurpose, $defaultcategory) = data_registry::get_defaults($contextlevel, $activity); + if (!$inheritpurpose) { + $this->assertEquals($purposeid, $defaultpurpose); + } + if (!$inheritcategory) { + $this->assertEquals($categoryid, $defaultcategory); + } + } + /** * Perform setup for the test_add_request_contexts_with_status_xxxxx tests. * diff --git a/admin/tool/dataprivacy/tests/external_test.php b/admin/tool/dataprivacy/tests/external_test.php index 71d0111605a..d7cded9b5e1 100644 --- a/admin/tool/dataprivacy/tests/external_test.php +++ b/admin/tool/dataprivacy/tests/external_test.php @@ -28,6 +28,7 @@ global $CFG; require_once($CFG->dirroot . '/webservice/tests/helpers.php'); use tool_dataprivacy\api; +use tool_dataprivacy\context_instance; use tool_dataprivacy\external; /** @@ -282,4 +283,278 @@ class tool_dataprivacy_external_testcase extends externallib_advanced_testcase { $this->expectException(dml_missing_record_exception::class); external::get_data_request($this->requestid + 1); } + + /** + * Test for \tool_dataprivacy\external::set_context_defaults() + * when called by a user that doesn't have the manage registry capability. + */ + public function test_set_context_defaults_no_capability() { + $generator = $this->getDataGenerator(); + $user = $generator->create_user(); + $this->setUser($user); + $this->expectException(required_capability_exception::class); + external::set_context_defaults(CONTEXT_COURSECAT, context_instance::INHERIT, context_instance::INHERIT, '', false); + } + + /** + * Test for \tool_dataprivacy\external::set_context_defaults(). + * + * We're just checking the module context level here to test the WS function. + * More testing is done in \tool_dataprivacy_api_testcase::test_set_context_defaults(). + * + * @dataProvider get_options_provider + * @param bool $modulelevel Whether defaults are to be applied on the module context level or for an activity only. + * @param bool $override Whether to override instances. + */ + public function test_set_context_defaults($modulelevel, $override) { + $this->setAdminUser(); + $generator = $this->getDataGenerator(); + + // Generate course cat, course, block, assignment, forum instances. + $coursecat = $generator->create_category(); + $course = $generator->create_course(['category' => $coursecat->id]); + $assign = $generator->create_module('assign', ['course' => $course->id]); + list($course, $assigncm) = get_course_and_cm_from_instance($assign->id, 'assign'); + $assigncontext = context_module::instance($assigncm->id); + + // Generate purpose and category. + $category1 = api::create_category((object)['name' => 'Test category 1']); + $category2 = api::create_category((object)['name' => 'Test category 2']); + $purpose1 = api::create_purpose((object)[ + 'name' => 'Test purpose 1', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' + ]); + $purpose2 = api::create_purpose((object)[ + 'name' => 'Test purpose 2', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' + ]); + + // Set a custom purpose and ID for this assignment instance. + $assignctxinstance = api::set_context_instance((object) [ + 'contextid' => $assigncontext->id, + 'purposeid' => $purpose1->get('id'), + 'categoryid' => $category1->get('id'), + ]); + + $modulename = $modulelevel ? 'assign' : ''; + $categoryid = $category2->get('id'); + $purposeid = $purpose2->get('id'); + $result = external::set_context_defaults(CONTEXT_MODULE, $categoryid, $purposeid, $modulename, $override); + + // Extract the result. + $return = external_api::clean_returnvalue(external::set_context_defaults_returns(), $result); + $this->assertTrue($return['result']); + + // Check the assignment context instance. + $instanceexists = context_instance::record_exists($assignctxinstance->get('id')); + if ($override) { + // The custom assign instance should have been deleted. + $this->assertFalse($instanceexists); + } else { + // The custom assign instance should still exist. + $this->assertTrue($instanceexists); + } + + // Check the saved defaults. + list($savedpurpose, $savedcategory) = \tool_dataprivacy\data_registry::get_defaults(CONTEXT_MODULE, $modulename); + $this->assertEquals($categoryid, $savedcategory); + $this->assertEquals($purposeid, $savedpurpose); + } + + /** + * Test for \tool_dataprivacy\external::get_category_options() + * when called by a user that doesn't have the manage registry capability. + */ + public function test_get_category_options_no_capability() { + $generator = $this->getDataGenerator(); + $user = $generator->create_user(); + $this->setUser($user); + $this->expectException(required_capability_exception::class); + external::get_category_options(true, true); + } + + /** + * Data provider for \tool_dataprivacy_external_testcase::test_XX_options(). + */ + public function get_options_provider() { + return [ + [false, false], + [false, true], + [true, false], + [true, true], + ]; + } + + /** + * Test for \tool_dataprivacy\external::get_category_options(). + * + * @dataProvider get_options_provider + * @param bool $includeinherit Whether "Inherit" would be included to the options. + * @param bool $includenotset Whether "Not set" would be included to the options. + */ + public function test_get_category_options($includeinherit, $includenotset) { + $this->setAdminUser(); + + // Prepare our expected options. + $expectedoptions = []; + if ($includeinherit) { + $expectedoptions[] = [ + 'id' => context_instance::INHERIT, + 'name' => get_string('inherit', 'tool_dataprivacy'), + ]; + } + + if ($includenotset) { + $expectedoptions[] = [ + 'id' => context_instance::NOTSET, + 'name' => get_string('notset', 'tool_dataprivacy'), + ]; + } + + for ($i = 1; $i <= 3; $i++) { + $category = api::create_category((object)['name' => 'Category ' . $i]); + $expectedoptions[] = [ + 'id' => $category->get('id'), + 'name' => $category->get('name'), + ]; + } + + // Call the WS function. + $result = external::get_category_options($includeinherit, $includenotset); + + // Extract the options. + $return = (object) external_api::clean_returnvalue(external::get_category_options_returns(), $result); + $options = $return->options; + + // Make sure everything checks out. + $this->assertCount(count($expectedoptions), $options); + foreach ($options as $option) { + $this->assertContains($option, $expectedoptions); + } + } + + /** + * Test for \tool_dataprivacy\external::get_purpose_options() + * when called by a user that doesn't have the manage registry capability. + */ + public function test_get_purpose_options_no_capability() { + $generator = $this->getDataGenerator(); + $user = $generator->create_user(); + $this->setUser($user); + $this->expectException(required_capability_exception::class); + external::get_category_options(true, true); + } + + /** + * Test for \tool_dataprivacy\external::get_purpose_options(). + * + * @dataProvider get_options_provider + * @param bool $includeinherit Whether "Inherit" would be included to the options. + * @param bool $includenotset Whether "Not set" would be included to the options. + */ + public function test_get_purpose_options($includeinherit, $includenotset) { + $this->setAdminUser(); + + // Prepare our expected options. + $expectedoptions = []; + if ($includeinherit) { + $expectedoptions[] = [ + 'id' => context_instance::INHERIT, + 'name' => get_string('inherit', 'tool_dataprivacy'), + ]; + } + + if ($includenotset) { + $expectedoptions[] = [ + 'id' => context_instance::NOTSET, + 'name' => get_string('notset', 'tool_dataprivacy'), + ]; + } + + for ($i = 1; $i <= 3; $i++) { + $purpose = api::create_purpose((object)[ + 'name' => 'Purpose ' . $i, 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' + ]); + $expectedoptions[] = [ + 'id' => $purpose->get('id'), + 'name' => $purpose->get('name'), + ]; + } + + // Call the WS function. + $result = external::get_purpose_options($includeinherit, $includenotset); + + // Extract the options. + $return = (object) external_api::clean_returnvalue(external::get_purpose_options_returns(), $result); + $options = $return->options; + + // Make sure everything checks out. + $this->assertCount(count($expectedoptions), $options); + foreach ($options as $option) { + $this->assertContains($option, $expectedoptions); + } + } + + /** + * Data provider for \tool_dataprivacy_external_testcase::get_activity_options(). + */ + public function get_activity_options_provider() { + return [ + [false, false, true], + [false, true, true], + [true, false, true], + [true, true, true], + [false, false, false], + [false, true, false], + [true, false, false], + [true, true, false], + ]; + } + + /** + * Test for \tool_dataprivacy\external::get_activity_options(). + * + * @dataProvider get_activity_options_provider + * @param bool $inheritcategory Whether the category would be set to "Inherit". + * @param bool $inheritpurpose Whether the purpose would be set to "Inherit". + * @param bool $nodefaults Whether to fetch only activities that don't have defaults. + */ + public function test_get_activity_options($inheritcategory, $inheritpurpose, $nodefaults) { + $this->setAdminUser(); + + $category = api::create_category((object)['name' => 'Test category']); + $purpose = api::create_purpose((object)[ + 'name' => 'Test purpose ', 'retentionperiod' => 'PT1M', 'lawfulbases' => 'gdpr_art_6_1_a' + ]); + $categoryid = $category->get('id'); + $purposeid = $purpose->get('id'); + + if ($inheritcategory) { + $categoryid = context_instance::INHERIT; + } + if ($inheritpurpose) { + $purposeid = context_instance::INHERIT; + } + + // Set the context default for the assignment module. + api::set_context_defaults(CONTEXT_MODULE, $categoryid, $purposeid, 'assign'); + + // Call the WS function. + $result = external::get_activity_options($nodefaults); + + // Extract the options. + $return = (object) external_api::clean_returnvalue(external::get_activity_options_returns(), $result); + $options = $return->options; + + $pluginwithdefaults = [ + 'name' => 'assign', + 'displayname' => get_string('pluginname', 'assign') + ]; + + // If we don't want plugins with defaults to be listed or if both of the category and purpose are set to inherit, + // the assign module should be listed. + if (!$nodefaults || ($inheritcategory && $inheritpurpose)) { + $this->assertContains($pluginwithdefaults, $options); + } else { + $this->assertNotContains($pluginwithdefaults, $options); + } + } }