MDL-62781 core_question: Remove unnecessary assertion
[moodle.git] / question / tests / privacy_provider_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/>.
17 /**
18  * Privacy provider tests.
19  *
20  * @package    core_question
21  * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 use core_privacy\local\metadata\collection;
26 use core_privacy\local\request\deletion_criteria;
27 use core_privacy\local\request\writer;
28 use core_question\privacy\provider;
30 defined('MOODLE_INTERNAL') || die();
32 global $CFG;
33 require_once($CFG->libdir . '/xmlize.php');
34 require_once(__DIR__ . '/privacy_helper.php');
35 require_once(__DIR__ . '/../engine/tests/helpers.php');
37 /**
38  * Privacy provider tests class.
39  *
40  * @package    core_question
41  * @copyright  2018 Andrew Nicols <andrew@nicols.co.uk>
42  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43  */
44 class core_question_privacy_provider_testcase extends \core_privacy\tests\provider_testcase {
46     // Include the privacy helper which has assertions on it.
47     use core_question_privacy_helper;
49     /**
50      * Prepare a question attempt.
51      *
52      * @return  question_usage_by_activity
53      */
54     protected function prepare_question_attempt() {
55         // Create a question with a usage from the current user.
56         $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
57         $cat = $questiongenerator->create_question_category();
58         $quba = question_engine::make_questions_usage_by_activity('core_question_preview', context_system::instance());
59         $quba->set_preferred_behaviour('deferredfeedback');
60         $questiondata = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]);
61         $question = question_bank::load_question($questiondata->id);
62         $quba->add_question($question);
63         $quba->start_all_questions();
65         question_engine::save_questions_usage_by_activity($quba);
67         return $quba;
68     }
70     /**
71      * Test that calling export_question_usage on a usage belonging to a
72      * different user does not export any data.
73      */
74     public function test_export_question_usage_no_usage() {
75         $this->resetAfterTest();
77         $quba = $this->prepare_question_attempt();
79         // Create a question with a usage from the current user.
80         $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
81         $cat = $questiongenerator->create_question_category();
82         $quba = question_engine::make_questions_usage_by_activity('core_question_preview', context_system::instance());
83         $quba->set_preferred_behaviour('deferredfeedback');
84         $questiondata = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]);
85         $question = question_bank::load_question($questiondata->id);
86         $quba->add_question($question);
87         $quba->start_all_questions();
89         question_engine::save_questions_usage_by_activity($quba);
91         // Set the user.
92         $testuser = $this->getDataGenerator()->create_user();
93         $this->setUser($testuser);
94         $context = $quba->get_owning_context();
95         $options = new \question_display_options();
97         provider::export_question_usage($testuser->id, $context, [], $quba->get_id(), $options, false);
98         $writer = writer::with_context($context);
100         $this->assertFalse($writer->has_any_data_in_any_context());
101     }
103     /**
104      * Test that calling export_question_usage on a usage belonging to a
105      * different user but ignoring the user match
106      */
107     public function test_export_question_usage_with_usage() {
108         $this->resetAfterTest();
110         $quba = $this->prepare_question_attempt();
112         // Create a question with a usage from the current user.
113         $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
114         $cat = $questiongenerator->create_question_category();
115         $quba = question_engine::make_questions_usage_by_activity('core_question_preview', context_system::instance());
116         $quba->set_preferred_behaviour('deferredfeedback');
118         $questiondata = $questiongenerator->create_question('truefalse', 'true', ['category' => $cat->id]);
119         $quba->add_question(question_bank::load_question($questiondata->id));
120         $questiondata = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]);
121         $quba->add_question(question_bank::load_question($questiondata->id));
123         // Set the user and answer the questions.
124         $testuser = $this->getDataGenerator()->create_user();
125         $this->setUser($testuser);
127         $quba->start_all_questions();
128         $quba->process_action(1, ['answer' => 1]);
129         $quba->process_action(2, ['answer' => 'cat']);
130         $quba->finish_all_questions();
132         question_engine::save_questions_usage_by_activity($quba);
134         $context = $quba->get_owning_context();
136         // Export all questions for this attempt.
137         $options = new \question_display_options();
138         provider::export_question_usage($testuser->id, $context, [], $quba->get_id(), $options, true);
139         $writer = writer::with_context($context);
141         $this->assertTrue($writer->has_any_data_in_any_context());
142         $this->assertTrue($writer->has_any_data());
144         $slots = $quba->get_slots();
145         $this->assertCount(2, $slots);
147         foreach ($slots as $slotno) {
148             $data = $writer->get_data([get_string('questions', 'core_question'), $slotno]);
149             $this->assertNotNull($data);
150             $this->assert_question_slot_equals($quba, $slotno, $options, $data);
151         }
153         $this->assertEmpty($writer->get_data([get_string('questions', 'core_question'), $quba->next_slot_number()]));
155         // Disable some options and re-export.
156         writer::reset();
157         $options = new \question_display_options();
158         $options->hide_all_feedback();
159         $options->flags = \question_display_options::HIDDEN;
160         $options->marks = \question_display_options::HIDDEN;
162         provider::export_question_usage($testuser->id, $context, [], $quba->get_id(), $options, true);
163         $writer = writer::with_context($context);
165         $this->assertTrue($writer->has_any_data_in_any_context());
166         $this->assertTrue($writer->has_any_data());
168         $slots = $quba->get_slots();
169         $this->assertCount(2, $slots);
171         foreach ($slots as $slotno) {
172             $data = $writer->get_data([get_string('questions', 'core_question'), $slotno]);
173             $this->assertNotNull($data);
174             $this->assert_question_slot_equals($quba, $slotno, $options, $data);
175         }
177         $this->assertEmpty($writer->get_data([get_string('questions', 'core_question'), $quba->next_slot_number()]));
178     }
180     /**
181      * Test that questions owned by a user are exported and never deleted.
182      */
183     public function test_question_owned_is_handled() {
184         global $DB;
185         $this->resetAfterTest();
187         $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
189         // Create the two test users.
190         $user = $this->getDataGenerator()->create_user();
191         $otheruser = $this->getDataGenerator()->create_user();
193         // Create one question as each user in diferent contexts.
194         $this->setUser($user);
195         $userdata = $questiongenerator->setup_course_and_questions();
196         $expectedcontext = \context_course::instance($userdata[1]->id);
198         $this->setUser($otheruser);
199         $otheruserdata = $questiongenerator->setup_course_and_questions();
200         $unexpectedcontext = \context_course::instance($otheruserdata[1]->id);
202         // And create another one where we'll update a question as the test user.
203         $moreotheruserdata = $questiongenerator->setup_course_and_questions();
204         $otherexpectedcontext = \context_course::instance($moreotheruserdata[1]->id);
205         $morequestions = $moreotheruserdata[3];
207         // Update the third set of questions.
208         $this->setUser($user);
210         foreach ($morequestions as $question) {
211             $questiongenerator->update_question($question);
212         }
214         // Run the get_contexts_for_userid as default user.
215         $this->setUser();
217         // There should be two contexts returned - the first course, and the third.
218         $contextlist = provider::get_contexts_for_userid($user->id);
219         $this->assertCount(2, $contextlist);
221         $expectedcontexts = [
222                 $expectedcontext->id,
223                 $otherexpectedcontext->id,
224             ];
225         $this->assertEquals($expectedcontexts, $contextlist->get_contextids(), 'Contexts not equal', 0.0, 10, true);
227         // Run the export_user_Data as the test user.
228         $this->setUser($user);
230         $approvedcontextlist = new \core_privacy\tests\request\approved_contextlist(
231             \core_user::get_user($user->id),
232             'core_question',
233             $expectedcontexts
234         );
235         provider::export_user_data($approvedcontextlist);
237         // There should be data for the user's question context.
238         $writer = writer::with_context($expectedcontext);
239         $this->assertTrue($writer->has_any_data());
241         // And for the course we updated.
242         $otherwriter = writer::with_context($otherexpectedcontext);
243         $this->assertTrue($otherwriter->has_any_data());
245         // But not for the other user's course.
246         $otherwriter = writer::with_context($unexpectedcontext);
247         $this->assertFalse($otherwriter->has_any_data());
249         // The question data is exported as an XML export in custom files.
250         $writer = writer::with_context($expectedcontext);
251         $subcontext = [get_string('questionbank', 'core_question')];
253         $exportfile = $writer->get_custom_file($subcontext, 'questions.xml');
254         $this->assertNotEmpty($exportfile);
256         $xmlized = xmlize($exportfile);
257         $xmlquestions = $xmlized['quiz']['#']['question'];
259         $this->assertCount(2, $xmlquestions);
261         // Run the delete functions as default user.
262         $this->setUser();
264         // Find out how many questions are in the question bank to start with.
265         $questioncount = $DB->count_records('question');
267         // The delete functions should do nothing here.
269         // Delete for all users in context.
270         provider::delete_data_for_all_users_in_context($expectedcontext);
271         $this->assertEquals($questioncount, $DB->count_records('question'));
273         provider::delete_data_for_user($approvedcontextlist);
274         $this->assertEquals($questioncount, $DB->count_records('question'));
275     }
277     /**
278      * Deleting questions should only unset their created and modified user.
279      */
280     public function test_question_delete_data_for_user_anonymised() {
281         global $DB;
282         $this->resetAfterTest(true);
284         $user = \core_user::get_user_by_username('admin');
285         $otheruser = $this->getDataGenerator()->create_user();
287         $course = $this->getDataGenerator()->create_course();
288         $context = \context_course::instance($course->id);
289         $othercourse = $this->getDataGenerator()->create_course();
290         $othercontext = \context_course::instance($othercourse->id);
292         // Create a couple of questions.
293         $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
294         $cat = $questiongenerator->create_question_category([
295             'contextid' => $context->id,
296         ]);
297         $othercat = $questiongenerator->create_question_category([
298             'contextid' => $othercontext->id,
299         ]);
301         // Create questions:
302         // Q1 - Created by the UUT, Modified by UUT.
303         // Q2 - Created by the UUT, Modified by the other user.
304         // Q3 - Created by the other user, Modified by UUT
305         // Q4 - Created by the other user, Modified by the other user.
306         // Q5 - Created by the UUT, Modified by the UUT, but in a different context.
307         $this->setUser($user);
308         $q1 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
309         $q2 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
311         $this->setUser($otheruser);
312         $questiongenerator->update_question($q2);
313         $q3 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
314         $q4 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
316         $this->setUser($user);
317         $questiongenerator->update_question($q3);
318         $q5 = $questiongenerator->create_question('shortanswer', null, array('category' => $othercat->id));
320         $approvedcontextlist = new \core_privacy\tests\request\approved_contextlist(
321             $user,
322             'core_question',
323             [$context->id]
324         );
326         // Find out how many questions are in the question bank to start with.
327         $questioncount = $DB->count_records('question');
329         // Delete the data and check it is removed.
330         $this->setUser();
331         provider::delete_data_for_user($approvedcontextlist);
333         $this->assertEquals($questioncount, $DB->count_records('question'));
335         $qrecord = $DB->get_record('question', ['id' => $q1->id]);
336         $this->assertEquals(0, $qrecord->createdby);
337         $this->assertEquals(0, $qrecord->modifiedby);
339         $qrecord = $DB->get_record('question', ['id' => $q2->id]);
340         $this->assertEquals(0, $qrecord->createdby);
341         $this->assertEquals($otheruser->id, $qrecord->modifiedby);
343         $qrecord = $DB->get_record('question', ['id' => $q3->id]);
344         $this->assertEquals($otheruser->id, $qrecord->createdby);
345         $this->assertEquals(0, $qrecord->modifiedby);
347         $qrecord = $DB->get_record('question', ['id' => $q4->id]);
348         $this->assertEquals($otheruser->id, $qrecord->createdby);
349         $this->assertEquals($otheruser->id, $qrecord->modifiedby);
351         $qrecord = $DB->get_record('question', ['id' => $q5->id]);
352         $this->assertEquals($user->id, $qrecord->createdby);
353         $this->assertEquals($user->id, $qrecord->modifiedby);
354     }
356     /**
357      * Deleting questions should only unset their created and modified user for all questions in a context.
358      */
359     public function test_question_delete_data_for_all_users_in_context_anonymised() {
360         global $DB;
361         $this->resetAfterTest(true);
363         $user = \core_user::get_user_by_username('admin');
364         $otheruser = $this->getDataGenerator()->create_user();
366         $course = $this->getDataGenerator()->create_course();
367         $context = \context_course::instance($course->id);
368         $othercourse = $this->getDataGenerator()->create_course();
369         $othercontext = \context_course::instance($othercourse->id);
371         // Create a couple of questions.
372         $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question');
373         $cat = $questiongenerator->create_question_category([
374             'contextid' => $context->id,
375         ]);
376         $othercat = $questiongenerator->create_question_category([
377             'contextid' => $othercontext->id,
378         ]);
380         // Create questions:
381         // Q1 - Created by the UUT, Modified by UUT.
382         // Q2 - Created by the UUT, Modified by the other user.
383         // Q3 - Created by the other user, Modified by UUT
384         // Q4 - Created by the other user, Modified by the other user.
385         // Q5 - Created by the UUT, Modified by the UUT, but in a different context.
386         $this->setUser($user);
387         $q1 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
388         $q2 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
390         $this->setUser($otheruser);
391         $questiongenerator->update_question($q2);
392         $q3 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
393         $q4 = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id));
395         $this->setUser($user);
396         $questiongenerator->update_question($q3);
397         $q5 = $questiongenerator->create_question('shortanswer', null, array('category' => $othercat->id));
399         // Find out how many questions are in the question bank to start with.
400         $questioncount = $DB->count_records('question');
402         // Delete the data and check it is removed.
403         $this->setUser();
404         provider::delete_data_for_all_users_in_context($context);
406         $this->assertEquals($questioncount, $DB->count_records('question'));
408         $qrecord = $DB->get_record('question', ['id' => $q1->id]);
409         $this->assertEquals(0, $qrecord->createdby);
410         $this->assertEquals(0, $qrecord->modifiedby);
412         $qrecord = $DB->get_record('question', ['id' => $q2->id]);
413         $this->assertEquals(0, $qrecord->createdby);
414         $this->assertEquals(0, $qrecord->modifiedby);
416         $qrecord = $DB->get_record('question', ['id' => $q3->id]);
417         $this->assertEquals(0, $qrecord->createdby);
418         $this->assertEquals(0, $qrecord->modifiedby);
420         $qrecord = $DB->get_record('question', ['id' => $q4->id]);
421         $this->assertEquals(0, $qrecord->createdby);
422         $this->assertEquals(0, $qrecord->modifiedby);
424         $qrecord = $DB->get_record('question', ['id' => $q5->id]);
425         $this->assertEquals($user->id, $qrecord->createdby);
426         $this->assertEquals($user->id, $qrecord->modifiedby);
427     }