Proyectos de Subversion Moodle

Rev

Rev 11 | | Comparar con el anterior | 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 core_completion;
18
 
19
/**
20
 * Test completion API.
21
 *
22
 * @package core_completion
23
 * @category test
24
 * @copyright 2017 Mark Nelson <markn@moodle.com>
25
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1441 ariadna 26
 * @covers \core_completion\api
1 efrain 27
 */
1441 ariadna 28
final class api_test extends \advanced_testcase {
1 efrain 29
 
30
    /**
31
     * Test setup.
32
     */
33
    public function setUp(): void {
1441 ariadna 34
        parent::setUp();
1 efrain 35
        $this->resetAfterTest();
36
    }
37
 
11 efrain 38
    public function test_update_completion_date_event(): void {
1 efrain 39
        global $CFG, $DB;
40
 
41
        $this->setAdminUser();
42
 
43
        // Create a course.
44
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
45
 
46
        // Create an assign activity.
47
        $time = time();
48
        $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
49
 
50
        // Create the completion event.
51
        $CFG->enablecompletion = true;
52
        \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time);
53
 
54
        // Check that there is now an event in the database.
55
        $events = $DB->get_records('event');
56
        $this->assertCount(1, $events);
57
 
58
        // Get the event.
59
        $event = reset($events);
60
 
61
        // Confirm the event is correct.
62
        $this->assertEquals('assign', $event->modulename);
63
        $this->assertEquals($assign->id, $event->instance);
64
        $this->assertEquals(CALENDAR_EVENT_TYPE_ACTION, $event->type);
65
        $this->assertEquals(\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED, $event->eventtype);
66
        $this->assertEquals($time, $event->timestart);
67
        $this->assertEquals($time, $event->timesort);
68
 
69
        require_once($CFG->dirroot . '/course/lib.php');
70
        // Delete the module.
71
        course_delete_module($assign->cmid);
72
 
73
        // Check we don't get a failure when called on a deleted module.
74
        \core_completion\api::update_completion_date_event($assign->cmid, 'assign', null, $time);
75
    }
76
 
11 efrain 77
    public function test_update_completion_date_event_update(): void {
1 efrain 78
        global $CFG, $DB;
79
 
80
        $this->setAdminUser();
81
 
82
        // Create a course.
83
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
84
 
85
        // Create an assign activity.
86
        $time = time();
87
        $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
88
 
89
        // Create the event.
90
        $CFG->enablecompletion = true;
91
        \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time);
92
 
93
        // Call it again, but this time with a different time.
94
        \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time + DAYSECS);
95
 
96
        // Check that there is still only one event in the database.
97
        $events = $DB->get_records('event');
98
        $this->assertCount(1, $events);
99
 
100
        // Get the event.
101
        $event = reset($events);
102
 
103
        // Confirm that the event has been updated.
104
        $this->assertEquals('assign', $event->modulename);
105
        $this->assertEquals($assign->id, $event->instance);
106
        $this->assertEquals(CALENDAR_EVENT_TYPE_ACTION, $event->type);
107
        $this->assertEquals(\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED, $event->eventtype);
108
        $this->assertEquals($time + DAYSECS, $event->timestart);
109
        $this->assertEquals($time + DAYSECS, $event->timesort);
110
    }
111
 
11 efrain 112
    public function test_update_completion_date_event_delete(): void {
1 efrain 113
        global $CFG, $DB;
114
 
115
        $this->setAdminUser();
116
 
117
        // Create a course.
118
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
119
 
120
        // Create an assign activity.
121
        $time = time();
122
        $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
123
 
124
        // Create the event.
125
        $CFG->enablecompletion = true;
126
        \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time);
127
 
128
        // Call it again, but the time specified as null.
129
        \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, null);
130
 
131
        // Check that there is no event in the database.
132
        $this->assertEquals(0, $DB->count_records('event'));
133
    }
134
 
11 efrain 135
    public function test_update_completion_date_event_completion_disabled(): void {
1 efrain 136
        global $CFG, $DB;
137
 
138
        $this->setAdminUser();
139
 
140
        // Create a course.
141
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
142
 
143
        // Create an assign activity.
144
        $time = time();
145
        $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
146
 
147
        // Try and create the completion event with completion disabled.
148
        $CFG->enablecompletion = false;
149
        \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time);
150
 
151
        // Check that there is no event in the database.
152
        $this->assertEquals(0, $DB->count_records('event'));
153
    }
154
 
11 efrain 155
    public function test_update_completion_date_event_update_completion_disabled(): void {
1 efrain 156
        global $CFG, $DB;
157
 
158
        $this->setAdminUser();
159
 
160
        // Create a course.
161
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
162
 
163
        // Create an assign activity.
164
        $time = time();
165
        $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
166
 
167
        // Create the completion event.
168
        $CFG->enablecompletion = true;
169
        \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time);
