MDL-63513 mod_assignment: Add removal of context users.
[moodle.git] / lib / tests / grading_externallib_test.php
blob7d2984facd18b08448f5de4fa190c7ce32ba605a
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.
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 defined('MOODLE_INTERNAL') || die();
19 global $CFG;
21 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
23 /**
24 * Unit tests for the grading API defined in core_grading_external class.
26 * @package core_grading
27 * @category external
28 * @copyright 2013 Paul Charsley
29 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
31 class core_grading_externallib_testcase extends externallib_advanced_testcase {
33 /**
34 * Test get_definitions
36 public function test_get_definitions() {
37 global $DB, $CFG, $USER;
39 $this->resetAfterTest(true);
40 // Create a course and assignment.
41 $coursedata['idnumber'] = 'idnumbercourse';
42 $coursedata['fullname'] = 'Lightwork Course';
43 $coursedata['summary'] = 'Lightwork Course description';
44 $coursedata['summaryformat'] = FORMAT_MOODLE;
45 $course = self::getDataGenerator()->create_course($coursedata);
47 $assigndata['course'] = $course->id;
48 $assigndata['name'] = 'lightwork assignment';
50 $cm = self::getDataGenerator()->create_module('assign', $assigndata);
52 // Create manual enrolment record.
53 $manualenroldata['enrol'] = 'manual';
54 $manualenroldata['status'] = 0;
55 $manualenroldata['courseid'] = $course->id;
56 $enrolid = $DB->insert_record('enrol', $manualenroldata);
58 // Create a teacher and give them capabilities.
59 $coursecontext = context_course::instance($course->id);
60 $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $coursecontext->id, 3);
61 $modulecontext = context_module::instance($cm->cmid);
62 $this->assignUserCapability('mod/assign:grade', $modulecontext->id, $roleid);
64 // Create the teacher's enrolment record.
65 $userenrolmentdata['status'] = 0;
66 $userenrolmentdata['enrolid'] = $enrolid;
67 $userenrolmentdata['userid'] = $USER->id;
68 $DB->insert_record('user_enrolments', $userenrolmentdata);
70 // Create a grading area.
71 $gradingarea = array(
72 'contextid' => $modulecontext->id,
73 'component' => 'mod_assign',
74 'areaname' => 'submissions',
75 'activemethod' => 'rubric'
77 $areaid = $DB->insert_record('grading_areas', $gradingarea);
79 // Create a rubric grading definition.
80 $rubricdefinition = array (
81 'areaid' => $areaid,
82 'method' => 'rubric',
83 'name' => 'test',
84 'status' => 20,
85 'copiedfromid' => 1,
86 'timecreated' => 1,
87 'usercreated' => $USER->id,
88 'timemodified' => 1,
89 'usermodified' => $USER->id,
90 'timecopied' => 0
92 $definitionid = $DB->insert_record('grading_definitions', $rubricdefinition);
94 // Create a criterion with levels.
95 $rubriccriteria1 = array (
96 'definitionid' => $definitionid,
97 'sortorder' => 1,
98 'description' => 'Demonstrate an understanding of disease control',
99 'descriptionformat' => 0
101 $criterionid1 = $DB->insert_record('gradingform_rubric_criteria', $rubriccriteria1);
102 $rubriclevel1 = array (
103 'criterionid' => $criterionid1,
104 'score' => 5,
105 'definition' => 'pass',
106 'definitionformat' => 0
108 $DB->insert_record('gradingform_rubric_levels', $rubriclevel1);
109 $rubriclevel2 = array (
110 'criterionid' => $criterionid1,
111 'score' => 10,
112 'definition' => 'excellent',
113 'definitionformat' => 0
115 $DB->insert_record('gradingform_rubric_levels', $rubriclevel2);
117 // Create a second criterion with levels.
118 $rubriccriteria2 = array (
119 'definitionid' => $definitionid,
120 'sortorder' => 2,
121 'description' => 'Demonstrate an understanding of brucellosis',
122 'descriptionformat' => 0
124 $criterionid2 = $DB->insert_record('gradingform_rubric_criteria', $rubriccriteria2);
125 $rubriclevel1 = array (
126 'criterionid' => $criterionid2,
127 'score' => 5,
128 'definition' => 'pass',
129 'definitionformat' => 0
131 $DB->insert_record('gradingform_rubric_levels', $rubriclevel1);
132 $rubriclevel2 = array (
133 'criterionid' => $criterionid2,
134 'score' => 10,
135 'definition' => 'excellent',
136 'definitionformat' => 0
138 $DB->insert_record('gradingform_rubric_levels', $rubriclevel2);
140 // Call the external function.
141 $cmids = array ($cm->cmid);
142 $areaname = 'submissions';
143 $result = core_grading_external::get_definitions($cmids, $areaname);
144 $result = external_api::clean_returnvalue(core_grading_external::get_definitions_returns(), $result);
146 $this->assertEquals(1, count($result['areas']));
147 $this->assertEquals(1, count($result['areas'][0]['definitions']));
148 $definition = $result['areas'][0]['definitions'][0];
150 $this->assertEquals($rubricdefinition['method'], $definition['method']);
151 $this->assertEquals($USER->id, $definition['usercreated']);
153 require_once("$CFG->dirroot/grade/grading/lib.php");
154 require_once($CFG->dirroot.'/grade/grading/form/'.$rubricdefinition['method'].'/lib.php');
156 $gradingmanager = get_grading_manager($areaid);
158 $this->assertEquals(1, count($definition[$rubricdefinition['method']]));
160 $rubricdetails = $definition[$rubricdefinition['method']];
161 $details = call_user_func('gradingform_'.$rubricdefinition['method'].'_controller::get_external_definition_details');
163 $this->assertEquals(2, count($rubricdetails[key($details)]));
165 $found = false;
166 foreach ($rubricdetails[key($details)] as $criterion) {
167 if ($criterion['id'] == $criterionid1) {
168 $this->assertEquals($rubriccriteria1['description'], $criterion['description']);
169 $this->assertEquals(2, count($criterion['levels']));
170 $found = true;
171 break;
174 $this->assertTrue($found);
178 * Test get_gradingform_instances
180 public function test_get_gradingform_instances() {
181 global $DB, $USER;
183 $this->resetAfterTest(true);
184 // Create a course and assignment.
185 $coursedata['idnumber'] = 'idnumbercourse';
186 $coursedata['fullname'] = 'Lightwork Course';
187 $coursedata['summary'] = 'Lightwork Course description';
188 $coursedata['summaryformat'] = FORMAT_MOODLE;
189 $course = self::getDataGenerator()->create_course($coursedata);
191 $assigndata['course'] = $course->id;
192 $assigndata['name'] = 'lightwork assignment';
194 $assign = self::getDataGenerator()->create_module('assign', $assigndata);
196 // Create manual enrolment record.
197 $manualenroldata['enrol'] = 'manual';
198 $manualenroldata['status'] = 0;
199 $manualenroldata['courseid'] = $course->id;
200 $enrolid = $DB->insert_record('enrol', $manualenroldata);
202 // Create a teacher and give them capabilities.
203 $coursecontext = context_course::instance($course->id);
204 $roleid = $this->assignUserCapability('moodle/course:viewparticipants', $coursecontext->id, 3);
205 $modulecontext = context_module::instance($assign->cmid);
206 $this->assignUserCapability('mod/assign:grade', $modulecontext->id, $roleid);
208 // Create the teacher's enrolment record.
209 $userenrolmentdata['status'] = 0;
210 $userenrolmentdata['enrolid'] = $enrolid;
211 $userenrolmentdata['userid'] = $USER->id;
212 $DB->insert_record('user_enrolments', $userenrolmentdata);
214 // Create a student with an assignment grade.
215 $student = self::getDataGenerator()->create_user();
216 $assigngrade = new stdClass();
217 $assigngrade->assignment = $assign->id;
218 $assigngrade->userid = $student->id;
219 $assigngrade->timecreated = time();
220 $assigngrade->timemodified = $assigngrade->timecreated;
221 $assigngrade->grader = $USER->id;
222 $assigngrade->grade = 50;
223 $assigngrade->attemptnumber = 0;
224 $gid = $DB->insert_record('assign_grades', $assigngrade);
226 // Create a grading area.
227 $gradingarea = array(
228 'contextid' => $modulecontext->id,
229 'component' => 'mod_assign',
230 'areaname' => 'submissions',
231 'activemethod' => 'rubric'
233 $areaid = $DB->insert_record('grading_areas', $gradingarea);
235 // Create a rubric grading definition.
236 $rubricdefinition = array (
237 'areaid' => $areaid,
238 'method' => 'rubric',
239 'name' => 'test',
240 'status' => 20,
241 'copiedfromid' => 1,
242 'timecreated' => 1,
243 'usercreated' => $USER->id,
244 'timemodified' => 1,
245 'usermodified' => $USER->id,
246 'timecopied' => 0
248 $definitionid = $DB->insert_record('grading_definitions', $rubricdefinition);
250 // Create a criterion with a level.
251 $rubriccriteria = array (
252 'definitionid' => $definitionid,
253 'sortorder' => 1,
254 'description' => 'Demonstrate an understanding of disease control',
255 'descriptionformat' => 0
257 $criterionid = $DB->insert_record('gradingform_rubric_criteria', $rubriccriteria);
258 $rubriclevel = array (
259 'criterionid' => $criterionid,
260 'score' => 50,
261 'definition' => 'pass',
262 'definitionformat' => 0
264 $levelid = $DB->insert_record('gradingform_rubric_levels', $rubriclevel);
266 // Create a grading instance.
267 $instance = array (
268 'definitionid' => $definitionid,
269 'raterid' => $USER->id,
270 'itemid' => $gid,
271 'status' => 1,
272 'feedbackformat' => 0,
273 'timemodified' => 1
275 $instanceid = $DB->insert_record('grading_instances', $instance);
277 // Create a filling.
278 $filling = array (
279 'instanceid' => $instanceid,
280 'criterionid' => $criterionid,
281 'levelid' => $levelid,
282 'remark' => 'excellent work',
283 'remarkformat' => 0
285 $DB->insert_record('gradingform_rubric_fillings', $filling);
287 // Call the external function.
288 $result = core_grading_external::get_gradingform_instances($definitionid, 0);
289 $result = external_api::clean_returnvalue(core_grading_external::get_gradingform_instances_returns(), $result);
291 $this->assertEquals(1, count($result['instances']));
292 $this->assertEquals($USER->id, $result['instances'][0]['raterid']);
293 $this->assertEquals($gid, $result['instances'][0]['itemid']);
294 $this->assertEquals(1, $result['instances'][0]['status']);
295 $this->assertEquals(1, $result['instances'][0]['timemodified']);
296 $this->assertEquals(1, count($result['instances'][0]['rubric']));
297 $this->assertEquals(1, count($result['instances'][0]['rubric']['criteria']));
298 $criteria = $result['instances'][0]['rubric']['criteria'];
299 $this->assertEquals($criterionid, $criteria[0]['criterionid']);
300 $this->assertEquals($levelid, $criteria[0]['levelid']);
301 $this->assertEquals('excellent work', $criteria[0]['remark']);
306 * Test save_definitions for rubric grading method
308 public function test_save_definitions_rubric() {
309 global $DB, $CFG, $USER;
311 $this->resetAfterTest(true);
312 // Create a course and assignment.
313 $course = self::getDataGenerator()->create_course();
314 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
315 $params['course'] = $course->id;
316 $instance = $generator->create_instance($params);
317 $cm = get_coursemodule_from_instance('assign', $instance->id);
318 $context = context_module::instance($cm->id);
319 $coursecontext = context_course::instance($course->id);
321 // Create the teacher.
322 $teacher = self::getDataGenerator()->create_user();
323 $USER->id = $teacher->id;
324 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
325 $this->assignUserCapability('moodle/grade:managegradingforms', $context->id, $teacherrole->id);
326 $this->getDataGenerator()->enrol_user($teacher->id,
327 $course->id,
328 $teacherrole->id);
330 // The grading area to insert.
331 $gradingarea = array(
332 'cmid' => $cm->id,
333 'contextid' => $context->id,
334 'component' => 'mod_assign',
335 'areaname' => 'submissions',
336 'activemethod' => 'rubric'
339 // The rubric definition to insert.
340 $rubricdefinition = array(
341 'method' => 'rubric',
342 'name' => 'test',
343 'description' => '',
344 'status' => 20,
345 'copiedfromid' => 1,
346 'timecreated' => 1,
347 'usercreated' => $teacher->id,
348 'timemodified' => 1,
349 'usermodified' => $teacher->id,
350 'timecopied' => 0
353 // The criterion to insert.
354 $rubriccriteria1 = array (
355 'sortorder' => 1,
356 'description' => 'Demonstrate an understanding of disease control',
357 'descriptionformat' => 0
360 // 3 levels for the criterion.
361 $rubriclevel1 = array (
362 'score' => 50,
363 'definition' => 'pass',
364 'definitionformat' => 0
366 $rubriclevel2 = array (
367 'score' => 100,
368 'definition' => 'excellent',
369 'definitionformat' => 0
371 $rubriclevel3 = array (
372 'score' => 0,
373 'definition' => 'fail',
374 'definitionformat' => 0
377 $rubriccriteria1['levels'] = array($rubriclevel1, $rubriclevel2, $rubriclevel3);
378 $rubricdefinition['rubric'] = array('rubric_criteria' => array($rubriccriteria1));
379 $gradingarea['definitions'] = array($rubricdefinition);
381 $results = core_grading_external::save_definitions(array($gradingarea));
383 $area = $DB->get_record('grading_areas',
384 array('contextid' => $context->id, 'component' => 'mod_assign', 'areaname' => 'submissions'),
385 '*', MUST_EXIST);
386 $this->assertEquals($area->activemethod, 'rubric');
388 $definition = $DB->get_record('grading_definitions', array('areaid' => $area->id, 'method' => 'rubric'), '*', MUST_EXIST);
389 $this->assertEquals($rubricdefinition['name'], $definition->name);
391 $criterion1 = $DB->get_record('gradingform_rubric_criteria', array('definitionid' => $definition->id), '*', MUST_EXIST);
392 $levels = $DB->get_records('gradingform_rubric_levels', array('criterionid' => $criterion1->id));
393 $validlevelcount = 0;
394 $expectedvalue = true;
395 foreach ($levels as $level) {
396 if ($level->score == 0) {
397 $this->assertEquals('fail', $level->definition);
398 $validlevelcount++;
399 } else if ($level->score == 50) {
400 $this->assertEquals('pass', $level->definition);
401 $validlevelcount++;
402 } else if ($level->score == 100) {
403 $this->assertEquals('excellent', $level->definition);
404 $excellentlevelid = $level->id;
405 $validlevelcount++;
406 } else {
407 $expectedvalue = false;
410 $this->assertEquals(3, $validlevelcount);
411 $this->assertTrue($expectedvalue, 'A level with an unexpected score was found');
413 // Test add a new level and modify an existing.
414 // Test add a new criteria and modify an existing.
415 // Test modify a definition.
417 // The rubric definition to update.
418 $rubricdefinition = array(
419 'id' => $definition->id,
420 'method' => 'rubric',
421 'name' => 'test changed',
422 'description' => '',
423 'status' => 20,
424 'copiedfromid' => 1,
425 'timecreated' => 1,
426 'usercreated' => $teacher->id,
427 'timemodified' => 1,
428 'usermodified' => $teacher->id,
429 'timecopied' => 0
432 // A criterion to update.
433 $rubriccriteria1 = array (
434 'id' => $criterion1->id,
435 'sortorder' => 1,
436 'description' => 'Demonstrate an understanding of rabies control',
437 'descriptionformat' => 0
440 // A new criterion to add.
441 $rubriccriteria2 = array (
442 'sortorder' => 2,
443 'description' => 'Demonstrate an understanding of anthrax control',
444 'descriptionformat' => 0
447 // A level to update.
448 $rubriclevel2 = array (
449 'id' => $excellentlevelid,
450 'score' => 75,
451 'definition' => 'excellent',
452 'definitionformat' => 0
455 // A level to insert.
456 $rubriclevel4 = array (
457 'score' => 100,
458 'definition' => 'superb',
459 'definitionformat' => 0
462 $rubriccriteria1['levels'] = array($rubriclevel1, $rubriclevel2, $rubriclevel3, $rubriclevel4);
463 $rubricdefinition['rubric'] = array('rubric_criteria' => array($rubriccriteria1, $rubriccriteria2));
464 $gradingarea['definitions'] = array($rubricdefinition);
466 $results = core_grading_external::save_definitions(array($gradingarea));
468 // Test definition name change.
469 $definition = $DB->get_record('grading_definitions', array('id' => $definition->id), '*', MUST_EXIST);
470 $this->assertEquals('test changed', $definition->name);
472 // Test criteria description change.
473 $modifiedcriteria = $DB->get_record('gradingform_rubric_criteria', array('id' => $criterion1->id), '*', MUST_EXIST);
474 $this->assertEquals('Demonstrate an understanding of rabies control', $modifiedcriteria->description);
476 // Test new criteria added.
477 $newcriteria = $DB->get_record('gradingform_rubric_criteria',
478 array('definitionid' => $definition->id, 'sortorder' => 2), '*', MUST_EXIST);
479 $this->assertEquals('Demonstrate an understanding of anthrax control', $newcriteria->description);
481 // Test excellent level score change from 100 to 75.
482 $modifiedlevel = $DB->get_record('gradingform_rubric_levels', array('id' => $excellentlevelid), '*', MUST_EXIST);
483 $this->assertEquals(75, $modifiedlevel->score);
485 // Test new superb level added.
486 $newlevel = $DB->get_record('gradingform_rubric_levels',
487 array('criterionid' => $criterion1->id, 'score' => 100), '*', MUST_EXIST);
488 $this->assertEquals('superb', $newlevel->definition);
490 // Test remove a level
491 // Test remove a criterion
492 // The rubric definition with the removed criterion and levels.
493 $rubricdefinition = array(
494 'id' => $definition->id,
495 'method' => 'rubric',
496 'name' => 'test changed',
497 'description' => '',
498 'status' => 20,
499 'copiedfromid' => 1,
500 'timecreated' => 1,
501 'usercreated' => $teacher->id,
502 'timemodified' => 1,
503 'usermodified' => $teacher->id,
504 'timecopied' => 0
507 $rubriccriteria1 = array (
508 'id' => $criterion1->id,
509 'sortorder' => 1,
510 'description' => 'Demonstrate an understanding of rabies control',
511 'descriptionformat' => 0
514 $rubriclevel1 = array (
515 'score' => 0,
516 'definition' => 'fail',
517 'definitionformat' => 0
519 $rubriclevel2 = array (
520 'score' => 100,
521 'definition' => 'pass',
522 'definitionformat' => 0
525 $rubriccriteria1['levels'] = array($rubriclevel1, $rubriclevel2);
526 $rubricdefinition['rubric'] = array('rubric_criteria' => array($rubriccriteria1));
527 $gradingarea['definitions'] = array($rubricdefinition);
529 $results = core_grading_external::save_definitions(array($gradingarea));
531 // Only 1 criterion should now exist.
532 $this->assertEquals(1, $DB->count_records('gradingform_rubric_criteria', array('definitionid' => $definition->id)));
533 $criterion1 = $DB->get_record('gradingform_rubric_criteria', array('definitionid' => $definition->id), '*', MUST_EXIST);
534 $this->assertEquals('Demonstrate an understanding of rabies control', $criterion1->description);
535 // This criterion should only have 2 levels.
536 $this->assertEquals(2, $DB->count_records('gradingform_rubric_levels', array('criterionid' => $criterion1->id)));
538 $gradingarea['activemethod'] = 'invalid';
539 $this->expectException('moodle_exception');
540 $results = core_grading_external::save_definitions(array($gradingarea));
545 * Tests save_definitions for the marking guide grading method
547 public function test_save_definitions_marking_guide() {
548 global $DB, $CFG, $USER;
550 $this->resetAfterTest(true);
551 // Create a course and assignment.
552 $course = self::getDataGenerator()->create_course();
553 $generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
554 $params['course'] = $course->id;
555 $instance = $generator->create_instance($params);
556 $cm = get_coursemodule_from_instance('assign', $instance->id);
557 $context = context_module::instance($cm->id);
558 $coursecontext = context_course::instance($course->id);
560 // Create the teacher.
561 $teacher = self::getDataGenerator()->create_user();
562 $USER->id = $teacher->id;
563 $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
564 $this->assignUserCapability('moodle/grade:managegradingforms', $context->id, $teacherrole->id);
565 $this->getDataGenerator()->enrol_user($teacher->id,
566 $course->id,
567 $teacherrole->id);
569 // Test insert a grading area with guide definition, criteria and comments.
570 $gradingarea = array(
571 'cmid' => $cm->id,
572 'contextid' => $context->id,
573 'component' => 'mod_assign',
574 'areaname' => 'submissions',
575 'activemethod' => 'guide'
578 $guidedefinition = array(
579 'method' => 'guide',
580 'name' => 'test',
581 'description' => '',
582 'status' => 20,
583 'copiedfromid' => 1,
584 'timecreated' => 1,
585 'usercreated' => $teacher->id,
586 'timemodified' => 1,
587 'usermodified' => $teacher->id,
588 'timecopied' => 0
591 $guidecomment = array(
592 'sortorder' => 1,
593 'description' => 'Students need to show that they understand the control of zoonoses',
594 'descriptionformat' => 0
596 $guidecriteria1 = array (
597 'sortorder' => 1,
598 'shortname' => 'Rabies Control',
599 'description' => 'Understand rabies control techniques',
600 'descriptionformat' => 0,
601 'descriptionmarkers' => 'Student must demonstrate that they understand rabies control',
602 'descriptionmarkersformat' => 0,
603 'maxscore' => 50
605 $guidecriteria2 = array (
606 'sortorder' => 2,
607 'shortname' => 'Anthrax Control',
608 'description' => 'Understand anthrax control',
609 'descriptionformat' => 0,
610 'descriptionmarkers' => 'Student must demonstrate that they understand anthrax control',
611 'descriptionmarkersformat' => 0,
612 'maxscore' => 50
615 $guidedefinition['guide'] = array('guide_criteria' => array($guidecriteria1, $guidecriteria2),
616 'guide_comments' => array($guidecomment));
617 $gradingarea['definitions'] = array($guidedefinition);
619 $results = core_grading_external::save_definitions(array($gradingarea));
620 $area = $DB->get_record('grading_areas',
621 array('contextid' => $context->id, 'component' => 'mod_assign', 'areaname' => 'submissions'),
622 '*', MUST_EXIST);
623 $this->assertEquals($area->activemethod, 'guide');
625 $definition = $DB->get_record('grading_definitions', array('areaid' => $area->id, 'method' => 'guide'), '*', MUST_EXIST);
626 $this->assertEquals($guidedefinition['name'], $definition->name);
627 $this->assertEquals(2, $DB->count_records('gradingform_guide_criteria', array('definitionid' => $definition->id)));
628 $this->assertEquals(1, $DB->count_records('gradingform_guide_comments', array('definitionid' => $definition->id)));
630 // Test removal of a criteria.
631 $guidedefinition['guide'] = array('guide_criteria' => array($guidecriteria1),
632 'guide_comments' => array($guidecomment));
633 $gradingarea['definitions'] = array($guidedefinition);
634 $results = core_grading_external::save_definitions(array($gradingarea));
635 $this->assertEquals(1, $DB->count_records('gradingform_guide_criteria', array('definitionid' => $definition->id)));
637 // Test an invalid method in the definition.
638 $guidedefinition['method'] = 'invalid';
639 $gradingarea['definitions'] = array($guidedefinition);
640 $this->expectException('invalid_parameter_exception');
641 $results = core_grading_external::save_definitions(array($gradingarea));