MDL-57918 mod_data: Minor refactors for the new WS
[moodle.git] / mod / data / tests / externallib_test.php
CommitLineData
067b3fda
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 * Database module external functions tests
19 *
20 * @package mod_data
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 2.9
25 */
26
27defined('MOODLE_INTERNAL') || die();
28
29global $CFG;
30
31require_once($CFG->dirroot . '/webservice/tests/helpers.php');
32
33/**
34 * Database module external functions tests
35 *
36 * @package mod_data
37 * @category external
38 * @copyright 2015 Juan Leyva <juan@moodle.com>
39 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 * @since Moodle 2.9
41 */
42class mod_data_external_testcase extends externallib_advanced_testcase {
43
9fac7c86
JL
44 /**
45 * Set up for every test
46 */
47 public function setUp() {
48 global $DB;
49 $this->resetAfterTest();
50 $this->setAdminUser();
51
52 // Setup test data.
ef6aea9d
JL
53 $course = new stdClass();
54 $course->groupmode = SEPARATEGROUPS;
55 $course->groupmodeforce = true;
56 $this->course = $this->getDataGenerator()->create_course($course);
9fac7c86
JL
57 $this->data = $this->getDataGenerator()->create_module('data', array('course' => $this->course->id));
58 $this->context = context_module::instance($this->data->cmid);
59 $this->cm = get_coursemodule_from_instance('data', $this->data->id);
60
61 // Create users.
62 $this->student1 = self::getDataGenerator()->create_user();
63 $this->student2 = self::getDataGenerator()->create_user();
ef6aea9d 64 $this->student3 = self::getDataGenerator()->create_user();
9fac7c86
JL
65 $this->teacher = self::getDataGenerator()->create_user();
66
67 // Users enrolments.
68 $this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
69 $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
70 $this->getDataGenerator()->enrol_user($this->student1->id, $this->course->id, $this->studentrole->id, 'manual');
71 $this->getDataGenerator()->enrol_user($this->student2->id, $this->course->id, $this->studentrole->id, 'manual');
ef6aea9d 72 $this->getDataGenerator()->enrol_user($this->student3->id, $this->course->id, $this->studentrole->id, 'manual');
9fac7c86 73 $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
ef6aea9d
JL
74
75 $this->group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
76 $this->group2 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
77 groups_add_member($this->group1, $this->student1);
78 groups_add_member($this->group1, $this->student2);
79 groups_add_member($this->group2, $this->student3);
9fac7c86
JL
80 }
81
067b3fda
JL
82 /**
83 * Test get databases by courses
84 */
85 public function test_mod_data_get_databases_by_courses() {
86 global $DB;
87
88 $this->resetAfterTest(true);
89
90 // Create users.
91 $student = self::getDataGenerator()->create_user();
92 $teacher = self::getDataGenerator()->create_user();
93
94 // Set to the student user.
95 self::setUser($student);
96
97 // Create courses to add the modules.
98 $course1 = self::getDataGenerator()->create_course();
99 $course2 = self::getDataGenerator()->create_course();
100
101 // First database.
102 $record = new stdClass();
103 $record->introformat = FORMAT_HTML;
104 $record->course = $course1->id;
105 $database1 = self::getDataGenerator()->create_module('data', $record);
106
107 // Second database.
108 $record = new stdClass();
109 $record->introformat = FORMAT_HTML;
110 $record->course = $course2->id;
111 $database2 = self::getDataGenerator()->create_module('data', $record);
112
113 $studentrole = $DB->get_record('role', array('shortname' => 'student'));
114 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
115
116 // Users enrolments.
117 $this->getDataGenerator()->enrol_user($student->id, $course1->id, $studentrole->id, 'manual');
118 $this->getDataGenerator()->enrol_user($teacher->id, $course1->id, $teacherrole->id, 'manual');
119
120 // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
121 $enrol = enrol_get_plugin('manual');
122 $enrolinstances = enrol_get_instances($course2->id, true);
123 foreach ($enrolinstances as $courseenrolinstance) {
124 if ($courseenrolinstance->enrol == "manual") {
125 $instance2 = $courseenrolinstance;
126 break;
127 }
128 }
129 $enrol->enrol_user($instance2, $student->id, $studentrole->id);
130
131 // Create what we expect to be returned when querying the two courses.
132 // First for the student user.
133 $expectedfields = array('id', 'coursemodule', 'course', 'name', 'comments', 'timeavailablefrom',
134 'timeavailableto', 'timeviewfrom', 'timeviewto', 'requiredentries', 'requiredentriestoview',
f97305b0
JL
135 'intro', 'introformat', 'introfiles', 'maxentries', 'rssarticles', 'singletemplate', 'listtemplate',
136 'listtemplateheader', 'listtemplatefooter', 'addtemplate', 'rsstemplate', 'rsstitletemplate',
137 'csstemplate', 'jstemplate', 'asearchtemplate', 'approval', 'defaultsort', 'defaultsortdir', 'manageapproved');
067b3fda
JL
138
139 // Add expected coursemodule.
140 $database1->coursemodule = $database1->cmid;
7ef49bd3 141 $database1->introfiles = [];
067b3fda 142 $database2->coursemodule = $database2->cmid;
7ef49bd3 143 $database2->introfiles = [];
067b3fda
JL
144
145 $expected1 = array();
146 $expected2 = array();
147 foreach ($expectedfields as $field) {
f97305b0
JL
148 if ($field == 'approval' or $field == 'manageapproved') {
149 $database1->{$field} = (bool) $database1->{$field};
150 $database2->{$field} = (bool) $database2->{$field};
151 }
067b3fda
JL
152 $expected1[$field] = $database1->{$field};
153 $expected2[$field] = $database2->{$field};
154 }
8352aa50
JL
155 $expected1['comments'] = (bool) $expected1['comments'];
156 $expected2['comments'] = (bool) $expected2['comments'];
067b3fda
JL
157
158 $expecteddatabases = array();
159 $expecteddatabases[] = $expected2;
160 $expecteddatabases[] = $expected1;
161
162 // Call the external function passing course ids.
163 $result = mod_data_external::get_databases_by_courses(array($course2->id, $course1->id));
8352aa50 164 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
067b3fda
JL
165 $this->assertEquals($expecteddatabases, $result['databases']);
166
167 // Call the external function without passing course id.
168 $result = mod_data_external::get_databases_by_courses();
8352aa50 169 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
067b3fda
JL
170 $this->assertEquals($expecteddatabases, $result['databases']);
171
172 // Unenrol user from second course and alter expected databases.
173 $enrol->unenrol_user($instance2, $student->id);
174 array_shift($expecteddatabases);
175
176 // Call the external function without passing course id.
177 $result = mod_data_external::get_databases_by_courses();
8352aa50 178 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
067b3fda
JL
179 $this->assertEquals($expecteddatabases, $result['databases']);
180
181 // Call for the second course we unenrolled the user from, expected warning.
182 $result = mod_data_external::get_databases_by_courses(array($course2->id));
183 $this->assertCount(1, $result['warnings']);
8352aa50 184 $this->assertEquals('1', $result['warnings'][0]['warningcode']);
067b3fda
JL
185 $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
186
187 // Now, try as a teacher for getting all the additional fields.
188 self::setUser($teacher);
189
f97305b0 190 $additionalfields = array('scale', 'assessed', 'assesstimestart', 'assesstimefinish', 'editany', 'notification', 'timemodified');
067b3fda
JL
191
192 foreach ($additionalfields as $field) {
f97305b0
JL
193 if ($field == 'editany') {
194 $database1->{$field} = (bool) $database1->{$field};
8352aa50 195 }
f97305b0 196 $expecteddatabases[0][$field] = $database1->{$field};
067b3fda
JL
197 }
198 $result = mod_data_external::get_databases_by_courses();
8352aa50
JL
199 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
200 $this->assertEquals($expecteddatabases, $result['databases']);
201
202 // Admin should get all the information.
203 self::setAdminUser();
204
205 $result = mod_data_external::get_databases_by_courses(array($course1->id));
206 $result = external_api::clean_returnvalue(mod_data_external::get_databases_by_courses_returns(), $result);
067b3fda
JL
207 $this->assertEquals($expecteddatabases, $result['databases']);
208 }
9fac7c86
JL
209
210 /**
211 * Test view_database invalid id.
212 */
213 public function test_view_database_invalid_id() {
214
215 // Test invalid instance id.
216 $this->setExpectedException('moodle_exception');
217 mod_data_external::view_database(0);
218 }
219
220 /**
221 * Test view_database not enrolled user.
222 */
223 public function test_view_database_not_enrolled_user() {
224
225 $usernotenrolled = self::getDataGenerator()->create_user();
226 $this->setUser($usernotenrolled);
227
228 $this->setExpectedException('moodle_exception');
229 mod_data_external::view_database(0);
230 }
231
232 /**
233 * Test view_database no capabilities.
234 */
235 public function test_view_database_no_capabilities() {
236 // Test user with no capabilities.
237 // We need a explicit prohibit since this capability is allowed for students by default.
238 assign_capability('mod/data:viewpage', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
239 accesslib_clear_all_caches_for_unit_testing();
240
241 $this->setExpectedException('moodle_exception');
242 mod_data_external::view_database(0);
243 }
244
245 /**
246 * Test view_database.
247 */
248 public function test_view_database() {
249
250 // Test user with full capabilities.
251 $this->setUser($this->student1);
252
253 // Trigger and capture the event.
254 $sink = $this->redirectEvents();
255
256 $result = mod_data_external::view_database($this->data->id);
257 $result = external_api::clean_returnvalue(mod_data_external::view_database_returns(), $result);
258
259 $events = $sink->get_events();
260 $this->assertCount(1, $events);
261 $event = array_shift($events);
262
263 // Checking that the event contains the expected values.
264 $this->assertInstanceOf('\mod_data\event\course_module_viewed', $event);
265 $this->assertEquals($this->context, $event->get_context());
266 $moodledata = new \moodle_url('/mod/data/view.php', array('id' => $this->cm->id));
267 $this->assertEquals($moodledata, $event->get_url());
268 $this->assertEventContextNotUsed($event);
269 $this->assertNotEmpty($event->get_name());
270 }
cac43b9b
JL
271
272 /**
273 * Test get_data_access_information for student.
274 */
275 public function test_get_data_access_information_student() {
276 global $DB;
277 // Modify the database to add access restrictions.
278 $this->data->timeavailablefrom = time() + DAYSECS;
279 $this->data->requiredentries = 2;
280 $this->data->requiredentriestoview = 2;
281 $DB->update_record('data', $this->data);
282
283 // Test user with full capabilities.
284 $this->setUser($this->student1);
285
286 $result = mod_data_external::get_data_access_information($this->data->id);
287 $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result);
288
ef6aea9d 289 $this->assertEquals($this->group1->id, $result['groupid']);
cac43b9b
JL
290
291 $this->assertFalse($result['canmanageentries']);
292 $this->assertFalse($result['canapprove']);
293 $this->assertTrue($result['canaddentry']); // It return true because it doen't check time restrictions.
294 $this->assertFalse($result['timeavailable']);
295 $this->assertFalse($result['inreadonlyperiod']);
296 $this->assertEquals(0, $result['numentries']);
297 $this->assertEquals($this->data->requiredentries, $result['entrieslefttoadd']);
298 $this->assertEquals($this->data->requiredentriestoview, $result['entrieslefttoview']);
299 }
300
301 /**
302 * Test get_data_access_information for teacher.
303 */
304 public function test_get_data_access_information_teacher() {
305 global $DB;
306 // Modify the database to add access restrictions.
307 $this->data->timeavailablefrom = time() + DAYSECS;
308 $this->data->requiredentries = 2;
309 $this->data->requiredentriestoview = 2;
310 $DB->update_record('data', $this->data);
311
312 // Test user with full capabilities.
313 $this->setUser($this->teacher);
314
315 $result = mod_data_external::get_data_access_information($this->data->id);
316 $result = external_api::clean_returnvalue(mod_data_external::get_data_access_information_returns(), $result);
317
318 $this->assertEquals(0, $result['groupid']);
319
320 $this->assertTrue($result['canmanageentries']);
321 $this->assertTrue($result['canapprove']);
322 $this->assertTrue($result['canaddentry']); // It return true because it doen't check time restrictions.
323 $this->assertTrue($result['timeavailable']);
324 $this->assertFalse($result['inreadonlyperiod']);
325 $this->assertEquals(0, $result['numentries']);
326 $this->assertEquals(0, $result['entrieslefttoadd']);
327 $this->assertEquals(0, $result['entrieslefttoview']);
328 }
ef6aea9d
JL
329
330 /**
331 * Helper method to populate the database with some entries.
332 *
333 * @return array the entry ids created
334 */
335 public function populate_database_with_entries() {
336 global $DB;
337
338 $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
339 $fieldtypes = array('checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url');
340
341 $count = 1;
342 // Creating test Fields with default parameter values.
343 foreach ($fieldtypes as $fieldtype) {
344 $fieldname = 'field-' . $count;
345 $record = new StdClass();
346 $record->name = $fieldname;
347 $record->type = $fieldtype;
348 $record->required = 1;
349
350 $generator->create_field($record, $this->data);
351 $count++;
352 }
353 // Get all the fields created.
354 $fields = $DB->get_records('data_fields', array('dataid' => $this->data->id), 'id');
355
356 // Populate with contents, creating a new entry.
357 $contents = array();
358 $contents[] = array('opt1', 'opt2', 'opt3', 'opt4');
359 $contents[] = '01-01-2037'; // It should be lower than 2038, to avoid failing on 32-bit windows.
360 $contents[] = 'menu1';
361 $contents[] = array('multimenu1', 'multimenu2', 'multimenu3', 'multimenu4');
362 $contents[] = '12345';
363 $contents[] = 'radioopt1';
364 $contents[] = 'text for testing';
365 $contents[] = '<p>text area testing<br /></p>';
366 $contents[] = array('example.url', 'sampleurl');
367 $count = 0;
368 $fieldcontents = array();
369 foreach ($fields as $fieldrecord) {
370 $fieldcontents[$fieldrecord->id] = $contents[$count++];
371 }
372
373 $this->setUser($this->student1);
374 $entry11 = $generator->create_entry($this->data, $fieldcontents, $this->group1->id);
375 $this->setUser($this->student2);
376 $entry12 = $generator->create_entry($this->data, $fieldcontents, $this->group1->id);
377
378 $this->setUser($this->student3);
379 $entry21 = $generator->create_entry($this->data, $fieldcontents, $this->group2->id);
380 return [$entry11, $entry12, $entry21];
381 }
382
383 /**
384 * Test get_entries
385 */
386 public function test_get_entries() {
387 global $DB;
388 list($entry11, $entry12, $entry21) = self::populate_database_with_entries();
389
390 // First of all, expect to see only my group entries (not other users in other groups ones).
391 $this->setUser($this->student1);
392 $result = mod_data_external::get_entries($this->data->id);
393 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
394 $this->assertCount(0, $result['warnings']);
395 $this->assertCount(2, $result['entries']);
396 $this->assertEquals(2, $result['totalcount']);
397 $this->assertEquals($entry11, $result['entries'][0]['id']);
398 $this->assertEquals($this->student1->id, $result['entries'][0]['userid']);
399 $this->assertEquals($this->group1->id, $result['entries'][0]['groupid']);
400 $this->assertEquals($this->data->id, $result['entries'][0]['dataid']);
401 $this->assertEquals($entry12, $result['entries'][1]['id']);
402 $this->assertEquals($this->student2->id, $result['entries'][1]['userid']);
403 $this->assertEquals($this->group1->id, $result['entries'][1]['groupid']);
404 $this->assertEquals($this->data->id, $result['entries'][1]['dataid']);
405 // Other user in same group.
406 $this->setUser($this->student2);
407 $result = mod_data_external::get_entries($this->data->id);
408 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
409 $this->assertCount(0, $result['warnings']);
410 $this->assertCount(2, $result['entries']);
411 $this->assertEquals(2, $result['totalcount']);
412
413 // Now try with the user in the second group that must see only one entry.
414 $this->setUser($this->student3);
415 $result = mod_data_external::get_entries($this->data->id);
416 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
417 $this->assertCount(0, $result['warnings']);
418 $this->assertCount(1, $result['entries']);
419 $this->assertEquals(1, $result['totalcount']);
420 $this->assertEquals($entry21, $result['entries'][0]['id']);
421 $this->assertEquals($this->student3->id, $result['entries'][0]['userid']);
422 $this->assertEquals($this->group2->id, $result['entries'][0]['groupid']);
423 $this->assertEquals($this->data->id, $result['entries'][0]['dataid']);
424
425 // Now, as teacher we should see all (we have permissions to view all groups).
426 $this->setUser($this->teacher);
427 $result = mod_data_external::get_entries($this->data->id);
428 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
429 $this->assertCount(0, $result['warnings']);
430 $this->assertCount(3, $result['entries']);
431 $this->assertEquals(3, $result['totalcount']);
432
433 $entries = $DB->get_records('data_records', array('dataid' => $this->data->id), 'id');
434 $this->assertCount(3, $entries);
435 $count = 0;
436 foreach ($entries as $entry) {
437 $this->assertEquals($entry->id, $result['entries'][$count]['id']);
438 $count++;
439 }
440
441 // Basic test passing the parameter (instead having to calculate it).
442 $this->setUser($this->student1);
443 $result = mod_data_external::get_entries($this->data->id, $this->group1->id);
444 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
445 $this->assertCount(0, $result['warnings']);
446 $this->assertCount(2, $result['entries']);
447 $this->assertEquals(2, $result['totalcount']);
448
449 // Test ordering (reverse).
450 $this->setUser($this->student1);
451 $result = mod_data_external::get_entries($this->data->id, $this->group1->id, false, null, 'DESC');
452 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
453 $this->assertCount(0, $result['warnings']);
454 $this->assertCount(2, $result['entries']);
455 $this->assertEquals(2, $result['totalcount']);
456 $this->assertEquals($entry12, $result['entries'][0]['id']);
457
458 // Test pagination.
459 $this->setUser($this->student1);
460 $result = mod_data_external::get_entries($this->data->id, $this->group1->id, false, null, null, 0, 1);
461 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
462 $this->assertCount(0, $result['warnings']);
463 $this->assertCount(1, $result['entries']);
464 $this->assertEquals(2, $result['totalcount']);
465 $this->assertEquals($entry11, $result['entries'][0]['id']);
466
467 $result = mod_data_external::get_entries($this->data->id, $this->group1->id, false, null, null, 1, 1);
468 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
469 $this->assertCount(0, $result['warnings']);
470 $this->assertCount(1, $result['entries']);
471 $this->assertEquals(2, $result['totalcount']);
472 $this->assertEquals($entry12, $result['entries'][0]['id']);
473
474 // Now test the return contents.
475 data_generate_default_template($this->data, 'listtemplate', 0, false, true); // Generate a default list template.
476 $result = mod_data_external::get_entries($this->data->id, $this->group1->id, true, null, null, 0, 2);
477 $result = external_api::clean_returnvalue(mod_data_external::get_entries_returns(), $result);
478 $this->assertCount(0, $result['warnings']);
479 $this->assertCount(2, $result['entries']);
480 $this->assertEquals(2, $result['totalcount']);
481 $this->assertCount(9, $result['entries'][0]['contents']);
482 $this->assertCount(9, $result['entries'][1]['contents']);
483 // Search for some content.
484 $this->assertTrue(strpos($result['listviewcontents'], 'opt1') !== false);
485 $this->assertTrue(strpos($result['listviewcontents'], 'January') !== false);
486 $this->assertTrue(strpos($result['listviewcontents'], 'menu1') !== false);
487 $this->assertTrue(strpos($result['listviewcontents'], 'text for testing') !== false);
488 $this->assertTrue(strpos($result['listviewcontents'], 'sampleurl') !== false);
489 }
067b3fda 490}