MDL-50349 scorm: New WS mod_scorm_get_scorms_by_courses
[moodle.git] / mod / scorm / tests / externallib_test.php
CommitLineData
e9bf3011
JL
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 * SCORM module external functions tests
19 *
20 * @package mod_scorm
21 * @category external
22 * @copyright 2015 Juan Leyva <juan@moodle.com>
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 * @since Moodle 3.0
25 */
26
27defined('MOODLE_INTERNAL') || die();
28
29global $CFG;
30
31require_once($CFG->dirroot . '/webservice/tests/helpers.php');
32require_once($CFG->dirroot . '/mod/scorm/lib.php');
33
34/**
35 * SCORM module external functions tests
36 *
37 * @package mod_scorm
38 * @category external
39 * @copyright 2015 Juan Leyva <juan@moodle.com>
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41 * @since Moodle 3.0
42 */
43class mod_scorm_external_testcase extends externallib_advanced_testcase {
44
45 /**
22de67f4 46 * Set up for every test
e9bf3011 47 */
22de67f4 48 public function setUp() {
e9bf3011 49 global $DB;
22de67f4 50 $this->resetAfterTest();
e9bf3011 51 $this->setAdminUser();
22de67f4 52
e9bf3011 53 // Setup test data.
22de67f4
JL
54 $this->course = $this->getDataGenerator()->create_course();
55 $this->scorm = $this->getDataGenerator()->create_module('scorm', array('course' => $this->course->id));
56 $this->context = context_module::instance($this->scorm->cmid);
57 $this->cm = get_coursemodule_from_instance('scorm', $this->scorm->id);
58
59 // Create users.
60 $this->student = self::getDataGenerator()->create_user();
61 $this->teacher = self::getDataGenerator()->create_user();
62
63 // Users enrolments.
64 $this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
65 $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
66 $this->getDataGenerator()->enrol_user($this->student->id, $this->course->id, $this->studentrole->id, 'manual');
67 $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
68 }
69
70 /**
71 * Test view_scorm
72 */
73 public function test_view_scorm() {
74 global $DB;
e9bf3011
JL
75
76 // Test invalid instance id.
77 try {
78 mod_scorm_external::view_scorm(0);
79 $this->fail('Exception expected due to invalid mod_scorm instance id.');
80 } catch (moodle_exception $e) {
81 $this->assertEquals('invalidrecord', $e->errorcode);
82 }
83
84 // Test not-enrolled user.
85 $user = self::getDataGenerator()->create_user();
86 $this->setUser($user);
87 try {
22de67f4 88 mod_scorm_external::view_scorm($this->scorm->id);
e9bf3011
JL
89 $this->fail('Exception expected due to not enrolled user.');
90 } catch (moodle_exception $e) {
91 $this->assertEquals('requireloginerror', $e->errorcode);
92 }
93
94 // Test user with full capabilities.
22de67f4
JL
95 $this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
96 $this->getDataGenerator()->enrol_user($user->id, $this->course->id, $this->studentrole->id);
e9bf3011
JL
97
98 // Trigger and capture the event.
99 $sink = $this->redirectEvents();
100
22de67f4 101 $result = mod_scorm_external::view_scorm($this->scorm->id);
e9bf3011
JL
102 $result = external_api::clean_returnvalue(mod_scorm_external::view_scorm_returns(), $result);
103
104 $events = $sink->get_events();
105 $this->assertCount(1, $events);
106 $event = array_shift($events);
107
108 // Checking that the event contains the expected values.
109 $this->assertInstanceOf('\mod_scorm\event\course_module_viewed', $event);
22de67f4
JL
110 $this->assertEquals($this->context, $event->get_context());
111 $moodleurl = new \moodle_url('/mod/scorm/view.php', array('id' => $this->cm->id));
e9bf3011
JL
112 $this->assertEquals($moodleurl, $event->get_url());
113 $this->assertEventContextNotUsed($event);
114 $this->assertNotEmpty($event->get_name());
115 }
22de67f4
JL
116
117 /**
118 * Test get scorm attempt count
119 */
120 public function test_mod_scorm_get_scorm_attempt_count_own_empty() {
121 // Set to the student user.
122 self::setUser($this->student);
123
124 // Retrieve my attempts (should be 0).
125 $result = mod_scorm_external::get_scorm_attempt_count($this->scorm->id, $this->student->id);
126 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_attempt_count_returns(), $result);
127 $this->assertEquals(0, $result['attemptscount']);
128 }
129
130 public function test_mod_scorm_get_scorm_attempt_count_own_with_complete() {
131 // Set to the student user.
132 self::setUser($this->student);
133
134 // Create attempts.
135 $scoes = scorm_get_scoes($this->scorm->id);
136 $sco = array_shift($scoes);
137 scorm_insert_track($this->student->id, $this->scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed');
138 scorm_insert_track($this->student->id, $this->scorm->id, $sco->id, 2, 'cmi.core.lesson_status', 'completed');
139
140 $result = mod_scorm_external::get_scorm_attempt_count($this->scorm->id, $this->student->id);
141 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_attempt_count_returns(), $result);
142 $this->assertEquals(2, $result['attemptscount']);
143 }
144
145 public function test_mod_scorm_get_scorm_attempt_count_own_incomplete() {
146 // Set to the student user.
147 self::setUser($this->student);
148
149 // Create a complete attempt, and an incomplete attempt.
150 $scoes = scorm_get_scoes($this->scorm->id);
151 $sco = array_shift($scoes);
152 scorm_insert_track($this->student->id, $this->scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed');
153 scorm_insert_track($this->student->id, $this->scorm->id, $sco->id, 2, 'cmi.core.credit', '0');
154
155 $result = mod_scorm_external::get_scorm_attempt_count($this->scorm->id, $this->student->id, true);
156 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_attempt_count_returns(), $result);
157 $this->assertEquals(1, $result['attemptscount']);
158 }
159
160 public function test_mod_scorm_get_scorm_attempt_count_others_as_teacher() {
161 // As a teacher.
162 self::setUser($this->teacher);
163
164 // Create a completed attempt for student.
165 $scoes = scorm_get_scoes($this->scorm->id);
166 $sco = array_shift($scoes);
167 scorm_insert_track($this->student->id, $this->scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed');
168
169 // I should be able to view the attempts for my students.
170 $result = mod_scorm_external::get_scorm_attempt_count($this->scorm->id, $this->student->id);
171 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_attempt_count_returns(), $result);
172 $this->assertEquals(1, $result['attemptscount']);
173 }
174
175 public function test_mod_scorm_get_scorm_attempt_count_others_as_student() {
176 // Create a second student.
177 $student2 = self::getDataGenerator()->create_user();
178 $this->getDataGenerator()->enrol_user($student2->id, $this->course->id, $this->studentrole->id, 'manual');
179
180 // As a student.
181 self::setUser($student2);
182
183 // I should not be able to view the attempts of another student.
184 $this->setExpectedException('required_capability_exception');
185 mod_scorm_external::get_scorm_attempt_count($this->scorm->id, $this->student->id);
186 }
187
188 public function test_mod_scorm_get_scorm_attempt_count_invalid_instanceid() {
189 // As student.
190 self::setUser($this->student);
191
192 // Test invalid instance id.
193 $this->setExpectedException('moodle_exception');
194 mod_scorm_external::get_scorm_attempt_count(0, $this->student->id);
195 }
196
197 public function test_mod_scorm_get_scorm_attempt_count_invalid_userid() {
198 // As student.
199 self::setUser($this->student);
200
201 $this->setExpectedException('moodle_exception');
202 mod_scorm_external::get_scorm_attempt_count($this->scorm->id, -1);
203 }
dfe927c8
JL
204
205 /**
206 * Test get scorm scoes
207 */
208 public function test_mod_scorm_get_scorm_scoes() {
209 global $DB;
210
211 $this->resetAfterTest(true);
212
213 // Create users.
214 $student = self::getDataGenerator()->create_user();
215 $teacher = self::getDataGenerator()->create_user();
216
217 // Set to the student user.
218 self::setUser($student);
219
220 // Create courses to add the modules.
221 $course = self::getDataGenerator()->create_course();
222
223 // First scorm, dates restriction.
224 $record = new stdClass();
225 $record->course = $course->id;
226 $record->timeopen = time() + DAYSECS;
227 $record->timeclose = $record->timeopen + DAYSECS;
228 $scorm = self::getDataGenerator()->create_module('scorm', $record);
229
230 // Users enrolments.
231 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
232 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
233 $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual');
234 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual');
235
236 // Retrieve my scoes, warning!.
237 try {
238 mod_scorm_external::get_scorm_scoes($scorm->id);
239 $this->fail('Exception expected due to invalid dates.');
240 } catch (moodle_exception $e) {
241 $this->assertEquals('notopenyet', $e->errorcode);
242 }
243
244 $scorm->timeopen = time() - DAYSECS;
245 $scorm->timeclose = time() - HOURSECS;
246 $DB->update_record('scorm', $scorm);
247
248 try {
249 mod_scorm_external::get_scorm_scoes($scorm->id);
250 $this->fail('Exception expected due to invalid dates.');
251 } catch (moodle_exception $e) {
252 $this->assertEquals('expired', $e->errorcode);
253 }
254
255 // Retrieve my scoes, user with permission.
256 self::setUser($teacher);
257 $result = mod_scorm_external::get_scorm_scoes($scorm->id);
258 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_scoes_returns(), $result);
259 $this->assertCount(2, $result['scoes']);
260 $this->assertCount(0, $result['warnings']);
261
262 $scoes = scorm_get_scoes($scorm->id);
263 $sco = array_shift($scoes);
264 $this->assertEquals((array) $sco, $result['scoes'][0]);
265
266 $sco = array_shift($scoes);
267 // Remove specific sco data.
268 unset($sco->isvisible);
269 unset($sco->parameters);
270 $this->assertEquals((array) $sco, $result['scoes'][1]);
271
272 // Use organization.
273 $organization = 'golf_sample_default_org';
274 $result = mod_scorm_external::get_scorm_scoes($scorm->id, $organization);
275 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_scoes_returns(), $result);
276 $this->assertCount(1, $result['scoes']);
277 $this->assertEquals($organization, $result['scoes'][0]['organization']);
278 $this->assertCount(0, $result['warnings']);
279
280 // Test invalid instance id.
281 try {
282 mod_scorm_external::get_scorm_scoes(0);
283 $this->fail('Exception expected due to invalid instance id.');
284 } catch (moodle_exception $e) {
285 $this->assertEquals('invalidrecord', $e->errorcode);
286 }
287 }
822e9df7
JL
288
289 /*
290 * Test get scorm user data
291 */
292 public function test_mod_scorm_get_scorm_user_data() {
293 global $DB;
294
295 $this->resetAfterTest(true);
296
297 // Create users.
298 $student1 = self::getDataGenerator()->create_user();
299 $teacher = self::getDataGenerator()->create_user();
300
301 // Set to the student user.
302 self::setUser($student1);
303
304 // Create courses to add the modules.
305 $course = self::getDataGenerator()->create_course();
306
307 // First scorm.
308 $record = new stdClass();
309 $record->course = $course->id;
310 $scorm = self::getDataGenerator()->create_module('scorm', $record);
311
312 // Users enrolments.
313 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
314 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
315 $this->getDataGenerator()->enrol_user($student1->id, $course->id, $studentrole->id, 'manual');
316 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual');
317
318 // Create attempts.
319 $scoes = scorm_get_scoes($scorm->id);
320 $sco = array_shift($scoes);
321 scorm_insert_track($student1->id, $scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed');
322 scorm_insert_track($student1->id, $scorm->id, $sco->id, 1, 'cmi.core.score.raw', '80');
323 scorm_insert_track($student1->id, $scorm->id, $sco->id, 2, 'cmi.core.lesson_status', 'completed');
324
325 $result = mod_scorm_external::get_scorm_user_data($scorm->id, 1);
326 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_user_data_returns(), $result);
327 $this->assertCount(2, $result['data']);
328 // Find our tracking data.
329 $found = 0;
330 foreach ($result['data'] as $scodata) {
331 foreach ($scodata['userdata'] as $userdata) {
332 if ($userdata['element'] == 'cmi.core.lesson_status' and $userdata['value'] == 'completed') {
333 $found++;
334 }
335 if ($userdata['element'] == 'cmi.core.score.raw' and $userdata['value'] == '80') {
336 $found++;
337 }
338 }
339 }
340 $this->assertEquals(2, $found);
341
342 // Test invalid instance id.
343 try {
344 mod_scorm_external::get_scorm_user_data(0, 1);
345 $this->fail('Exception expected due to invalid instance id.');
346 } catch (moodle_exception $e) {
347 $this->assertEquals('invalidrecord', $e->errorcode);
348 }
349 }
6b4ceb24
JL
350
351 /**
352 * Test insert scorm tracks
353 */
354 public function test_mod_scorm_insert_scorm_tracks() {
355 global $DB;
356
357 $this->resetAfterTest(true);
358
359 // Create users.
360 $student = self::getDataGenerator()->create_user();
361
362 // Set to the student user.
363 self::setUser($student);
364
365 // Create courses to add the modules.
366 $course = self::getDataGenerator()->create_course();
367
368 // First scorm, dates restriction.
369 $record = new stdClass();
370 $record->course = $course->id;
371 $record->timeopen = time() + DAYSECS;
372 $record->timeclose = $record->timeopen + DAYSECS;
373 $scorm = self::getDataGenerator()->create_module('scorm', $record);
374
375 // Get a SCO.
376 $scoes = scorm_get_scoes($scorm->id);
377 $sco = array_shift($scoes);
378
379 // Tracks.
380 $tracks = array();
381 $tracks[] = array(
382 'element' => 'cmi.core.lesson_status',
383 'value' => 'completed'
384 );
385 $tracks[] = array(
386 'element' => 'cmi.core.score.raw',
387 'value' => '80'
388 );
389
390 // Users enrolments.
391 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
392 $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual');
393
394 // Exceptions first.
395 try {
396 mod_scorm_external::insert_scorm_tracks($sco->id, 1, $tracks);
397 $this->fail('Exception expected due to dates');
398 } catch (moodle_exception $e) {
399 $this->assertEquals('notopenyet', $e->errorcode);
400 }
401
402 $scorm->timeopen = time() - DAYSECS;
403 $scorm->timeclose = time() - HOURSECS;
404 $DB->update_record('scorm', $scorm);
405
406 try {
407 mod_scorm_external::insert_scorm_tracks($sco->id, 1, $tracks);
408 $this->fail('Exception expected due to dates');
409 } catch (moodle_exception $e) {
410 $this->assertEquals('expired', $e->errorcode);
411 }
412
413 // Test invalid instance id.
414 try {
415 mod_scorm_external::insert_scorm_tracks(0, 1, $tracks);
416 $this->fail('Exception expected due to invalid sco id.');
417 } catch (moodle_exception $e) {
418 $this->assertEquals('cannotfindsco', $e->errorcode);
419 }
420
421 $scorm->timeopen = 0;
422 $scorm->timeclose = 0;
423 $DB->update_record('scorm', $scorm);
424
425 // Retrieve my tracks.
426 $result = mod_scorm_external::insert_scorm_tracks($sco->id, 1, $tracks);
427 $result = external_api::clean_returnvalue(mod_scorm_external::insert_scorm_tracks_returns(), $result);
428 $this->assertCount(0, $result['warnings']);
429
430 $trackids = $DB->get_records('scorm_scoes_track', array('userid' => $student->id, 'scoid' => $sco->id,
431 'scormid' => $scorm->id, 'attempt' => 1));
f26274a4
JL
432 // We use asort here to prevent problems with ids ordering.
433 $expectedkeys = array_keys($trackids);
434 $this->assertEquals(asort($expectedkeys), asort($result['trackids']));
6b4ceb24 435 }
6b5e69eb
JL
436
437 /**
438 * Test get scorm sco tracks
439 */
440 public function test_mod_scorm_get_scorm_sco_tracks() {
441 global $DB;
442
443 $this->resetAfterTest(true);
444
445 // Create users.
446 $student = self::getDataGenerator()->create_user();
447 $otherstudent = self::getDataGenerator()->create_user();
448 $teacher = self::getDataGenerator()->create_user();
449
450 // Set to the student user.
451 self::setUser($student);
452
453 // Create courses to add the modules.
454 $course = self::getDataGenerator()->create_course();
455
456 // First scorm.
457 $record = new stdClass();
458 $record->course = $course->id;
459 $scorm = self::getDataGenerator()->create_module('scorm', $record);
460
461 // Users enrolments.
462 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
463 $teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
464 $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual');
465 $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual');
466
467 // Create attempts.
468 $scoes = scorm_get_scoes($scorm->id);
469 $sco = array_shift($scoes);
470 scorm_insert_track($student->id, $scorm->id, $sco->id, 1, 'cmi.core.lesson_status', 'completed');
471 scorm_insert_track($student->id, $scorm->id, $sco->id, 1, 'cmi.core.score.raw', '80');
472 scorm_insert_track($student->id, $scorm->id, $sco->id, 2, 'cmi.core.lesson_status', 'completed');
473
474 $result = mod_scorm_external::get_scorm_sco_tracks($sco->id, $student->id, 1);
475 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_sco_tracks_returns(), $result);
476 // 7 default elements + 2 custom ones.
35219d8b
JL
477 $this->assertCount(9, $result['data']['tracks']);
478 $this->assertEquals(1, $result['data']['attempt']);
6b5e69eb
JL
479 // Find our tracking data.
480 $found = 0;
35219d8b 481 foreach ($result['data']['tracks'] as $userdata) {
6b5e69eb
JL
482 if ($userdata['element'] == 'cmi.core.lesson_status' and $userdata['value'] == 'completed') {
483 $found++;
484 }
485 if ($userdata['element'] == 'cmi.core.score.raw' and $userdata['value'] == '80') {
486 $found++;
487 }
488 }
489 $this->assertEquals(2, $found);
490
491 // Capabilities check.
492 try {
493 mod_scorm_external::get_scorm_sco_tracks($sco->id, $otherstudent->id);
494 $this->fail('Exception expected due to invalid instance id.');
495 } catch (required_capability_exception $e) {
496 $this->assertEquals('nopermissions', $e->errorcode);
497 }
498
499 self::setUser($teacher);
35219d8b 500 // Ommit the attempt parameter, the function should calculate the last attempt.
6b5e69eb
JL
501 $result = mod_scorm_external::get_scorm_sco_tracks($sco->id, $student->id);
502 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_sco_tracks_returns(), $result);
503 // 7 default elements + 1 custom one.
35219d8b
JL
504 $this->assertCount(8, $result['data']['tracks']);
505 $this->assertEquals(2, $result['data']['attempt']);
6b5e69eb
JL
506
507 // Test invalid instance id.
508 try {
509 mod_scorm_external::get_scorm_sco_tracks(0, 1);
510 $this->fail('Exception expected due to invalid instance id.');
511 } catch (moodle_exception $e) {
512 $this->assertEquals('cannotfindsco', $e->errorcode);
513 }
514 // Invalid user.
515 try {
516 mod_scorm_external::get_scorm_sco_tracks($sco->id, 0);
517 $this->fail('Exception expected due to invalid instance id.');
518 } catch (moodle_exception $e) {
519 $this->assertEquals('invaliduser', $e->errorcode);
520 }
521 }
91ea3678
JL
522
523 /*
524 * Test get scorms by courses
525 */
526 public function test_mod_scorm_get_scorms_by_courses() {
527 global $DB;
528
529 $this->resetAfterTest(true);
530
531 // Create users.
532 $student = self::getDataGenerator()->create_user();
533 $teacher = self::getDataGenerator()->create_user();
534
535 // Set to the student user.
536 self::setUser($student);
537
538 // Create courses to add the modules.
539 $course1 = self::getDataGenerator()->create_course();
540 $course2 = self::getDataGenerator()->create_course();
541
542 // First scorm.
543 $record = new stdClass();
544 $record->introformat = FORMAT_HTML;
545 $record->course = $course1->id;
546 $scorm1 = self::getDataGenerator()->create_module('scorm', $record);
547
548 // Second scorm.
549 $record = new stdClass();
550 $record->introformat = FORMAT_HTML;
551 $record->course = $course2->id;
552 $scorm2 = self::getDataGenerator()->create_module('scorm', $record);
553
554 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
555 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
556
557 // Users enrolments.
558 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
559 $this->getDataGenerator()->enrol_user($teacher->id, $course1->id, $teacherrole->id, 'manual');
560
561 // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
562 $enrol = enrol_get_plugin('manual');
563 $enrolinstances = enrol_get_instances($course2->id, true);
564 foreach ($enrolinstances as $courseenrolinstance) {
565 if ($courseenrolinstance->enrol == "manual") {
566 $instance2 = $courseenrolinstance;
567 break;
568 }
569 }
570 $enrol->enrol_user($instance2, $student->id, $studentrole->id);
571
572 $returndescription = mod_scorm_external::get_scorms_by_courses_returns();
573
574 // Test open/close dates.
575
576 $timenow = time();
577 $scorm1->timeopen = $timenow - DAYSECS;
578 $scorm1->timeclose = $timenow - HOURSECS;
579 $DB->update_record('scorm', $scorm1);
580
581 $result = mod_scorm_external::get_scorms_by_courses(array($course1->id));
582 $result = external_api::clean_returnvalue($returndescription, $result);
583 $this->assertCount(1, $result['warnings']);
584 // Only 'id', 'coursemodule', 'course', 'name', 'intro', 'introformat'.
585 $this->assertCount(6, $result['scorms'][0]);
586 $this->assertEquals('expired', $result['warnings'][0]['warningcode']);
587
588 $scorm1->timeopen = $timenow + DAYSECS;
589 $scorm1->timeclose = $scorm1->timeopen + DAYSECS;
590 $DB->update_record('scorm', $scorm1);
591
592 $result = mod_scorm_external::get_scorms_by_courses(array($course1->id));
593 $result = external_api::clean_returnvalue($returndescription, $result);
594 $this->assertCount(1, $result['warnings']);
595 // Only 'id', 'coursemodule', 'course', 'name', 'intro', 'introformat'.
596 $this->assertCount(6, $result['scorms'][0]);
597 $this->assertEquals('notopenyet', $result['warnings'][0]['warningcode']);
598
599 // Reset times.
600 $scorm1->timeopen = 0;
601 $scorm1->timeclose = 0;
602 $DB->update_record('scorm', $scorm1);
603
604 // Create what we expect to be returned when querying the two courses.
605 // First for the student user.
606 $expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'version', 'maxgrade',
607 'grademethod', 'whatgrade', 'maxattempt', 'forcecompleted', 'forcenewattempt', 'lastattemptlock',
608 'displayattemptstatus', 'displaycoursestructure', 'sha1hash', 'md5hash', 'revision', 'launch',
609 'skipview', 'hidebrowse', 'hidetoc', 'nav', 'navpositionleft', 'navpositiontop', 'auto',
610 'popup', 'width', 'height', 'timeopen', 'timeclose', 'displayactivityname', 'packagesize',
611 'packageurl', 'scormtype', 'reference');
612
613 // Add expected coursemodule and data.
614 $scorm1->coursemodule = $scorm1->cmid;
615 $scorm1->section = 0;
616 $scorm1->visible = true;
617 $scorm1->groupmode = 0;
618 $scorm1->groupingid = 0;
619
620 $scorm2->coursemodule = $scorm2->cmid;
621 $scorm2->section = 0;
622 $scorm2->visible = true;
623 $scorm2->groupmode = 0;
624 $scorm2->groupingid = 0;
625
626 // SCORM size. The same package is used in both SCORMs.
627 $scormcontext1 = context_module::instance($scorm1->cmid);
628 $scormcontext2 = context_module::instance($scorm2->cmid);
629 $fs = get_file_storage();
630 $packagefile = $fs->get_file($scormcontext1->id, 'mod_scorm', 'package', 0, '/', $scorm1->reference);
631 $packagesize = $packagefile->get_filesize();
632
633 $packageurl1 = moodle_url::make_webservice_pluginfile_url(
634 $scormcontext1->id, 'mod_scorm', 'package', 0, '/', $scorm1->reference)->out(false);
635 $packageurl2 = moodle_url::make_webservice_pluginfile_url(
636 $scormcontext2->id, 'mod_scorm', 'package', 0, '/', $scorm2->reference)->out(false);
637
638 $scorm1->packagesize = $packagesize;
639 $scorm1->packageurl = $packageurl1;
640 $scorm2->packagesize = $packagesize;
641 $scorm2->packageurl = $packageurl2;
642
643 $expected1 = array();
644 $expected2 = array();
645 foreach ($expectedfields as $field) {
646
647 // Since we return the fields used as boolean as PARAM_BOOL instead PARAM_INT we need to force casting here.
648 // From the returned fields definition we obtain the type expected for the field.
649 $fieldtype = $returndescription->keys['scorms']->content->keys[$field]->type;
650 if ($fieldtype == PARAM_BOOL) {
651 $expected1[$field] = (bool) $scorm1->{$field};
652 $expected2[$field] = (bool) $scorm2->{$field};
653 } else {
654 $expected1[$field] = $scorm1->{$field};
655 $expected2[$field] = $scorm2->{$field};
656 }
657 }
658
659 $expectedscorms = array();
660 $expectedscorms[] = $expected2;
661 $expectedscorms[] = $expected1;
662
663 // Call the external function passing course ids.
664 $result = mod_scorm_external::get_scorms_by_courses(array($course2->id, $course1->id));
665 $result = external_api::clean_returnvalue($returndescription, $result);
666 $this->assertEquals($expectedscorms, $result['scorms']);
667
668 // Call the external function without passing course id.
669 $result = mod_scorm_external::get_scorms_by_courses();
670 $result = external_api::clean_returnvalue($returndescription, $result);
671 $this->assertEquals($expectedscorms, $result['scorms']);
672
673 // Unenrol user from second course and alter expected scorms.
674 $enrol->unenrol_user($instance2, $student->id);
675 array_shift($expectedscorms);
676
677 // Call the external function without passing course id.
678 $result = mod_scorm_external::get_scorms_by_courses();
679 $result = external_api::clean_returnvalue($returndescription, $result);
680 $this->assertEquals($expectedscorms, $result['scorms']);
681
682 // Call for the second course we unenrolled the user from, expected warning.
683 $result = mod_scorm_external::get_scorms_by_courses(array($course2->id));
684 $this->assertCount(1, $result['warnings']);
685 $this->assertEquals('1', $result['warnings'][0]['warningcode']);
686 $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
687
688 // Now, try as a teacher for getting all the additional fields.
689 self::setUser($teacher);
690
691 $additionalfields = array('updatefreq', 'timemodified', 'options',
692 'completionstatusrequired', 'completionscorerequired', 'autocommit',
693 'section', 'visible', 'groupmode', 'groupingid');
694
695 foreach ($additionalfields as $field) {
696 $fieldtype = $returndescription->keys['scorms']->content->keys[$field]->type;
697
698 if ($fieldtype == PARAM_BOOL) {
699 $expectedscorms[0][$field] = (bool) $scorm1->{$field};
700 } else {
701 $expectedscorms[0][$field] = $scorm1->{$field};
702 }
703 }
704
705 $result = mod_scorm_external::get_scorms_by_courses();
706 $result = external_api::clean_returnvalue($returndescription, $result);
707 $this->assertEquals($expectedscorms, $result['scorms']);
708
709 // Even with the SCORM closed in time teacher should retrieve the info.
710 $scorm1->timeopen = $timenow - DAYSECS;
711 $scorm1->timeclose = $timenow - HOURSECS;
712 $DB->update_record('scorm', $scorm1);
713
714 $expectedscorms[0]['timeopen'] = $scorm1->timeopen;
715 $expectedscorms[0]['timeclose'] = $scorm1->timeclose;
716
717 $result = mod_scorm_external::get_scorms_by_courses();
718 $result = external_api::clean_returnvalue($returndescription, $result);
719 $this->assertEquals($expectedscorms, $result['scorms']);
720
721 // Admin also should get all the information.
722 self::setAdminUser();
723
724 $result = mod_scorm_external::get_scorms_by_courses(array($course1->id));
725 $result = external_api::clean_returnvalue($returndescription, $result);
726 $this->assertEquals($expectedscorms, $result['scorms']);
727 }
e9bf3011 728}