Proyectos de Subversion Moodle

Rev

| 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
/**
18
 * External function test for get_attempts.
19
 *
20
 * @package    mod_h5pactivity
21
 * @category   external
22
 * @since      Moodle 3.9
23
 * @copyright  2020 Ferran Recio <ferran@moodle.com>
24
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25
 */
26
 
27
namespace mod_h5pactivity\external;
28
 
29
defined('MOODLE_INTERNAL') || die();
30
 
31
global $CFG;
32
require_once($CFG->dirroot . '/webservice/tests/helpers.php');
33
 
34
use mod_h5pactivity\local\manager;
35
use core_external\external_api;
36
use externallib_advanced_testcase;
37
 
38
/**
39
 * External function test for get_attempts.
40
 *
41
 * @package    mod_h5pactivity
42
 * @copyright  2020 Ferran Recio <ferran@moodle.com>
43
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44
 */
45
class get_attempts_test extends externallib_advanced_testcase {
46
 
47
    /**
48
     * Test the behaviour of get_attempts.
49
     *
50
     * @dataProvider execute_data
51
     * @param int $grademethod the activity grading method
52
     * @param string $loginuser the user which calls the webservice
53
     * @param string|null $participant the user to get the data
54
     * @param bool $createattempts if the student user has attempts created
55
     * @param int|null $count the expected number of attempts returned (null for exception)
56
     */
57
    public function test_execute(int $grademethod, string $loginuser, ?string $participant,
58
            bool $createattempts, ?int $count): void {
59
 
60
        $this->resetAfterTest();
61
        $this->setAdminUser();
62
 
63
        $course = $this->getDataGenerator()->create_course();
64
        $activity = $this->getDataGenerator()->create_module('h5pactivity',
65
                ['course' => $course, 'enabletracking' => 1, 'grademethod' => $grademethod]);
66
 
67
        $manager = manager::create_from_instance($activity);
68
        $cm = $manager->get_coursemodule();
69
 
70
        // Prepare users: 1 teacher, 2 students, 1 unenroled user.
71
        $users = [
72
            'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'),
73
            'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
74
            'other' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
75
            'noenrolled' => $this->getDataGenerator()->create_user(),
76
        ];
77
 
78
        $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
79
 
80
        if ($createattempts) {
81
            $user = $users['student'];
82
            $params = ['cmid' => $cm->id, 'userid' => $user->id];
83
            $generator->create_content($activity, $params);
84
            $generator->create_content($activity, $params);
85
        }
86
 
87
        // Create another user with 2 attempts to validate no cross attempts are returned.
88
        $user = $users['other'];
89
        $params = ['cmid' => $cm->id, 'userid' => $user->id];
90
        $generator->create_content($activity, $params);
91
        $generator->create_content($activity, $params);
92
 
93
        // Execute external method.
94
        $this->setUser($users[$loginuser]);
95
        $userids = ($participant) ? [$users[$participant]->id] : [];
96
        $checkuserid = ($participant) ? $users[$participant]->id : $users[$loginuser]->id;
97
 
98
        $result = get_attempts::execute($activity->id, $userids);
99
        $result = external_api::clean_returnvalue(
100
            get_attempts::execute_returns(),
101
            $result
102
        );
103
 
104
        // Validate general structure.
105
        $this->assertArrayHasKey('activityid', $result);
106
        $this->assertArrayHasKey('usersattempts', $result);
107
        $this->assertArrayHasKey('warnings', $result);
108
 
109
        $this->assertEquals($activity->id, $result['activityid']);
110
 
111
        if ($count === null) {
112
            $this->assertCount(1, $result['warnings']);
113
            $this->assertCount(0, $result['usersattempts']);
114
            return;
115
        }
116
 
117
        $this->assertCount(0, $result['warnings']);
118
        $this->assertCount(1, $result['usersattempts']);
119
 
120
        $userattempts = $result['usersattempts'][0];
121
        $this->assertEquals($checkuserid, $userattempts['userid']);
122
 
123
        // Validate scored attempts.
124
        if ($grademethod == manager::GRADEMANUAL || $grademethod == manager::GRADEAVERAGEATTEMPT || $count == 0) {
125
            $this->assertArrayNotHasKey('scored', $userattempts);
126
        } else {
127
            $this->assertArrayHasKey('scored', $userattempts);
128
            list($dbgrademethod, $title) = $manager->get_selected_attempt();
129
            $this->assertEquals($grademethod, $dbgrademethod);
130
            $this->assertEquals($grademethod, $userattempts['scored']['grademethod']);
131
            $this->assertEquals($title, $userattempts['scored']['title']);
132
            $this->assertCount(1, $userattempts['scored']['attempts']);
133
        }
134
 
135
        // Validate returned attempts.
136
        $this->assertCount($count, $userattempts['attempts']);
137
        foreach ($userattempts['attempts'] as $attempt) {
138
            $this->assertArrayHasKey('id', $attempt);
139
            $this->assertEquals($checkuserid, $attempt['userid']);
140
            $this->assertArrayHasKey('timecreated', $attempt);
141
            $this->assertArrayHasKey('timemodified', $attempt);
142
            $this->assertArrayHasKey('attempt', $attempt);
143
            $this->assertArrayHasKey('rawscore', $attempt);
144
            $this->assertArrayHasKey('maxscore', $attempt);
145
            $this->assertArrayHasKey('duration', $attempt);
146
            $this->assertArrayHasKey('completion', $attempt);
147
            $this->assertArrayHasKey('success', $attempt);
148
            $this->assertArrayHasKey('scaled', $attempt);
149
        }
150
    }
