25f60f490c48903381574624f1994fc3799aa36b
[moodle.git] / course / tests / privacy_test.php
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  * Privacy tests for core_course.
18  *
19  * @package    core_course
20  * @category   test
21  * @copyright  2018 Adrian Greeve <adrian@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
27 global $CFG;
28 require_once($CFG->dirroot . '/completion/tests/fixtures/completion_creation.php');
30 /**
31  * Unit tests for course/classes/privacy/policy
32  *
33  * @copyright  2018 Adrian Greeve <adrian@moodle.com>
34  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35  */
36 class core_course_privacy_testcase extends \core_privacy\tests\provider_testcase {
38     use completion_creation;
40     /**
41      * Test getting the appropriate context for the userid. This should only ever
42      * return the user context for the user id supplied.
43      */
44     public function test_get_contexts_for_userid() {
45         $this->resetAfterTest();
46         $user = $this->getDataGenerator()->create_user();
47         $this->create_course_completion();
48         $this->complete_course($user);
49         $contextlist = \core_course\privacy\provider::get_contexts_for_userid($user->id);
50         $this->assertEquals($this->coursecontext->id, $contextlist->current()->id);
51     }
53     /**
54      * Test fetching users within a context.
55      */
56     public function test_get_users_in_context() {
57         $this->resetAfterTest();
58         $component = 'core_course';
60         $user1 = $this->getDataGenerator()->create_user();
61         $user2 = $this->getDataGenerator()->create_user();
62         $user3 = $this->getDataGenerator()->create_user();
64         // User1 and user2 complete course.
65         $this->create_course_completion();
66         $this->complete_course($user1);
67         $this->complete_course($user2);
69         // User3 is enrolled but has not completed course.
70         $this->getDataGenerator()->enrol_user($user3->id, $this->course->id, 'student');
72         // Ensure only users that have course completion are returned.
73         $userlist = new \core_privacy\local\request\userlist($this->coursecontext, $component);
74         \core_course\privacy\provider::get_users_in_context($userlist);
75         $expected = [$user1->id, $user2->id];
76         $actual = $userlist->get_userids();
77         sort($expected);
78         sort($actual);
79         $this->assertCount(2, $actual);
80         $this->assertEquals($expected, $actual);
81     }
83     /**
84      * Test that user data is exported.
85      */
86     public function test_export_user_data() {
87         $this->resetAfterTest();
88         $user = $this->getDataGenerator()->create_user();
89         $this->create_course_completion();
90         $this->complete_course($user);
91         $approvedlist = new \core_privacy\local\request\approved_contextlist($user, 'core_course',
92                 [$this->coursecontext->id]);
93         $writer = \core_privacy\local\request\writer::with_context($this->coursecontext);
94         \core_course\privacy\provider::export_user_data($approvedlist);
95         $completiondata = $writer->get_data([get_string('privacy:completionpath', 'course')]);
96         $this->assertEquals('In progress', $completiondata->status);
97         $this->assertCount(2, $completiondata->criteria);
98     }
100     /**
101      * Verify that if a module context is included in the contextlist_collection and its parent course is not, the
102      * export_context_data() call picks this up, and that the contextual course information is included.
103      */
104     public function test_export_context_data_module_context_only() {
105         $this->resetAfterTest();
107         // Create a course and a single module.
108         $course1 = $this->getDataGenerator()->create_course(['fullname' => 'Course 1', 'shortname' => 'C1']);
109         $context1 = context_course::instance($course1->id);
110         $modassign = $this->getDataGenerator()->create_module('assign', ['course' => $course1->id, 'name' => 'assign test 1']);
111         $assigncontext = context_module::instance($modassign->cmid);
113         // Now, let's assume during user info export, only the coursemodule context is returned in the contextlist_collection.
114         $user = $this->getDataGenerator()->create_user();
115         $collection = new \core_privacy\local\request\contextlist_collection($user->id);
116         $approvedlist = new \core_privacy\local\request\approved_contextlist($user, 'mod_assign', [$assigncontext->id]);
117         $collection->add_contextlist($approvedlist);
119         // Now, verify that core_course will detect this, and add relevant contextual information.
120         \core_course\privacy\provider::export_context_data($collection);
121         $writer = \core_privacy\local\request\writer::with_context($context1);
122         $this->assertTrue($writer->has_any_data());
123         $writerdata = $writer->get_data();
124         $this->assertObjectHasAttribute('fullname', $writerdata);
125         $this->assertObjectHasAttribute('shortname', $writerdata);
126         $this->assertObjectHasAttribute('idnumber', $writerdata);
127         $this->assertObjectHasAttribute('summary', $writerdata);
128     }
130     /**
131      * Verify that if a module context and its parent course context are both included in the contextlist_collection, that course
132      * contextual information is present in the export.
133      */
134     public function test_export_context_data_course_and_module_contexts() {
135         $this->resetAfterTest();
137         // Create a course and a single module.
138         $course1 = $this->getDataGenerator()->create_course(['fullname' => 'Course 1', 'shortname' => 'C1', 'format' => 'site']);
139         $context1 = context_course::instance($course1->id);
140         $modassign = $this->getDataGenerator()->create_module('assign', ['course' => $course1->id, 'name' => 'assign test 1']);
141         $assigncontext = context_module::instance($modassign->cmid);
143         // Now, assume during user info export, that both module and course contexts are returned in the contextlist_collection.
144         $user = $this->getDataGenerator()->create_user();
145         $collection = new \core_privacy\local\request\contextlist_collection($user->id);
146         $approvedlist = new \core_privacy\local\request\approved_contextlist($user, 'mod_assign', [$assigncontext->id]);
147         $approvedlist2 = new \core_privacy\local\request\approved_contextlist($user, 'core_course', [$context1->id]);
148         $collection->add_contextlist($approvedlist);
149         $collection->add_contextlist($approvedlist2);
151         // Now, verify that core_course still adds relevant contextual information, even for courses which are explicitly listed in
152         // the contextlist_collection.
153         \core_course\privacy\provider::export_context_data($collection);
154         $writer = \core_privacy\local\request\writer::with_context($context1);
155         $this->assertTrue($writer->has_any_data());
156         $writerdata = $writer->get_data();
157         $this->assertObjectHasAttribute('fullname', $writerdata);
158         $this->assertObjectHasAttribute('shortname', $writerdata);
159         $this->assertObjectHasAttribute('idnumber', $writerdata);
160         $this->assertObjectHasAttribute('summary', $writerdata);
161     }
163     /**
164      * Test deleting all user data for one context.
165      */
166     public function test_delete_data_for_all_users_in_context() {
167         global $DB;
168         $this->resetAfterTest();
169         $user1 = $this->getDataGenerator()->create_user();
170         $user2 = $this->getDataGenerator()->create_user();
171         $this->create_course_completion();
172         $this->complete_course($user1);
173         $this->complete_course($user2);
174         $records = $DB->get_records('course_modules_completion');
175         $this->assertCount(2, $records);
176         $records = $DB->get_records('course_completion_crit_compl');
177         $this->assertCount(2, $records);
178         \core_course\privacy\provider::delete_data_for_all_users_in_context($this->coursecontext);
179         $records = $DB->get_records('course_modules_completion');
180         $this->assertCount(0, $records);
181         $records = $DB->get_records('course_completion_crit_compl');
182         $this->assertCount(0, $records);
183     }
185     /**
186      * Test deleting data for only one user.
187      */
188     public function test_delete_data_for_user() {
189         global $DB;
190         $this->resetAfterTest();
191         $user1 = $this->getDataGenerator()->create_user();
192         $user2 = $this->getDataGenerator()->create_user();
193         $this->create_course_completion();
194         $this->complete_course($user1);
195         $this->complete_course($user2);
196         $records = $DB->get_records('course_modules_completion');
197         $this->assertCount(2, $records);
198         $records = $DB->get_records('course_completion_crit_compl');
199         $this->assertCount(2, $records);
200         $approvedlist = new \core_privacy\local\request\approved_contextlist($user1, 'core_course',
201                 [$this->coursecontext->id]);
202         \core_course\privacy\provider::delete_data_for_user($approvedlist);
203         $records = $DB->get_records('course_modules_completion');
204         $this->assertCount(1, $records);
205         $records = $DB->get_records('course_completion_crit_compl');
206         $this->assertCount(1, $records);
207     }
209     /**
210      * Test deleting data within a context for an approved userlist.
211      */
212     public function test_delete_data_for_users() {
213         global $DB;
214         $this->resetAfterTest();
216         $component = 'core_course';
217         $user1 = $this->getDataGenerator()->create_user();
218         $user2 = $this->getDataGenerator()->create_user();
219         $user3 = $this->getDataGenerator()->create_user();
221         $this->create_course_completion();
222         $this->complete_course($user1);
223         $this->complete_course($user2);
224         $this->complete_course($user3);
226         // Ensure records exist for all users before delete.
227         $records = $DB->get_records('course_modules_completion');
228         $this->assertCount(3, $records);
229         $records = $DB->get_records('course_completion_crit_compl');
230         $this->assertCount(3, $records);
232         $approveduserids = [$user1->id, $user3->id];
233         $approvedlist = new \core_privacy\local\request\approved_userlist($this->coursecontext, $component, $approveduserids);
234         \core_course\privacy\provider::delete_data_for_users($approvedlist);
236         // Ensure content is only deleted for approved userlist.
237         $records = $DB->get_records('course_modules_completion');
238         $this->assertCount(1, $records);
239         $record = reset($records);
240         $this->assertEquals($user2->id, $record->userid);
241         $records = $DB->get_records('course_completion_crit_compl');
242         $this->assertCount(1, $records);
243         $record = reset($records);
244         $this->assertEquals($user2->id, $record->userid);
245     }