MDL-51629 mod_survey: New WS mod_survey_submit_answers
[moodle.git] / mod / survey / tests / externallib_test.php
CommitLineData
a2926eb3
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 * Survey module external functions tests
19 *
20 * @package mod_survey
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/survey/lib.php');
33
34/**
35 * Survey module external functions tests
36 *
37 * @package mod_survey
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_survey_external_testcase extends externallib_advanced_testcase {
44
45 /**
46 * Set up for every test
47 */
48 public function setUp() {
49 global $DB;
50 $this->resetAfterTest();
51 $this->setAdminUser();
52
53 // Setup test data.
54 $this->course = $this->getDataGenerator()->create_course();
55 $this->survey = $this->getDataGenerator()->create_module('survey', array('course' => $this->course->id));
56 $this->context = context_module::instance($this->survey->cmid);
57 $this->cm = get_coursemodule_from_instance('survey', $this->survey->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 /*
72 * Test get surveys by courses
73 */
74 public function test_mod_survey_get_surveys_by_courses() {
75 global $DB;
76
77 // Create additional course.
78 $course2 = self::getDataGenerator()->create_course();
79
80 // Second survey.
81 $record = new stdClass();
82 $record->course = $course2->id;
83 $survey2 = self::getDataGenerator()->create_module('survey', $record);
84 // Force empty intro.
85 $DB->set_field('survey', 'intro', '', array('id' => $survey2->id));
86
87 // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
88 $enrol = enrol_get_plugin('manual');
89 $enrolinstances = enrol_get_instances($course2->id, true);
90 foreach ($enrolinstances as $courseenrolinstance) {
91 if ($courseenrolinstance->enrol == "manual") {
92 $instance2 = $courseenrolinstance;
93 break;
94 }
95 }
96 $enrol->enrol_user($instance2, $this->student->id, $this->studentrole->id);
97
98 self::setUser($this->student);
99
100 $returndescription = mod_survey_external::get_surveys_by_courses_returns();
101
102 // Create what we expect to be returned when querying the two courses.
103 // First for the student user.
104 $expectedfields = array('id', 'coursemodule', 'course', 'name', 'intro', 'introformat', 'template', 'days', 'questions',
105 'surveydone');
106
107 // Add expected coursemodule and data.
108 $survey1 = $this->survey;
109 $survey1->coursemodule = $survey1->cmid;
110 $survey1->introformat = 1;
111 $survey1->surveydone = 0;
112 $survey1->section = 0;
113 $survey1->visible = true;
114 $survey1->groupmode = 0;
115 $survey1->groupingid = 0;
116
117 $survey2->coursemodule = $survey2->cmid;
118 $survey2->introformat = 1;
119 $survey2->surveydone = 0;
120 $survey2->section = 0;
121 $survey2->visible = true;
122 $survey2->groupmode = 0;
123 $survey2->groupingid = 0;
124 $tempo = $DB->get_field("survey", "intro", array("id" => $survey2->template));
125 $survey2->intro = nl2br(get_string($tempo, "survey"));
126
127 foreach ($expectedfields as $field) {
f772b515
JL
128 $expected1[$field] = $survey1->{$field};
129 $expected2[$field] = $survey2->{$field};
a2926eb3
JL
130 }
131
132 $expectedsurveys = array($expected2, $expected1);
133
134 // Call the external function passing course ids.
135 $result = mod_survey_external::get_surveys_by_courses(array($course2->id, $this->course->id));
136 $result = external_api::clean_returnvalue($returndescription, $result);
137
138 $this->assertEquals($expectedsurveys, $result['surveys']);
139 $this->assertCount(0, $result['warnings']);
140
141 // Call the external function without passing course id.
142 $result = mod_survey_external::get_surveys_by_courses();
143 $result = external_api::clean_returnvalue($returndescription, $result);
144 $this->assertEquals($expectedsurveys, $result['surveys']);
145 $this->assertCount(0, $result['warnings']);
146
147 // Unenrol user from second course and alter expected surveys.
148 $enrol->unenrol_user($instance2, $this->student->id);
149 array_shift($expectedsurveys);
150
151 // Call the external function without passing course id.
152 $result = mod_survey_external::get_surveys_by_courses();
153 $result = external_api::clean_returnvalue($returndescription, $result);
154 $this->assertEquals($expectedsurveys, $result['surveys']);
155
156 // Call for the second course we unenrolled the user from, expected warning.
157 $result = mod_survey_external::get_surveys_by_courses(array($course2->id));
158 $this->assertCount(1, $result['warnings']);
159 $this->assertEquals('1', $result['warnings'][0]['warningcode']);
160 $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
161
162 // Now, try as a teacher for getting all the additional fields.
163 self::setUser($this->teacher);
164
165 $additionalfields = array('timecreated', 'timemodified', 'section', 'visible', 'groupmode', 'groupingid');
166
167 foreach ($additionalfields as $field) {
f772b515 168 $expectedsurveys[0][$field] = $survey1->{$field};
a2926eb3
JL
169 }
170
171 $result = mod_survey_external::get_surveys_by_courses();
172 $result = external_api::clean_returnvalue($returndescription, $result);
173 $this->assertEquals($expectedsurveys, $result['surveys']);
174
175 // Admin also should get all the information.
176 self::setAdminUser();
177
178 $result = mod_survey_external::get_surveys_by_courses(array($this->course->id));
179 $result = external_api::clean_returnvalue($returndescription, $result);
180 $this->assertEquals($expectedsurveys, $result['surveys']);
181
182 // Now, prohibit capabilities.
183 $this->setUser($this->student);
184 $contextcourse1 = context_course::instance($this->course->id);
185 // Prohibit capability = mod/survey:participate on Course1 for students.
186 assign_capability('mod/survey:participate', CAP_PROHIBIT, $this->studentrole->id, $contextcourse1->id);
187 accesslib_clear_all_caches_for_unit_testing();
188
189 $surveys = mod_survey_external::get_surveys_by_courses(array($this->course->id));
190 $surveys = external_api::clean_returnvalue(mod_survey_external::get_surveys_by_courses_returns(), $surveys);
191 $this->assertFalse(isset($surveys['surveys'][0]['intro']));
192 }
193
75516809
JL
194 /**
195 * Test view_survey
196 */
197 public function test_view_survey() {
198 global $DB;
199
200 // Test invalid instance id.
201 try {
202 mod_survey_external::view_survey(0);
203 $this->fail('Exception expected due to invalid mod_survey instance id.');
204 } catch (moodle_exception $e) {
205 $this->assertEquals('invalidrecord', $e->errorcode);
206 }
207
208 // Test not-enrolled user.
209 $usernotenrolled = self::getDataGenerator()->create_user();
210 $this->setUser($usernotenrolled);
211 try {
212 mod_survey_external::view_survey($this->survey->id);
213 $this->fail('Exception expected due to not enrolled user.');
214 } catch (moodle_exception $e) {
215 $this->assertEquals('requireloginerror', $e->errorcode);
216 }
217
218 // Test user with full capabilities.
219 $this->setUser($this->student);
220
221 // Trigger and capture the event.
222 $sink = $this->redirectEvents();
223
224 $result = mod_survey_external::view_survey($this->survey->id);
225 $result = external_api::clean_returnvalue(mod_survey_external::view_survey_returns(), $result);
226 $this->assertTrue($result['status']);
227
228 $events = $sink->get_events();
229 $this->assertCount(1, $events);
230 $event = array_shift($events);
231
232 // Checking that the event contains the expected values.
233 $this->assertInstanceOf('\mod_survey\event\course_module_viewed', $event);
234 $this->assertEquals($this->context, $event->get_context());
235 $moodlesurvey = new \moodle_url('/mod/survey/view.php', array('id' => $this->cm->id));
236 $this->assertEquals($moodlesurvey, $event->get_url());
237 $this->assertEventContextNotUsed($event);
238 $this->assertNotEmpty($event->get_name());
239
240 // Test user with no capabilities.
241 // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
242 assign_capability('mod/survey:participate', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
243 accesslib_clear_all_caches_for_unit_testing();
244
245 try {
246 mod_survey_external::view_survey($this->survey->id);
247 $this->fail('Exception expected due to missing capability.');
248 } catch (moodle_exception $e) {
249 $this->assertEquals('nopermissions', $e->errorcode);
250 }
251
252 }
253
f772b515
JL
254 /**
255 * Test get_questions
256 */
257 public function test_get_questions() {
258 global $DB;
259
260 // Test user with full capabilities.
261 $this->setUser($this->student);
262
263 // Build our expectation array.
264 $expectedquestions = array();
265 $questions = survey_get_questions($this->survey);
266 foreach ($questions as $q) {
267 if ($q->type >= 0) {
268 $expectedquestions[$q->id] = $q;
269 if ($q->multi) {
270 $subquestions = survey_get_subquestions($q);
271 foreach ($subquestions as $sq) {
272 $expectedquestions[$sq->id] = $sq;
273 }
274 }
275 }
276 }
277
278 $result = mod_survey_external::get_questions($this->survey->id);
279 $result = external_api::clean_returnvalue(mod_survey_external::get_questions_returns(), $result);
280
281 // Check we receive the same questions.
282 $this->assertCount(0, $result['warnings']);
283 foreach ($result['questions'] as $q) {
284 $this->assertEquals(get_string($expectedquestions[$q['id']]->text, 'survey'), $q['text']);
285 $this->assertEquals(get_string($expectedquestions[$q['id']]->shorttext, 'survey'), $q['shorttext']);
286 $this->assertEquals($expectedquestions[$q['id']]->multi, $q['multi']);
287 $this->assertEquals($expectedquestions[$q['id']]->type, $q['type']);
288 // Parent questions must have parent eq to 0.
289 if ($q['multi']) {
290 $this->assertEquals(0, $q['parent']);
291 $this->assertEquals(get_string($expectedquestions[$q['id']]->options, 'survey'), $q['options']);
292 }
293 }
294
295 // Test user with no capabilities.
296 // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
297 assign_capability('mod/survey:participate', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
298 accesslib_clear_all_caches_for_unit_testing();
299
300 try {
301 mod_survey_external::get_questions($this->survey->id);
302 $this->fail('Exception expected due to missing capability.');
303 } catch (moodle_exception $e) {
304 $this->assertEquals('nopermissions', $e->errorcode);
305 }
306 }
307
55dca60f
JL
308 /**
309 * Test submit_answers
310 */
311 public function test_submit_answers() {
312 global $DB;
313
314 // Test user with full capabilities.
315 $this->setUser($this->student);
316
317 // Build our questions and responses array.
318 $realquestions = array();
319 $questions = survey_get_questions($this->survey);
320 $i = 5;
321 foreach ($questions as $q) {
322 if ($q->type >= 0) {
323 if ($q->multi) {
324 $subquestions = survey_get_subquestions($q);
325 foreach ($subquestions as $sq) {
326 $realquestions[] = array(
327 'key' => 'q' . $sq->id,
328 'value' => $i % 5 + 1 // Values between 1 and 5.
329 );
330 $i++;
331 }
332 } else {
333 $realquestions[] = array(
334 'key' => 'q' . $q->id,
335 'value' => $i % 5 + 1
336 );
337 $i++;
338 }
339 }
340 }
341
342 $result = mod_survey_external::submit_answers($this->survey->id, $realquestions);
343 $result = external_api::clean_returnvalue(mod_survey_external::submit_answers_returns(), $result);
344
345 $this->assertTrue($result['status']);
346 $this->assertCount(0, $result['warnings']);
347
348 $dbanswers = $DB->get_records_menu('survey_answers', array('survey' => $this->survey->id), '', 'question, answer1');
349 foreach ($realquestions as $q) {
350 $id = str_replace('q', '', $q['key']);
351 $this->assertEquals($q['value'], $dbanswers[$id]);
352 }
353
354 // Submit again, we expect an error here.
355 try {
356 mod_survey_external::submit_answers($this->survey->id, $realquestions);
357 $this->fail('Exception expected due to answers already submitted.');
358 } catch (moodle_exception $e) {
359 $this->assertEquals('alreadysubmitted', $e->errorcode);
360 }
361
362 // Test user with no capabilities.
363 // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
364 assign_capability('mod/survey:participate', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
365 accesslib_clear_all_caches_for_unit_testing();
366
367 try {
368 mod_survey_external::submit_answers($this->survey->id, $realquestions);
369 $this->fail('Exception expected due to missing capability.');
370 } catch (moodle_exception $e) {
371 $this->assertEquals('nopermissions', $e->errorcode);
372 }
373
374 // Test not-enrolled user.
375 $usernotenrolled = self::getDataGenerator()->create_user();
376 $this->setUser($usernotenrolled);
377 try {
378 mod_survey_external::submit_answers($this->survey->id, $realquestions);
379 $this->fail('Exception expected due to not enrolled user.');
380 } catch (moodle_exception $e) {
381 $this->assertEquals('requireloginerror', $e->errorcode);
382 }
383 }
384
a2926eb3 385}