MDL-50353 scorm: New Web Service mod_scorm_insert_scorm_tracks
[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));
432
433 $this->assertEquals(array_keys($trackids), $result['trackids']);
434 }
e9bf3011 435}