170
 
171
        // Disable completion.
172
        $CFG->enablecompletion = false;
173
 
174
        // Try and update the completion date.
175
        \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time + DAYSECS);
176
 
177
        // Check that there is an event in the database.
178
        $events = $DB->get_records('event');
179
        $this->assertCount(1, $events);
180
 
181
        // Get the event.
182
        $event = reset($events);
183
 
184
        // Confirm the event has not changed.
185
        $this->assertEquals('assign', $event->modulename);
186
        $this->assertEquals($assign->id, $event->instance);
187
        $this->assertEquals(CALENDAR_EVENT_TYPE_ACTION, $event->type);
188
        $this->assertEquals(\core_completion\api::COMPLETION_EVENT_TYPE_DATE_COMPLETION_EXPECTED, $event->eventtype);
189
        $this->assertEquals($time, $event->timestart);
190
        $this->assertEquals($time, $event->timesort);
191
    }
192
 
11 efrain 193
    public function test_update_completion_date_event_delete_completion_disabled(): void {
1 efrain 194
        global $CFG, $DB;
195
 
196
        $this->setAdminUser();
197
 
198
        // Create a course.
199
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
200
 
201
        // Create an assign activity.
202
        $time = time();
203
        $assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id));
204
 
205
        // Create the completion event.
206
        $CFG->enablecompletion = true;
207
        \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, $time);
208
 
209
        // Disable completion.
210
        $CFG->enablecompletion = false;
211
 
212
        // Should still be able to delete completion events even when completion is disabled.
213
        \core_completion\api::update_completion_date_event($assign->cmid, 'assign', $assign, null);
214
 
215
        // Check that there is now no event in the database.
216
        $this->assertEquals(0, $DB->count_records('event'));
217
    }
218
 
219
    /**
220
     * Test for mark_course_completions_activity_criteria().
221
     */
11 efrain 222
    public function test_mark_course_completions_activity_criteria(): void {
1 efrain 223
        global $DB, $CFG;
224
        require_once($CFG->dirroot.'/completion/criteria/completion_criteria_activity.php');
225
        $this->resetAfterTest(true);
226
 
227
        $course = $this->getDataGenerator()->create_course(array('enablecompletion' => 1));
228
        $student1 = $this->getDataGenerator()->create_user();
229
        $student2 = $this->getDataGenerator()->create_user();
230
 
231
        $teacher = $this->getDataGenerator()->create_user();
232
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
233
        $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
234
 
235
        $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
236
        $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id);
237
        $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id);
238
 
239
        $data = $this->getDataGenerator()->create_module('data', array('course' => $course->id),
240
            array('completion' => 1));
241
        $cmdata = get_coursemodule_from_id('data', $data->cmid);
242
        $cm = get_coursemodule_from_instance('data', $data->id);
243
        $c = new \completion_info($course);
244
 
245
        // Add activity completion criteria.
246
        $criteriadata = new \stdClass();
247
        $criteriadata->id = $course->id;
248
        $criteriadata->criteria_activity = array();
249
        // Some activities.
250
        $criteriadata->criteria_activity[$cmdata->id] = 1;
251
        $criterion = new \completion_criteria_activity();
252
        $criterion->update_config($criteriadata);
253
 
254
        $this->setUser($teacher);
255
 
256
        // Mark activity complete for both users.
257
        $completion = new \stdClass();
258
        $completion->coursemoduleid = $cm->id;
259
        $completion->completionstate = COMPLETION_COMPLETE;
260
        $completion->timemodified = time();
261
        $completion->viewed = COMPLETION_NOT_VIEWED;
262
        $completion->overrideby = null;
263
 
264
        $completion->id = 0;
265
        $completion->userid = $student1->id;
266
        $c->internal_set_data($cm, $completion, true);
267
 
268
        $completion->id = 0;
269
        $completion->userid = $student2->id;
270
        $c->internal_set_data($cm, $completion, true);
271
 
272
        // Run instant course completions for student1. Only student1 will be marked as completed a course.
273
        $userdata = ['userid' => $student1->id, 'courseid' => $course->id];
274
        $actual = $DB->get_records('course_completions');
275
        $this->assertEmpty($actual);
276
 
277
        $coursecompletionid = \core_completion\api::mark_course_completions_activity_criteria($userdata);
278
 
279
        $actual = $DB->get_records('course_completions');
280
        $this->assertEquals(reset($actual)->id, $coursecompletionid);
281
        $this->assertEquals(1, count($actual));