151
 
152
    /**
153
     * Data provider for the test_execute tests.
154
     *
155
     * @return  array
156
     */
157
    public function execute_data(): array {
158
        return [
159
            // Teacher checking a user with attempts.
160
            'Manual grade, Teacher asking participant with attempts' => [
161
                manager::GRADEMANUAL, 'editingteacher', 'student', true, 2
162
            ],
163
            'Highest grade, Teacher asking participant with attempts' => [
164
                manager::GRADEHIGHESTATTEMPT, 'editingteacher', 'student', true, 2
165
            ],
166
            'Average grade, Teacher asking participant with attempts' => [
167
                manager::GRADEAVERAGEATTEMPT, 'editingteacher', 'student', true, 2
168
            ],
169
            'Last grade, Teacher asking participant with attempts' => [
170
                manager::GRADELASTATTEMPT, 'editingteacher', 'student', true, 2
171
            ],
172
            'First grade, Teacher asking participant with attempts' => [
173
                manager::GRADEFIRSTATTEMPT, 'editingteacher', 'student', true, 2
174
            ],
175
            // Teacher checking a user without attempts.
176
            'Manual grade, Teacher asking participant without attempts' => [
177
                manager::GRADEMANUAL, 'editingteacher', 'student', false, 0
178
            ],
179
            'Highest grade, Teacher asking participant without attempts' => [
180
                manager::GRADEHIGHESTATTEMPT, 'editingteacher', 'student', false, 0
181
            ],
182
            'Average grade, Teacher asking participant without attempts' => [
183
                manager::GRADEAVERAGEATTEMPT, 'editingteacher', 'student', false, 0
184
            ],
185
            'Last grade, Teacher asking participant without attempts' => [
186
                manager::GRADELASTATTEMPT, 'editingteacher', 'student', false, 0
187
            ],
188
            'First grade, Teacher asking participant without attempts' => [
189
                manager::GRADEFIRSTATTEMPT, 'editingteacher', 'student', false, 0
190
            ],
191
            // Student checking own attempts specifying userid.
192
            'Manual grade, check same user attempts report with attempts' => [
193
                manager::GRADEMANUAL, 'student', 'student', true, 2
194
            ],
195
            'Highest grade, check same user attempts report with attempts' => [
196
                manager::GRADEHIGHESTATTEMPT, 'student', 'student', true, 2
197
            ],
198
            'Average grade, check same user attempts report with attempts' => [
199
                manager::GRADEAVERAGEATTEMPT, 'student', 'student', true, 2
200
            ],
201
            'Last grade, check same user attempts report with attempts' => [
202
                manager::GRADELASTATTEMPT, 'student', 'student', true, 2
203
            ],
204
            'First grade, check same user attempts report with attempts' => [
205
                manager::GRADEFIRSTATTEMPT, 'student', 'student', true, 2
206
            ],
207
            // Student checking own attempts.
208
            'Manual grade, check own attempts report with attempts' => [
209
                manager::GRADEMANUAL, 'student', null, true, 2
210
            ],
211
            'Highest grade, check own attempts report with attempts' => [
212
                manager::GRADEHIGHESTATTEMPT, 'student', null, true, 2
213
            ],
214
            'Average grade, check own attempts report with attempts' => [
215
                manager::GRADEAVERAGEATTEMPT, 'student', null, true, 2
216
            ],
217
            'Last grade, check own attempts report with attempts' => [
218
                manager::GRADELASTATTEMPT, 'student', null, true, 2
219
            ],
220
            'First grade, check own attempts report with attempts' => [
221
                manager::GRADEFIRSTATTEMPT, 'student', null, true, 2
222
            ],
223
            // Student checking own report without attempts.
224
            'Manual grade, check own attempts report without attempts' => [
225
                manager::GRADEMANUAL, 'student', 'student', false, 0
226
            ],
227
            'Highest grade, check own attempts report without attempts' => [
228
                manager::GRADEHIGHESTATTEMPT, 'student', 'student', false, 0
229
            ],
230
            'Average grade, check own attempts report without attempts' => [
231
                manager::GRADEAVERAGEATTEMPT, 'student', 'student', false, 0
232
            ],
233
            'Last grade, check own attempts report without attempts' => [
234
                manager::GRADELASTATTEMPT, 'student', 'student', false, 0
235
            ],
236
            'First grade, check own attempts report without attempts' => [
237
                manager::GRADEFIRSTATTEMPT, 'student', 'student', false, 0
238
            ],
239
            // Student trying to get another user attempts.
240
            'Manual grade, student trying to stalk another student' => [
241
                manager::GRADEMANUAL, 'student', 'other', false, null
242
            ],
243
            'Highest grade, student trying to stalk another student' => [
244
                manager::GRADEHIGHESTATTEMPT, 'student', 'other', false, null
245
            ],
246
            'Average grade, student trying to stalk another student' => [
247
                manager::GRADEAVERAGEATTEMPT, 'student', 'other', false, null
248
            ],
249
            'Last grade, student trying to stalk another student' => [
250
                manager::GRADELASTATTEMPT, 'student', 'other', false, null
251
            ],
252
            'First grade, student trying to stalk another student' => [
253
                manager::GRADEFIRSTATTEMPT, 'student', 'other', false, null
254
            ],
255
            // Teacher trying to get a non enroled user attempts.
256
            'Manual grade, teacher trying to get an non enrolled user attempts' => [
257
                manager::GRADEMANUAL, 'editingteacher', 'noenrolled', false, null
258
            ],
259
            'Highest grade, teacher trying to get an non enrolled user attempts' => [
260
                manager::GRADEHIGHESTATTEMPT, 'editingteacher', 'noenrolled', false, null
261
            ],
262
            'Average grade, teacher trying to get an non enrolled user attempts' => [
263
                manager::GRADEAVERAGEATTEMPT, 'editingteacher', 'noenrolled', false, null
264
            ],
265
            'Last grade, teacher trying to get an non enrolled user attempts' => [
266
                manager::GRADELASTATTEMPT, 'editingteacher', 'noenrolled', false, null
267
            ],
268
            'First grade, teacher trying to get an non enrolled user attempts' => [
269
                manager::GRADEFIRSTATTEMPT, 'editingteacher', 'noenrolled', false, null
270
            ],
271
            // Student trying to get a non enroled user attempts.
272
            'Manual grade, student trying to get an non enrolled user attempts' => [
273
                manager::GRADEMANUAL, 'student', 'noenrolled', false, null
274
            ],
275
            'Highest grade, student trying to get an non enrolled user attempts' => [
276
                manager::GRADEHIGHESTATTEMPT, 'student', 'noenrolled', false, null
277
            ],
278
            'Average grade, student trying to get an non enrolled user attempts' => [
279
                manager::GRADEAVERAGEATTEMPT, 'student', 'noenrolled', false, null
280
            ],
281
            'Last grade, student trying to get an non enrolled user attempts' => [
282
                manager::GRADELASTATTEMPT, 'student', 'noenrolled', false, null
283
            ],
284
            'First grade, student trying to get an non enrolled user attempts' => [
285
                manager::GRADEFIRSTATTEMPT, 'student', 'noenrolled', false, null
286
            ],
287
        ];
288
    }
