Differences Between: [Versions 400 and 403] [Versions 401 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Contains the class containing unit tests for the quiz notify attempt manual grading completed cron task. 19 * 20 * @package mod_quiz 21 * @copyright 2021 The Open University 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace mod_quiz; 26 27 use advanced_testcase; 28 use context_course; 29 use context_module; 30 use mod_quiz\task\quiz_notify_attempt_manual_grading_completed; 31 use question_engine; 32 use mod_quiz\quiz_settings; 33 use stdClass; 34 35 defined('MOODLE_INTERNAL') || die(); 36 37 38 /** 39 * Class containing unit tests for the quiz notify attempt manual grading completed cron task. 40 * 41 * @package mod_quiz 42 * @copyright 2021 The Open University 43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 44 */ 45 class quiz_notify_attempt_manual_grading_completed_test extends advanced_testcase { 46 /** @var \stdClass $course Test course to contain quiz. */ 47 protected $course; 48 49 /** @var \stdClass $quiz A test quiz. */ 50 protected $quiz; 51 52 /** @var context The quiz context. */ 53 protected $context; 54 55 /** @var stdClass The course_module. */ 56 protected $cm; 57 58 /** @var stdClass The student test. */ 59 protected $student; 60 61 /** @var stdClass The teacher test. */ 62 protected $teacher; 63 64 /** @var quiz_settings Object containing the quiz settings. */ 65 protected $quizobj; 66 67 /** @var question_usage_by_activity The question usage for this quiz attempt. */ 68 protected $quba; 69 70 /** 71 * Standard test setup. 72 * 73 * Create a course with a quiz and a student and a(n editing) teacher. 74 * the quiz has a truefalse question and an essay question. 75 * 76 * Also create some bits of a quiz attempt to be used later. 77 */ 78 public function setUp(): void { 79 global $DB; 80 81 $this->resetAfterTest(); 82 $this->setAdminUser(); 83 84 // Setup test data. 85 $this->course = $this->getDataGenerator()->create_course(); 86 $this->quiz = $this->getDataGenerator()->create_module('quiz', ['course' => $this->course->id]); 87 $this->context = context_module::instance($this->quiz->cmid); 88 $this->cm = get_coursemodule_from_instance('quiz', $this->quiz->id); 89 90 // Create users. 91 $this->student = self::getDataGenerator()->create_user(); 92 $this->teacher = self::getDataGenerator()->create_user(); 93 94 // Users enrolments. 95 $studentrole = $DB->get_record('role', ['shortname' => 'student']); 96 $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']); 97 98 // Allow student to receive messages. 99 $coursecontext = context_course::instance($this->course->id); 100 assign_capability('mod/quiz:emailnotifyattemptgraded', CAP_ALLOW, $studentrole->id, $coursecontext, true); 101 102 $this->getDataGenerator()->enrol_user($this->student->id, $this->course->id, $studentrole->id); 103 $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $teacherrole->id); 104 105 // Make a quiz. 106 $quizgenerator = $this->getDataGenerator()->get_plugin_generator('mod_quiz'); 107 $this->quiz = $quizgenerator->create_instance(['course' => $this->course->id, 'questionsperpage' => 0, 108 'grade' => 100.0, 'sumgrades' => 2]); 109 110 // Create a truefalse question and an essay question. 111 $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); 112 $cat = $questiongenerator->create_question_category(); 113 $truefalse = $questiongenerator->create_question('truefalse', null, ['category' => $cat->id]); 114 $essay = $questiongenerator->create_question('essay', null, ['category' => $cat->id]); 115 116 // Add them to the quiz. 117 quiz_add_quiz_question($truefalse->id, $this->quiz); 118 quiz_add_quiz_question($essay->id, $this->quiz); 119 120 $this->quizobj = quiz_settings::create($this->quiz->id); 121 $this->quba = question_engine::make_questions_usage_by_activity('mod_quiz', $this->quizobj->get_context()); 122 $this->quba->set_preferred_behaviour($this->quizobj->get_quiz()->preferredbehaviour); 123 } 124 125 /** 126 * Test SQL querry get list attempt in condition. 127 */ 128 public function test_get_list_of_attempts_within_conditions() { 129 global $DB; 130 131 $timenow = time(); 132 133 // Create an attempt to be completely graded (one hour ago). 134 $attempt1 = quiz_create_attempt($this->quizobj, 1, null, $timenow - HOURSECS, false, $this->student->id); 135 quiz_start_new_attempt($this->quizobj, $this->quba, $attempt1, 1, $timenow - HOURSECS); 136 quiz_attempt_save_started($this->quizobj, $this->quba, $attempt1); 137 138 // Process some responses from the student (30 mins ago) and submit (20 mins ago). 139 $attemptobj1 = quiz_attempt::create($attempt1->id); 140 $tosubmit = [2 => ['answer' => 'Student 1 answer', 'answerformat' => FORMAT_HTML]]; 141 $attemptobj1->process_submitted_actions($timenow - 30 * MINSECS, false, $tosubmit); 142 $attemptobj1->process_finish($timenow - 20 * MINSECS, false); 143 144 // Finish the attempt of student (now). 145 $attemptobj1->get_question_usage()->manual_grade(2, 'Good!', 1, FORMAT_HTML); 146 question_engine::save_questions_usage_by_activity($attemptobj1->get_question_usage()); 147 148 $update = new stdClass(); 149 $update->id = $attemptobj1->get_attemptid(); 150 $update->timemodified = $timenow; 151 $update->sumgrades = $attemptobj1->get_question_usage()->get_total_mark(); 152 $DB->update_record('quiz_attempts', $update); 153 $attemptobj1->get_quizobj()->get_grade_calculator()->recompute_final_grade(); 154 155 // Not quite time to send yet. 156 $task = new quiz_notify_attempt_manual_grading_completed(); 157 $task->set_time_for_testing($timenow + 5 * HOURSECS - 1); 158 $attempts = $task->get_list_of_attempts(); 159 $this->assertEquals(0, iterator_count($attempts)); 160 161 // After time to send. 162 $task->set_time_for_testing($timenow + 5 * HOURSECS + 1); 163 $attempts = $task->get_list_of_attempts(); 164 $this->assertEquals(1, iterator_count($attempts)); 165 } 166 167 /** 168 * Test SQL query does not return attempts if the grading is not complete yet. 169 */ 170 public function test_get_list_of_attempts_without_manual_graded() { 171 172 $timenow = time(); 173 174 // Create an attempt which won't be graded (1 hour ago). 175 $attempt2 = quiz_create_attempt($this->quizobj, 2, null, $timenow - HOURSECS, false, $this->student->id); 176 quiz_start_new_attempt($this->quizobj, $this->quba, $attempt2, 2, $timenow - HOURSECS); 177 quiz_attempt_save_started($this->quizobj, $this->quba, $attempt2); 178 179 // Process some responses from the student (30 mins ago) and submit (now). 180 $attemptobj2 = quiz_attempt::create($attempt2->id); 181 $tosubmit = [2 => ['answer' => 'Answer of student 2.', 'answerformat' => FORMAT_HTML]]; 182 $attemptobj2->process_submitted_actions($timenow - 30 * MINSECS, false, $tosubmit); 183 $attemptobj2->process_finish($timenow, false); 184 185 // After time to notify, except attempt not graded, so it won't appear. 186 $task = new quiz_notify_attempt_manual_grading_completed(); 187 $task->set_time_for_testing($timenow + 5 * HOURSECS + 1); 188 $attempts = $task->get_list_of_attempts(); 189 190 $this->assertEquals(0, iterator_count($attempts)); 191 } 192 193 /** 194 * Test notify manual grading completed task which the user attempt has not capability. 195 */ 196 public function test_notify_manual_grading_completed_task_without_capability() { 197 global $DB; 198 199 // Create an attempt for a user without the capability. 200 $timenow = time(); 201 $attempt = quiz_create_attempt($this->quizobj, 3, null, $timenow, false, $this->teacher->id); 202 quiz_start_new_attempt($this->quizobj, $this->quba, $attempt, 3, $timenow - HOURSECS); 203 quiz_attempt_save_started($this->quizobj, $this->quba, $attempt); 204 205 // Process some responses and submit. 206 $attemptobj = quiz_attempt::create($attempt->id); 207 $tosubmit = [2 => ['answer' => 'Answer of teacher.', 'answerformat' => FORMAT_HTML]]; 208 $attemptobj->process_submitted_actions($timenow - 30 * MINSECS, false, $tosubmit); 209 $attemptobj->process_finish($timenow - 20 * MINSECS, false); 210 211 // Grade the attempt. 212 $attemptobj->get_question_usage()->manual_grade(2, 'Good!', 1, FORMAT_HTML); 213 question_engine::save_questions_usage_by_activity($attemptobj->get_question_usage()); 214 215 $update = new stdClass(); 216 $update->id = $attemptobj->get_attemptid(); 217 $update->timemodified = $timenow; 218 $update->sumgrades = $attemptobj->get_question_usage()->get_total_mark(); 219 $DB->update_record('quiz_attempts', $update); 220 $attemptobj->get_quizobj()->get_grade_calculator()->recompute_final_grade(); 221 222 // Run the quiz notify attempt manual graded task. 223 ob_start(); 224 $task = new quiz_notify_attempt_manual_grading_completed(); 225 $task->set_time_for_testing($timenow + 5 * HOURSECS + 1); 226 $task->execute(); 227 ob_get_clean(); 228 229 $attemptobj = quiz_attempt::create($attempt->id); 230 $this->assertEquals($attemptobj->get_attempt()->timefinish, $attemptobj->get_attempt()->gradednotificationsenttime); 231 } 232 233 /** 234 * Test notify manual grading completed task which the user attempt has capability. 235 */ 236 public function test_notify_manual_grading_completed_task_with_capability() { 237 global $DB; 238 239 // Create an attempt with capability. 240 $timenow = time(); 241 $attempt = quiz_create_attempt($this->quizobj, 4, null, $timenow, false, $this->student->id); 242 quiz_start_new_attempt($this->quizobj, $this->quba, $attempt, 4, $timenow - HOURSECS); 243 quiz_attempt_save_started($this->quizobj, $this->quba, $attempt); 244 245 // Process some responses from the student. 246 $attemptobj = quiz_attempt::create($attempt->id); 247 $tosubmit = [2 => ['answer' => 'Answer of student.', 'answerformat' => FORMAT_HTML]]; 248 $attemptobj->process_submitted_actions($timenow - 30 * MINSECS, false, $tosubmit); 249 $attemptobj->process_finish($timenow - 20 * MINSECS, false); 250 251 // Finish the attempt of student. 252 $attemptobj->get_question_usage()->manual_grade(2, 'Good!', 1, FORMAT_HTML); 253 question_engine::save_questions_usage_by_activity($attemptobj->get_question_usage()); 254 255 $update = new stdClass(); 256 $update->id = $attemptobj->get_attemptid(); 257 $update->timemodified = $timenow; 258 $update->sumgrades = $attemptobj->get_question_usage()->get_total_mark(); 259 $DB->update_record('quiz_attempts', $update); 260 $attemptobj->get_quizobj()->get_grade_calculator()->recompute_final_grade(); 261 262 // Run the quiz notify attempt manual graded task. 263 ob_start(); 264 $task = new quiz_notify_attempt_manual_grading_completed(); 265 $task->set_time_for_testing($timenow + 5 * HOURSECS + 1); 266 $task->execute(); 267 ob_get_clean(); 268 269 $attemptobj = quiz_attempt::create($attempt->id); 270 271 $this->assertNotEquals(null, $attemptobj->get_attempt()->gradednotificationsenttime); 272 $this->assertNotEquals($attemptobj->get_attempt()->timefinish, $attemptobj->get_attempt()->gradednotificationsenttime); 273 } 274 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body