Differences Between: [Versions 311 and 402] [Versions 400 and 402] [Versions 401 and 402]
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 /** 18 * Unit tests for privacy. 19 * 20 * @package search_simpledb 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 */ 24 namespace search_simpledb\privacy; 25 26 use search_simpledb\privacy\provider; 27 use core_privacy\local\request\transform; 28 use core_privacy\local\request\writer; 29 30 defined('MOODLE_INTERNAL') || die(); 31 32 global $CFG; 33 require_once($CFG->dirroot . '/search/tests/fixtures/testable_core_search.php'); 34 require_once($CFG->dirroot . '/search/tests/fixtures/mock_search_area.php'); 35 36 /** 37 * Unit tests for privacy. 38 * 39 * @package search_simpledb 40 * @copyright 2018 David MonllaĆ³ {@link http://www.davidmonllao.com} 41 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 42 */ 43 class provider_test extends \core_privacy\tests\provider_testcase { 44 45 /** @var \search_simpledb\engine database engine. */ 46 protected $engine; 47 48 /** @var \testable_core_search core search class adapted to unit test. */ 49 protected $search; 50 51 /** @var \core_search_generator core search generator class adapted to unit test. */ 52 protected $generator = null; 53 54 /** @var \stdClass course record.*/ 55 protected $c1; 56 57 /** @var \stdClass course record.*/ 58 protected $c2; 59 60 /** @var \context_course context instance. */ 61 protected $c1context; 62 63 /** @var \context_course context instance. */ 64 protected $c2context; 65 66 /** @var \stdClass user record. */ 67 protected $u1; 68 69 /** @var \stdClass user record. */ 70 protected $u2; 71 72 public function setUp(): void { 73 global $DB; 74 75 if ($this->requires_manual_index_update()) { 76 // We need to update fulltext index manually, which requires an alter table statement. 77 $this->preventResetByRollback(); 78 } 79 80 $this->resetAfterTest(); 81 set_config('enableglobalsearch', true); 82 83 // Inject search_simpledb engine into the testable core search as we need to add the mock 84 // search component to it. 85 86 $this->engine = new \search_simpledb\engine(); 87 $this->search = \testable_core_search::instance($this->engine); 88 $areaid = \core_search\manager::generate_areaid('core_mocksearch', 'mock_search_area'); 89 $this->search->add_search_area($areaid, new \core_mocksearch\search\mock_search_area()); 90 91 $this->generator = self::getDataGenerator()->get_plugin_generator('core_search'); 92 $this->generator->setup(); 93 94 $this->c1 = $this->getDataGenerator()->create_course(); 95 $this->c2 = $this->getDataGenerator()->create_course(); 96 97 $this->c1context = \context_course::instance($this->c1->id); 98 $this->c2context = \context_course::instance($this->c2->id); 99 100 $this->u1 = $this->getDataGenerator()->create_user(); 101 $this->u2 = $this->getDataGenerator()->create_user(); 102 103 $this->getDataGenerator()->enrol_user($this->u1->id, $this->c1->id, 'student'); 104 $this->getDataGenerator()->enrol_user($this->u1->id, $this->c2->id, 'student'); 105 $this->getDataGenerator()->enrol_user($this->u2->id, $this->c1->id, 'student'); 106 $this->getDataGenerator()->enrol_user($this->u2->id, $this->c2->id, 'student'); 107 108 $record = (object)[ 109 'userid' => $this->u1->id, 110 'contextid' => $this->c1context->id, 111 'title' => 'vi', 112 'content' => 'va', 113 'description1' => 'san', 114 'description2' => 'jose' 115 ]; 116 $this->generator->create_record($record); 117 $this->generator->create_record((object)['userid' => $this->u1->id, 'contextid' => $this->c2context->id]); 118 $this->generator->create_record((object)['userid' => $this->u2->id, 'contextid' => $this->c2context->id]); 119 $this->generator->create_record((object)['userid' => $this->u2->id, 'contextid' => $this->c1context->id]); 120 $this->generator->create_record((object)['owneruserid' => $this->u1->id, 'contextid' => $this->c1context->id]); 121 $this->generator->create_record((object)['owneruserid' => $this->u1->id, 'contextid' => $this->c2context->id]); 122 $this->generator->create_record((object)['owneruserid' => $this->u2->id, 'contextid' => $this->c1context->id]); 123 $this->generator->create_record((object)['owneruserid' => $this->u2->id, 'contextid' => $this->c2context->id]); 124 $this->search->index(); 125 126 $this->setAdminUser(); 127 } 128 129 /** 130 * tearDown 131 * 132 * @return void 133 */ 134 public function tearDown(): void { 135 // Call parent tearDown() first. 136 parent::tearDown(); 137 138 // For unit tests before PHP 7, teardown is called even on skip. So only do our teardown if we did setup. 139 if ($this->generator) { 140 // Moodle DML freaks out if we don't teardown the temp table after each run. 141 $this->generator->teardown(); 142 $this->generator = null; 143 } 144 } 145 146 /** 147 * Test fetching contexts for a given user ID. 148 */ 149 public function test_get_contexts_for_userid() { 150 // Ensure both contexts are found for both users. 151 $expected = [$this->c1context->id, $this->c2context->id]; 152 sort($expected); 153 154 // User 1. 155 $contextlist = provider::get_contexts_for_userid($this->u1->id); 156 $this->assertCount(2, $contextlist); 157 158 $actual = $contextlist->get_contextids(); 159 sort($actual); 160 $this->assertEquals($expected, $actual); 161 162 // User 2. 163 $contextlist = provider::get_contexts_for_userid($this->u2->id); 164 $this->assertCount(2, $contextlist); 165 166 $actual = $contextlist->get_contextids(); 167 sort($actual); 168 $this->assertEquals($expected, $actual); 169 } 170 171 /** 172 * Test fetching user IDs for a given context. 173 */ 174 public function test_get_users_in_context() { 175 $component = 'search_simpledb'; 176 177 // Ensure both users are found for both contexts. 178 $expected = [$this->u1->id, $this->u2->id]; 179 sort($expected); 180 181 // User 1. 182 $userlist = new \core_privacy\local\request\userlist($this->c1context, $component); 183 provider::get_users_in_context($userlist); 184 $this->assertCount(2, $userlist); 185 186 $actual = $userlist->get_userids(); 187 sort($actual); 188 $this->assertEquals($expected, $actual); 189 190 // User 2. 191 $userlist = new \core_privacy\local\request\userlist($this->c2context, $component); 192 provider::get_users_in_context($userlist); 193 $this->assertCount(2, $userlist); 194 195 $actual = $userlist->get_userids(); 196 sort($actual); 197 $this->assertEquals($expected, $actual); 198 } 199 200 /** 201 * Test export user data. 202 * 203 * @return null 204 */ 205 public function test_export_user_data() { 206 global $DB; 207 208 $contextlist = new \core_privacy\local\request\approved_contextlist($this->u1, 'search_simpledb', 209 [$this->c1context->id]); 210 provider::export_user_data($contextlist); 211 $writer = \core_privacy\local\request\writer::with_context($this->c1context); 212 $this->assertTrue($writer->has_any_data()); 213 $u1c1 = $DB->get_record('search_simpledb_index', ['userid' => $this->u1->id, 'contextid' => $this->c1context->id]); 214 $data = $writer->get_data([get_string('search', 'search'), $u1c1->docid]); 215 216 $this->assertEquals($this->c1context->get_context_name(true, true), $data->context); 217 $this->assertEquals('vi', $data->title); 218 $this->assertEquals('va', $data->content); 219 $this->assertEquals('san', $data->description1); 220 $this->assertEquals('jose', $data->description2); 221 } 222 223 /** 224 * Test delete search for context. 225 * 226 * @return null 227 */ 228 public function test_delete_data_for_all_users() { 229 global $DB; 230 231 $this->assertEquals(8, $DB->count_records('search_simpledb_index')); 232 233 provider::delete_data_for_all_users_in_context($this->c1context); 234 $this->assertEquals(0, $DB->count_records('search_simpledb_index', ['contextid' => $this->c1context->id])); 235 $this->assertEquals(4, $DB->count_records('search_simpledb_index')); 236 237 $u2context = \context_user::instance($this->u2->id); 238 provider::delete_data_for_all_users_in_context($u2context); 239 $this->assertEquals(0, $DB->count_records('search_simpledb_index', ['contextid' => $u2context->id])); 240 $this->assertEquals(2, $DB->count_records('search_simpledb_index')); 241 } 242 243 /** 244 * Test delete search for user. 245 * 246 * @return null 247 */ 248 public function test_delete_data_for_user() { 249 global $DB; 250 251 $contextlist = new \core_privacy\local\request\approved_contextlist($this->u1, 'search_simpledb', 252 [$this->c1context->id]); 253 provider::delete_data_for_user($contextlist); 254 $select = 'contextid = :contextid AND (owneruserid = :owneruserid OR userid = :userid)'; 255 $params = ['contextid' => $this->c1context->id, 'owneruserid' => $this->u1->id, 'userid' => $this->u1->id]; 256 $this->assertEquals(0, $DB->count_records_select('search_simpledb_index', $select, $params)); 257 $this->assertEquals(2, $DB->count_records('search_simpledb_index', ['contextid' => $this->c1context->id])); 258 $this->assertEquals(6, $DB->count_records('search_simpledb_index')); 259 260 $contextlist = new \core_privacy\local\request\approved_contextlist($this->u2, 'search_simpledb', 261 [$this->c2context->id]); 262 provider::delete_data_for_user($contextlist); 263 $select = 'contextid = :contextid AND (owneruserid = :owneruserid OR userid = :userid)'; 264 $params = ['contextid' => $this->c2context->id, 'owneruserid' => $this->u2->id, 'userid' => $this->u2->id]; 265 $this->assertEquals(0, $DB->count_records_select('search_simpledb_index', $select, $params)); 266 $this->assertEquals(2, $DB->count_records('search_simpledb_index', ['contextid' => $this->c2context->id])); 267 $this->assertEquals(4, $DB->count_records('search_simpledb_index')); 268 } 269 270 /** 271 * Test deleting data for an approved userlist. 272 */ 273 public function test_delete_data_for_users() { 274 global $DB; 275 $component = 'search_simpledb'; 276 $select = 'contextid = :contextid AND (owneruserid = :owneruserid OR userid = :userid)'; 277 278 // Ensure expected amount of data for both users exists in each context. 279 $this->assertEquals(4, $DB->count_records('search_simpledb_index', ['contextid' => $this->c1context->id])); 280 $this->assertEquals(4, $DB->count_records('search_simpledb_index', ['contextid' => $this->c2context->id])); 281 282 // Delete user 1's data in context 1. 283 $approveduserids = [$this->u1->id]; 284 $approvedlist = new \core_privacy\local\request\approved_userlist($this->c1context, $component, $approveduserids); 285 provider::delete_data_for_users($approvedlist); 286 287 $params = ['contextid' => $this->c1context->id, 'owneruserid' => $this->u1->id, 'userid' => $this->u1->id]; 288 $this->assertEquals(0, $DB->count_records_select('search_simpledb_index', $select, $params)); 289 290 // Ensure user 2's data in context 1 is retained. 291 $params = ['contextid' => $this->c1context->id, 'owneruserid' => $this->u2->id, 'userid' => $this->u2->id]; 292 $this->assertEquals(2, $DB->count_records_select('search_simpledb_index', $select, $params)); 293 294 // Ensure both users' data in context 2 is retained. 295 $params = ['contextid' => $this->c2context->id, 'owneruserid' => $this->u1->id, 'userid' => $this->u1->id]; 296 $this->assertEquals(2, $DB->count_records_select('search_simpledb_index', $select, $params)); 297 $params = ['contextid' => $this->c2context->id, 'owneruserid' => $this->u2->id, 'userid' => $this->u2->id]; 298 $this->assertEquals(2, $DB->count_records_select('search_simpledb_index', $select, $params)); 299 } 300 301 /** 302 * Mssql with fulltext support requires manual updates. 303 * 304 * @return bool 305 */ 306 private function requires_manual_index_update() { 307 global $DB; 308 return ($DB->get_dbfamily() === 'mssql' && $DB->is_fulltext_search_supported()); 309 } 310 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body