Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  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  }