282
        $this->assertEquals($student1->id, reset($actual)->userid);
283
 
284
        // Run course completions cron. Both students will be marked as completed a course.
285
        $coursecompletionid = \core_completion\api::mark_course_completions_activity_criteria();
286
        $this->assertEquals(0, $coursecompletionid);
287
        $actual = $DB->get_records('course_completions');
288
        $students = [$student1->id, $student2->id];
289
        $this->assertEquals(2, count($actual));
290
        $this->assertContains(reset($actual)->userid, $students);
291
        $this->assertContains(end($actual)->userid, $students);
292
    }
293
 
294
    /**
295
     * Test for mark_course_completions_activity_criteria() with different completionpassgrade settings.
296
     */
11 efrain 297
    public function test_mark_course_completions_activity_criteria_completion_states(): void {
1 efrain 298
        global $DB, $CFG;
299
        require_once($CFG->dirroot . '/completion/criteria/completion_criteria_activity.php');
300
        $this->resetAfterTest(true);
301
 
302
        $courses[] = $this->getDataGenerator()->create_course(['shortname' => 'completionpassgradenotset',
303
            'enablecompletion' => 1]);
304
        $courses[] = $this->getDataGenerator()->create_course(['shortname' => 'completionpassgradeset',
305
            'enablecompletion' => 1]);
306
 
307
        $student1 = $this->getDataGenerator()->create_user();
308
        $student2 = $this->getDataGenerator()->create_user();
309
 
310
        $teacher = $this->getDataGenerator()->create_user();
311
        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
312
        $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
313
 
314
        foreach ($courses as $course) {
315
            $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id);
316
            $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id);
317
            $this->getDataGenerator()->enrol_user($student2->id, $course->id, $studentrole->id);
318
 
319
            $completioncriteria = [
320
                'completionusegrade' => 1,
321
                'gradepass' => 50
322
            ];
323
 
324
            if ($course->shortname == 'completionpassgradeset') {
325
                $completioncriteria['completionpassgrade'] = 1;
326
            }
327
 
328
            /** @var \mod_assign_generator $assigngenerator */
329
            $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
330
            $assign = $assigngenerator->create_instance([
331
                    'course' => $course->id,
332
                    'completion' => COMPLETION_ENABLED,
333
                ] + $completioncriteria);
334
 
335
            $cmassing = get_coursemodule_from_id('assign', $assign->cmid);
336
            $cm = get_coursemodule_from_instance('assign', $assign->id);
337
            $c = new \completion_info($course);
338
 
339
            // Add activity completion criteria.
340
            $criteriadata = new \stdClass();
341
            $criteriadata->id = $course->id;
342
            $criteriadata->criteria_activity = array();
343
            // Some activities.
344
            $criteriadata->criteria_activity[$cmassing->id] = 1;
345
            $criterion = new \completion_criteria_activity();
346
            $criterion->update_config($criteriadata);
347
 
348
            $this->setUser($teacher);
349
 
350
            // Mark user completions.
351
            $completion = new \stdClass();
352
            $completion->coursemoduleid = $cm->id;
353
            $completion->timemodified = time();
354
            $completion->viewed = COMPLETION_NOT_VIEWED;
355
            $completion->overrideby = null;
356
 
357
            // Student1 achieved passgrade.
358
            $completion->id = 0;
359
            $completion->completionstate = COMPLETION_COMPLETE_PASS;
360
            $completion->userid = $student1->id;
361
            $c->internal_set_data($cm, $completion, true);
362
 
363
            // Student2 has not achieved passgrade.
364
            $completion->id = 0;
365
            $completion->completionstate = COMPLETION_COMPLETE_FAIL;
366
            $completion->userid = $student2->id;
367
            $c->internal_set_data($cm, $completion, true);
368
 
369
            $actual = $DB->get_records('course_completions', ['course' => $course->id]);
370
            $this->assertEmpty($actual);
371
 
372
            // Run course completions cron.
373
            $coursecompletionid = \core_completion\api::mark_course_completions_activity_criteria();
374
            $this->assertEquals(0, $coursecompletionid);
375
            $actual = $DB->get_records('course_completions', ['course' => $course->id]);
376
 
377
            if ($course->shortname == 'completionpassgradeset') {
378
                // Only student1 has completed a course.
379
                $this->assertEquals(1, count($actual));
380
                $this->assertEquals($student1->id, reset($actual)->userid);
381
            } else {
382
                // Both students completed a course.
383
                $students = [$student1->id, $student2->id];
384
                $this->assertEquals(2, count($actual));
385
                $this->assertContains(reset($actual)->userid, $students);
386
                $this->assertContains(end($actual)->userid, $students);
387
            }
388
        }
389
    }
390
}