289
 
290
    /**
291
     * Test the behaviour of get_attempts when tracking is not enabled.
292
     *
293
     */
294
    public function test_execute_no_tracking(): void {
295
 
296
        $this->resetAfterTest();
297
        $this->setAdminUser();
298
 
299
        $course = $this->getDataGenerator()->create_course();
300
        $activity = $this->getDataGenerator()->create_module('h5pactivity',
301
                ['course' => $course, 'enabletracking' => 0]);
302
 
303
        $manager = manager::create_from_instance($activity);
304
        $cm = $manager->get_coursemodule();
305
 
306
        // Prepare users: 1 teacher, 1 student.
307
        $users = [
308
            'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'),
309
            'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
310
        ];
311
 
312
        // Execute external method.
313
        $this->setUser($users['editingteacher']);
314
 
315
        $result = get_attempts::execute($activity->id, [$users['student']->id]);
316
        $result = external_api::clean_returnvalue(
317
            get_attempts::execute_returns(),
318
            $result
319
        );
320
 
321
        $this->assertCount(1, $result['warnings']);
322
        $this->assertCount(0, $result['usersattempts']);
323
    }
324
 
325
    /**
326
     * Test the behaviour of get_attempts when own review is not allowed.
327
     *
328
     */
329
    public function test_execute_no_own_review(): void {
330
 
331
        $this->resetAfterTest();
332
        $this->setAdminUser();
333
 
334
        $course = $this->getDataGenerator()->create_course();
335
        $activity = $this->getDataGenerator()->create_module('h5pactivity',
336
                ['course' => $course, 'enabletracking' => 1, 'reviewmode' => manager::REVIEWNONE]);
337
 
338
        $manager = manager::create_from_instance($activity);
339
        $cm = $manager->get_coursemodule();
340
 
341
        // Prepare users: 1 student.
342
        $users = [
343
            'student' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
344
        ];
345
 
346
        // Execute external method.
347
        $this->setUser($users['student']);
348
 
349
        $result = get_attempts::execute($activity->id);
350
        $result = external_api::clean_returnvalue(
351
            get_attempts::execute_returns(),
352
            $result
353
        );
354
 
355
        $this->assertCount(1, $result['warnings']);
356
        $this->assertCount(0, $result['usersattempts']);
357
    }
