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