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