MDL-68680 core_grades: check grade item before trigger delete event
[moodle.git] / lib / grade / tests / grade_grade_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  * @package    core_grades
19  * @category   phpunit
20  * @copyright  nicolas@moodle.com
21  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22  */
24 defined('MOODLE_INTERNAL') || die();
26 require_once(__DIR__.'/fixtures/lib.php');
29 class core_grade_grade_testcase extends grade_base_testcase {
31     public function test_grade_grade() {
32         $this->sub_test_grade_grade_construct();
33         $this->sub_test_grade_grade_insert();
34         $this->sub_test_grade_grade_update();
35         $this->sub_test_grade_grade_fetch();
36         $this->sub_test_grade_grade_fetch_all();
37         $this->sub_test_grade_grade_load_grade_item();
38         $this->sub_test_grade_grade_standardise_score();
39         $this->sub_test_grade_grade_is_locked();
40         $this->sub_test_grade_grade_set_hidden();
41         $this->sub_test_grade_grade_is_hidden();
42         $this->sub_test_grade_grade_deleted();
43         $this->sub_test_grade_grade_deleted_event();
44     }
46     protected function sub_test_grade_grade_construct() {
47         $params = new stdClass();
49         $params->itemid = $this->grade_items[0]->id;
50         $params->userid = 1;
51         $params->rawgrade = 88;
52         $params->rawgrademax = 110;
53         $params->rawgrademin = 18;
55         $grade_grade = new grade_grade($params, false);
56         $this->assertEquals($params->itemid, $grade_grade->itemid);
57         $this->assertEquals($params->rawgrade, $grade_grade->rawgrade);
58     }
60     protected function sub_test_grade_grade_insert() {
61         $grade_grade = new grade_grade();
62         $this->assertTrue(method_exists($grade_grade, 'insert'));
64         $grade_grade->itemid = $this->grade_items[0]->id;
65         $grade_grade->userid = 10;
66         $grade_grade->rawgrade = 88;
67         $grade_grade->rawgrademax = 110;
68         $grade_grade->rawgrademin = 18;
70         // Check the grade_item's needsupdate variable first.
71         $grade_grade->load_grade_item();
72         $this->assertEmpty($grade_grade->grade_item->needsupdate);
74         $grade_grade->insert();
76         $last_grade_grade = end($this->grade_grades);
78         $this->assertEquals($grade_grade->id, $last_grade_grade->id + 1);
80         // Timecreated will only be set if the grade was submitted by an activity module.
81         $this->assertTrue(empty($grade_grade->timecreated));
82         // Timemodified will only be set if the grade was submitted by an activity module.
83         $this->assertTrue(empty($grade_grade->timemodified));
85         // Keep our collection the same as is in the database.
86         $this->grade_grades[] = $grade_grade;
87     }
89     protected function sub_test_grade_grade_update() {
90         $grade_grade = new grade_grade($this->grade_grades[0], false);
91         $this->assertTrue(method_exists($grade_grade, 'update'));
92     }
94     protected function sub_test_grade_grade_fetch() {
95         $grade_grade = new grade_grade();
96         $this->assertTrue(method_exists($grade_grade, 'fetch'));
98         $grades = grade_grade::fetch(array('id'=>$this->grade_grades[0]->id));
99         $this->assertEquals($this->grade_grades[0]->id, $grades->id);
100         $this->assertEquals($this->grade_grades[0]->rawgrade, $grades->rawgrade);
101     }
103     protected function sub_test_grade_grade_fetch_all() {
104         $grade_grade = new grade_grade();
105         $this->assertTrue(method_exists($grade_grade, 'fetch_all'));
107         $grades = grade_grade::fetch_all(array());
108         $this->assertEquals(count($this->grade_grades), count($grades));
109     }
111     protected function sub_test_grade_grade_load_grade_item() {
112         $grade_grade = new grade_grade($this->grade_grades[0], false);
113         $this->assertTrue(method_exists($grade_grade, 'load_grade_item'));
114         $this->assertNull($grade_grade->grade_item);
115         $this->assertNotEmpty($grade_grade->itemid);
116         $this->assertNotNull($grade_grade->load_grade_item());
117         $this->assertNotNull($grade_grade->grade_item);
118         $this->assertEquals($this->grade_items[0]->id, $grade_grade->grade_item->id);
119     }
122     protected function sub_test_grade_grade_standardise_score() {
123         $this->assertEquals(4, round(grade_grade::standardise_score(6, 0, 7, 0, 5)));
124         $this->assertEquals(40, grade_grade::standardise_score(50, 30, 80, 0, 100));
125     }
128     /*
129      * Disabling this test: the set_locked() arguments have been modified, rendering these tests useless until they are re-written
131     protected function test_grade_grade_set_locked() {
132         $grade_item = new grade_item($this->grade_items[0]);
133         $grade = new grade_grade($grade_item->get_final(1));
134         $this->assertTrue(method_exists($grade, 'set_locked'));
136         $this->assertTrue(empty($grade_item->locked));
137         $this->assertTrue(empty($grade->locked));
139         $this->assertTrue($grade->set_locked(true));
140         $this->assertFalse(empty($grade->locked));
141         $this->assertTrue($grade->set_locked(false));
142         $this->assertTrue(empty($grade->locked));
144         $this->assertTrue($grade_item->set_locked(true, true));
145         $grade = new grade_grade($grade_item->get_final(1));
147         $this->assertFalse(empty($grade->locked));
148         $this->assertFalse($grade->set_locked(true, false));
150         $this->assertTrue($grade_item->set_locked(true, false));
151         $grade = new grade_grade($grade_item->get_final(1));
153         $this->assertTrue($grade->set_locked(true, false));
154     }
155     */
157     protected function sub_test_grade_grade_is_locked() {
158         $grade = new grade_grade($this->grade_grades[0], false);
159         $this->assertTrue(method_exists($grade, 'is_locked'));
161         $this->assertFalse($grade->is_locked());
162         $grade->locked = time();
163         $this->assertTrue($grade->is_locked());
164     }
166     protected function sub_test_grade_grade_set_hidden() {
167         $grade = new grade_grade($this->grade_grades[0], false);
168         $grade_item = new grade_item($this->grade_items[0], false);
169         $this->assertTrue(method_exists($grade, 'set_hidden'));
171         $this->assertEquals(0, $grade_item->hidden);
172         $this->assertEquals(0, $grade->hidden);
174         $grade->set_hidden(0);
175         $this->assertEquals(0, $grade->hidden);
177         $grade->set_hidden(1);
178         $this->assertEquals(1, $grade->hidden);
180         $grade->set_hidden(0);
181         $this->assertEquals(0, $grade->hidden);
182     }
184     protected function sub_test_grade_grade_is_hidden() {
185         $grade = new grade_grade($this->grade_grades[0], false);
186         $this->assertTrue(method_exists($grade, 'is_hidden'));
188         $this->assertFalse($grade->is_hidden());
189         $grade->hidden = 1;
190         $this->assertTrue($grade->is_hidden());
192         $grade->hidden = time()-666;
193         $this->assertFalse($grade->is_hidden());
195         $grade->hidden = time()+666;
196         $this->assertTrue($grade->is_hidden());
197     }
199     public function test_flatten_dependencies() {
200         // First test a simple normal case.
201         $a = array(1 => array(2, 3), 2 => array(), 3 => array(4), 4 => array());
202         $b = array();
203         $expecteda = array(1 => array(2, 3, 4), 2 => array(), 3 => array(4), 4 => array());
204         $expectedb = array(1 => 1);
206         test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b);
207         $this->assertSame($expecteda, $a);
208         $this->assertSame($expectedb, $b);
210         // Edge case - empty arrays.
211         $a = $b = $expecteda = $expectedb = array();
213         test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b);
214         $this->assertSame($expecteda, $a);
215         $this->assertSame($expectedb, $b);
217         // Circular dependency.
218         $a = array(1 => array(2), 2 => array(3), 3 => array(1));
219         $b = array();
220         $expecteda = array(1 => array(1, 2, 3), 2 => array(1, 2, 3), 3 => array(1, 2, 3));
222         test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b);
223         $this->assertSame($expecteda, $a);
224         // Note - we don't test the depth when we got circular dependencies - the main thing we wanted to test was that there was
225         // no ka-boom. The result would be hard to understand and doesn't matter.
227         // Circular dependency 2.
228         $a = array(1 => array(2), 2 => array(3), 3 => array(4), 4 => array(2, 1));
229         $b = array();
230         $expecteda = array(1 => array(1, 2, 3, 4), 2 => array(1, 2, 3, 4), 3 => array(1, 2, 3, 4), 4 => array(1, 2, 3, 4));
232         test_grade_grade_flatten_dependencies_array::test_flatten_dependencies_array($a, $b);
233         $this->assertSame($expecteda, $a);
234     }
236     public function test_grade_grade_min_max() {
237         global $CFG;
238         $initialminmaxtouse = $CFG->grade_minmaxtouse;
240         $this->setAdminUser();
241         $course = $this->getDataGenerator()->create_course();
242         $user = $this->getDataGenerator()->create_user();
243         $assignrecord = $this->getDataGenerator()->create_module('assign', array('course' => $course, 'grade' => 100));
244         $cm = get_coursemodule_from_instance('assign', $assignrecord->id);
245         $assigncontext = context_module::instance($cm->id);
246         $assign = new assign($assigncontext, $cm, $course);
248         // Fetch the assignment item.
249         $giparams = array('itemtype' => 'mod', 'itemmodule' => 'assign', 'iteminstance' => $assignrecord->id,
250                 'courseid' => $course->id, 'itemnumber' => 0);
251         $gi = grade_item::fetch($giparams);
252         $this->assertEquals(0, $gi->grademin);
253         $this->assertEquals(100, $gi->grademax);
255         // Give a grade to the student.
256         $usergrade = $assign->get_user_grade($user->id, true);
257         $usergrade->grade = 10;
258         $assign->update_grade($usergrade);
260         // Check the grade stored in gradebook.
261         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
262         $this->assertEquals(10, $gg->rawgrade);
263         $this->assertEquals(0, $gg->get_grade_min());
264         $this->assertEquals(100, $gg->get_grade_max());
266         // Change the min/max grade of the item.
267         $gi->grademax = 50;
268         $gi->grademin = 2;
269         $gi->update();
271         // Fetch the updated item.
272         $gi = grade_item::fetch($giparams);
274         // Now check the grade grade min/max with system setting.
275         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
276         grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting.
278         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
279         $this->assertEquals(2, $gg->get_grade_min());
280         $this->assertEquals(50, $gg->get_grade_max());
282         // Now with other system setting.
283         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
284         grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting, and reset static cache.
285         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
286         $this->assertEquals(0, $gg->get_grade_min());
287         $this->assertEquals(100, $gg->get_grade_max());
289         // Now with overriden setting in course.
290         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
291         grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_GRADE);
292         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
293         $this->assertEquals(0, $gg->get_grade_min());
294         $this->assertEquals(100, $gg->get_grade_max());
296         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
297         grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM);
298         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
299         $this->assertEquals(2, $gg->get_grade_min());
300         $this->assertEquals(50, $gg->get_grade_max());
302         $CFG->grade_minmaxtouse = $initialminmaxtouse;
303     }
305     public function test_grade_grade_min_max_with_course_item() {
306         global $CFG, $DB;
307         $initialminmaxtouse = $CFG->grade_minmaxtouse;
309         $this->setAdminUser();
310         $course = $this->getDataGenerator()->create_course();
311         $user = $this->getDataGenerator()->create_user();
312         $gi = grade_item::fetch_course_item($course->id);
314         // Fetch the category item.
315         $this->assertEquals(0, $gi->grademin);
316         $this->assertEquals(100, $gi->grademax);
318         // Give a grade to the student.
319         $gi->update_final_grade($user->id, 10);
321         // Check the grade min/max stored in gradebook.
322         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
323         $this->assertEquals(0, $gg->get_grade_min());
324         $this->assertEquals(100, $gg->get_grade_max());
326         // Change the min/max grade of the item.
327         $gi->grademin = 2;
328         $gi->grademax = 50;
329         $gi->update();
331         // Fetch the updated item.
332         $gi = grade_item::fetch_course_item($course->id);
334         // Now check the grade grade min/max with system setting.
335         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
336         grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting.
338         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
339         $this->assertEquals(0, $gg->get_grade_min());
340         $this->assertEquals(100, $gg->get_grade_max());
342         // Now with other system setting.
343         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
344         grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting, and reset static cache.
345         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
346         $this->assertEquals(0, $gg->get_grade_min());
347         $this->assertEquals(100, $gg->get_grade_max());
349         // Now with overriden setting in course.
350         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
351         grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_GRADE);
352         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
353         $this->assertEquals(0, $gg->get_grade_min());
354         $this->assertEquals(100, $gg->get_grade_max());
356         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
357         grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM);
358         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
359         $this->assertEquals(0, $gg->get_grade_min());
360         $this->assertEquals(100, $gg->get_grade_max());
362         $CFG->grade_minmaxtouse = $initialminmaxtouse;
363     }
365     public function test_grade_grade_min_max_with_category_item() {
366         global $CFG, $DB;
367         $initialminmaxtouse = $CFG->grade_minmaxtouse;
369         $this->setAdminUser();
370         $course = $this->getDataGenerator()->create_course();
371         $user = $this->getDataGenerator()->create_user();
372         $coursegi = grade_item::fetch_course_item($course->id);
374         // Create a category item.
375         $gc = new grade_category(array('courseid' => $course->id, 'fullname' => 'test'), false);
376         $gc->insert();
377         $gi = $gc->get_grade_item();
378         $gi->grademax = 100;
379         $gi->grademin = 0;
380         $gi->update();
382         // Fetch the category item.
383         $giparams = array('itemtype' => 'category', 'iteminstance' => $gc->id);
384         $gi = grade_item::fetch($giparams);
385         $this->assertEquals(0, $gi->grademin);
386         $this->assertEquals(100, $gi->grademax);
388         // Give a grade to the student.
389         $gi->update_final_grade($user->id, 10);
391         // Check the grade min/max stored in gradebook.
392         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
393         $this->assertEquals(0, $gg->get_grade_min());
394         $this->assertEquals(100, $gg->get_grade_max());
396         // Change the min/max grade of the item.
397         $gi->grademin = 2;
398         $gi->grademax = 50;
399         $gi->update();
401         // Fetch the updated item.
402         $gi = grade_item::fetch($giparams);
404         // Now check the grade grade min/max with system setting.
405         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
406         grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting.
408         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
409         $this->assertEquals(0, $gg->get_grade_min());
410         $this->assertEquals(100, $gg->get_grade_max());
412         // Now with other system setting.
413         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
414         grade_set_setting($course->id, 'minmaxtouse', null); // Ensure no course setting, and reset static cache.
415         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
416         $this->assertEquals(0, $gg->get_grade_min());
417         $this->assertEquals(100, $gg->get_grade_max());
419         // Now with overriden setting in course.
420         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
421         grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_GRADE);
422         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
423         $this->assertEquals(0, $gg->get_grade_min());
424         $this->assertEquals(100, $gg->get_grade_max());
426         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
427         grade_set_setting($course->id, 'minmaxtouse', GRADE_MIN_MAX_FROM_GRADE_ITEM);
428         $gg = grade_grade::fetch(array('userid' => $user->id, 'itemid' => $gi->id));
429         $this->assertEquals(0, $gg->get_grade_min());
430         $this->assertEquals(100, $gg->get_grade_max());
432         $CFG->grade_minmaxtouse = $initialminmaxtouse;
433     }
435     /**
436      * Tests when a grade_grade has been deleted.
437      */
438     public function sub_test_grade_grade_deleted() {
439         $dg = $this->getDataGenerator();
441         // Create the data we need for the tests.
442         $fs = new file_storage();
443         $u1 = $dg->create_user();
444         $c1 = $dg->create_course();
445         $a1 = $dg->create_module('assign', ['course' => $c1->id]);
446         $a1context = context_module::instance($a1->cmid);
448         $gi = new grade_item($dg->create_grade_item(
449             [
450                 'courseid' => $c1->id,
451                 'itemtype' => 'mod',
452                 'itemmodule' => 'assign',
453                 'iteminstance' => $a1->id
454             ]
455         ), false);
457         // Add feedback files to copy as our update.
458         $this->add_feedback_file_to_copy();
460         $grades['feedback'] = 'Nice feedback!';
461         $grades['feedbackformat'] = FORMAT_MOODLE;
462         $grades['feedbackfiles'] = [
463             'contextid' => 1,
464             'component' => 'test',
465             'filearea' => 'testarea',
466             'itemid' => 1
467         ];
469         $grades['userid'] = $u1->id;
470         grade_update('mod/assign', $gi->courseid, $gi->itemtype, $gi->itemmodule, $gi->iteminstance,
471             $gi->itemnumber, $grades);
473         // Feedback file area.
474         $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_FEEDBACK_FILEAREA);
475         $this->assertEquals(2, count($files));
477         // History file area.
478         $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_HISTORY_FEEDBACK_FILEAREA);
479         $this->assertEquals(2, count($files));
481         $gg = grade_grade::fetch(array('userid' => $u1->id, 'itemid' => $gi->id));
483         $gg->delete();
485         // Feedback file area.
486         $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_FEEDBACK_FILEAREA);
487         $this->assertEquals(0, count($files));
489         // History file area.
490         $files = $fs->get_area_files($a1context->id, GRADE_FILE_COMPONENT, GRADE_HISTORY_FEEDBACK_FILEAREA);
491         $this->assertEquals(2, count($files));
492     }
494     /**
495      * Creates a feedback file to copy to the gradebook area.
496      */
497     private function add_feedback_file_to_copy() {
498         $dummy = array(
499             'contextid' => 1,
500             'component' => 'test',
501             'filearea' => 'testarea',
502             'itemid' => 1,
503             'filepath' => '/',
504             'filename' => 'feedback1.txt'
505         );
507         $fs = get_file_storage();
508         $fs->create_file_from_string($dummy, '');
509     }
511     /**
512      * Tests grade_deleted event.
513      */
514     public function sub_test_grade_grade_deleted_event() {
515         global $DB;
516         $dg = $this->getDataGenerator();
518         // Create the data we need for the tests.
519         $u1 = $dg->create_user();
520         $u2 = $dg->create_user();
521         $c1 = $dg->create_course();
522         $a1 = $dg->create_module('assign', ['course' => $c1->id]);
524         $gi = new grade_item($dg->create_grade_item(
525             [
526                 'courseid' => $c1->id,
527                 'itemtype' => 'mod',
528                 'itemmodule' => 'assign',
529                 'iteminstance' => $a1->id
530             ]
531         ), false);
533         grade_update('mod/assign', $gi->courseid, $gi->itemtype, $gi->itemmodule, $gi->iteminstance,
534             $gi->itemnumber, ['userid' => $u1->id]);
535         grade_update('mod/assign', $gi->courseid, $gi->itemtype, $gi->itemmodule, $gi->iteminstance,
536             $gi->itemnumber, ['userid' => $u2->id]);
538         $gg = grade_grade::fetch(array('userid' => $u1->id, 'itemid' => $gi->id));
539         $this->assertEquals($u1->id, $gg->userid);
540         $gg->load_grade_item();
541         $this->assertEquals($gi->id, $gg->grade_item->id);
543         // Delete user with valid grade item.
544         $sink = $this->redirectEvents();
545         grade_user_delete($u1->id);
546         $events = $sink->get_events();
547         $event = reset($events);
548         $sink->close();
549         $this->assertInstanceOf('core\event\grade_deleted', $event);
551         $gg = grade_grade::fetch(array('userid' => $u2->id, 'itemid' => $gi->id));
552         $this->assertEquals($u2->id, $gg->userid);
553         $gg->load_grade_item();
554         $this->assertEquals($gi->id, $gg->grade_item->id);
556         // Delete grade item, mock up orphaned grade_grades.
557         $DB->delete_records('grade_items', ['id' => $gi->id]);
558         $gg = grade_grade::fetch(array('userid' => $u2->id, 'itemid' => $gi->id));
559         $this->assertEquals($u2->id, $gg->userid);
561         // No event is triggered and there is a debugging message.
562         $sink = $this->redirectEvents();
563         grade_user_delete($u2->id);
564         $this->assertDebuggingCalled("Missing grade item id $gi->id");
565         $events = $sink->get_events();
566         $sink->close();
567         $this->assertEmpty($events);
569         // The grade should be deleted.
570         $gg = grade_grade::fetch(array('userid' => $u2->id, 'itemid' => $gi->id));
571         $this->assertEmpty($gg);
572     }