2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * PHPUnit tests for plugin rule class.
20 * @package quizaccess_seb
21 * @author Andrew Madden <andrewmadden@catalyst-au.net>
22 * @copyright 2019 Catalyst IT
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 use quizaccess_seb\quiz_settings;
27 use quizaccess_seb\settings_provider;
29 defined('MOODLE_INTERNAL') || die();
31 require_once(__DIR__ . '/test_helper_trait.php');
34 * PHPUnit tests for plugin rule class.
36 * @copyright 2020 Catalyst IT
37 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39 class quizaccess_seb_rule__testcase extends advanced_testcase {
40 use quizaccess_seb_test_helper_trait;
43 * Called before every test.
45 public function setUp(): void {
48 $this->resetAfterTest();
49 $this->course = $this->getDataGenerator()->create_course();
54 * Helper method to get SEB download link for testing.
58 private function get_seb_download_link() {
59 return 'https://safeexambrowser.org/download_en.html';
63 * Helper method to get SEB launch link for testing.
67 private function get_seb_launch_link() {
68 return 'sebs://www.example.com/moodle/mod/quiz/accessrule/seb/config.php';
72 * Helper method to get SEB config download link for testing.
76 private function get_seb_config_download_link() {
77 return 'https://www.example.com/moodle/mod/quiz/accessrule/seb/config.php';
81 * Provider to return valid form field data when saving settings.
85 public function valid_form_data_provider() : array {
87 'valid seb_requiresafeexambrowser' => ['seb_requiresafeexambrowser', '0'],
88 'valid seb_linkquitseb0' => ['seb_linkquitseb', 'http://safeexambrowser.org/macosx'],
89 'valid seb_linkquitseb1' => ['seb_linkquitseb', 'safeexambrowser.org/macosx'],
90 'valid seb_linkquitseb2' => ['seb_linkquitseb', 'www.safeexambrowser.org/macosx'],
91 'valid seb_linkquitseb3' => ['seb_linkquitseb', 'any.type.of.url.looking.thing'],
92 'valid seb_linkquitseb4' => ['seb_linkquitseb', 'http://any.type.of.url.looking.thing'],
97 * Provider to return invalid form field data when saving settings.
101 public function invalid_form_data_provider() : array {
103 'invalid seb_requiresafeexambrowser' => ['seb_requiresafeexambrowser', 'Uh oh!'],
104 'invalid seb_linkquitseb0' => ['seb_linkquitseb', '\0'],
105 'invalid seb_linkquitseb1' => ['seb_linkquitseb', 'invalid url'],
106 'invalid seb_linkquitseb2' => ['seb_linkquitseb', 'http]://safeexambrowser.org/macosx'],
107 'invalid seb_linkquitseb3' => ['seb_linkquitseb', '0'],
108 'invalid seb_linkquitseb4' => ['seb_linkquitseb', 'seb://any.type.of.url.looking.thing'],
113 * Test no errors are found with valid data.
115 * @param string $setting
116 * @param string $data
118 * @dataProvider valid_form_data_provider
120 public function test_validate_settings_with_valid_data(string $setting, string $data) {
121 $this->setAdminUser();
122 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
124 $form = $this->createMock('mod_quiz_mod_form');
125 $form->method('get_context')->willReturn(context_module::instance($this->quiz->cmid));
127 // Validate settings with a dummy form.
128 $errors = quizaccess_seb::validate_settings_form_fields([], [
129 'instance' => $this->quiz->id,
130 'coursemodule' => $this->quiz->cmid,
133 $this->assertEmpty($errors);
137 * Test errors are found with invalid data.
139 * @param string $setting
140 * @param string $data
142 * @dataProvider invalid_form_data_provider
144 public function test_validate_settings_with_invalid_data(string $setting, string $data) {
145 $this->setAdminUser();
147 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
148 $form = $this->createMock('mod_quiz_mod_form');
149 $form->method('get_context')->willReturn(context_module::instance($this->quiz->cmid));
151 // Validate settings with a dummy form and quiz instance.
152 $errors = quizaccess_seb::validate_settings_form_fields([], [
153 'instance' => $this->quiz->id,
154 'coursemodule' => $this->quiz->cmid,
157 $this->assertEquals([$setting => 'Data submitted is invalid'], $errors);
161 * Test settings validation is not run if settings are locked.
163 public function test_settings_validation_is_not_run_if_settings_are_locked() {
164 $user = $this->getDataGenerator()->create_user();
165 $this->quiz = $this->create_test_quiz($this->course);
166 $this->attempt_quiz($this->quiz, $user);
168 $this->setAdminUser();
170 $form = $this->createMock('mod_quiz_mod_form');
171 $form->method('get_context')->willReturn(context_module::instance($this->quiz->cmid));
173 // Validate settings with a dummy form and quiz instance.
174 $errors = quizaccess_seb::validate_settings_form_fields([], [
175 'instance' => $this->quiz->id,
176 'coursemodule' => $this->quiz->cmid, 'seb_requiresafeexambrowser' => 'Uh oh!'
178 $this->assertEmpty($errors);
182 * Test settings validation is not run if settings are conflicting.
184 public function test_settings_validation_is_not_run_if_conflicting_permissions() {
185 $this->setAdminUser();
186 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
188 $form = $this->createMock('mod_quiz_mod_form');
189 $form->method('get_context')->willReturn(context_module::instance($this->quiz->cmid));
191 $user = $this->getDataGenerator()->create_user();
192 $roleid = $this->getDataGenerator()->create_role();
193 $context = context_module::instance($this->quiz->cmid);
194 assign_capability('quizaccess/seb:manage_seb_requiresafeexambrowser', CAP_ALLOW, $roleid, $context->id);
195 $this->getDataGenerator()->role_assign($roleid, $user->id, $context->id);
197 // By default The user won't have permissions to configure manually.
198 $this->setUser($user);
200 // Validate settings with a dummy form and quiz instance.
201 $errors = quizaccess_seb::validate_settings_form_fields([], [
202 'instance' => $this->quiz->id,
203 'coursemodule' => $this->quiz->cmid,
204 'seb_requiresafeexambrowser' => 'Uh oh!'
206 $this->assertEmpty($errors);
210 * Test bypassing validation if user don't have permissions to manage seb settings.
212 public function test_validate_settings_is_not_run_if_a_user_do_not_have_permissions_to_manage_seb_settings() {
213 // Set the user who can't change seb settings. So validation should be bypassed.
214 $user = $this->getDataGenerator()->create_user();
215 $this->setUser($user);
217 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
218 $form = $this->createMock('mod_quiz_mod_form');
219 $form->method('get_context')->willReturn(context_module::instance($this->quiz->cmid));
221 // Validate settings with a dummy form and quiz instance.
222 $errors = quizaccess_seb::validate_settings_form_fields([], [
223 'instance' => $this->quiz->id,
224 'coursemodule' => $this->quiz->cmid, 'seb_requiresafeexambrowser' => 'Uh oh!'
226 $this->assertEmpty($errors);
230 * Test settings are saved to DB.
232 public function test_create_settings_with_existing_quiz() {
235 $this->setAdminUser();
237 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_NO);
238 $this->assertFalse($DB->record_exists('quizaccess_seb_quizsettings', ['quizid' => $this->quiz->id]));
240 $this->quiz->seb_requiresafeexambrowser = settings_provider::USE_SEB_CONFIG_MANUALLY;
241 quizaccess_seb::save_settings($this->quiz);
242 $this->assertNotFalse($DB->record_exists('quizaccess_seb_quizsettings', ['quizid' => $this->quiz->id]));
246 * Test settings are not saved to DB if settings are locked.
248 public function test_settings_are_not_saved_if_settings_are_locked() {
251 $this->setAdminUser();
252 $this->quiz = $this->create_test_quiz($this->course);
254 $user = $this->getDataGenerator()->create_user();
255 $this->setUser($user);
256 $this->attempt_quiz($this->quiz, $user);
258 $this->setAdminUser();
259 $this->quiz->seb_requiresafeexambrowser = settings_provider::USE_SEB_CONFIG_MANUALLY;
260 quizaccess_seb::save_settings($this->quiz);
261 $this->assertFalse($DB->record_exists('quizaccess_seb_quizsettings', ['quizid' => $this->quiz->id]));
265 * Test settings are not saved to DB if conflicting permissions.
267 public function test_settings_are_not_saved_if_conflicting_permissions() {
268 $this->setAdminUser();
269 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
271 $user = $this->getDataGenerator()->create_user();
272 $roleid = $this->getDataGenerator()->create_role();
273 $context = context_module::instance($this->quiz->cmid);
274 assign_capability('quizaccess/seb:manage_seb_requiresafeexambrowser', CAP_ALLOW, $roleid, $context->id);
275 $this->getDataGenerator()->role_assign($roleid, $user->id, $context->id);
277 // By default The user won't have permissions to configure manually.
278 $this->setUser($user);
280 $this->quiz->seb_requiresafeexambrowser = settings_provider::USE_SEB_NO;
281 quizaccess_seb::save_settings($this->quiz);
283 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
284 $this->assertEquals(settings_provider::USE_SEB_CONFIG_MANUALLY, $quizsettings->get('requiresafeexambrowser'));
288 * Test exception thrown if cm could not be found while saving settings.
290 public function test_save_settings_throw_an_exception_if_cm_not_found() {
293 $this->expectException(dml_missing_record_exception::class);
294 $this->expectExceptionMessage('Can\'t find data record in database.');
296 $this->setAdminUser();
298 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
299 $DB->delete_records('quiz', ['id' => $this->quiz->id]);
300 $this->quiz->seb_requiresafeexambrowser = settings_provider::USE_SEB_NO;
301 quizaccess_seb::save_settings($this->quiz);
305 * Test nothing happens when deleted is called without settings saved.
307 public function test_delete_settings_without_existing_settings() {
309 $this->setAdminUser();
311 $quiz = new stdClass();
313 quizaccess_seb::delete_settings($quiz);
314 $this->assertFalse($DB->record_exists('quizaccess_seb_quizsettings', ['quizid' => $quiz->id]));
318 * Test settings are deleted from DB.
320 public function test_delete_settings_with_existing_settings() {
322 $this->setAdminUser();
324 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
326 // Using a generator will create the quiz_settings record.
327 $this->assertNotFalse($DB->record_exists('quizaccess_seb_quizsettings', ['quizid' => $this->quiz->id]));
328 quizaccess_seb::delete_settings($this->quiz);
329 $this->assertFalse($DB->record_exists('quizaccess_seb_quizsettings', ['quizid' => $this->quiz->id]));
333 * A helper method to check invalid config key.
335 protected function check_invalid_config_key() {
336 // Create an event sink, trigger event and retrieve event.
337 $sink = $this->redirectEvents();
339 // Check that correct error message is returned.
340 $errormsg = $this->make_rule()->prevent_access();
341 $this->assertNotEmpty($errormsg);
342 $this->assertStringContainsString("The config key or browser exam keys could not be validated. "
343 . "Please ensure you are using the Safe Exam Browser with correct configuration file.", $errormsg);
344 $this->assertStringContainsString($this->get_seb_download_link(), $errormsg);
345 $this->assertStringContainsString($this->get_seb_launch_link(), $errormsg);
346 $this->assertStringContainsString($this->get_seb_config_download_link(), $errormsg);
348 $events = $sink->get_events();
349 $this->assertEquals(1, count($events));
350 $event = reset($events);
352 // Test that the event data is as expected.
353 $this->assertInstanceOf('\quizaccess_seb\event\access_prevented', $event);
354 $this->assertEquals('Invalid SEB config key', $event->other['reason']);
358 * Test access prevented if config key is invalid.
360 public function test_access_prevented_if_config_key_invalid() {
363 $this->setAdminUser();
364 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
366 // Set up dummy request.
367 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
368 $_SERVER['HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH'] = 'Broken config key';
370 $user = $this->getDataGenerator()->create_user();
371 $this->setUser($user);
373 $this->check_invalid_config_key();
377 * Test access prevented if config keys is invalid and using uploaded config.
379 public function test_access_prevented_if_config_key_invalid_uploaded_config() {
382 $this->setAdminUser();
383 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
385 // Set quiz setting to require seb and save BEK.
386 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
387 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
388 $xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
389 $this->create_module_test_file($xml, $this->quiz->cmid);
390 $quizsettings->save();
392 // Set up dummy request.
393 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
394 $_SERVER['HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH'] = 'Broken config key';
396 $user = $this->getDataGenerator()->create_user();
397 $this->setUser($user);
399 $this->check_invalid_config_key();
403 * Test access prevented if config keys is invalid and using template.
405 public function test_access_prevented_if_config_key_invalid_uploaded_template() {
408 $this->setAdminUser();
409 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
411 // Set quiz setting to require seb and save BEK.
412 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
413 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
414 $quizsettings->set('templateid', $this->create_template()->get('id'));
415 $quizsettings->save();
417 // Set up dummy request.
418 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
419 $_SERVER['HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH'] = 'Broken config key';
421 $user = $this->getDataGenerator()->create_user();
422 $this->setUser($user);
424 $this->check_invalid_config_key();
428 * Test access not prevented if config key matches header.
430 public function test_access_allowed_if_config_key_valid() {
433 $this->setAdminUser();
434 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
436 $user = $this->getDataGenerator()->create_user();
437 $this->setUser($user);
439 // Set quiz setting to require seb.
440 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
442 // Set up dummy request.
443 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
444 $expectedhash = hash('sha256', $FULLME . $quizsettings->get_config_key());
445 $_SERVER['HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH'] = $expectedhash;
447 // Check that correct error message is returned.
448 $this->assertFalse($this->make_rule()->prevent_access());
452 * Test access not prevented if config key matches header.
454 public function test_access_allowed_if_config_key_valid_uploaded_config() {
457 $this->setAdminUser();
458 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
460 // Set quiz setting to require seb and save BEK.
461 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
462 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
463 $quizsettings->set('templateid', $this->create_template()->get('id'));
464 $quizsettings->save();
466 $user = $this->getDataGenerator()->create_user();
467 $this->setUser($user);
469 // Set up dummy request.
470 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
471 $expectedhash = hash('sha256', $FULLME . $quizsettings->get_config_key());
472 $_SERVER['HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH'] = $expectedhash;
474 // Check that correct error message is returned.
475 $this->assertFalse($this->make_rule()->prevent_access());
479 * Test access not prevented if config key matches header.
481 public function test_access_allowed_if_config_key_valid_template() {
484 $this->setAdminUser();
485 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
487 // Set quiz setting to require seb and save BEK.
488 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
489 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
490 $xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
491 $this->create_module_test_file($xml, $this->quiz->cmid);
492 $quizsettings->save();
494 $user = $this->getDataGenerator()->create_user();
495 $this->setUser($user);
497 // Set up dummy request.
498 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
499 $expectedhash = hash('sha256', $FULLME . $quizsettings->get_config_key());
500 $_SERVER['HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH'] = $expectedhash;
502 // Check that correct error message is returned.
503 $this->assertFalse($this->make_rule()->prevent_access());
507 * Test access not prevented if browser exam keys match headers.
509 public function test_access_allowed_if_browser_exam_keys_valid() {
512 $this->setAdminUser();
513 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
515 $user = $this->getDataGenerator()->create_user();
516 $this->setUser($user);
518 // Set quiz setting to require seb and save BEK.
519 $browserexamkey = hash('sha256', 'testkey');
520 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
521 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG); // Doesn't check config key.
522 $quizsettings->set('allowedbrowserexamkeys', $browserexamkey);
523 $quizsettings->save();
525 // Set up dummy request.
526 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
527 $expectedhash = hash('sha256', $FULLME . $browserexamkey);
528 $_SERVER['HTTP_X_SAFEEXAMBROWSER_REQUESTHASH'] = $expectedhash;
529 $_SERVER['HTTP_USER_AGENT'] = 'SEB';
531 // Check that correct error message is returned.
532 $this->assertFalse($this->make_rule()->prevent_access());
536 * Test access not prevented if browser exam keys match headers.
538 public function test_access_allowed_if_browser_exam_keys_valid_use_uploaded_file() {
541 $this->setAdminUser();
542 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
544 // Set quiz setting to require seb and save BEK.
545 $browserexamkey = hash('sha256', 'testkey');
546 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
547 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
548 $quizsettings->set('allowedbrowserexamkeys', $browserexamkey);
549 $xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
550 $this->create_module_test_file($xml, $this->quiz->cmid);
551 $quizsettings->save();
553 // Set up dummy request.
554 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
555 $expectedbrowserkey = hash('sha256', $FULLME . $browserexamkey);
556 $_SERVER['HTTP_X_SAFEEXAMBROWSER_REQUESTHASH'] = $expectedbrowserkey;
557 $expectedconfigkey = hash('sha256', $FULLME . $quizsettings->get_config_key());
558 $_SERVER['HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH'] = $expectedconfigkey;
560 $user = $this->getDataGenerator()->create_user();
561 $this->setUser($user);
563 // Check that correct error message is returned.
564 $this->assertFalse($this->make_rule()->prevent_access());
568 * A helper method to check invalid browser key.
570 * @param bool $downloadseblink Make sure download SEB link is present.
571 * @param bool $launchlink Make sure launch SEB link is present.
572 * @param bool $downloadconfiglink Make download config link is present.
574 protected function check_invalid_browser_exam_key($downloadseblink = true, $launchlink = true, $downloadconfiglink = true) {
575 // Create an event sink, trigger event and retrieve event.
576 $sink = $this->redirectEvents();
578 // Check that correct error message is returned.
579 $errormsg = $this->make_rule()->prevent_access();
580 $this->assertNotEmpty($errormsg);
581 $this->assertStringContainsString("The config key or browser exam keys could not be validated. "
582 . "Please ensure you are using the Safe Exam Browser with correct configuration file.", $errormsg);
584 if ($downloadseblink) {
585 $this->assertStringContainsString($this->get_seb_download_link(), $errormsg);
587 $this->assertStringNotContainsString($this->get_seb_download_link(), $errormsg);
591 $this->assertStringContainsString($this->get_seb_launch_link(), $errormsg);
593 $this->assertStringNotContainsString($this->get_seb_launch_link(), $errormsg);
596 if ($downloadconfiglink) {
597 $this->assertStringContainsString($this->get_seb_config_download_link(), $errormsg);
599 $this->assertStringNotContainsString($this->get_seb_config_download_link(), $errormsg);
602 $events = $sink->get_events();
603 $this->assertEquals(1, count($events));
604 $event = reset($events);
606 // Test that the event data is as expected.
607 $this->assertInstanceOf('\quizaccess_seb\event\access_prevented', $event);
608 $this->assertEquals('Invalid SEB browser key', $event->other['reason']);
612 * Test access prevented if browser exam keys do not match headers.
614 public function test_access_prevented_if_browser_exam_keys_are_invalid() {
615 $this->setAdminUser();
616 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
618 $user = $this->getDataGenerator()->create_user();
619 $this->setUser($user);
621 // Set quiz setting to require seb and save BEK.
622 $browserexamkey = hash('sha256', 'testkey');
623 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
624 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG); // Doesn't check config key.
625 $quizsettings->set('allowedbrowserexamkeys', $browserexamkey);
626 $quizsettings->save();
628 // Set up dummy request.
629 $_SERVER['HTTP_X_SAFEEXAMBROWSER_REQUESTHASH'] = 'Broken browser key';
630 $_SERVER['HTTP_USER_AGENT'] = 'SEB';
632 $this->check_invalid_browser_exam_key(true, false, false);
636 * Test access prevented if browser exam keys do not match headers and using uploaded config.
638 public function test_access_prevented_if_browser_exam_keys_are_invalid_use_uploaded_file() {
641 $this->setAdminUser();
642 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
644 // Set quiz setting to require seb and save BEK.
645 $browserexamkey = hash('sha256', 'testkey');
646 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
647 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
648 $quizsettings->set('allowedbrowserexamkeys', $browserexamkey);
649 $xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
650 $this->create_module_test_file($xml, $this->quiz->cmid);
651 $quizsettings->save();
653 // Set up dummy request.
654 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
655 $expectedhash = hash('sha256', $FULLME . $quizsettings->get_config_key());
656 $_SERVER['HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH'] = $expectedhash;
658 // Set up broken browser key.
659 $_SERVER['HTTP_X_SAFEEXAMBROWSER_REQUESTHASH'] = 'Broken browser key';
661 $user = $this->getDataGenerator()->create_user();
662 $this->setUser($user);
664 $this->check_invalid_browser_exam_key();
668 * Test access not prevented if browser exam keys do not match headers and using template.
670 public function test_access_prevented_if_browser_exam_keys_are_invalid_use_template() {
673 $this->setAdminUser();
674 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
676 // Set quiz setting to require seb and save BEK.
677 $browserexamkey = hash('sha256', 'testkey');
678 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
679 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
680 $quizsettings->set('allowedbrowserexamkeys', $browserexamkey);
681 $quizsettings->set('templateid', $this->create_template()->get('id'));
682 $quizsettings->save();
684 // Set up dummy request.
685 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
686 $expectedhash = hash('sha256', $FULLME . $quizsettings->get_config_key());
687 $_SERVER['HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH'] = $expectedhash;
689 // Set up broken browser key.
690 $_SERVER['HTTP_X_SAFEEXAMBROWSER_REQUESTHASH'] = 'Broken browser key';
692 $user = $this->getDataGenerator()->create_user();
693 $this->setUser($user);
695 // Check that correct error message is returned.
696 $this->assertFalse($this->make_rule()->prevent_access());
700 * Test access allowed if using client configuration and SEB user agent header is valid.
702 public function test_access_allowed_if_using_client_config_basic_header_is_valid() {
703 $this->setAdminUser();
704 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
706 $user = $this->getDataGenerator()->create_user();
707 $this->setUser($user);
709 // Set quiz setting to require seb.
710 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
711 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG); // Doesn't check config key.
712 $quizsettings->save();
714 // Set up basic dummy request.
715 $_SERVER['HTTP_USER_AGENT'] = 'SEB_TEST_SITE';
717 // Check that correct error message is returned.
718 $this->assertFalse($this->make_rule()->prevent_access());
722 * Test access prevented if using client configuration and SEB user agent header is invalid.
724 public function test_access_prevented_if_using_client_configuration_and_basic_head_is_invalid() {
725 $this->setAdminUser();
726 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
728 $user = $this->getDataGenerator()->create_user();
729 $this->setUser($user);
731 // Set quiz setting to require seb.
732 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
733 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG); // Doesn't check config key.
734 $quizsettings->save();
736 // Set up basic dummy request.
737 $_SERVER['HTTP_USER_AGENT'] = 'WRONG_TEST_SITE';
739 // Create an event sink, trigger event and retrieve event.
740 $sink = $this->redirectEvents();
742 // Check that correct error message is returned.
743 $this->assertStringContainsString(
744 'This quiz has been configured to use the Safe Exam Browser with client configuration.',
745 $this->make_rule()->prevent_access()
748 $events = $sink->get_events();
749 $this->assertEquals(1, count($events));
750 $event = reset($events);
752 // Test that the event data is as expected.
753 $this->assertInstanceOf('\quizaccess_seb\event\access_prevented', $event);
754 $this->assertEquals('No Safe Exam Browser is being used.', $event->other['reason']);
758 * Test access allowed if using client configuration and SEB user agent header is invalid and use uploaded file.
760 public function test_access_allowed_if_using_client_configuration_and_basic_head_is_invalid_use_uploaded_config() {
763 $this->setAdminUser();
764 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
766 // Set quiz setting to require seb.
767 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
768 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG); // Doesn't check basic header.
769 $xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
770 $this->create_module_test_file($xml, $this->quiz->cmid);
771 $quizsettings->save();
773 // Set up dummy request.
774 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
775 $expectedhash = hash('sha256', $FULLME . $quizsettings->get_config_key());
776 $_SERVER['HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH'] = $expectedhash;
777 $_SERVER['HTTP_USER_AGENT'] = 'WRONG_TEST_SITE';
779 $user = $this->getDataGenerator()->create_user();
780 $this->setUser($user);
782 // Check that correct error message is returned.
783 $this->assertFalse($this->make_rule()->prevent_access());
787 * Test access allowed if using client configuration and SEB user agent header is invalid and use template.
789 public function test_access_allowed_if_using_client_configuration_and_basic_head_is_invalid_use_template() {
792 $this->setAdminUser();
793 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
795 // Set quiz setting to require seb.
796 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
797 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
798 $quizsettings->set('templateid', $this->create_template()->get('id'));
799 $quizsettings->save();
801 // Set up dummy request.
802 $FULLME = 'https://example.com/moodle/mod/quiz/attempt.php?attemptid=123&page=4';
803 $expectedhash = hash('sha256', $FULLME . $quizsettings->get_config_key());
804 $_SERVER['HTTP_X_SAFEEXAMBROWSER_CONFIGKEYHASH'] = $expectedhash;
805 $_SERVER['HTTP_USER_AGENT'] = 'WRONG_TEST_SITE';
807 $user = $this->getDataGenerator()->create_user();
808 $this->setUser($user);
810 // Check that correct error message is returned.
811 $this->assertFalse($this->make_rule()->prevent_access());
815 * Test access not prevented if SEB not required.
817 public function test_access_allowed_if_seb_not_required() {
818 $this->setAdminUser();
819 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
821 $user = $this->getDataGenerator()->create_user();
822 $this->setUser($user);
824 // Set quiz setting to not require seb.
825 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
826 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_NO);
827 $quizsettings->save();
829 // The rule will not exist as the settings are not configured for SEB usage.
830 $this->assertNull($this->make_rule());
834 * Test access not prevented if USER has bypass capability.
836 public function test_access_allowed_if_user_has_bypass_capability() {
837 $this->setAdminUser();
838 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
840 $user = $this->getDataGenerator()->create_user();
841 $this->setUser($user);
843 // Set the bypass SEB check capability to $USER.
844 $this->assign_user_capability('quizaccess/seb:bypassseb', context_module::instance($this->quiz->cmid)->id);
846 // Check that correct error message is returned.
847 $this->assertFalse($this->make_rule()->prevent_access());
851 * Test that quiz form cannot be saved if using template, but not actually pick one.
853 public function test_mod_quiz_form_cannot_be_saved_using_template_and_template_is_not_set() {
854 $this->setAdminUser();
855 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
857 $form = $this->createMock('mod_quiz_mod_form');
858 $form->method('get_context')->willReturn(context_module::instance($this->quiz->cmid));
860 // Validate settings with a dummy form.
861 $errors = quizaccess_seb::validate_settings_form_fields([], [
862 'instance' => $this->quiz->id,
863 'coursemodule' => $this->quiz->cmid,
864 'seb_requiresafeexambrowser' => settings_provider::USE_SEB_TEMPLATE
867 $this->assertContains(get_string('invalidtemplate', 'quizaccess_seb'), $errors);
871 * Test that quiz form cannot be saved if uploaded invalid file.
873 public function test_mod_quiz_form_cannot_be_saved_using_uploaded_file_and_file_is_not_valid() {
874 $this->setAdminUser();
875 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
877 $form = $this->createMock('mod_quiz_mod_form');
878 $form->method('get_context')->willReturn(context_module::instance($this->quiz->cmid));
880 // Validate settings with a dummy form.
881 $errors = quizaccess_seb::validate_settings_form_fields([], [
882 'instance' => $this->quiz->id,
883 'coursemodule' => $this->quiz->cmid,
884 'seb_requiresafeexambrowser' => settings_provider::USE_SEB_UPLOAD_CONFIG,
885 'filemanager_sebconfigfile' => 0,
888 $this->assertContains(get_string('filenotpresent', 'quizaccess_seb'), $errors);
892 * Test that quiz form cannot be saved if the global settings are set to require a password and no password is set.
894 public function test_mod_quiz_form_cannot_be_saved_if_global_settings_force_quiz_password_and_none_is_set() {
895 $this->setAdminUser();
896 // Set global settings to require quiz password but set password to be empty.
897 set_config('quizpasswordrequired', '1', 'quizaccess_seb');
898 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
900 $form = $this->createMock('mod_quiz_mod_form');
901 $form->method('get_context')->willReturn(context_module::instance($this->quiz->cmid));
903 // Validate settings with a dummy form.
904 $errors = quizaccess_seb::validate_settings_form_fields([], [
905 'instance' => $this->quiz->id,
906 'coursemodule' => $this->quiz->cmid,
907 'seb_requiresafeexambrowser' => settings_provider::USE_SEB_CONFIG_MANUALLY,
910 $this->assertContains(get_string('passwordnotset', 'quizaccess_seb'), $errors);
914 * Test that access to quiz is allowed if global setting is set to restrict quiz if no quiz password is set, and global quiz
917 public function test_mod_quiz_form_can_be_saved_if_global_settings_force_quiz_password_and_is_set() {
918 $this->setAdminUser();
919 // Set global settings to require quiz password but set password to be empty.
920 set_config('quizpasswordrequired', '1', 'quizaccess_seb');
922 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
924 $form = $this->createMock('mod_quiz_mod_form');
925 $form->method('get_context')->willReturn(context_module::instance($this->quiz->cmid));
927 // Validate settings with a dummy form.
928 $errors = quizaccess_seb::validate_settings_form_fields([], [
929 'instance' => $this->quiz->id,
930 'coursemodule' => $this->quiz->cmid,
931 'quizpassword' => 'set',
932 'seb_requiresafeexambrowser' => settings_provider::USE_SEB_CONFIG_MANUALLY,
934 $this->assertNotContains(get_string('passwordnotset', 'quizaccess_seb'), $errors);
938 * Test that quiz form can be saved if the global settings are set to require a password and no seb usage selected.
940 public function test_mod_quiz_form_can_be_saved_if_global_settings_force_quiz_password_and_none_no_seb() {
941 $this->setAdminUser();
942 // Set global settings to require quiz password but set password to be empty.
943 set_config('quizpasswordrequired', '1', 'quizaccess_seb');
944 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_NO);
946 $form = $this->createMock('mod_quiz_mod_form');
947 $form->method('get_context')->willReturn(context_module::instance($this->quiz->cmid));
949 // Validate settings with a dummy form.
950 $errors = quizaccess_seb::validate_settings_form_fields([], [
951 'instance' => $this->quiz->id,
952 'coursemodule' => $this->quiz->cmid,
953 'seb_requiresafeexambrowser' => settings_provider::USE_SEB_NO,
956 $this->assertNotContains(get_string('passwordnotset', 'quizaccess_seb'), $errors);
960 * Test get_download_seb_button, checks for empty config setting quizaccess_seb/downloadlink.
962 public function test_get_download_seb_button() {
963 $this->setAdminUser();
964 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
966 $user = $this->getDataGenerator()->create_user();
967 $this->setUser($user);
969 $reflection = new \ReflectionClass('quizaccess_seb');
970 $method = $reflection->getMethod('get_download_seb_button');
971 $method->setAccessible(true);
973 // The current default contents.
974 $this->assertStringContainsString($this->get_seb_download_link(), $method->invoke($this->make_rule()));
976 set_config('downloadlink', '', 'quizaccess_seb');
978 // Will not return any button if the URL is empty.
979 $this->assertSame('', $method->invoke($this->make_rule()));
983 * Test get_download_seb_button shows download SEB link when required,
985 public function test_get_get_action_buttons_shows_download_seb_link() {
986 $this->setAdminUser();
987 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
989 $user = $this->getDataGenerator()->create_user();
990 $this->setUser($user);
992 $reflection = new \ReflectionClass('quizaccess_seb');
993 $method = $reflection->getMethod('get_action_buttons');
994 $method->setAccessible(true);
996 $this->assertStringContainsString($this->get_seb_download_link(), $method->invoke($this->make_rule()));
998 $this->quiz->seb_showsebdownloadlink = 0;
999 $this->assertStringNotContainsString($this->get_seb_download_link(), $method->invoke($this->make_rule()));
1003 * Test get_download_seb_button shows SEB config related links when required.
1005 public function test_get_get_action_buttons_shows_launch_and_download_config_links() {
1006 $this->setAdminUser();
1007 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
1009 $user = $this->getDataGenerator()->create_user();
1010 $this->setUser($user);
1012 $reflection = new \ReflectionClass('quizaccess_seb');
1013 $method = $reflection->getMethod('get_action_buttons');
1014 $method->setAccessible(true);
1016 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
1018 // Should see link when using manually.
1019 $this->assertStringContainsString($this->get_seb_launch_link(), $method->invoke($this->make_rule()));
1020 $this->assertStringContainsString($this->get_seb_config_download_link(), $method->invoke($this->make_rule()));
1022 // Should see links when using template.
1023 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_TEMPLATE);
1024 $quizsettings->set('templateid', $this->create_template()->get('id'));
1025 $quizsettings->save();
1026 $this->assertStringContainsString($this->get_seb_launch_link(), $method->invoke($this->make_rule()));
1027 $this->assertStringContainsString($this->get_seb_config_download_link(), $method->invoke($this->make_rule()));
1029 // Should see links when using uploaded config.
1030 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_UPLOAD_CONFIG);
1031 $xml = file_get_contents(__DIR__ . '/fixtures/unencrypted.seb');
1032 $this->create_module_test_file($xml, $this->quiz->cmid);
1033 $quizsettings->save();
1034 $this->assertStringContainsString($this->get_seb_launch_link(), $method->invoke($this->make_rule()));
1035 $this->assertStringContainsString($this->get_seb_config_download_link(), $method->invoke($this->make_rule()));
1037 // Shouldn't see links if using client config.
1038 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG);
1039 $quizsettings->save();
1040 $this->assertStringNotContainsString($this->get_seb_launch_link(), $method->invoke($this->make_rule()));
1041 $this->assertStringNotContainsString($this->get_seb_config_download_link(), $method->invoke($this->make_rule()));
1045 * Test get_download_seb_button shows SEB config related links as configured in "showseblinks".
1047 public function test_get_get_action_buttons_shows_launch_and_download_config_links_as_configured() {
1048 $this->setAdminUser();
1049 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
1051 $user = $this->getDataGenerator()->create_user();
1052 $this->setUser($user);
1054 $reflection = new \ReflectionClass('quizaccess_seb');
1055 $method = $reflection->getMethod('get_action_buttons');
1056 $method->setAccessible(true);
1058 set_config('showseblinks', 'seb,http', 'quizaccess_seb');
1059 $this->assertStringContainsString($this->get_seb_launch_link(), $method->invoke($this->make_rule()));
1060 $this->assertStringContainsString($this->get_seb_config_download_link(), $method->invoke($this->make_rule()));
1062 set_config('showseblinks', 'http', 'quizaccess_seb');
1063 $this->assertStringNotContainsString($this->get_seb_launch_link(), $method->invoke($this->make_rule()));
1064 $this->assertStringContainsString($this->get_seb_config_download_link(), $method->invoke($this->make_rule()));
1066 set_config('showseblinks', 'seb', 'quizaccess_seb');
1067 $this->assertStringContainsString($this->get_seb_launch_link(), $method->invoke($this->make_rule()));
1068 $this->assertStringNotContainsString($this->get_seb_config_download_link(), $method->invoke($this->make_rule()));
1070 set_config('showseblinks', '', 'quizaccess_seb');
1071 $this->assertStringNotContainsString($this->get_seb_launch_link(), $method->invoke($this->make_rule()));
1072 $this->assertStringNotContainsString($this->get_seb_config_download_link(), $method->invoke($this->make_rule()));
1076 * Test get_quit_button. If attempt count is greater than 0
1078 public function test_get_quit_button() {
1079 $this->setAdminUser();
1080 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CLIENT_CONFIG);
1081 $this->quiz->seb_linkquitseb = "http://test.quit.link";
1083 $user = $this->getDataGenerator()->create_user();
1084 $this->attempt_quiz($this->quiz, $user);
1085 $this->setUser($user);
1087 // Set-up the button to be called.
1088 $reflection = new \ReflectionClass('quizaccess_seb');
1089 $method = $reflection->getMethod('get_quit_button');
1090 $method->setAccessible(true);
1092 $button = $method->invoke($this->make_rule());
1093 $this->assertStringContainsString("http://test.quit.link", $button);
1097 * Test description, checks for a valid SEB session and attempt count .
1099 public function test_description() {
1100 $this->setAdminUser();
1101 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CLIENT_CONFIG);
1103 $this->quiz->seb_linkquitseb = "http://test.quit.link";
1105 // Set up basic dummy request.
1106 $_SERVER['HTTP_USER_AGENT'] = 'SEB_TEST_SITE';
1108 $user = $this->getDataGenerator()->create_user();
1109 $this->attempt_quiz($this->quiz, $user);
1111 $description = $this->make_rule()->description();
1112 $this->assertCount(2, $description);
1113 $this->assertEquals($description[0], get_string('sebrequired', 'quizaccess_seb'));
1114 $this->assertEquals($description[1], '');
1116 // Set the user as display_quit_button() uses the global $USER.
1117 $this->setUser($user);
1118 $description = $this->make_rule()->description();
1119 $this->assertCount(2, $description);
1120 $this->assertEquals($description[0], get_string('sebrequired', 'quizaccess_seb'));
1122 // The button is contained in the description when a quiz attempt is finished.
1123 $this->assertStringContainsString("http://test.quit.link", $description[1]);
1127 * Test description displays download SEB config button when required.
1129 public function test_description_shows_download_config_link_when_required() {
1130 $this->setAdminUser();
1131 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
1133 $quizsettings = quiz_settings::get_record(['quizid' => $this->quiz->id]);
1135 $user = $this->getDataGenerator()->create_user();
1136 $roleid = $this->getDataGenerator()->create_role();
1137 $context = context_module::instance($this->quiz->cmid);
1138 assign_capability('quizaccess/seb:bypassseb', CAP_ALLOW, $roleid, $context->id);
1140 $this->setUser($user);
1142 // Can see just basic description with standard perms.
1143 $description = $this->make_rule()->description();
1144 $this->assertCount(1, $description);
1145 $this->assertEquals($description[0], get_string('sebrequired', 'quizaccess_seb'));
1147 // Can see download config link as have bypass SEB permissions.
1148 $this->getDataGenerator()->role_assign($roleid, $user->id, $context->id);
1149 $description = $this->make_rule()->description();
1150 $this->assertCount(3, $description);
1151 $this->assertEquals($description[0], get_string('sebrequired', 'quizaccess_seb'));
1152 $this->assertStringContainsString($this->get_seb_config_download_link(), $description[1]);
1154 // Can't see download config link as usage method doesn't have SEB config to download.
1155 $quizsettings->set('requiresafeexambrowser', settings_provider::USE_SEB_CLIENT_CONFIG);
1156 $quizsettings->save();
1157 $description = $this->make_rule()->description();
1158 $this->assertCount(2, $description);
1159 $this->assertEquals($description[0], get_string('sebrequired', 'quizaccess_seb'));
1163 * Test block display before a quiz started.
1165 public function test_blocks_display_before_attempt_started() {
1168 $this->setAdminUser();
1169 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CLIENT_CONFIG);
1171 $user = $this->getDataGenerator()->create_user();
1172 $this->setUser($user);
1174 // We will check if we show only fake blocks. Which means no other blocks on a page.
1175 $reflection = new \ReflectionClass('block_manager');
1176 $property = $reflection->getProperty('fakeblocksonly');
1177 $property->setAccessible(true);
1179 $this->assertFalse($property->getValue($PAGE->blocks));
1181 // Don't display blocks before start.
1182 set_config('displayblocksbeforestart', 0, 'quizaccess_seb');
1183 $this->set_up_quiz_view_page();
1184 $this->make_rule()->prevent_access();
1185 $this->assertEquals('secure', $PAGE->pagelayout);
1186 $this->assertTrue($property->getValue($PAGE->blocks));
1188 // Display blocks before start.
1189 set_config('displayblocksbeforestart', 1, 'quizaccess_seb');
1190 $this->set_up_quiz_view_page();
1191 $this->make_rule()->prevent_access();
1192 $this->assertEquals('secure', $PAGE->pagelayout);
1193 $this->assertFalse($property->getValue($PAGE->blocks));
1197 * Test block display after a quiz completed.
1199 public function test_blocks_display_after_attempt_finished() {
1202 $this->setAdminUser();
1203 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CLIENT_CONFIG);
1206 $user = $this->getDataGenerator()->create_user();
1207 $this->attempt_quiz($this->quiz, $user);
1208 $this->setUser($user);
1210 // We will check if we show only fake blocks. Which means no other blocks on a page.
1211 $reflection = new \ReflectionClass('block_manager');
1212 $property = $reflection->getProperty('fakeblocksonly');
1213 $property->setAccessible(true);
1215 $this->assertFalse($property->getValue($PAGE->blocks));
1217 // Don't display blocks after finish.
1218 set_config('displayblockswhenfinished', 0, 'quizaccess_seb');
1219 $this->set_up_quiz_view_page();
1220 $this->make_rule()->prevent_access();
1221 $this->assertEquals('secure', $PAGE->pagelayout);
1222 $this->assertTrue($property->getValue($PAGE->blocks));
1224 // Display blocks after finish.
1225 set_config('displayblockswhenfinished', 1, 'quizaccess_seb');
1226 $this->set_up_quiz_view_page();
1227 $this->make_rule()->prevent_access();
1228 $this->assertEquals('secure', $PAGE->pagelayout);
1229 $this->assertFalse($property->getValue($PAGE->blocks));
1233 * Test we can decide if need to redirect to SEB config link.
1235 public function test_should_redirect_to_seb_config_link() {
1236 $this->setAdminUser();
1237 $this->quiz = $this->create_test_quiz($this->course, settings_provider::USE_SEB_CONFIG_MANUALLY);
1239 $reflection = new \ReflectionClass('quizaccess_seb');
1240 $method = $reflection->getMethod('should_redirect_to_seb_config_link');
1241 $method->setAccessible(true);
1243 set_config('autoreconfigureseb', '0', 'quizaccess_seb');
1244 $_SERVER['HTTP_USER_AGENT'] = 'TEST';
1245 $this->assertFalse($method->invoke($this->make_rule()));
1247 set_config('autoreconfigureseb', '0', 'quizaccess_seb');
1248 $_SERVER['HTTP_USER_AGENT'] = 'SEB';
1249 $this->assertFalse($method->invoke($this->make_rule()));
1251 set_config('autoreconfigureseb', '1', 'quizaccess_seb');
1252 $_SERVER['HTTP_USER_AGENT'] = 'TEST';
1253 $this->assertFalse($method->invoke($this->make_rule()));
1255 set_config('autoreconfigureseb', '1', 'quizaccess_seb');
1256 $_SERVER['HTTP_USER_AGENT'] = 'SEB';
1257 $this->assertTrue($method->invoke($this->make_rule()));