Merge branch 'MDL-62218-master' of git://github.com/ryanwyllie/moodle
[moodle.git] / analytics / 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/>.
17 /**
18  * Unit tests for privacy.
19  *
20  * @package   core_analytics
21  * @copyright 2018 David MonllaĆ³ {@link http://www.davidmonllao.com}
22  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 use \core_analytics\privacy\provider;
26 use core_privacy\local\request\transform;
27 use core_privacy\local\request\writer;
28 use core_privacy\local\request\approved_contextlist;
30 defined('MOODLE_INTERNAL') || die();
32 require_once(__DIR__ . '/fixtures/test_indicator_max.php');
33 require_once(__DIR__ . '/fixtures/test_indicator_min.php');
34 require_once(__DIR__ . '/fixtures/test_target_site_users.php');
35 require_once(__DIR__ . '/fixtures/test_target_course_users.php');
36 require_once(__DIR__ . '/fixtures/test_analyser.php');
38 /**
39  * Unit tests for privacy.
40  *
41  * @package   core_analytics
42  * @copyright 2018 David MonllaĆ³ {@link http://www.davidmonllao.com}
43  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44  */
45 class core_analytics_privacy_model_testcase extends \core_privacy\tests\provider_testcase {
47     public function setUp() {
49         $this->resetAfterTest(true);
50         $this->setAdminUser();
52         $timesplittingid = '\core\analytics\time_splitting\single_range';
53         $target = \core_analytics\manager::get_target('test_target_site_users');
54         $indicators = array('test_indicator_max');
55         foreach ($indicators as $key => $indicator) {
56             $indicators[$key] = \core_analytics\manager::get_indicator($indicator);
57         }
58         $this->model1 = \core_analytics\model::create($target, $indicators, $timesplittingid);
59         $this->modelobj1 = $this->model1->get_model_obj();
61         $target = \core_analytics\manager::get_target('test_target_course_users');
62         $indicators = array('test_indicator_min');
63         foreach ($indicators as $key => $indicator) {
64             $indicators[$key] = \core_analytics\manager::get_indicator($indicator);
65         }
66         $this->model2 = \core_analytics\model::create($target, $indicators, $timesplittingid);
67         $this->modelobj2 = $this->model1->get_model_obj();
69         $this->u1 = $this->getDataGenerator()->create_user(['firstname' => 'a111111111111', 'lastname' => 'a']);
70         $this->u2 = $this->getDataGenerator()->create_user(['firstname' => 'a222222222222', 'lastname' => 'a']);
71         $this->u3 = $this->getDataGenerator()->create_user(['firstname' => 'b333333333333', 'lastname' => 'b']);
72         $this->u4 = $this->getDataGenerator()->create_user(['firstname' => 'b444444444444', 'lastname' => 'b']);
74         $this->c1 = $this->getDataGenerator()->create_course(['visible' => false]);
75         $this->c2 = $this->getDataGenerator()->create_course();
77         $this->getDataGenerator()->enrol_user($this->u1->id, $this->c1->id, 'student');
78         $this->getDataGenerator()->enrol_user($this->u2->id, $this->c1->id, 'student');
79         $this->getDataGenerator()->enrol_user($this->u3->id, $this->c1->id, 'student');
80         $this->getDataGenerator()->enrol_user($this->u4->id, $this->c1->id, 'student');
81         $this->getDataGenerator()->enrol_user($this->u1->id, $this->c2->id, 'student');
82         $this->getDataGenerator()->enrol_user($this->u2->id, $this->c2->id, 'student');
83         $this->getDataGenerator()->enrol_user($this->u3->id, $this->c2->id, 'student');
84         $this->getDataGenerator()->enrol_user($this->u4->id, $this->c2->id, 'student');
86         $this->setAdminUser();
88         $this->model1->train();
89         $this->model1->predict();
90         $this->model2->train();
91         $this->model2->predict();
93         list($total, $predictions) = $this->model2->get_predictions(\context_course::instance($this->c1->id));
95         $this->setUser($this->u3);
96         $prediction = reset($predictions);
97         $prediction->action_executed('notuseful', $this->model2->get_target());
99         $this->setAdminUser();
100     }
102     /**
103      * Test delete a context.
104      *
105      * @return null
106      */
107     public function test_delete_context_data() {
108         global $DB;
110         // We have 2 predictions for model1 and 4 predictions for model2.
111         $this->assertEquals(6, $DB->count_records('analytics_predictions'));
112         $this->assertEquals(14, $DB->count_records('analytics_indicator_calc'));
114         // We have 1 prediction action.
115         $this->assertEquals(1, $DB->count_records('analytics_prediction_actions'));
117         $coursecontext = \context_course::instance($this->c1->id);
119         // Delete the course that was used for prediction.
120         provider::delete_data_for_all_users_in_context($coursecontext);
122         // The course predictions are deleted.
123         $this->assertEquals(4, $DB->count_records('analytics_predictions'));
125         // Calculations related to that context are deleted.
126         $this->assertEmpty($DB->count_records('analytics_indicator_calc', ['contextid' => $coursecontext->id]));
128         // The deleted context prediction actions are deleted as well.
129         $this->assertEquals(0, $DB->count_records('analytics_prediction_actions'));
130     }
132     /**
133      * Test delete a user.
134      *
135      * @return null
136      */
137     public function test_delete_user_data() {
138         global $DB;
140         $usercontexts = provider::get_contexts_for_userid($this->u3->id);
141         $contextlist = new \core_privacy\local\request\approved_contextlist($this->u3, 'core_analytics',
142                                                                             $usercontexts->get_contextids());
143         provider::delete_data_for_user($contextlist);
145         // The site level prediction for u3 was deleted.
146         $this->assertEquals(3, $DB->count_records('analytics_predictions'));
147         $this->assertEquals(0, $DB->count_records('analytics_prediction_actions'));
149         $usercontexts = provider::get_contexts_for_userid($this->u1->id);
150         $contextlist = new \core_privacy\local\request\approved_contextlist($this->u1, 'core_analytics',
151                                                                             $usercontexts->get_contextids());
152         provider::delete_data_for_user($contextlist);
153         // We have nothing for u1.
154         $this->assertEquals(3, $DB->count_records('analytics_predictions'));
156         $usercontexts = provider::get_contexts_for_userid($this->u4->id);
157         $contextlist = new \core_privacy\local\request\approved_contextlist($this->u4, 'core_analytics',
158                                                                             $usercontexts->get_contextids());
159         provider::delete_data_for_user($contextlist);
160         $this->assertEquals(0, $DB->count_records('analytics_predictions'));
161     }
163     /**
164      * Test export user data.
165      *
166      * @return null
167      */
168     public function test_export_data() {
169         global $DB;
171         $system = \context_system::instance();
172         list($total, $predictions) = $this->model1->get_predictions($system);
173         foreach ($predictions as $key => $prediction) {
174             if ($prediction->get_prediction_data()->sampleid !== $this->u3->id) {
175                 $otheruserprediction = $prediction;
176                 break;
177             }
178         }
179         $this->setUser($this->u3);
180         $otheruserprediction->action_executed('notuseful', $this->model1->get_target());
181         $this->setAdminUser();
183         $this->export_context_data_for_user($this->u3->id, $system, 'core_analytics');
184         $writer = \core_privacy\local\request\writer::with_context($system);
185         $this->assertTrue($writer->has_any_data());
187         $u3prediction = $DB->get_record('analytics_predictions', ['contextid' => $system->id, 'sampleid' => $this->u3->id]);
188         $data = $writer->get_data([get_string('analytics', 'analytics'),
189             get_string('privacy:metadata:analytics:predictions', 'analytics'), $u3prediction->id]);
190         $this->assertEquals(get_string('adminhelplogs'), $data->target);
191         $this->assertEquals(get_string('coresystem'), $data->context);
192         $this->assertEquals('firstname first char is not A', $data->prediction);
194         $u3calculation = $DB->get_record('analytics_indicator_calc', ['contextid' => $system->id, 'sampleid' => $this->u3->id]);
195         $data = $writer->get_data([get_string('analytics', 'analytics'),
196             get_string('privacy:metadata:analytics:indicatorcalc', 'analytics'), $u3calculation->id]);
197         $this->assertEquals('Allow stealth activities', $data->indicator);
198         $this->assertEquals(get_string('coresystem'), $data->context);
199         $this->assertEquals(get_string('yes'), $data->calculation);
201         $sql = "SELECT apa.id FROM {analytics_prediction_actions} apa
202                   JOIN {analytics_predictions} ap ON ap.id = apa.predictionid
203                  WHERE ap.contextid = :contextid AND apa.userid = :userid AND ap.modelid = :modelid";
204         $params = ['contextid' => $system->id, 'userid' => $this->u3->id, 'modelid' => $this->model1->get_id()];
205         $u3action = $DB->get_record_sql($sql, $params);
206         $data = $writer->get_data([get_string('analytics', 'analytics'),
207             get_string('privacy:metadata:analytics:predictionactions', 'analytics'), $u3action->id]);
208         $this->assertEquals(get_string('adminhelplogs'), $data->target);
209         $this->assertEquals(get_string('coresystem'), $data->context);
210         $this->assertEquals('notuseful', $data->action);
212     }