MDL-69319 mod_lti: remove unused vars from externallib_test
[moodle.git] / mod / lti / tests / externallib_test.php
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/>.
17 /**
18  * External tool module external functions tests
19  *
20  * @package    mod_lti
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  */
27 defined('MOODLE_INTERNAL') || die();
29 global $CFG;
31 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
32 require_once($CFG->dirroot . '/mod/lti/lib.php');
34 /**
35  * External tool module external functions tests
36  *
37  * @package    mod_lti
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  */
43 class mod_lti_external_testcase extends externallib_advanced_testcase {
45     /**
46      * Set up for every test
47      */
48     public function setUp() {
49         $this->resetAfterTest();
50     }
52     /**
53      * Sets up some basic test data including course, users, roles, and an lti instance, for use in some tests.
54      * @return array
55      */
56     protected function setup_test_data() {
57         global $DB;
58         $this->setAdminUser();
60         // Setup test data.
61         $course = $this->getDataGenerator()->create_course();
62         $lti = $this->getDataGenerator()->create_module(
63             'lti',
64             ['course' => $course->id, 'toolurl' => 'http://localhost/not/real/tool.php']
65         );
66         $context = context_module::instance($lti->cmid);
67         $cm = get_coursemodule_from_instance('lti', $lti->id);
69         // Create users.
70         $student = self::getDataGenerator()->create_user();
71         $teacher = self::getDataGenerator()->create_user();
73         // Users enrolments.
74         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
75         $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
76         $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual');
77         $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $teacherrole->id, 'manual');
79         return [
80             'course' => $course,
81             'lti' => $lti,
82             'context' => $context,
83             'cm' => $cm,
84             'student' => $student,
85             'teacher' => $teacher,
86             'studentrole' => $studentrole,
87             'teacherrole' => $teacherrole
88         ];
89     }
91     /**
92      * Test view_lti
93      */
94     public function test_get_tool_launch_data() {
95         global $USER;
97         [
98             'course' => $course,
99             'lti' => $lti
100         ] = $this->setup_test_data();
102         $result = mod_lti_external::get_tool_launch_data($lti->id);
103         $result = external_api::clean_returnvalue(mod_lti_external::get_tool_launch_data_returns(), $result);
105         // Basic test, the function returns what it's expected.
106         self::assertEquals($lti->toolurl, $result['endpoint']);
107         self::assertCount(36, $result['parameters']);
109         // Check some parameters.
110         $parameters = array();
111         foreach ($result['parameters'] as $param) {
112             $parameters[$param['name']] = $param['value'];
113         }
114         self::assertEquals($lti->resourcekey, $parameters['oauth_consumer_key']);
115         self::assertEquals($course->fullname, $parameters['context_title']);
116         self::assertEquals($course->shortname, $parameters['context_label']);
117         self::assertEquals($USER->id, $parameters['user_id']);
118         self::assertEquals($USER->firstname, $parameters['lis_person_name_given']);
119         self::assertEquals($USER->lastname, $parameters['lis_person_name_family']);
120         self::assertEquals(fullname($USER), $parameters['lis_person_name_full']);
121         self::assertEquals($USER->username, $parameters['ext_user_username']);
122         self::assertEquals("phpunit", $parameters['tool_consumer_instance_name']);
123         self::assertEquals("PHPUnit test site", $parameters['tool_consumer_instance_description']);
125     }
127     /*
128      * Test get ltis by courses
129      */
130     public function test_mod_lti_get_ltis_by_courses() {
131         [
132             'course' => $course,
133             'lti' => $lti,
134             'student' => $student,
135             'teacher' => $teacher,
136             'studentrole' => $studentrole,
137         ] = $this->setup_test_data();
139         // Create additional course.
140         $course2 = self::getDataGenerator()->create_course();
142         // Second lti.
143         $record = new stdClass();
144         $record->course = $course2->id;
145         $lti2 = self::getDataGenerator()->create_module('lti', $record);
147         // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
148         $enrol = enrol_get_plugin('manual');
149         $enrolinstances = enrol_get_instances($course2->id, true);
150         foreach ($enrolinstances as $courseenrolinstance) {
151             if ($courseenrolinstance->enrol == "manual") {
152                 $instance2 = $courseenrolinstance;
153                 break;
154             }
155         }
156         $enrol->enrol_user($instance2, $student->id, $studentrole->id);
158         self::setUser($student);
160         $returndescription = mod_lti_external::get_ltis_by_courses_returns();
162         // Create what we expect to be returned when querying the two courses.
163         // First for the student user.
164         $expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'introfiles', 'launchcontainer',
165                                 'showtitlelaunch', 'showdescriptionlaunch', 'icon', 'secureicon');
167         // Add expected coursemodule and data.
168         $lti1 = $lti;
169         $lti1->coursemodule = $lti1->cmid;
170         $lti1->introformat = 1;
171         $lti1->section = 0;
172         $lti1->visible = true;
173         $lti1->groupmode = 0;
174         $lti1->groupingid = 0;
175         $lti1->introfiles = [];
177         $lti2->coursemodule = $lti2->cmid;
178         $lti2->introformat = 1;
179         $lti2->section = 0;
180         $lti2->visible = true;
181         $lti2->groupmode = 0;
182         $lti2->groupingid = 0;
183         $lti2->introfiles = [];
185         foreach ($expectedfields as $field) {
186                 $expected1[$field] = $lti1->{$field};
187                 $expected2[$field] = $lti2->{$field};
188         }
190         $expectedltis = array($expected2, $expected1);
192         // Call the external function passing course ids.
193         $result = mod_lti_external::get_ltis_by_courses(array($course2->id, $course->id));
194         $result = external_api::clean_returnvalue($returndescription, $result);
196         $this->assertEquals($expectedltis, $result['ltis']);
197         $this->assertCount(0, $result['warnings']);
199         // Call the external function without passing course id.
200         $result = mod_lti_external::get_ltis_by_courses();
201         $result = external_api::clean_returnvalue($returndescription, $result);
202         $this->assertEquals($expectedltis, $result['ltis']);
203         $this->assertCount(0, $result['warnings']);
205         // Unenrol user from second course and alter expected ltis.
206         $enrol->unenrol_user($instance2, $student->id);
207         array_shift($expectedltis);
209         // Call the external function without passing course id.
210         $result = mod_lti_external::get_ltis_by_courses();
211         $result = external_api::clean_returnvalue($returndescription, $result);
212         $this->assertEquals($expectedltis, $result['ltis']);
214         // Call for the second course we unenrolled the user from, expected warning.
215         $result = mod_lti_external::get_ltis_by_courses(array($course2->id));
216         $result = external_api::clean_returnvalue($returndescription, $result);
217         $this->assertCount(1, $result['warnings']);
218         $this->assertEquals('1', $result['warnings'][0]['warningcode']);
219         $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
221         // Now, try as a teacher for getting all the additional fields.
222         self::setUser($teacher);
224         $additionalfields = array('timecreated', 'timemodified', 'typeid', 'toolurl', 'securetoolurl',
225                         'instructorchoicesendname', 'instructorchoicesendemailaddr', 'instructorchoiceallowroster',
226                         'instructorchoiceallowsetting', 'instructorcustomparameters', 'instructorchoiceacceptgrades', 'grade',
227                         'resourcekey', 'password', 'debuglaunch', 'servicesalt', 'visible', 'groupmode', 'groupingid');
229         foreach ($additionalfields as $field) {
230                 $expectedltis[0][$field] = $lti1->{$field};
231         }
233         $result = mod_lti_external::get_ltis_by_courses();
234         $result = external_api::clean_returnvalue($returndescription, $result);
235         $this->assertEquals($expectedltis, $result['ltis']);
237         // Admin also should get all the information.
238         self::setAdminUser();
240         $result = mod_lti_external::get_ltis_by_courses(array($course->id));
241         $result = external_api::clean_returnvalue($returndescription, $result);
242         $this->assertEquals($expectedltis, $result['ltis']);
244         // Now, prohibit capabilities.
245         $this->setUser($student);
246         $contextcourse1 = context_course::instance($course->id);
247         // Prohibit capability = mod:lti:view on Course1 for students.
248         assign_capability('mod/lti:view', CAP_PROHIBIT, $studentrole->id, $contextcourse1->id);
249         // Empty all the caches that may be affected by this change.
250         accesslib_clear_all_caches_for_unit_testing();
251         course_modinfo::clear_instance_cache();
253         $ltis = mod_lti_external::get_ltis_by_courses(array($course->id));
254         $ltis = external_api::clean_returnvalue(mod_lti_external::get_ltis_by_courses_returns(), $ltis);
255         $this->assertCount(0, $ltis['ltis']);
256     }
258     /**
259      * Test view_lti
260      */
261     public function test_view_lti() {
262         [
263             'lti' => $lti,
264             'context' => $context,
265             'cm' => $cm,
266             'student' => $student,
267             'studentrole' => $studentrole,
268         ] = $this->setup_test_data();
270         // Test invalid instance id.
271         try {
272             mod_lti_external::view_lti(0);
273             $this->fail('Exception expected due to invalid mod_lti instance id.');
274         } catch (moodle_exception $e) {
275             $this->assertEquals('invalidrecord', $e->errorcode);
276         }
278         // Test not-enrolled user.
279         $usernotenrolled = self::getDataGenerator()->create_user();
280         $this->setUser($usernotenrolled);
281         try {
282             mod_lti_external::view_lti($lti->id);
283             $this->fail('Exception expected due to not enrolled user.');
284         } catch (moodle_exception $e) {
285             $this->assertEquals('requireloginerror', $e->errorcode);
286         }
288         // Test user with full capabilities.
289         $this->setUser($student);
291         // Trigger and capture the event.
292         $sink = $this->redirectEvents();
294         $result = mod_lti_external::view_lti($lti->id);
295         // The value of the result isn't needed but validation is.
296         external_api::clean_returnvalue(mod_lti_external::view_lti_returns(), $result);
298         $events = $sink->get_events();
299         $this->assertCount(1, $events);
300         $event = array_shift($events);
302         // Checking that the event contains the expected values.
303         $this->assertInstanceOf('\mod_lti\event\course_module_viewed', $event);
304         $this->assertEquals($context, $event->get_context());
305         $moodlelti = new \moodle_url('/mod/lti/view.php', array('id' => $cm->id));
306         $this->assertEquals($moodlelti, $event->get_url());
307         $this->assertEventContextNotUsed($event);
308         $this->assertNotEmpty($event->get_name());
310         // Test user with no capabilities.
311         // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
312         assign_capability('mod/lti:view', CAP_PROHIBIT, $studentrole->id, $context->id);
313         // Empty all the caches that may be affected by this change.
314         accesslib_clear_all_caches_for_unit_testing();
315         course_modinfo::clear_instance_cache();
317         try {
318             mod_lti_external::view_lti($lti->id);
319             $this->fail('Exception expected due to missing capability.');
320         } catch (moodle_exception $e) {
321             $this->assertEquals('requireloginerror', $e->errorcode);
322         }
324     }
326     /*
327      * Test create tool proxy
328      */
329     public function test_mod_lti_create_tool_proxy() {
330         $this->setAdminUser();
331         $capabilities = ['AA', 'BB'];
332         $proxy = mod_lti_external::create_tool_proxy('Test proxy', $this->getExternalTestFileUrl('/test.html'), $capabilities, []);
333         $proxy = (object) external_api::clean_returnvalue(mod_lti_external::create_tool_proxy_returns(), $proxy);
335         $this->assertEquals('Test proxy', $proxy->name);
336         $this->assertEquals($this->getExternalTestFileUrl('/test.html'), $proxy->regurl);
337         $this->assertEquals(LTI_TOOL_PROXY_STATE_PENDING, $proxy->state);
338         $this->assertEquals(implode("\n", $capabilities), $proxy->capabilityoffered);
339     }
341     /*
342      * Test create tool proxy with duplicate url
343      */
344     public function test_mod_lti_create_tool_proxy_duplicateurl() {
345         $this->setAdminUser();
346         $this->expectException('moodle_exception');
347         mod_lti_external::create_tool_proxy('Test proxy 1', $this->getExternalTestFileUrl('/test.html'), array(), array());
348         mod_lti_external::create_tool_proxy('Test proxy 2', $this->getExternalTestFileUrl('/test.html'), array(), array());
349     }
351     /*
352      * Test create tool proxy without sufficient capability
353      */
354     public function test_mod_lti_create_tool_proxy_without_capability() {
355         $course = $this->getDataGenerator()->create_course();
356         $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
357         $this->setUser($teacher);
358         $this->expectException('required_capability_exception');
359         mod_lti_external::create_tool_proxy('Test proxy', $this->getExternalTestFileUrl('/test.html'), array(), array());
360     }
362     /*
363      * Test delete tool proxy
364      */
365     public function test_mod_lti_delete_tool_proxy() {
366         $this->setAdminUser();
367         $proxy = mod_lti_external::create_tool_proxy('Test proxy', $this->getExternalTestFileUrl('/test.html'), array(), array());
368         $proxy = (object) external_api::clean_returnvalue(mod_lti_external::create_tool_proxy_returns(), $proxy);
369         $this->assertNotEmpty(lti_get_tool_proxy($proxy->id));
371         $proxy = mod_lti_external::delete_tool_proxy($proxy->id);
372         $proxy = (object) external_api::clean_returnvalue(mod_lti_external::delete_tool_proxy_returns(), $proxy);
374         $this->assertEquals('Test proxy', $proxy->name);
375         $this->assertEquals($this->getExternalTestFileUrl('/test.html'), $proxy->regurl);
376         $this->assertEquals(LTI_TOOL_PROXY_STATE_PENDING, $proxy->state);
377         $this->assertEmpty(lti_get_tool_proxy($proxy->id));
378     }
380     /*
381      * Test get tool proxy registration request
382      */
383     public function test_mod_lti_get_tool_proxy_registration_request() {
384         $this->setAdminUser();
385         $proxy = mod_lti_external::create_tool_proxy('Test proxy', $this->getExternalTestFileUrl('/test.html'), array(), array());
386         $proxy = (object) external_api::clean_returnvalue(mod_lti_external::create_tool_proxy_returns(), $proxy);
388         $request = mod_lti_external::get_tool_proxy_registration_request($proxy->id);
389         $request = external_api::clean_returnvalue(mod_lti_external::get_tool_proxy_registration_request_returns(),
390             $request);
392         $this->assertEquals('ToolProxyRegistrationRequest', $request['lti_message_type']);
393         $this->assertEquals('LTI-2p0', $request['lti_version']);
394     }
396     /*
397      * Test get tool types
398      */
399     public function test_mod_lti_get_tool_types() {
400         // Create a tool proxy.
401         $this->setAdminUser();
402         $proxy = mod_lti_external::create_tool_proxy('Test proxy', $this->getExternalTestFileUrl('/test.html'), array(), array());
403         $proxy = (object) external_api::clean_returnvalue(mod_lti_external::create_tool_proxy_returns(), $proxy);
405         // Create a tool type, associated with that proxy.
406         $type = new stdClass();
407         $data = new stdClass();
408         $type->state = LTI_TOOL_STATE_CONFIGURED;
409         $type->name = "Test tool";
410         $type->description = "Example description";
411         $type->toolproxyid = $proxy->id;
412         $type->baseurl = $this->getExternalTestFileUrl('/test.html');
413         lti_add_type($type, $data);
415         $types = mod_lti_external::get_tool_types($proxy->id);
416         $types = external_api::clean_returnvalue(mod_lti_external::get_tool_types_returns(), $types);
418         $this->assertEquals(1, count($types));
419         $type = $types[0];
420         $this->assertEquals('Test tool', $type['name']);
421         $this->assertEquals('Example description', $type['description']);
422     }
424     /*
425      * Test create tool type
426      */
427     public function test_mod_lti_create_tool_type() {
428         $this->setAdminUser();
429         $type = mod_lti_external::create_tool_type($this->getExternalTestFileUrl('/ims_cartridge_basic_lti_link.xml'), '', '');
430         $type = external_api::clean_returnvalue(mod_lti_external::create_tool_type_returns(), $type);
432         $this->assertEquals('Example tool', $type['name']);
433         $this->assertEquals('Example tool description', $type['description']);
434         $this->assertEquals('https://download.moodle.org/unittest/test.jpg', $type['urls']['icon']);
435         $typeentry = lti_get_type($type['id']);
436         $this->assertEquals('http://www.example.com/lti/provider.php', $typeentry->baseurl);
437         $config = lti_get_type_config($type['id']);
438         $this->assertTrue(isset($config['sendname']));
439         $this->assertTrue(isset($config['sendemailaddr']));
440         $this->assertTrue(isset($config['acceptgrades']));
441         $this->assertTrue(isset($config['forcessl']));
442     }
444     /*
445      * Test create tool type failure from non existant file
446      */
447     public function test_mod_lti_create_tool_type_nonexistant_file() {
448         $this->expectException('moodle_exception');
449         mod_lti_external::create_tool_type($this->getExternalTestFileUrl('/doesntexist.xml'), '', '');
450     }
452     /*
453      * Test create tool type failure from xml that is not a cartridge
454      */
455     public function test_mod_lti_create_tool_type_bad_file() {
456         $this->expectException('moodle_exception');
457         mod_lti_external::create_tool_type($this->getExternalTestFileUrl('/rsstest.xml'), '', '');
458     }
460     /*
461      * Test creating of tool types without sufficient capability
462      */
463     public function test_mod_lti_create_tool_type_without_capability() {
464         $course = $this->getDataGenerator()->create_course();
465         $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
466         $this->setUser($teacher);
467         $this->expectException('required_capability_exception');
468         mod_lti_external::create_tool_type($this->getExternalTestFileUrl('/ims_cartridge_basic_lti_link.xml'), '', '');
469     }
471     /*
472      * Test update tool type
473      */
474     public function test_mod_lti_update_tool_type() {
475         $this->setAdminUser();
476         $type = mod_lti_external::create_tool_type($this->getExternalTestFileUrl('/ims_cartridge_basic_lti_link.xml'), '', '');
477         $type = external_api::clean_returnvalue(mod_lti_external::create_tool_type_returns(), $type);
479         $type = mod_lti_external::update_tool_type($type['id'], 'New name', 'New description', LTI_TOOL_STATE_PENDING);
480         $type = external_api::clean_returnvalue(mod_lti_external::update_tool_type_returns(), $type);
482         $this->assertEquals('New name', $type['name']);
483         $this->assertEquals('New description', $type['description']);
484         $this->assertEquals('Pending', $type['state']['text']);
485     }
487     /*
488      * Test delete tool type
489      */
490     public function test_mod_lti_delete_tool_type() {
491         $this->setAdminUser();
492         $type = mod_lti_external::create_tool_type($this->getExternalTestFileUrl('/ims_cartridge_basic_lti_link.xml'), '', '');
493         $type = external_api::clean_returnvalue(mod_lti_external::create_tool_type_returns(), $type);
494         $this->assertNotEmpty(lti_get_type($type['id']));
496         $type = mod_lti_external::delete_tool_type($type['id']);
497         $type = external_api::clean_returnvalue(mod_lti_external::delete_tool_type_returns(), $type);
498         $this->assertEmpty(lti_get_type($type['id']));
499     }
501     /*
502      * Test delete tool type without sufficient capability
503      */
504     public function test_mod_lti_delete_tool_type_without_capability() {
505         $this->setAdminUser();
506         $type = mod_lti_external::create_tool_type($this->getExternalTestFileUrl('/ims_cartridge_basic_lti_link.xml'), '', '');
507         $type = external_api::clean_returnvalue(mod_lti_external::create_tool_type_returns(), $type);
508         $this->assertNotEmpty(lti_get_type($type['id']));
509         $this->expectException('required_capability_exception');
510         $course = $this->getDataGenerator()->create_course();
511         $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher');
512         $this->setUser($teacher);
513         mod_lti_external::delete_tool_type($type['id']);
514     }
516     /*
517      * Test is cartridge
518      */
519     public function test_mod_lti_is_cartridge() {
520         $this->setAdminUser();
521         $result = mod_lti_external::is_cartridge($this->getExternalTestFileUrl('/ims_cartridge_basic_lti_link.xml'));
522         $result = external_api::clean_returnvalue(mod_lti_external::is_cartridge_returns(), $result);
523         $this->assertTrue($result['iscartridge']);
525         $result = mod_lti_external::is_cartridge($this->getExternalTestFileUrl('/test.html'));
526         $result = external_api::clean_returnvalue(mod_lti_external::is_cartridge_returns(), $result);
527         $this->assertFalse($result['iscartridge']);
528     }