Merge branch 'MDL-81073' of https://github.com/paulholden/moodle
[moodle.git] / mod / quiz / tests / quiz_notify_attempt_manual_grading_completed_test.php
blob0ff60cbc727f9beef1f4ee655df2b9daabcc2248
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.
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/>.
17 /**
18 * Contains the class containing unit tests for the quiz notify attempt manual grading completed cron task.
20 * @package mod_quiz
21 * @copyright 2021 The Open University
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 namespace mod_quiz;
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;
35 defined('MOODLE_INTERNAL') || die();
38 /**
39 * Class containing unit tests for the quiz notify attempt manual grading completed cron task.
41 * @package mod_quiz
42 * @copyright 2021 The Open University
43 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
45 class quiz_notify_attempt_manual_grading_completed_test extends advanced_testcase {
46 /** @var \stdClass $course Test course to contain quiz. */
47 protected $course;
49 /** @var \stdClass $quiz A test quiz. */
50 protected $quiz;
52 /** @var context The quiz context. */
53 protected $context;
55 /** @var stdClass The course_module. */
56 protected $cm;
58 /** @var stdClass The student test. */
59 protected $student;
61 /** @var stdClass The teacher test. */
62 protected $teacher;
64 /** @var quiz_settings Object containing the quiz settings. */
65 protected $quizobj;
67 /** @var question_usage_by_activity The question usage for this quiz attempt. */
68 protected $quba;
70 /**
71 * Standard test setup.
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.
76 * Also create some bits of a quiz attempt to be used later.
78 public function setUp(): void {
79 global $DB;
81 $this->resetAfterTest();
82 $this->setAdminUser();
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);
90 // Create users.
91 $this->student = self::getDataGenerator()->create_user();
92 $this->teacher = self::getDataGenerator()->create_user();
94 // Users enrolments.
95 $studentrole = $DB->get_record('role', ['shortname' => 'student']);
96 $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
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);
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);
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]);
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]);
116 // Add them to the quiz.
117 quiz_add_quiz_question($truefalse->id, $this->quiz);
118 quiz_add_quiz_question($essay->id, $this->quiz);
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);
126 * Test SQL querry get list attempt in condition.
128 public function test_get_list_of_attempts_within_conditions() {
129 global $DB;
131 $timenow = time();
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);
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);
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());
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();
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));
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));
168 * Test SQL query does not return attempts if the grading is not complete yet.
170 public function test_get_list_of_attempts_without_manual_graded() {
172 $timenow = time();
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);
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);
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();
190 $this->assertEquals(0, iterator_count($attempts));
194 * Test notify manual grading completed task which the user attempt has not capability.
196 public function test_notify_manual_grading_completed_task_without_capability() {
197 global $DB;
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);
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);
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());
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();
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();
229 $attemptobj = quiz_attempt::create($attempt->id);
230 $this->assertEquals($attemptobj->get_attempt()->timefinish, $attemptobj->get_attempt()->gradednotificationsenttime);
234 * Test notify manual grading completed task which the user attempt has capability.
236 public function test_notify_manual_grading_completed_task_with_capability() {
237 global $DB;
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);
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);
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());
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();
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();
269 $attemptobj = quiz_attempt::create($attempt->id);
271 $this->assertNotEquals(null, $attemptobj->get_attempt()->gradednotificationsenttime);
272 $this->assertNotEquals($attemptobj->get_attempt()->timefinish, $attemptobj->get_attempt()->gradednotificationsenttime);