See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401] [Versions 401 and 402] [Versions 401 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 namespace mod_quiz; 18 19 use mod_quiz_overdue_attempt_updater; 20 use question_engine; 21 use quiz; 22 23 defined('MOODLE_INTERNAL') || die(); 24 25 global $CFG; 26 require_once($CFG->dirroot.'/group/lib.php'); 27 28 /** 29 * Unit tests for quiz attempt overdue handling 30 * 31 * @package mod_quiz 32 * @category test 33 * @copyright 2012 Matt Petro 34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 */ 36 class attempts_test extends \advanced_testcase { 37 38 /** 39 * Test the functions quiz_update_open_attempts(), get_list_of_overdue_attempts() and 40 * update_overdue_attempts(). 41 */ 42 public function test_bulk_update_functions() { 43 global $DB,$CFG; 44 45 require_once($CFG->dirroot.'/mod/quiz/cronlib.php'); 46 47 $this->resetAfterTest(); 48 49 $this->setAdminUser(); 50 51 // Setup course, user and groups 52 53 $course = $this->getDataGenerator()->create_course(); 54 $user1 = $this->getDataGenerator()->create_user(); 55 $studentrole = $DB->get_record('role', ['shortname' => 'student']); 56 $this->assertNotEmpty($studentrole); 57 $this->assertTrue(enrol_try_internal_enrol($course->id, $user1->id, $studentrole->id)); 58 $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 59 $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 60 $group3 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 61 $this->assertTrue(groups_add_member($group1, $user1)); 62 $this->assertTrue(groups_add_member($group2, $user1)); 63 64 $usertimes = []; 65 66 /** @var mod_quiz_generator $quizgenerator */ 67 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 68 69 // Basic quiz settings 70 71 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 72 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 73 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 74 $usertimes[$attemptid] = ['timeclose' => 1200, 'timelimit' => 600, 'message' => 'Test1A', 'time1000state' => 'finished']; 75 76 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 1800]); 77 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 78 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 79 $usertimes[$attemptid] = ['timeclose' => 1200, 'timelimit' => 1800, 'message' => 'Test1B', 'time1000state' => 'inprogress']; 80 81 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 0]); 82 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 83 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 84 $usertimes[$attemptid] = ['timeclose' => 1200, 'timelimit' => 0, 'message' => 'Test1C', 'time1000state' => 'inprogress']; 85 86 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 0, 'timelimit' => 600]); 87 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 88 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 89 $usertimes[$attemptid] = ['timeclose' => 0, 'timelimit' => 600, 'message' => 'Test1D', 'time1000state' => 'finished']; 90 91 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 0, 'timelimit' => 0]); 92 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 93 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 94 $usertimes[$attemptid] = ['timeclose' => 0, 'timelimit' => 0, 'message' => 'Test1E', 'time1000state' => 'inprogress']; 95 96 // Group overrides 97 98 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 0]); 99 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 100 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 101 $DB->insert_record('quiz_overrides', 102 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => null]); 103 $usertimes[$attemptid] = ['timeclose' => 1300, 'timelimit' => 0, 'message' => 'Test2A', 'time1000state' => 'inprogress']; 104 105 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 0]); 106 $DB->insert_record('quiz_overrides', 107 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1100, 'timelimit' => null]); 108 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 109 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 110 $usertimes[$attemptid] = ['timeclose' => 1100, 'timelimit' => 0, 'message' => 'Test2B', 'time1000state' => 'inprogress']; 111 112 $quiz = $quizgenerator->create_instance( 113 ['course' => $course->id, 'timeclose' => 0, 'timelimit' => 600, 'overduehandling' => 'autoabandon']); 114 $DB->insert_record('quiz_overrides', 115 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => null, 'timelimit' => 700]); 116 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 117 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 118 $usertimes[$attemptid] = ['timeclose' => 0, 'timelimit' => 700, 'message' => 'Test2C', 'time1000state' => 'abandoned']; 119 120 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 0, 'timelimit' => 600]); 121 $DB->insert_record('quiz_overrides', 122 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => null, 'timelimit' => 500]); 123 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 124 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 125 $usertimes[$attemptid] = ['timeclose' => 0, 'timelimit' => 500, 'message' => 'Test2D', 'time1000state' => 'finished']; 126 127 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 0, 'timelimit' => 600]); 128 $DB->insert_record('quiz_overrides', 129 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => null, 'timelimit' => 0]); 130 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 131 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 132 $usertimes[$attemptid] = ['timeclose' => 0, 'timelimit' => 0, 'message' => 'Test2E', 'time1000state' => 'inprogress']; 133 134 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 135 $DB->insert_record('quiz_overrides', 136 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 500]); 137 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 138 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 139 $usertimes[$attemptid] = ['timeclose' => 1300, 'timelimit' => 500, 'message' => 'Test2F', 'time1000state' => 'finished']; 140 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 141 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 142 $usertimes[$attemptid] = ['timeclose' => 1300, 'timelimit' => 500, 'message' => 'Test2G', 'time1000state' => 'inprogress']; 143 144 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 145 $DB->insert_record('quiz_overrides', 146 ['quiz' => $quiz->id, 'groupid' => $group3->id, 'timeclose' => 1300, 'timelimit' => 500]); // User not in group. 147 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 148 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 149 $usertimes[$attemptid] = ['timeclose' => 1200, 'timelimit' => 600, 'message' => 'Test2H', 'time1000state' => 'finished']; 150 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 151 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 152 $usertimes[$attemptid] = ['timeclose' => 1200, 'timelimit' => 600, 'message' => 'Test2I', 'time1000state' => 'inprogress']; 153 154 // Multiple group overrides 155 156 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 157 $DB->insert_record('quiz_overrides', 158 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 501]); 159 $DB->insert_record('quiz_overrides', 160 ['quiz' => $quiz->id, 'groupid' => $group2->id, 'timeclose' => 1301, 'timelimit' => 500]); 161 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 162 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 163 $usertimes[$attemptid] = ['timeclose' => 1301, 'timelimit' => 501, 'message' => 'Test3A', 'time1000state' => 'finished']; 164 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 165 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 166 $usertimes[$attemptid] = ['timeclose' => 1301, 'timelimit' => 501, 'message' => 'Test3B', 'time1000state' => 'inprogress']; 167 168 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 169 $DB->insert_record('quiz_overrides', 170 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1301, 'timelimit' => 500]); 171 $DB->insert_record('quiz_overrides', 172 ['quiz' => $quiz->id, 'groupid' => $group2->id, 'timeclose' => 1300, 'timelimit' => 501]); 173 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 174 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 175 $usertimes[$attemptid] = ['timeclose' => 1301, 'timelimit' => 501, 'message' => 'Test3C', 'time1000state' => 'finished']; 176 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 177 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 178 $usertimes[$attemptid] = ['timeclose' => 1301, 'timelimit' => 501, 'message' => 'Test3D', 'time1000state' => 'inprogress']; 179 180 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600, 181 'overduehandling' => 'autoabandon']); 182 $DB->insert_record('quiz_overrides', 183 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1301, 'timelimit' => 500]); 184 $DB->insert_record('quiz_overrides', 185 ['quiz' => $quiz->id, 'groupid' => $group2->id, 'timeclose' => 1300, 'timelimit' => 501]); 186 $DB->insert_record('quiz_overrides', 187 ['quiz' => $quiz->id, 'groupid' => $group3->id, 'timeclose' => 1500, 'timelimit' => 1000]); // User not in group. 188 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 189 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 190 $usertimes[$attemptid] = ['timeclose' => 1301, 'timelimit' => 501, 'message' => 'Test3E', 'time1000state' => 'abandoned']; 191 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 192 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 193 $usertimes[$attemptid] = ['timeclose' => 1301, 'timelimit' => 501, 'message' => 'Test3F', 'time1000state' => 'inprogress']; 194 195 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 196 $DB->insert_record('quiz_overrides', 197 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 500]); 198 $DB->insert_record('quiz_overrides', 199 ['quiz' => $quiz->id, 'groupid' => $group2->id, 'timeclose' => null, 'timelimit' => 501]); 200 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 201 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 202 $usertimes[$attemptid] = ['timeclose' => 1300, 'timelimit' => 501, 'message' => 'Test3G', 'time1000state' => 'finished']; 203 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 204 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 205 $usertimes[$attemptid] = ['timeclose' => 1300, 'timelimit' => 501, 'message' => 'Test3H', 'time1000state' => 'inprogress']; 206 207 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 208 $DB->insert_record('quiz_overrides', 209 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 500]); 210 $DB->insert_record('quiz_overrides', 211 ['quiz' => $quiz->id, 'groupid' => $group2->id, 'timeclose' => 1301, 'timelimit' => null]); 212 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 213 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 214 $usertimes[$attemptid] = ['timeclose' => 1301, 'timelimit' => 500, 'message' => 'Test3I', 'time1000state' => 'finished']; 215 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 216 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 217 $usertimes[$attemptid] = ['timeclose' => 1301, 'timelimit' => 500, 'message' => 'Test3J', 'time1000state' => 'inprogress']; 218 219 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 220 $DB->insert_record('quiz_overrides', 221 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 500]); 222 $DB->insert_record('quiz_overrides', 223 ['quiz' => $quiz->id, 'groupid' => $group2->id, 'timeclose' => 1301, 'timelimit' => 0]); 224 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 225 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 226 $usertimes[$attemptid] = ['timeclose' => 1301, 'timelimit' => 0, 'message' => 'Test3K', 'time1000state' => 'inprogress']; 227 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 228 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 229 $usertimes[$attemptid] = ['timeclose' => 1301, 'timelimit' => 0, 'message' => 'Test3L', 'time1000state' => 'inprogress']; 230 231 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 232 $DB->insert_record('quiz_overrides', 233 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 500]); 234 $DB->insert_record('quiz_overrides', 235 ['quiz' => $quiz->id, 'groupid' => $group2->id, 'timeclose' => 0, 'timelimit' => 501]); 236 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 237 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 238 $usertimes[$attemptid] = ['timeclose' => 0, 'timelimit' => 501, 'message' => 'Test3M', 'time1000state' => 'finished']; 239 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 240 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 241 $usertimes[$attemptid] = ['timeclose' => 0, 'timelimit' => 501, 'message' => 'Test3N', 'time1000state' => 'inprogress']; 242 243 // User overrides 244 245 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 246 $DB->insert_record('quiz_overrides', 247 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 700]); 248 $DB->insert_record('quiz_overrides', 249 ['quiz' => $quiz->id, 'userid' => $user1->id, 'timeclose' => 1201, 'timelimit' => 601]); 250 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 251 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 252 $usertimes[$attemptid] = ['timeclose' => 1201, 'timelimit' => 601, 'message' => 'Test4A', 'time1000state' => 'finished']; 253 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 254 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 255 $usertimes[$attemptid] = ['timeclose' => 1201, 'timelimit' => 601, 'message' => 'Test4B', 'time1000state' => 'inprogress']; 256 257 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 258 $DB->insert_record('quiz_overrides', 259 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 700]); 260 $DB->insert_record('quiz_overrides', 261 ['quiz' => $quiz->id, 'userid' => $user1->id, 'timeclose' => 0, 'timelimit' => 601]); 262 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 263 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 264 $usertimes[$attemptid] = ['timeclose' => 0, 'timelimit' => 601, 'message' => 'Test4C', 'time1000state' => 'finished']; 265 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 266 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 267 $usertimes[$attemptid] = ['timeclose' => 0, 'timelimit' => 601, 'message' => 'Test4D', 'time1000state' => 'inprogress']; 268 269 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 270 $DB->insert_record('quiz_overrides', 271 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 700]); 272 $DB->insert_record('quiz_overrides', 273 ['quiz' => $quiz->id, 'userid' => $user1->id, 'timeclose' => 1201, 'timelimit' => 0]); 274 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 275 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 276 $usertimes[$attemptid] = ['timeclose' => 1201, 'timelimit' => 0, 'message' => 'Test4E', 'time1000state' => 'inprogress']; 277 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 278 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 279 $usertimes[$attemptid] = ['timeclose' => 1201, 'timelimit' => 0, 'message' => 'Test4F', 'time1000state' => 'inprogress']; 280 281 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600, 282 'overduehandling' => 'autoabandon']); 283 $DB->insert_record('quiz_overrides', 284 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 700]); 285 $DB->insert_record('quiz_overrides', 286 ['quiz' => $quiz->id, 'userid' => $user1->id, 'timeclose' => null, 'timelimit' => 601]); 287 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 288 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 289 $usertimes[$attemptid] = ['timeclose' => 1300, 'timelimit' => 601, 'message' => 'Test4G', 'time1000state' => 'abandoned']; 290 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 291 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 292 $usertimes[$attemptid] = ['timeclose' => 1300, 'timelimit' => 601, 'message' => 'Test4H', 'time1000state' => 'inprogress']; 293 294 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 295 $DB->insert_record('quiz_overrides', 296 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => null, 'timelimit' => 700]); 297 $DB->insert_record('quiz_overrides', 298 ['quiz' => $quiz->id, 'userid' => $user1->id, 'timeclose' => null, 'timelimit' => 601]); 299 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 300 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 301 $usertimes[$attemptid] = ['timeclose' => 1200, 'timelimit' => 601, 'message' => 'Test4I', 'time1000state' => 'finished']; 302 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 303 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 304 $usertimes[$attemptid] = ['timeclose' => 1200, 'timelimit' => 601, 'message' => 'Test4J', 'time1000state' => 'inprogress']; 305 306 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 307 $DB->insert_record('quiz_overrides', 308 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 700]); 309 $DB->insert_record('quiz_overrides', 310 ['quiz' => $quiz->id, 'userid' => $user1->id, 'timeclose' => 1201, 'timelimit' => null]); 311 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 312 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 313 $usertimes[$attemptid] = ['timeclose' => 1201, 'timelimit' => 700, 'message' => 'Test4K', 'time1000state' => 'finished']; 314 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 315 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 316 $usertimes[$attemptid] = ['timeclose' => 1201, 'timelimit' => 700, 'message' => 'Test4L', 'time1000state' => 'inprogress']; 317 318 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 319 $DB->insert_record('quiz_overrides', 320 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => null]); 321 $DB->insert_record('quiz_overrides', 322 ['quiz' => $quiz->id, 'userid' => $user1->id, 'timeclose' => 1201, 'timelimit' => null]); 323 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 324 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 325 $usertimes[$attemptid] = ['timeclose' => 1201, 'timelimit' => 600, 'message' => 'Test4M', 'time1000state' => 'finished']; 326 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 327 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 328 $usertimes[$attemptid] = ['timeclose' => 1201, 'timelimit' => 600, 'message' => 'Test4N', 'time1000state' => 'inprogress']; 329 330 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600]); 331 $DB->insert_record('quiz_overrides', 332 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => 700]); 333 $DB->insert_record('quiz_overrides', 334 ['quiz' => $quiz->id, 'userid' => 0, 'timeclose' => 1201, 'timelimit' => 601]); // Not user. 335 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 336 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 337 $usertimes[$attemptid] = ['timeclose' => 1300, 'timelimit' => 700, 'message' => 'Test4O', 'time1000state' => 'finished']; 338 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 339 'timestart' => 1000, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz), 'attempt' => 1]); 340 $usertimes[$attemptid] = ['timeclose' => 1300, 'timelimit' => 700, 'message' => 'Test4P', 'time1000state' => 'inprogress']; 341 342 // Attempt state overdue 343 344 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 600, 345 'overduehandling' => 'graceperiod', 'graceperiod' => 250]); 346 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'overdue', 347 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 348 $usertimes[$attemptid] = ['timeclose' => 1200, 'timelimit' => 600, 'message' => 'Test5A', 'time1000state' => 'overdue']; 349 350 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 0, 'timelimit' => 600, 351 'overduehandling' => 'graceperiod', 'graceperiod' => 250]); 352 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'overdue', 353 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 354 $usertimes[$attemptid] = ['timeclose' => 0, 'timelimit' => 600, 'message' => 'Test5B', 'time1000state' => 'overdue']; 355 356 // Compute expected end time for each attempt. 357 foreach ($usertimes as $attemptid => $times) { 358 $attempt = $DB->get_record('quiz_attempts', ['id' => $attemptid], '*', MUST_EXIST); 359 360 if ($times['timeclose'] > 0 && $times['timelimit'] > 0) { 361 $usertimes[$attemptid]['timedue'] = min($times['timeclose'], $attempt->timestart + $times['timelimit']); 362 } else if ($times['timeclose'] > 0) { 363 $usertimes[$attemptid]['timedue'] = $times['timeclose']; 364 } else if ($times['timelimit'] > 0) { 365 $usertimes[$attemptid]['timedue'] = $attempt->timestart + $times['timelimit']; 366 } 367 } 368 369 // 370 // Test quiz_update_open_attempts(). 371 // 372 373 quiz_update_open_attempts(['courseid' => $course->id]); 374 foreach ($usertimes as $attemptid => $times) { 375 $attempt = $DB->get_record('quiz_attempts', ['id' => $attemptid], '*', MUST_EXIST); 376 377 if ($attempt->state == 'overdue') { 378 $graceperiod = $DB->get_field('quiz', 'graceperiod', ['id' => $attempt->quiz]); 379 } else { 380 $graceperiod = 0; 381 } 382 if (isset($times['timedue'])) { 383 $this->assertEquals($times['timedue'] + $graceperiod, $attempt->timecheckstate, $times['message']); 384 } else { 385 $this->assertNull($attempt->timecheckstate, $times['message']); 386 } 387 } 388 389 // 390 // Test get_list_of_overdue_attempts(). 391 // 392 393 $overduehander = new mod_quiz_overdue_attempt_updater(); 394 395 $attempts = $overduehander->get_list_of_overdue_attempts(100000); // way in the future 396 $count = 0; 397 foreach ($attempts as $attempt) { 398 $this->assertTrue(isset($usertimes[$attempt->id])); 399 $times = $usertimes[$attempt->id]; 400 $this->assertEquals($times['timeclose'], $attempt->usertimeclose, $times['message']); 401 $this->assertEquals($times['timelimit'], $attempt->usertimelimit, $times['message']); 402 $count++; 403 404 } 405 $attempts->close(); 406 $this->assertEquals($DB->count_records_select('quiz_attempts', 'timecheckstate IS NOT NULL'), $count); 407 408 $attempts = $overduehander->get_list_of_overdue_attempts(0); // before all attempts 409 $count = 0; 410 foreach ($attempts as $attempt) { 411 $count++; 412 } 413 $attempts->close(); 414 $this->assertEquals(0, $count); 415 416 // 417 // Test update_overdue_attempts(). 418 // 419 420 [$count, $quizcount] = $overduehander->update_overdue_attempts(1000, 940); 421 422 $attempts = $DB->get_records('quiz_attempts', null, 'quiz, userid, attempt', 423 'id, quiz, userid, attempt, state, timestart, timefinish, timecheckstate'); 424 foreach ($attempts as $attempt) { 425 $this->assertTrue(isset($usertimes[$attempt->id])); 426 $times = $usertimes[$attempt->id]; 427 $this->assertEquals($times['time1000state'], $attempt->state, $times['message']); 428 switch ($times['time1000state']) { 429 case 'finished': 430 $this->assertEquals($times['timedue'], $attempt->timefinish, $times['message']); 431 $this->assertNull($attempt->timecheckstate, $times['message']); 432 break; 433 434 case 'overdue': 435 $this->assertEquals(0, $attempt->timefinish, $times['message']); 436 $graceperiod = $DB->get_field('quiz', 'graceperiod', ['id' => $attempt->quiz]); 437 $this->assertEquals($times['timedue'] + $graceperiod, $attempt->timecheckstate, $times['message']); 438 break; 439 440 case 'abandoned': 441 $this->assertEquals(0, $attempt->timefinish, $times['message']); 442 $this->assertNull($attempt->timecheckstate, $times['message']); 443 break; 444 } 445 } 446 447 $this->assertEquals(19, $count); 448 $this->assertEquals(19, $quizcount); 449 } 450 451 /** 452 * Make any old question usage for a quiz. 453 * 454 * The attempts used in test_bulk_update_functions must have some 455 * question usage to store in uniqueid, but they don't have to be 456 * very realistic. 457 * 458 * @param \stdClass $quiz 459 * @return int question usage id. 460 */ 461 protected function usage_id(\stdClass $quiz): int { 462 $quba = question_engine::make_questions_usage_by_activity('mod_quiz', 463 \context_module::instance($quiz->cmid)); 464 $quba->set_preferred_behaviour('deferredfeedback'); 465 question_engine::save_questions_usage_by_activity($quba); 466 return $quba->get_id(); 467 } 468 469 /** 470 * Test the group event handlers 471 */ 472 public function test_group_event_handlers() { 473 global $DB; 474 475 $this->resetAfterTest(); 476 477 $this->setAdminUser(); 478 479 // Setup course, user and groups 480 481 $course = $this->getDataGenerator()->create_course(); 482 $user1 = $this->getDataGenerator()->create_user(); 483 $studentrole = $DB->get_record('role', ['shortname' => 'student']); 484 $this->assertNotEmpty($studentrole); 485 $this->assertTrue(enrol_try_internal_enrol($course->id, $user1->id, $studentrole->id)); 486 $group1 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 487 $group2 = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 488 $this->assertTrue(groups_add_member($group1, $user1)); 489 $this->assertTrue(groups_add_member($group2, $user1)); 490 491 /** @var mod_quiz_generator $quizgenerator */ 492 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 493 494 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'timeclose' => 1200, 'timelimit' => 0]); 495 496 // add a group1 override 497 $DB->insert_record('quiz_overrides', 498 ['quiz' => $quiz->id, 'groupid' => $group1->id, 'timeclose' => 1300, 'timelimit' => null]); 499 500 // add an attempt 501 $attemptid = $DB->insert_record('quiz_attempts', ['quiz' => $quiz->id, 'userid' => $user1->id, 'state' => 'inprogress', 502 'timestart' => 100, 'timecheckstate' => 0, 'layout' => '', 'uniqueid' => $this->usage_id($quiz)]); 503 504 // update timecheckstate 505 quiz_update_open_attempts(['quizid' => $quiz->id]); 506 $this->assertEquals(1300, $DB->get_field('quiz_attempts', 'timecheckstate', ['id' => $attemptid])); 507 508 // remove from group 509 $this->assertTrue(groups_remove_member($group1, $user1)); 510 $this->assertEquals(1200, $DB->get_field('quiz_attempts', 'timecheckstate', ['id' => $attemptid])); 511 512 // add back to group 513 $this->assertTrue(groups_add_member($group1, $user1)); 514 $this->assertEquals(1300, $DB->get_field('quiz_attempts', 'timecheckstate', ['id' => $attemptid])); 515 516 // delete group 517 groups_delete_group($group1); 518 $this->assertEquals(1200, $DB->get_field('quiz_attempts', 'timecheckstate', ['id' => $attemptid])); 519 $this->assertEquals(0, $DB->count_records('quiz_overrides', ['quiz' => $quiz->id])); 520 521 // add a group2 override 522 $DB->insert_record('quiz_overrides', 523 ['quiz' => $quiz->id, 'groupid' => $group2->id, 'timeclose' => 1400, 'timelimit' => null]); 524 quiz_update_open_attempts(['quizid' => $quiz->id]); 525 $this->assertEquals(1400, $DB->get_field('quiz_attempts', 'timecheckstate', ['id' => $attemptid])); 526 527 // delete user1 from all groups 528 groups_delete_group_members($course->id, $user1->id); 529 $this->assertEquals(1200, $DB->get_field('quiz_attempts', 'timecheckstate', ['id' => $attemptid])); 530 531 // add back to group2 532 $this->assertTrue(groups_add_member($group2, $user1)); 533 $this->assertEquals(1400, $DB->get_field('quiz_attempts', 'timecheckstate', ['id' => $attemptid])); 534 535 // delete everyone from all groups 536 groups_delete_group_members($course->id); 537 $this->assertEquals(1200, $DB->get_field('quiz_attempts', 'timecheckstate', ['id' => $attemptid])); 538 } 539 540 /** 541 * Test the functions quiz_create_attempt_handling_errors 542 */ 543 public function test_quiz_create_attempt_handling_errors() { 544 $this->resetAfterTest(true); 545 $this->setAdminUser(); 546 547 // Make a quiz. 548 $course = $this->getDataGenerator()->create_course(); 549 $user1 = $this->getDataGenerator()->create_user(); 550 $student = $this->getDataGenerator()->create_user(); 551 $this->getDataGenerator()->enrol_user($student->id, $course->id, 'student'); 552 /** @var mod_quiz_generator $quizgenerator */ 553 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 554 /** @var core_question_generator $questiongenerator */ 555 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); 556 $quiz = $quizgenerator->create_instance(['course' => $course->id, 'questionsperpage' => 0, 'grade' => 100.0, 557 'sumgrades' => 2]); 558 // Create questions. 559 $cat = $questiongenerator->create_question_category(); 560 $saq = $questiongenerator->create_question('shortanswer', null, ['category' => $cat->id]); 561 $numq = $questiongenerator->create_question('numerical', null, ['category' => $cat->id]); 562 // Add them to the quiz. 563 quiz_add_quiz_question($saq->id, $quiz); 564 quiz_add_quiz_question($numq->id, $quiz); 565 $quizobj = quiz::create($quiz->id, $user1->id); 566 $quba = question_engine::make_questions_usage_by_activity('mod_quiz', $quizobj->get_context()); 567 $quba->set_preferred_behaviour($quizobj->get_quiz()->preferredbehaviour); 568 $timenow = time(); 569 // Create an attempt. 570 $attempt = quiz_create_attempt($quizobj, 1, null, $timenow, false, $user1->id); 571 quiz_start_new_attempt($quizobj, $quba, $attempt, 1, $timenow); 572 quiz_attempt_save_started($quizobj, $quba, $attempt); 573 $result = quiz_create_attempt_handling_errors($attempt->id, $quiz->cmid); 574 $this->assertEquals($result->get_attemptid(), $attempt->id); 575 try { 576 $result = quiz_create_attempt_handling_errors($attempt->id, 9999); 577 $this->fail('Exception expected due to invalid course module id.'); 578 } catch (\moodle_exception $e) { 579 $this->assertEquals('invalidcoursemodule', $e->errorcode); 580 } 581 try { 582 quiz_create_attempt_handling_errors(9999, $result->get_cmid()); 583 $this->fail('Exception expected due to quiz content change.'); 584 } catch (\moodle_exception $e) { 585 $this->assertEquals('attempterrorcontentchange', $e->errorcode); 586 } 587 try { 588 quiz_create_attempt_handling_errors(9999); 589 $this->fail('Exception expected due to invalid quiz attempt id.'); 590 } catch (\moodle_exception $e) { 591 $this->assertEquals('attempterrorinvalid', $e->errorcode); 592 } 593 // Set up as normal user without permission to view preview. 594 $this->setUser($student->id); 595 try { 596 quiz_create_attempt_handling_errors(9999, $result->get_cmid()); 597 $this->fail('Exception expected due to quiz content change for user without permission.'); 598 } catch (\moodle_exception $e) { 599 $this->assertEquals('attempterrorcontentchangeforuser', $e->errorcode); 600 } 601 try { 602 quiz_create_attempt_handling_errors($attempt->id, 9999); 603 $this->fail('Exception expected due to invalid course module id for user without permission.'); 604 } catch (\moodle_exception $e) { 605 $this->assertEquals('invalidcoursemodule', $e->errorcode); 606 } 607 } 608 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body