See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
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 * PHPUnit tests for quiz_settings class. 19 * 20 * @package quizaccess_seb 21 * @author Andrew Madden <andrewmadden@catalyst-au.net> 22 * @copyright 2019 Catalyst IT 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 use quizaccess_seb\quiz_settings; 27 use quizaccess_seb\settings_provider; 28 29 defined('MOODLE_INTERNAL') || die(); 30 31 require_once (__DIR__ . '/test_helper_trait.php'); 32 33 /** 34 * PHPUnit tests for quiz_settings class. 35 * 36 * @copyright 2020 Catalyst IT 37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 38 */ 39 class quizaccess_seb_quiz_settings_testcase extends advanced_testcase { 40 use quizaccess_seb_test_helper_trait; 41 42 /** @var context_module $context Test context. */ 43 protected $context; 44 45 /** @var moodle_url $url Test quiz URL. */ 46 protected $url; 47 48 /** 49 * Called before every test. 50 */ 51 public function setUp() { 52 parent::setUp(); 53 54 $this->resetAfterTest(); 55 56 $this->setAdminUser(); 57 $this->course = $this->getDataGenerator()->create_course(); 58 $this->quiz = $this->getDataGenerator()->create_module('quiz', [ 59 'course' => $this->course->id, 60 'seb_requiresafeexambrowser' => settings_provider::USE_SEB_CONFIG_MANUALLY, 61 ]); 62 $this->context = context_module::instance($this->quiz->cmid); 63 $this->url = new moodle_url("/mod/quiz/view.php", ['id' => $this->quiz->cmid]); 64 } 65 66 /** 67 * Test that config is generated immediately prior to saving quiz settings. 68 */ 69 public function test_config_is_created_from_quiz_settings() { 70 // Test settings to populate the in the object. 71 $settings = $this->get_test_settings(); 72 $settings->quizid = $this->quiz->id; 73 $settings->cmid = $this->quiz->cmid; 74 75 // Obtain the existing record that is created when using a generator. 76 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 77 78 // Update the settings with values from the test function. 79 $quizsettings->from_record($settings); 80 $quizsettings->save(); 81 82 $config = $quizsettings->get_config(); 83 $this->assertEquals( 84 "<?xml version=\"1.0\" encoding=\"UTF-8\"?> 85 <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"> 86 <plist version=\"1.0\"><dict><key>showTaskBar</key><true/><key>allowWlan</key><false/><key>showReloadButton</key><true/>" 87 . "<key>showTime</key><false/><key>showInputLanguage</key><true/><key>allowQuit</key><true/>" 88 . "<key>quitURLConfirm</key><true/><key>audioControlEnabled</key><true/><key>audioMute</key><false/>" 89 . "<key>allowSpellCheck</key><false/><key>browserWindowAllowReload</key><true/><key>URLFilterEnable</key><true/>" 90 . "<key>URLFilterEnableContentFilter</key><false/><key>hashedQuitPassword</key>" 91 . "<string>9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08</string><key>URLFilterRules</key>" 92 . "<array><dict><key>action</key><integer>1</integer><key>active</key><true/><key>expression</key>" 93 . "<string>test.com</string><key>regex</key><false/></dict></array><key>startURL</key><string>$this->url</string>" 94 . "<key>sendBrowserExamKey</key><true/><key>examSessionClearCookiesOnStart</key><false/>" 95 . "<key>allowPreferencesWindow</key><false/></dict></plist>\n", 96 $config); 97 } 98 99 /** 100 * Test that config string gets updated from quiz settings. 101 */ 102 public function test_config_is_updated_from_quiz_settings() { 103 // Test settings to populate the in the object. 104 $settings = $this->get_test_settings(); 105 $settings->quizid = $this->quiz->id; 106 $settings->cmid = $this->quiz->cmid; 107 108 // Obtain the existing record that is created when using a generator. 109 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 110 111 // Update the settings with values from the test function. 112 $quizsettings->from_record($settings); 113 $quizsettings->save(); 114 115 $config = $quizsettings->get_config(); 116 $this->assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?> 117 <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"> 118 <plist version=\"1.0\"><dict><key>showTaskBar</key><true/><key>allowWlan</key><false/><key>showReloadButton</key><true/>" 119 . "<key>showTime</key><false/><key>showInputLanguage</key><true/><key>allowQuit</key><true/>" 120 . "<key>quitURLConfirm</key><true/><key>audioControlEnabled</key><true/><key>audioMute</key><false/>" 121 . "<key>allowSpellCheck</key><false/><key>browserWindowAllowReload</key><true/><key>URLFilterEnable</key><true/>" 122 . "<key>URLFilterEnableContentFilter</key><false/><key>hashedQuitPassword</key>" 123 . "<string>9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08</string><key>URLFilterRules</key>" 124 . "<array><dict><key>action</key><integer>1</integer><key>active</key><true/><key>expression</key>" 125 . "<string>test.com</string><key>regex</key><false/></dict></array><key>startURL</key><string>$this->url</string>" 126 . "<key>sendBrowserExamKey</key><true/><key>examSessionClearCookiesOnStart</key><false/>" 127 . "<key>allowPreferencesWindow</key><false/></dict></plist>\n", $config); 128 129 $quizsettings->set('filterembeddedcontent', 1); // Alter the settings. 130 $quizsettings->save(); 131 $config = $quizsettings->get_config(); 132 $this->assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?> 133 <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"> 134 <plist version=\"1.0\"><dict><key>showTaskBar</key><true/><key>allowWlan</key><false/><key>showReloadButton</key><true/>" 135 . "<key>showTime</key><false/><key>showInputLanguage</key><true/><key>allowQuit</key><true/>" 136 . "<key>quitURLConfirm</key><true/><key>audioControlEnabled</key><true/><key>audioMute</key><false/>" 137 . "<key>allowSpellCheck</key><false/><key>browserWindowAllowReload</key><true/><key>URLFilterEnable</key><true/>" 138 . "<key>URLFilterEnableContentFilter</key><true/><key>hashedQuitPassword</key>" 139 . "<string>9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08</string><key>URLFilterRules</key>" 140 . "<array><dict><key>action</key><integer>1</integer><key>active</key><true/><key>expression</key>" 141 . "<string>test.com</string><key>regex</key><false/></dict></array><key>startURL</key><string>$this->url</string>" 142 . "<key>sendBrowserExamKey</key><true/><key>examSessionClearCookiesOnStart</key><false/>" 143 . "<key>allowPreferencesWindow</key><false/></dict></plist>\n", $config); 144 } 145 146 /** 147 * Test that config key is generated immediately prior to saving quiz settings. 148 */ 149 public function test_config_key_is_created_from_quiz_settings() { 150 $settings = $this->get_test_settings(); 151 152 $quizsettings = new quiz_settings(0, $settings); 153 $configkey = $quizsettings->get_config_key(); 154 $this->assertEquals("b35510bd754f9d106ff88b9d2dc1bb297cddc9fc7b4bdde2dbda4e7d9e4b50d8", 155 $configkey 156 ); 157 } 158 159 /** 160 * Test that config key is generated immediately prior to saving quiz settings. 161 */ 162 public function test_config_key_is_updated_from_quiz_settings() { 163 $settings = $this->get_test_settings(); 164 165 $quizsettings = new quiz_settings(0, $settings); 166 $configkey = $quizsettings->get_config_key(); 167 $this->assertEquals("b35510bd754f9d106ff88b9d2dc1bb297cddc9fc7b4bdde2dbda4e7d9e4b50d8", 168 $configkey); 169 170 $quizsettings->set('filterembeddedcontent', 1); // Alter the settings. 171 $configkey = $quizsettings->get_config_key(); 172 $this->assertEquals("58010792504cccc18f7b0e5c9680fe60b567e8c1b5fb9798654cc9bad9ddf30c", 173 $configkey); 174 } 175 176 /** 177 * Test that different URL filter expressions are turned into config XML. 178 * 179 * @param stdClass $settings Quiz settings 180 * @param string $expectedxml SEB Config XML. 181 * 182 * @dataProvider filter_rules_provider 183 */ 184 public function test_filter_rules_added_to_config(stdClass $settings, string $expectedxml) { 185 $quizsettings = new quiz_settings(0, $settings); 186 $config = $quizsettings->get_config(); 187 $this->assertEquals($expectedxml, $config); 188 } 189 190 /** 191 * Test that browser keys are validated and retrieved as an array instead of string. 192 */ 193 public function test_browser_exam_keys_are_retrieved_as_array() { 194 $quizsettings = new quiz_settings(); 195 $quizsettings->set('allowedbrowserexamkeys', "one two,three\nfour"); 196 $retrievedkeys = $quizsettings->get('allowedbrowserexamkeys'); 197 $this->assertEquals(['one', 'two', 'three', 'four'], $retrievedkeys); 198 } 199 200 /** 201 * Test validation of Browser Exam Keys. 202 * 203 * @param string $bek Browser Exam Key. 204 * @param string $expectederrorstring Expected error. 205 * 206 * @dataProvider bad_browser_exam_key_provider 207 */ 208 public function test_browser_exam_keys_validation_errors($bek, $expectederrorstring) { 209 $quizsettings = new quiz_settings(); 210 $quizsettings->set('allowedbrowserexamkeys', $bek); 211 $quizsettings->validate(); 212 $errors = $quizsettings->get_errors(); 213 $this->assertContains($expectederrorstring, $errors); 214 } 215 216 /** 217 * Test that uploaded seb file gets converted to config string. 218 */ 219 public function test_config_file_uploaded_converted_to_config() { 220 $url = new moodle_url("/mod/quiz/view.php", ['id' => $this->quiz->cmid]); 221 $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 222 . "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 223 . "<plist version=\"1.0\"><dict><key>hashedQuitPassword</key><string>hashedpassword</string>" 224 . "<key>allowWlan</key><false/><key>startURL</key><string>$url</string>" 225 . "<key>sendBrowserExamKey</key><true/></dict></plist>\n"; 226 $itemid = $this->create_module_test_file($xml, $this->quiz->cmid); 227 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 228 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG); 229 $quizsettings->save(); 230 $config = $quizsettings->get_config(); 231 $this->assertEquals($xml, $config); 232 } 233 234 /** 235 * Test test_no_config_file_uploaded 236 */ 237 public function test_no_config_file_uploaded() { 238 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 239 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG); 240 $cmid = $quizsettings->get('cmid'); 241 $this->expectException(moodle_exception::class); 242 $this->expectExceptionMessage("No uploaded SEB config file could be found for quiz with cmid: {$cmid}"); 243 $quizsettings->get_config(); 244 } 245 246 /** 247 * A helper function to build a config file. 248 * 249 * @param mixed $allowuserquitseb Required allowQuit setting. 250 * @param mixed $quitpassword Required hashedQuitPassword setting. 251 * 252 * @return string 253 */ 254 protected function get_config_xml($allowuserquitseb = null, $quitpassword = null) { 255 $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 256 . "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 257 . "<plist version=\"1.0\"><dict><key>allowWlan</key><false/><key>startURL</key>" 258 . "<string>https://safeexambrowser.org/start</string>" 259 . "<key>sendBrowserExamKey</key><true/>"; 260 261 if (!is_null($allowuserquitseb)) { 262 $allowuserquitseb = empty($allowuserquitseb) ? 'false' : 'true'; 263 $xml .= "<key>allowQuit</key><{$allowuserquitseb}/>"; 264 } 265 266 if (!is_null($quitpassword)) { 267 $xml .= "<key>hashedQuitPassword</key><string>{$quitpassword}</string>"; 268 } 269 270 $xml .= "</dict></plist>\n"; 271 272 return $xml; 273 } 274 275 /** 276 * Test using USE_SEB_TEMPLATE and have it override settings from the template when they are set. 277 */ 278 public function test_using_seb_template_override_settings_when_they_set_in_template() { 279 $xml = $this->get_config_xml(true, 'password'); 280 $template = $this->create_template($xml); 281 282 $this->assertContains("<key>startURL</key><string>https://safeexambrowser.org/start</string>", $template->get('content')); 283 $this->assertContains("<key>allowQuit</key><true/>", $template->get('content')); 284 $this->assertContains("<key>hashedQuitPassword</key><string>password</string>", $template->get('content')); 285 286 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 287 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE); 288 $quizsettings->set('templateid', $template->get('id')); 289 $quizsettings->set('allowuserquitseb', 1); 290 $quizsettings->save(); 291 292 $this->assertContains( 293 "<key>startURL</key><string>https://www.example.com/moodle/mod/quiz/view.php?id={$this->quiz->cmid}</string>", 294 $quizsettings->get_config() 295 ); 296 297 $this->assertContains("<key>allowQuit</key><true/>", $quizsettings->get_config()); 298 $this->assertNotContains("hashedQuitPassword", $quizsettings->get_config()); 299 300 $quizsettings->set('quitpassword', 'new password'); 301 $quizsettings->save(); 302 $hashedpassword = hash('SHA256', 'new password'); 303 $this->assertContains("<key>allowQuit</key><true/>", $quizsettings->get_config()); 304 $this->assertNotContains("<key>hashedQuitPassword</key><string>password</string>", $quizsettings->get_config()); 305 $this->assertContains("<key>hashedQuitPassword</key><string>{$hashedpassword}</string>", $quizsettings->get_config()); 306 307 $quizsettings->set('allowuserquitseb', 0); 308 $quizsettings->set('quitpassword', ''); 309 $quizsettings->save(); 310 $this->assertContains("<key>allowQuit</key><false/>", $quizsettings->get_config()); 311 $this->assertNotContains("hashedQuitPassword", $quizsettings->get_config()); 312 } 313 314 /** 315 * Test using USE_SEB_TEMPLATE and have it override settings from the template when they are not set. 316 */ 317 public function test_using_seb_template_override_settings_when_not_set_in_template() { 318 $xml = $this->get_config_xml(); 319 $template = $this->create_template($xml); 320 321 $this->assertContains("<key>startURL</key><string>https://safeexambrowser.org/start</string>", $template->get('content')); 322 $this->assertNotContains("<key>allowQuit</key><true/>", $template->get('content')); 323 $this->assertNotContains("<key>hashedQuitPassword</key><string>password</string>", $template->get('content')); 324 325 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 326 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE); 327 $quizsettings->set('templateid', $template->get('id')); 328 $quizsettings->set('allowuserquitseb', 1); 329 $quizsettings->save(); 330 331 $this->assertContains("<key>allowQuit</key><true/>", $quizsettings->get_config()); 332 $this->assertNotContains("hashedQuitPassword", $quizsettings->get_config()); 333 334 $quizsettings->set('quitpassword', 'new password'); 335 $quizsettings->save(); 336 $hashedpassword = hash('SHA256', 'new password'); 337 $this->assertContains("<key>allowQuit</key><true/>", $quizsettings->get_config()); 338 $this->assertContains("<key>hashedQuitPassword</key><string>{$hashedpassword}</string>", $quizsettings->get_config()); 339 340 $quizsettings->set('allowuserquitseb', 0); 341 $quizsettings->set('quitpassword', ''); 342 $quizsettings->save(); 343 $this->assertContains("<key>allowQuit</key><false/>", $quizsettings->get_config()); 344 $this->assertNotContains("hashedQuitPassword", $quizsettings->get_config()); 345 } 346 347 /** 348 * Test using USE_SEB_UPLOAD_CONFIG and use settings from the file if they are set. 349 */ 350 public function test_using_own_config_settings_are_not_overridden_if_set() { 351 $xml = $this->get_config_xml(true, 'password'); 352 $this->create_module_test_file($xml, $this->quiz->cmid); 353 354 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 355 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG); 356 $quizsettings->set('allowuserquitseb', 0); 357 $quizsettings->set('quitpassword', ''); 358 $quizsettings->save(); 359 360 $this->assertContains( 361 "<key>startURL</key><string>https://www.example.com/moodle/mod/quiz/view.php?id={$this->quiz->cmid}</string>", 362 $quizsettings->get_config() 363 ); 364 365 $this->assertContains("<key>allowQuit</key><true/>", $quizsettings->get_config()); 366 $this->assertContains("<key>hashedQuitPassword</key><string>password</string>", $quizsettings->get_config()); 367 368 $quizsettings->set('quitpassword', 'new password'); 369 $quizsettings->save(); 370 $hashedpassword = hash('SHA256', 'new password'); 371 372 $this->assertNotContains("<key>hashedQuitPassword</key><string>{$hashedpassword}</string>", $quizsettings->get_config()); 373 $this->assertContains("<key>allowQuit</key><true/>", $quizsettings->get_config()); 374 $this->assertContains("<key>hashedQuitPassword</key><string>password</string>", $quizsettings->get_config()); 375 376 $quizsettings->set('allowuserquitseb', 0); 377 $quizsettings->set('quitpassword', ''); 378 $quizsettings->save(); 379 380 $this->assertContains("<key>allowQuit</key><true/>", $quizsettings->get_config()); 381 $this->assertContains("<key>hashedQuitPassword</key><string>password</string>", $quizsettings->get_config()); 382 } 383 384 /** 385 * Test using USE_SEB_UPLOAD_CONFIG and use settings from the file if they are not set. 386 */ 387 public function test_using_own_config_settings_are_not_overridden_if_not_set() { 388 $xml = $this->get_config_xml(); 389 $this->create_module_test_file($xml, $this->quiz->cmid); 390 391 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 392 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG); 393 $quizsettings->set('allowuserquitseb', 1); 394 $quizsettings->set('quitpassword', ''); 395 $quizsettings->save(); 396 397 $this->assertContains( 398 "<key>startURL</key><string>https://www.example.com/moodle/mod/quiz/view.php?id={$this->quiz->cmid}</string>", 399 $quizsettings->get_config() 400 ); 401 402 $this->assertNotContains("allowQuit", $quizsettings->get_config()); 403 $this->assertNotContains("hashedQuitPassword", $quizsettings->get_config()); 404 405 $quizsettings->set('quitpassword', 'new password'); 406 $quizsettings->save(); 407 408 $this->assertNotContains("allowQuit", $quizsettings->get_config()); 409 $this->assertNotContains("hashedQuitPassword", $quizsettings->get_config()); 410 411 $quizsettings->set('allowuserquitseb', 0); 412 $quizsettings->set('quitpassword', ''); 413 $quizsettings->save(); 414 415 $this->assertNotContains("allowQuit", $quizsettings->get_config()); 416 $this->assertNotContains("hashedQuitPassword", $quizsettings->get_config()); 417 } 418 419 /** 420 * Test using USE_SEB_TEMPLATE populates the linkquitseb setting if a quitURL is found. 421 */ 422 public function test_template_has_quit_url_set() { 423 $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 424 . "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 425 . "<plist version=\"1.0\"><dict><key>hashedQuitPassword</key><string>hashedpassword</string>" 426 . "<key>allowWlan</key><false/><key>quitURL</key><string>http://seb.quit.url</string>" 427 . "<key>sendBrowserExamKey</key><true/></dict></plist>\n"; 428 429 $template = $this->create_template($xml); 430 431 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 432 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE); 433 $quizsettings->set('templateid', $template->get('id')); 434 435 $this->assertEmpty($quizsettings->get('linkquitseb')); 436 $quizsettings->save(); 437 438 $this->assertNotEmpty($quizsettings->get('linkquitseb')); 439 $this->assertEquals('http://seb.quit.url', $quizsettings->get('linkquitseb')); 440 } 441 442 /** 443 * Test using USE_SEB_UPLOAD_CONFIG populates the linkquitseb setting if a quitURL is found. 444 */ 445 public function test_config_file_uploaded_has_quit_url_set() { 446 $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 447 . "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 448 . "<plist version=\"1.0\"><dict><key>hashedQuitPassword</key><string>hashedpassword</string>" 449 . "<key>allowWlan</key><false/><key>quitURL</key><string>http://seb.quit.url</string>" 450 . "<key>sendBrowserExamKey</key><true/></dict></plist>\n"; 451 452 $itemid = $this->create_module_test_file($xml, $this->quiz->cmid); 453 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 454 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG); 455 456 $this->assertEmpty($quizsettings->get('linkquitseb')); 457 $quizsettings->save(); 458 459 $this->assertNotEmpty($quizsettings->get('linkquitseb')); 460 $this->assertEquals('http://seb.quit.url', $quizsettings->get('linkquitseb')); 461 } 462 463 /** 464 * Test template id set correctly. 465 */ 466 public function test_templateid_set_correctly_when_save_settings() { 467 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 468 $this->assertEquals(0, $quizsettings->get('templateid')); 469 470 $template = $this->create_template(); 471 $templateid = $template->get('id'); 472 473 // Initially set to USE_SEB_TEMPLATE with a template id. 474 $this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_TEMPLATE, $templateid); 475 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 476 $this->assertEquals($templateid, $quizsettings->get('templateid')); 477 478 // Case for USE_SEB_NO, ensure template id reverts to 0. 479 $this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_NO); 480 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 481 $this->assertEquals(0, $quizsettings->get('templateid')); 482 483 // Reverting back to USE_SEB_TEMPLATE. 484 $this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_TEMPLATE, $templateid); 485 486 // Case for USE_SEB_CONFIG_MANUALLY, ensure template id reverts to 0. 487 $this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_CONFIG_MANUALLY); 488 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 489 $this->assertEquals(0, $quizsettings->get('templateid')); 490 491 // Reverting back to USE_SEB_TEMPLATE. 492 $this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_TEMPLATE, $templateid); 493 494 // Case for USE_SEB_CLIENT_CONFIG, ensure template id reverts to 0. 495 $this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_CLIENT_CONFIG); 496 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 497 $this->assertEquals(0, $quizsettings->get('templateid')); 498 499 // Reverting back to USE_SEB_TEMPLATE. 500 $this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_TEMPLATE, $templateid); 501 502 // Case for USE_SEB_UPLOAD_CONFIG, ensure template id reverts to 0. 503 $xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb'); 504 $this->create_module_test_file($xml, $this->quiz->cmid); 505 $this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_UPLOAD_CONFIG); 506 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 507 $this->assertEquals(0, $quizsettings->get('templateid')); 508 509 // Case for USE_SEB_TEMPLATE, ensure template id is correct. 510 $this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_TEMPLATE, $templateid); 511 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 512 $this->assertEquals($templateid, $quizsettings->get('templateid')); 513 } 514 515 /** 516 * Helper function in tests to set USE_SEB_TEMPLATE and a template id on the quiz settings. 517 * 518 * @param quiz_settings $quizsettings Given quiz settings instance. 519 * @param int $savetype Type of SEB usage. 520 * @param int $templateid Template ID. 521 */ 522 public function save_settings_with_optional_template($quizsettings, $savetype, $templateid = 0) { 523 $quizsettings->set('requiresafeexambrowser', $savetype); 524 if (!empty($templateid)) { 525 $quizsettings->set('templateid', $templateid); 526 } 527 $quizsettings->save(); 528 } 529 530 /** 531 * Bad browser exam key data provider. 532 * 533 * @return array 534 */ 535 public function bad_browser_exam_key_provider() : array { 536 return [ 537 'Short string' => ['fdsf434r', 538 'A key should be a 64-character hex string.'], 539 'Non hex string' => ['aadf6799aadf6789aadf6789aadf6789aadf6789aadf6789aadf6789aadf678!', 540 'A key should be a 64-character hex string.'], 541 'Non unique' => ["aadf6799aadf6789aadf6789aadf6789aadf6789aadf6789aadf6789aadf6789" 542 . "\naadf6799aadf6789aadf6789aadf6789aadf6789aadf6789aadf6789aadf6789", 'The keys must all be different.'], 543 ]; 544 } 545 546 /** 547 * Provide settings for different filter rules. 548 * 549 * @return array Test data. 550 */ 551 public function filter_rules_provider() : array { 552 return [ 553 'enabled simple expessions' => [ 554 (object) [ 555 'requiresafeexambrowser' => settings_provider::USE_SEB_CONFIG_MANUALLY, 556 'quizid' => 1, 557 'cmid' => 1, 558 'expressionsallowed' => "test.com\r\nsecond.hello", 559 'regexallowed' => '', 560 'expressionsblocked' => '', 561 'regexblocked' => '', 562 ], 563 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 564 . "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 565 . "<plist version=\"1.0\"><dict><key>showTaskBar</key><true/>" 566 . "<key>allowWlan</key><false/><key>showReloadButton</key>" 567 . "<true/><key>showTime</key><true/><key>showInputLanguage</key><true/><key>allowQuit</key><true/>" 568 . "<key>quitURLConfirm</key><true/><key>audioControlEnabled</key><false/><key>audioMute</key><false/>" 569 . "<key>allowSpellCheck</key><false/><key>browserWindowAllowReload</key><true/><key>URLFilterEnable</key><false/>" 570 . "<key>URLFilterEnableContentFilter</key><false/><key>URLFilterRules</key><array>" 571 . "<dict><key>action</key><integer>1</integer><key>active</key><true/>" 572 . "<key>expression</key><string>test.com</string>" 573 . "<key>regex</key><false/></dict><dict><key>action</key><integer>1</integer>" 574 . "<key>active</key><true/><key>expression</key>" 575 . "<string>second.hello</string><key>regex</key><false/></dict></array>" 576 . "<key>startURL</key><string>https://www.example.com/moodle/mod/quiz/view.php?id=1</string>" 577 . "<key>sendBrowserExamKey</key><true/><key>examSessionClearCookiesOnStart</key><false/>" 578 . "<key>allowPreferencesWindow</key><false/></dict></plist>\n", 579 ], 580 'blocked simple expessions' => [ 581 (object) [ 582 'requiresafeexambrowser' => settings_provider::USE_SEB_CONFIG_MANUALLY, 583 'quizid' => 1, 584 'cmid' => 1, 585 'expressionsallowed' => '', 586 'regexallowed' => '', 587 'expressionsblocked' => "test.com\r\nsecond.hello", 588 'regexblocked' => '', 589 ], 590 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 591 . "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 592 . "<plist version=\"1.0\"><dict><key>showTaskBar</key><true/>" 593 . "<key>allowWlan</key><false/><key>showReloadButton</key>" 594 . "<true/><key>showTime</key><true/><key>showInputLanguage</key><true/><key>allowQuit</key><true/>" 595 . "<key>quitURLConfirm</key><true/><key>audioControlEnabled</key><false/><key>audioMute</key><false/>" 596 . "<key>allowSpellCheck</key><false/><key>browserWindowAllowReload</key><true/><key>URLFilterEnable</key><false/>" 597 . "<key>URLFilterEnableContentFilter</key><false/><key>URLFilterRules</key><array>" 598 . "<dict><key>action</key><integer>0</integer><key>active</key><true/>" 599 . "<key>expression</key><string>test.com</string>" 600 . "<key>regex</key><false/></dict><dict><key>action</key><integer>0</integer>" 601 . "<key>active</key><true/><key>expression</key>" 602 . "<string>second.hello</string><key>regex</key><false/></dict></array>" 603 . "<key>startURL</key><string>https://www.example.com/moodle/mod/quiz/view.php?id=1</string>" 604 . "<key>sendBrowserExamKey</key><true/><key>examSessionClearCookiesOnStart</key><false/>" 605 . "<key>allowPreferencesWindow</key><false/></dict></plist>\n", 606 ], 607 'enabled regex expessions' => [ 608 (object) [ 609 'requiresafeexambrowser' => settings_provider::USE_SEB_CONFIG_MANUALLY, 610 'quizid' => 1, 611 'cmid' => 1, 612 'expressionsallowed' => '', 613 'regexallowed' => "test.com\r\nsecond.hello", 614 'expressionsblocked' => '', 615 'regexblocked' => '', 616 ], 617 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 618 . "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 619 . "<plist version=\"1.0\"><dict><key>showTaskBar</key><true/>" 620 . "<key>allowWlan</key><false/><key>showReloadButton</key>" 621 . "<true/><key>showTime</key><true/><key>showInputLanguage</key><true/><key>allowQuit</key><true/>" 622 . "<key>quitURLConfirm</key><true/><key>audioControlEnabled</key><false/><key>audioMute</key><false/>" 623 . "<key>allowSpellCheck</key><false/><key>browserWindowAllowReload</key><true/><key>URLFilterEnable</key><false/>" 624 . "<key>URLFilterEnableContentFilter</key><false/><key>URLFilterRules</key><array>" 625 . "<dict><key>action</key><integer>1</integer><key>active</key><true/>" 626 . "<key>expression</key><string>test.com</string>" 627 . "<key>regex</key><true/></dict><dict><key>action</key><integer>1</integer>" 628 . "<key>active</key><true/><key>expression</key>" 629 . "<string>second.hello</string><key>regex</key><true/></dict></array>" 630 . "<key>startURL</key><string>https://www.example.com/moodle/mod/quiz/view.php?id=1</string>" 631 . "<key>sendBrowserExamKey</key><true/><key>examSessionClearCookiesOnStart</key><false/>" 632 . "<key>allowPreferencesWindow</key><false/></dict></plist>\n", 633 ], 634 'blocked regex expessions' => [ 635 (object) [ 636 'requiresafeexambrowser' => settings_provider::USE_SEB_CONFIG_MANUALLY, 637 'quizid' => 1, 638 'cmid' => 1, 639 'expressionsallowed' => '', 640 'regexallowed' => '', 641 'expressionsblocked' => '', 642 'regexblocked' => "test.com\r\nsecond.hello", 643 ], 644 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 645 . "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 646 . "<plist version=\"1.0\"><dict><key>showTaskBar</key><true/>" 647 . "<key>allowWlan</key><false/><key>showReloadButton</key>" 648 . "<true/><key>showTime</key><true/><key>showInputLanguage</key><true/><key>allowQuit</key><true/>" 649 . "<key>quitURLConfirm</key><true/><key>audioControlEnabled</key><false/><key>audioMute</key><false/>" 650 . "<key>allowSpellCheck</key><false/><key>browserWindowAllowReload</key><true/><key>URLFilterEnable</key><false/>" 651 . "<key>URLFilterEnableContentFilter</key><false/><key>URLFilterRules</key><array>" 652 . "<dict><key>action</key><integer>0</integer><key>active</key><true/>" 653 . "<key>expression</key><string>test.com</string>" 654 . "<key>regex</key><true/></dict><dict><key>action</key><integer>0</integer>" 655 . "<key>active</key><true/><key>expression</key>" 656 . "<string>second.hello</string><key>regex</key><true/></dict></array>" 657 . "<key>startURL</key><string>https://www.example.com/moodle/mod/quiz/view.php?id=1</string>" 658 . "<key>sendBrowserExamKey</key><true/><key>examSessionClearCookiesOnStart</key><false/>" 659 . "<key>allowPreferencesWindow</key><false/></dict></plist>\n", 660 ], 661 'multiple simple expessions' => [ 662 (object) [ 663 'requiresafeexambrowser' => settings_provider::USE_SEB_CONFIG_MANUALLY, 664 'quizid' => 1, 665 'cmid' => 1, 666 'expressionsallowed' => "*", 667 'regexallowed' => '', 668 'expressionsblocked' => '', 669 'regexblocked' => "test.com\r\nsecond.hello", 670 ], 671 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 672 . "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" 673 . "<plist version=\"1.0\"><dict><key>showTaskBar</key><true/>" 674 . "<key>allowWlan</key><false/><key>showReloadButton</key>" 675 . "<true/><key>showTime</key><true/><key>showInputLanguage</key><true/><key>allowQuit</key><true/>" 676 . "<key>quitURLConfirm</key><true/><key>audioControlEnabled</key><false/><key>audioMute</key><false/>" 677 . "<key>allowSpellCheck</key><false/><key>browserWindowAllowReload</key><true/><key>URLFilterEnable</key><false/>" 678 . "<key>URLFilterEnableContentFilter</key><false/><key>URLFilterRules</key><array><dict><key>action</key>" 679 . "<integer>1</integer><key>active</key><true/><key>expression</key><string>*</string>" 680 . "<key>regex</key><false/></dict>" 681 . "<dict><key>action</key><integer>0</integer><key>active</key><true/>" 682 . "<key>expression</key><string>test.com</string>" 683 . "<key>regex</key><true/></dict><dict><key>action</key><integer>0</integer>" 684 . "<key>active</key><true/><key>expression</key>" 685 . "<string>second.hello</string><key>regex</key><true/></dict></array>" 686 . "<key>startURL</key><string>https://www.example.com/moodle/mod/quiz/view.php?id=1</string>" 687 . "<key>sendBrowserExamKey</key><true/><key>examSessionClearCookiesOnStart</key><false/>" 688 . "<key>allowPreferencesWindow</key><false/></dict></plist>\n", 689 ], 690 ]; 691 } 692 693 /** 694 * Test that config and config key are null when expected. 695 */ 696 public function test_generates_config_values_as_null_when_expected() { 697 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 698 $this->assertNotNull($quizsettings->get_config()); 699 $this->assertNotNull($quizsettings->get_config_key()); 700 701 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_NO); 702 $quizsettings->save(); 703 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 704 $this->assertNull($quizsettings->get_config()); 705 $this->assertNull($quizsettings->get_config()); 706 707 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG); 708 $xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb'); 709 $this->create_module_test_file($xml, $this->quiz->cmid); 710 $quizsettings->save(); 711 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 712 $this->assertNotNull($quizsettings->get_config()); 713 $this->assertNotNull($quizsettings->get_config_key()); 714 715 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG); 716 $quizsettings->save(); 717 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 718 $this->assertNull($quizsettings->get_config()); 719 $this->assertNull($quizsettings->get_config_key()); 720 721 $template = $this->create_template(); 722 $templateid = $template->get('id'); 723 $this->save_settings_with_optional_template($quizsettings, settings_provider::USE_SEB_TEMPLATE, $templateid); 724 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 725 $this->assertNotNull($quizsettings->get_config()); 726 $this->assertNotNull($quizsettings->get_config_key()); 727 } 728 729 /** 730 * Test that quizsettings cache exists after creation. 731 */ 732 public function test_quizsettings_cache_exists_after_creation() { 733 $expected = quiz_settings::get_record(['quizid' => $this->quiz->id]); 734 $this->assertEquals($expected->to_record(), \cache::make('quizaccess_seb', 'quizsettings')->get($this->quiz->id)); 735 } 736 737 /** 738 * Test that quizsettings cache gets deleted after deletion. 739 */ 740 public function test_quizsettings_cache_purged_after_deletion() { 741 $this->assertNotEmpty(\cache::make('quizaccess_seb', 'quizsettings')->get($this->quiz->id)); 742 743 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 744 $quizsettings->delete(); 745 746 $this->assertFalse(\cache::make('quizaccess_seb', 'quizsettings')->get($this->quiz->id)); 747 } 748 749 /** 750 * Test that we can get quiz_settings by quiz id. 751 */ 752 public function test_get_quiz_settings_by_quiz_id() { 753 $expected = quiz_settings::get_record(['quizid' => $this->quiz->id]); 754 755 $this->assertEquals($expected->to_record(), quiz_settings::get_by_quiz_id($this->quiz->id)->to_record()); 756 757 // Check that data is getting from cache. 758 $expected->set('showsebtaskbar', 0); 759 $this->assertNotEquals($expected->to_record(), quiz_settings::get_by_quiz_id($this->quiz->id)->to_record()); 760 761 // Now save and check that cached as been updated. 762 $expected->save(); 763 $this->assertEquals($expected->to_record(), quiz_settings::get_by_quiz_id($this->quiz->id)->to_record()); 764 765 // Returns false for non existing quiz. 766 $this->assertFalse(quiz_settings::get_by_quiz_id(7777777)); 767 } 768 769 /** 770 * Test that SEB config cache exists after creation of the quiz. 771 */ 772 public function test_config_cache_exists_after_creation() { 773 $this->assertNotEmpty(\cache::make('quizaccess_seb', 'config')->get($this->quiz->id)); 774 } 775 776 /** 777 * Test that SEB config cache gets deleted after deletion. 778 */ 779 public function test_config_cache_purged_after_deletion() { 780 $this->assertNotEmpty(\cache::make('quizaccess_seb', 'config')->get($this->quiz->id)); 781 782 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 783 $quizsettings->delete(); 784 785 $this->assertFalse(\cache::make('quizaccess_seb', 'config')->get($this->quiz->id)); 786 } 787 788 /** 789 * Test that we can get SEB config by quiz id. 790 */ 791 public function test_get_config_by_quiz_id() { 792 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 793 $expected = $quizsettings->get_config(); 794 795 $this->assertEquals($expected, quiz_settings::get_config_by_quiz_id($this->quiz->id)); 796 797 // Check that data is getting from cache. 798 $quizsettings->set('showsebtaskbar', 0); 799 $this->assertNotEquals($quizsettings->get_config(), quiz_settings::get_config_by_quiz_id($this->quiz->id)); 800 801 // Now save and check that cached as been updated. 802 $quizsettings->save(); 803 $this->assertEquals($quizsettings->get_config(), quiz_settings::get_config_by_quiz_id($this->quiz->id)); 804 805 // Returns null for non existing quiz. 806 $this->assertNull(quiz_settings::get_config_by_quiz_id(7777777)); 807 } 808 809 /** 810 * Test that SEB config key cache exists after creation of the quiz. 811 */ 812 public function test_config_key_cache_exists_after_creation() { 813 $this->assertNotEmpty(\cache::make('quizaccess_seb', 'configkey')->get($this->quiz->id)); 814 } 815 816 /** 817 * Test that SEB config key cache gets deleted after deletion. 818 */ 819 public function test_config_key_cache_purged_after_deletion() { 820 $this->assertNotEmpty(\cache::make('quizaccess_seb', 'configkey')->get($this->quiz->id)); 821 822 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 823 $quizsettings->delete(); 824 825 $this->assertFalse(\cache::make('quizaccess_seb', 'configkey')->get($this->quiz->id)); 826 } 827 828 /** 829 * Test that we can get SEB config key by quiz id. 830 */ 831 public function test_get_config_key_by_quiz_id() { 832 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]); 833 $expected = $quizsettings->get_config_key(); 834 835 $this->assertEquals($expected, quiz_settings::get_config_key_by_quiz_id($this->quiz->id)); 836 837 // Check that data is getting from cache. 838 $quizsettings->set('showsebtaskbar', 0); 839 $this->assertNotEquals($quizsettings->get_config_key(), quiz_settings::get_config_key_by_quiz_id($this->quiz->id)); 840 841 // Now save and check that cached as been updated. 842 $quizsettings->save(); 843 $this->assertEquals($quizsettings->get_config_key(), quiz_settings::get_config_key_by_quiz_id($this->quiz->id)); 844 845 // Returns null for non existing quiz. 846 $this->assertNull(quiz_settings::get_config_key_by_quiz_id(7777777)); 847 } 848 849 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body