MDL-52457 mod_scorm: Fix return types definitions in SCORM WS
[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']);
77496aa5 479 $this->assertCount(0, $result['warnings']);
6b5e69eb
JL
480 // Find our tracking data.
481 $found = 0;
35219d8b 482 foreach ($result['data']['tracks'] as $userdata) {
6b5e69eb
JL
483 if ($userdata['element'] == 'cmi.core.lesson_status' and $userdata['value'] == 'completed') {
484 $found++;
485 }
486 if ($userdata['element'] == 'cmi.core.score.raw' and $userdata['value'] == '80') {
487 $found++;
488 }
489 }
490 $this->assertEquals(2, $found);
491
77496aa5
JL
492 // Try invalid attempt.
493 $result = mod_scorm_external::get_scorm_sco_tracks($sco->id, $student->id, 10);
494 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_sco_tracks_returns(), $result);
495 $this->assertCount(0, $result['data']['tracks']);
496 $this->assertEquals(10, $result['data']['attempt']);
497 $this->assertCount(1, $result['warnings']);
498 $this->assertEquals('notattempted', $result['warnings'][0]['warningcode']);
499
6b5e69eb
JL
500 // Capabilities check.
501 try {
502 mod_scorm_external::get_scorm_sco_tracks($sco->id, $otherstudent->id);
503 $this->fail('Exception expected due to invalid instance id.');
504 } catch (required_capability_exception $e) {
505 $this->assertEquals('nopermissions', $e->errorcode);
506 }
507
508 self::setUser($teacher);
35219d8b 509 // Ommit the attempt parameter, the function should calculate the last attempt.
6b5e69eb
JL
510 $result = mod_scorm_external::get_scorm_sco_tracks($sco->id, $student->id);
511 $result = external_api::clean_returnvalue(mod_scorm_external::get_scorm_sco_tracks_returns(), $result);
512 // 7 default elements + 1 custom one.
35219d8b
JL
513 $this->assertCount(8, $result['data']['tracks']);
514 $this->assertEquals(2, $result['data']['attempt']);
6b5e69eb
JL
515
516 // Test invalid instance id.
517 try {
518 mod_scorm_external::get_scorm_sco_tracks(0, 1);
519 $this->fail('Exception expected due to invalid instance id.');
520 } catch (moodle_exception $e) {
521 $this->assertEquals('cannotfindsco', $e->errorcode);
522 }
523 // Invalid user.
524 try {
525 mod_scorm_external::get_scorm_sco_tracks($sco->id, 0);
526 $this->fail('Exception expected due to invalid instance id.');
527 } catch (moodle_exception $e) {
528 $this->assertEquals('invaliduser', $e->errorcode);
529 }
530 }
91ea3678
JL
531
532 /*
533 * Test get scorms by courses
534 */
535 public function test_mod_scorm_get_scorms_by_courses() {
536 global $DB;
537
538 $this->resetAfterTest(true);
539
540 // Create users.
541 $student = self::getDataGenerator()->create_user();
542 $teacher = self::getDataGenerator()->create_user();
543
544 // Set to the student user.
545 self::setUser($student);
546
547 // Create courses to add the modules.
548 $course1 = self::getDataGenerator()->create_course();
549 $course2 = self::getDataGenerator()->create_course();
550
551 // First scorm.
552 $record = new stdClass();
553 $record->introformat = FORMAT_HTML;
554 $record->course = $course1->id;
4f3d1b0e
JL
555 $record->hidetoc = 2;
556 $record->displayattemptstatus = 2;
557 $record->skipview = 2;
91ea3678
JL
558 $scorm1 = self::getDataGenerator()->create_module('scorm', $record);
559
560 // Second scorm.
561 $record = new stdClass();
562 $record->introformat = FORMAT_HTML;
563 $record->course = $course2->id;
564 $scorm2 = self::getDataGenerator()->create_module('scorm', $record);
565
566 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
567 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
568
569 // Users enrolments.
570 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
571 $this->getDataGenerator()->enrol_user($teacher->id, $course1->id, $teacherrole->id, 'manual');
572
573 // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
574 $enrol = enrol_get_plugin('manual');
575 $enrolinstances = enrol_get_instances($course2->id, true);
576 foreach ($enrolinstances as $courseenrolinstance) {
577 if ($courseenrolinstance->enrol == "manual") {
578 $instance2 = $courseenrolinstance;
579 break;
580 }
581 }
582 $enrol->enrol_user($instance2, $student->id, $studentrole->id);
583
584 $returndescription = mod_scorm_external::get_scorms_by_courses_returns();
585
586 // Test open/close dates.
587
588 $timenow = time();
589 $scorm1->timeopen = $timenow - DAYSECS;
590 $scorm1->timeclose = $timenow - HOURSECS;
591 $DB->update_record('scorm', $scorm1);
592
593 $result = mod_scorm_external::get_scorms_by_courses(array($course1->id));
594 $result = external_api::clean_returnvalue($returndescription, $result);
595 $this->assertCount(1, $result['warnings']);
596 // Only 'id', 'coursemodule', 'course', 'name', 'intro', 'introformat'.
597 $this->assertCount(6, $result['scorms'][0]);
598 $this->assertEquals('expired', $result['warnings'][0]['warningcode']);
599
600 $scorm1->timeopen = $timenow + DAYSECS;
601 $scorm1->timeclose = $scorm1->timeopen + DAYSECS;
602 $DB->update_record('scorm', $scorm1);
603
604 $result = mod_scorm_external::get_scorms_by_courses(array($course1->id));
605 $result = external_api::clean_returnvalue($returndescription, $result);
606 $this->assertCount(1, $result['warnings']);
607 // Only 'id', 'coursemodule', 'course', 'name', 'intro', 'introformat'.
608 $this->assertCount(6, $result['scorms'][0]);
609 $this->assertEquals('notopenyet', $result['warnings'][0]['warningcode']);
610
611 // Reset times.
612 $scorm1->timeopen = 0;
613 $scorm1->timeclose = 0;
614 $DB->update_record('scorm', $scorm1);
615
616 // Create what we expect to be returned when querying the two courses.
617 // First for the student user.
618 $expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'version', 'maxgrade',
619 'grademethod', 'whatgrade', 'maxattempt', 'forcecompleted', 'forcenewattempt', 'lastattemptlock',
620 'displayattemptstatus', 'displaycoursestructure', 'sha1hash', 'md5hash', 'revision', 'launch',
621 'skipview', 'hidebrowse', 'hidetoc', 'nav', 'navpositionleft', 'navpositiontop', 'auto',
622 'popup', 'width', 'height', 'timeopen', 'timeclose', 'displayactivityname', 'packagesize',
623 'packageurl', 'scormtype', 'reference');
624
625 // Add expected coursemodule and data.
626 $scorm1->coursemodule = $scorm1->cmid;
627 $scorm1->section = 0;
628 $scorm1->visible = true;
629 $scorm1->groupmode = 0;
630 $scorm1->groupingid = 0;
631
632 $scorm2->coursemodule = $scorm2->cmid;
633 $scorm2->section = 0;
634 $scorm2->visible = true;
635 $scorm2->groupmode = 0;
636 $scorm2->groupingid = 0;
637
638 // SCORM size. The same package is used in both SCORMs.
639 $scormcontext1 = context_module::instance($scorm1->cmid);
640 $scormcontext2 = context_module::instance($scorm2->cmid);
641 $fs = get_file_storage();
642 $packagefile = $fs->get_file($scormcontext1->id, 'mod_scorm', 'package', 0, '/', $scorm1->reference);
643 $packagesize = $packagefile->get_filesize();
644
645 $packageurl1 = moodle_url::make_webservice_pluginfile_url(
646 $scormcontext1->id, 'mod_scorm', 'package', 0, '/', $scorm1->reference)->out(false);
647 $packageurl2 = moodle_url::make_webservice_pluginfile_url(
648 $scormcontext2->id, 'mod_scorm', 'package', 0, '/', $scorm2->reference)->out(false);
649
650 $scorm1->packagesize = $packagesize;
651 $scorm1->packageurl = $packageurl1;
652 $scorm2->packagesize = $packagesize;
653 $scorm2->packageurl = $packageurl2;
654
115ef5f9
DM
655 // Forced to boolean as it is returned as PARAM_BOOL.
656 $protectpackages = (bool)get_config('scorm', 'protectpackagedownloads');
657 $expected1 = array('protectpackagedownloads' => $protectpackages);
658 $expected2 = array('protectpackagedownloads' => $protectpackages);
91ea3678
JL
659 foreach ($expectedfields as $field) {
660
661 // Since we return the fields used as boolean as PARAM_BOOL instead PARAM_INT we need to force casting here.
662 // From the returned fields definition we obtain the type expected for the field.
663 $fieldtype = $returndescription->keys['scorms']->content->keys[$field]->type;
664 if ($fieldtype == PARAM_BOOL) {
665 $expected1[$field] = (bool) $scorm1->{$field};
666 $expected2[$field] = (bool) $scorm2->{$field};
667 } else {
668 $expected1[$field] = $scorm1->{$field};
669 $expected2[$field] = $scorm2->{$field};
670 }
671 }
672
673 $expectedscorms = array();
674 $expectedscorms[] = $expected2;
675 $expectedscorms[] = $expected1;
676
677 // Call the external function passing course ids.
678 $result = mod_scorm_external::get_scorms_by_courses(array($course2->id, $course1->id));
679 $result = external_api::clean_returnvalue($returndescription, $result);
680 $this->assertEquals($expectedscorms, $result['scorms']);
681
682 // Call the external function without passing course id.
683 $result = mod_scorm_external::get_scorms_by_courses();
684 $result = external_api::clean_returnvalue($returndescription, $result);
685 $this->assertEquals($expectedscorms, $result['scorms']);
686
687 // Unenrol user from second course and alter expected scorms.
688 $enrol->unenrol_user($instance2, $student->id);
689 array_shift($expectedscorms);
690
691 // Call the external function without passing course id.
692 $result = mod_scorm_external::get_scorms_by_courses();
693 $result = external_api::clean_returnvalue($returndescription, $result);
694 $this->assertEquals($expectedscorms, $result['scorms']);
695
696 // Call for the second course we unenrolled the user from, expected warning.
697 $result = mod_scorm_external::get_scorms_by_courses(array($course2->id));
698 $this->assertCount(1, $result['warnings']);
699 $this->assertEquals('1', $result['warnings'][0]['warningcode']);
700 $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
701
702 // Now, try as a teacher for getting all the additional fields.
703 self::setUser($teacher);
704
705 $additionalfields = array('updatefreq', 'timemodified', 'options',
706 'completionstatusrequired', 'completionscorerequired', 'autocommit',
707 'section', 'visible', 'groupmode', 'groupingid');
708
709 foreach ($additionalfields as $field) {
710 $fieldtype = $returndescription->keys['scorms']->content->keys[$field]->type;
711
712 if ($fieldtype == PARAM_BOOL) {
713 $expectedscorms[0][$field] = (bool) $scorm1->{$field};
714 } else {
715 $expectedscorms[0][$field] = $scorm1->{$field};
716 }
717 }
718
719 $result = mod_scorm_external::get_scorms_by_courses();
720 $result = external_api::clean_returnvalue($returndescription, $result);
721 $this->assertEquals($expectedscorms, $result['scorms']);
722
723 // Even with the SCORM closed in time teacher should retrieve the info.
724 $scorm1->timeopen = $timenow - DAYSECS;
725 $scorm1->timeclose = $timenow - HOURSECS;
726 $DB->update_record('scorm', $scorm1);
727
728 $expectedscorms[0]['timeopen'] = $scorm1->timeopen;
729 $expectedscorms[0]['timeclose'] = $scorm1->timeclose;
730
731 $result = mod_scorm_external::get_scorms_by_courses();
732 $result = external_api::clean_returnvalue($returndescription, $result);
733 $this->assertEquals($expectedscorms, $result['scorms']);
734
735 // Admin also should get all the information.
736 self::setAdminUser();
737
738 $result = mod_scorm_external::get_scorms_by_courses(array($course1->id));
739 $result = external_api::clean_returnvalue($returndescription, $result);
740 $this->assertEquals($expectedscorms, $result['scorms']);
741 }
e9bf3011 742}