Proyectos de Subversion Moodle

Rev

Ir a la última revisión | | Ultima modificación | Ver Log |

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