358
 
359
    /**
360
     * Test the behaviour of get_attempts getting more than one user at once.
361
     *
362
     * @dataProvider execute_multipleusers_data
363
     * @param string $loginuser the user which calls the webservice
364
     * @param string[] $participants the users to get the data
365
     * @param string[] $warnings the expected users with warnings
366
     * @param string[] $resultusers expected users in the resultusers
367
     */
368
    public function test_execute_multipleusers(string $loginuser, array $participants,
369
            array $warnings, array $resultusers): void {
370
 
371
        $this->resetAfterTest();
372
        $this->setAdminUser();
373
 
374
        $course = $this->getDataGenerator()->create_course();
375
        $activity = $this->getDataGenerator()->create_module('h5pactivity',
376
                ['course' => $course]);
377
 
378
        $manager = manager::create_from_instance($activity);
379
        $cm = $manager->get_coursemodule();
380
 
381
        // Prepare users: 1 teacher, 2 students with attempts, 1 student without, 1 no enrolled.
382
        $users = [
383
            'editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'),
384
            'student1' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
385
            'student2' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
386
            'noattempts' => $this->getDataGenerator()->create_and_enrol($course, 'student'),
387
            'noenrolled' => $this->getDataGenerator()->create_user(),
388
        ];
389
 
390
        // Generate attempts (student1 with 1 attempt, student2 with 2).
