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