391
        $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
392
 
393
        $user = $users['student1'];
394
        $params = ['cmid' => $cm->id, 'userid' => $user->id];
395
        $generator->create_content($activity, $params);
396
 
397
        $user = $users['student2'];
398
        $params = ['cmid' => $cm->id, 'userid' => $user->id];
399
        $generator->create_content($activity, $params);
400
        $generator->create_content($activity, $params);
401
 
402
        $countattempts = [
403
            $users['editingteacher']->id => 0,
404
            $users['student1']->id => 1,
405
            $users['student2']->id => 2,
406
            $users['noattempts']->id => 0,
407
            $users['noenrolled']->id => 0,
408
        ];
409
 
410
        // Execute external method.
411
        $this->setUser($users[$loginuser]);
412
 
413
        $userids = [];
414
        foreach ($participants as $participant) {
415
            $userids[] = $users[$participant]->id;
416
        }
417
 
418
        $result = get_attempts::execute($activity->id, $userids);
419
        $result = external_api::clean_returnvalue(
420
            get_attempts::execute_returns(),
421
            $result
422
        );
423
 
424
        $this->assertCount(count($warnings), $result['warnings']);
425
        $this->assertCount(count($resultusers), $result['usersattempts']);
426
 
427
        $expectedwarnings = [];
428
        foreach ($warnings as $warninguser) {
429
            $id = $users[$warninguser]->id;
430
            $expectedwarnings[$id] = $warninguser;
431
        }
432
 
433
        foreach ($result['warnings'] as $warning) {
434
            $this->assertEquals('user', $warning['item']);
435
            $this->assertEquals(1, $warning['warningcode']);
436
            $this->assertArrayHasKey($warning['itemid'], $expectedwarnings);
437
        }
438
 
439
        $expectedusers = [];
440
        foreach ($resultusers as $resultuser) {
441
            $id = $users[$resultuser]->id;
442
            $expectedusers[$id] = $resultuser;
443
        }
444
 
445
        foreach ($result['usersattempts'] as $usersattempts) {
446
            $this->assertArrayHasKey('userid', $usersattempts);
447
            $userid = $usersattempts['userid'];
448
            $this->assertArrayHasKey($userid, $expectedusers);
449
            $this->assertCount($countattempts[$userid], $usersattempts['attempts']);
450
            if ($countattempts[$userid]) {
451
                $this->assertArrayHasKey('scored', $usersattempts);
452
            }
453
        }
454
    }
455
 
456
    /**
457
     * Data provider for the test_execute_multipleusers.
458
     *
459
     * @return  array
460
     */
461
    public function execute_multipleusers_data(): array {
462
        return [
463
            // Teacher checks.
464
            'Teacher checking students with attempts' => [
465
                'editingteacher', ['student1', 'student2'], [], ['student1', 'student2']
466
            ],
467
            'Teacher checking one student with atempts and one not' => [
468
                'editingteacher', ['student1', 'noattempts'], [], ['student1', 'noattempts']
469
            ],
470
            'Teacher checking no students' => [
471
                'editingteacher', [], [], ['editingteacher']
472
            ],
473
            'Teacher checking one student and a no enrolled user' => [
474
                'editingteacher', ['student1', 'noenrolled'], ['noenrolled'], ['student1']
475
            ],
476
            // Student checks.
477
            'Student checking self attempts and another user' => [
478
                'student1', ['student1', 'student2'], ['student2'], ['student1']
479
            ],
480
            'Student checking no students' => [
481
                'student1', [], [], ['student1']
482
            ],
483
            'Student checking self attempts and a no enrolled user' => [
484
                'student1', ['student1', 'noenrolled'], ['noenrolled'], ['student1']
485
            ],
486
        ];
487
    }
488
}