a2b0df2d76d15493ae753336142f66a47353b967
[moodle.git] / lib / tests / event_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  * Tests for event manager, base event and observers.
19  *
20  * @package    core
21  * @category   phpunit
22  * @copyright  2013 Petr Skoda {@link http://skodak.org}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 require_once(__DIR__.'/fixtures/event_fixtures.php');
30 class core_event_testcase extends advanced_testcase {
32     const DEBUGGING_MSG = 'Events API using $handlers array has been deprecated in favour of Events 2 API, please use it instead.';
34     public function test_event_properties() {
35         global $USER;
37         $system = \context_system::instance();
38         $event = \core_tests\event\unittest_executed::create(array('context'=>$system, 'objectid'=>5, 'other'=>array('sample'=>null, 'xx'=>10)));
40         $this->assertSame('\core_tests\event\unittest_executed', $event->eventname);
41         $this->assertSame('core_tests', $event->component);
42         $this->assertSame('executed', $event->action);
43         $this->assertSame('unittest', $event->target);
44         $this->assertSame(5, $event->objectid);
45         $this->assertSame('u', $event->crud);
46         $this->assertSame(\core\event\base::LEVEL_PARTICIPATING, $event->edulevel);
48         $this->assertEquals($system, $event->get_context());
49         $this->assertSame($system->id, $event->contextid);
50         $this->assertSame($system->contextlevel, $event->contextlevel);
51         $this->assertSame($system->instanceid, $event->contextinstanceid);
53         $this->assertSame($USER->id, $event->userid);
54         $this->assertSame(0, $event->courseid);
56         $this->assertNull($event->relateduserid);
57         $this->assertFalse(isset($event->relateduserid));
59         $this->assertSame(0, $event->anonymous);
61         $this->assertSame(array('sample'=>null, 'xx'=>10), $event->other);
62         $this->assertTrue(isset($event->other['xx']));
63         $this->assertFalse(isset($event->other['sample']));
65         $this->assertLessThanOrEqual(time(), $event->timecreated);
67         try {
68             $event->courseid = 2;
69             $this->fail('Exception expected on event modification');
70         } catch (\moodle_exception $e) {
71             $this->assertInstanceOf('coding_exception', $e);
72         }
74         try {
75             $event->xxxx = 1;
76             $this->fail('Exception expected on event modification');
77         } catch (\moodle_exception $e) {
78             $this->assertInstanceOf('coding_exception', $e);
79         }
81         $event2 = \core_tests\event\unittest_executed::create(array('contextid'=>$system->id, 'objectid'=>5, 'anonymous'=>1, 'other'=>array('sample'=>null, 'xx'=>10)));
82         $this->assertEquals($event->get_context(), $event2->get_context());
83         $this->assertSame(1, $event2->anonymous);
85         $event3 = \core_tests\event\unittest_executed::create(array('contextid'=>$system->id, 'objectid'=>5, 'anonymous'=>true, 'other'=>array('sample'=>null, 'xx'=>10)));
86         $this->assertSame(1, $event3->anonymous);
87     }
89     public function test_event_properties_guessing() {
90         global $USER;
91         $this->resetAfterTest();
93         $course = $this->getDataGenerator()->create_course();
94         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
95         $context = context_module::instance($forum->cmid);
96         $event = \core_tests\event\unittest_executed::create(array('context' => $context, 'objectid' => 5));
98         // Check guessed course ID, and default properties.
99         $this->assertSame('\core_tests\event\unittest_executed', $event->eventname);
100         $this->assertSame('core_tests', $event->component);
101         $this->assertSame('executed', $event->action);
102         $this->assertSame('unittest', $event->target);
103         $this->assertSame(5, $event->objectid);
104         $this->assertEquals($context, $event->get_context());
105         $this->assertEquals($course->id, $event->courseid);
106         $this->assertSame($USER->id, $event->userid);
107         $this->assertNull($event->relateduserid);
109         $user = $this->getDataGenerator()->create_user();
110         $context = context_user::instance($user->id);
111         $event = \core_tests\event\unittest_executed::create(array('contextid' => $context->id, 'objectid' => 5));
113         // Check guessing on contextid, and user context level.
114         $this->assertEquals($context, $event->get_context());
115         $this->assertEquals($context->id, $event->contextid);
116         $this->assertEquals($context->contextlevel, $event->contextlevel);
117         $this->assertSame(0, $event->courseid);
118         $this->assertSame($USER->id, $event->userid);
119         $this->assertSame($user->id, $event->relateduserid);
120     }
122     public function test_observers_parsing() {
123         global $CFG;
125         $observers = array(
126             array(
127                 'eventname'   => '*',
128                 'callback'    => array('\core_tests\event\unittest_observer', 'observe_all_alt'),
129             ),
130             array(
131                 'eventname'   => '\core_tests\event\unittest_executed',
132                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
133                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
134             ),
135             array(
136                 'eventname'   => '*',
137                 'callback'    => array('\core_tests\event\unittest_observer', 'observe_all'),
138                 'includefile' => null,
139                 'internal'    => 1,
140                 'priority'    => 10,
141             ),
142             array(
143                 'eventname'   => '\core\event\unknown_executed',
144                 'callback'    => '\core_tests\event\unittest_observer::broken_observer',
145                 'priority'    => 100,
146             ),
147             array(
148                 'eventname'   => '\core_tests\event\unittest_executed',
149                 'callback'    => '\core_tests\event\unittest_observer::external_observer',
150                 'priority'    => 200,
151                 'internal'    => 0,
152             ),
153         );
155         $result = \core\event\manager::phpunit_replace_observers($observers);
156         $this->assertCount(3, $result);
158         $expected = array();
159         $observer = new stdClass();
160         $observer->callable = '\core_tests\event\unittest_observer::external_observer';
161         $observer->priority = 200;
162         $observer->internal = false;
163         $observer->includefile = null;
164         $observer->plugintype = null;
165         $observer->plugin = null;
166         $expected[0] = $observer;
167         $observer = new stdClass();
168         $observer->callable = '\core_tests\event\unittest_observer::observe_one';
169         $observer->priority = 0;
170         $observer->internal = true;
171         $observer->includefile = $CFG->dirroot.'/lib/tests/fixtures/event_fixtures.php';
172         $observer->plugintype = null;
173         $observer->plugin = null;
174         $expected[1] = $observer;
176         $this->assertEquals($expected, $result['\core_tests\event\unittest_executed']);
178         $expected = array();
179         $observer = new stdClass();
180         $observer->callable = '\core_tests\event\unittest_observer::broken_observer';
181         $observer->priority = 100;
182         $observer->internal = true;
183         $observer->includefile = null;
184         $observer->plugintype = null;
185         $observer->plugin = null;
186         $expected[0] = $observer;
188         $this->assertEquals($expected, $result['\core\event\unknown_executed']);
190         $expected = array();
191         $observer = new stdClass();
192         $observer->callable = array('\core_tests\event\unittest_observer', 'observe_all');
193         $observer->priority = 10;
194         $observer->internal = true;
195         $observer->includefile = null;
196         $observer->plugintype = null;
197         $observer->plugin = null;
198         $expected[0] = $observer;
199         $observer = new stdClass();
200         $observer->callable = array('\core_tests\event\unittest_observer', 'observe_all_alt');
201         $observer->priority = 0;
202         $observer->internal = true;
203         $observer->includefile = null;
204         $observer->plugintype = null;
205         $observer->plugin = null;
206         $expected[1] = $observer;
208         $this->assertEquals($expected, $result['\core\event\base']);
210         // Now test broken stuff...
212         $observers = array(
213             array(
214                 'eventname'   => 'core_tests\event\unittest_executed', // Fix leading backslash.
215                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
216                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
217                 'internal'    => 1, // Cast to bool.
218             ),
219         );
220         $result = \core\event\manager::phpunit_replace_observers($observers);
221         $this->assertCount(1, $result);
222         $expected = array();
223         $observer = new stdClass();
224         $observer->callable = '\core_tests\event\unittest_observer::observe_one';
225         $observer->priority = 0;
226         $observer->internal = true;
227         $observer->includefile = $CFG->dirroot.'/lib/tests/fixtures/event_fixtures.php';
228         $observer->plugintype = null;
229         $observer->plugin = null;
230         $expected[0] = $observer;
231         $this->assertEquals($expected, $result['\core_tests\event\unittest_executed']);
233         $observers = array(
234             array(
235                 // Missing eventclass.
236                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
237                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
238             ),
239         );
240         $result = \core\event\manager::phpunit_replace_observers($observers);
241         $this->assertCount(0, $result);
242         $this->assertDebuggingCalled();
244         $observers = array(
245             array(
246                 'eventname'   => '', // Empty eventclass.
247                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
248                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
249             ),
250         );
251         $result = \core\event\manager::phpunit_replace_observers($observers);
252         $this->assertCount(0, $result);
253         $this->assertDebuggingCalled();
255         $observers = array(
256             array(
257                 'eventname'   => '\core_tests\event\unittest_executed',
258                 // Missing callable.
259                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
260             ),
261         );
262         $result = \core\event\manager::phpunit_replace_observers($observers);
263         $this->assertCount(0, $result);
264         $this->assertDebuggingCalled();
266         $observers = array(
267             array(
268                 'eventname'   => '\core_tests\event\unittest_executed',
269                 'callback'    => '', // Empty callable.
270                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
271             ),
272         );
273         $result = \core\event\manager::phpunit_replace_observers($observers);
274         $this->assertCount(0, $result);
275         $this->assertDebuggingCalled();
277         $observers = array(
278             array(
279                 'eventname'   => '\core_tests\event\unittest_executed',
280                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
281                 'includefile' => 'lib/tests/fixtures/event_fixtures.php_xxx', // Missing file.
282             ),
283         );
284         $result = \core\event\manager::phpunit_replace_observers($observers);
285         $this->assertCount(0, $result);
286         $this->assertDebuggingCalled();
287     }
289     public function test_normal_dispatching() {
290         $observers = array(
291             array(
292                 'eventname'   => '\core_tests\event\unittest_executed',
293                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
294             ),
295             array(
296                 'eventname'   => '*',
297                 'callback'    => '\core_tests\event\unittest_observer::observe_all',
298                 'includefile' => null,
299                 'internal'    => 1,
300                 'priority'    => 9999,
301             ),
302         );
304         \core\event\manager::phpunit_replace_observers($observers);
305         \core_tests\event\unittest_observer::reset();
307         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
308         $event1->nest = 1;
309         $this->assertFalse($event1->is_triggered());
310         $this->assertFalse($event1->is_dispatched());
311         $this->assertFalse($event1->is_restored());
312         $event1->trigger();
313         $this->assertTrue($event1->is_triggered());
314         $this->assertTrue($event1->is_dispatched());
315         $this->assertFalse($event1->is_restored());
317         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
318         $event1->trigger();
320         $this->assertSame(
321             array('observe_all-nesting-1', 'observe_one-1', 'observe_all-666', 'observe_one-666', 'observe_all-2', 'observe_one-2'),
322             \core_tests\event\unittest_observer::$info);
323     }
325     public function test_event_sink() {
326         $sink = $this->redirectEvents();
327         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
328         $event1->trigger();
329         $this->assertSame(1, $sink->count());
330         $retult = $sink->get_events();
331         $this->assertSame($event1, $retult[0]);
333         $event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
334         $event2->trigger();
335         $this->assertSame(2, $sink->count());
336         $retult = $sink->get_events();
337         $this->assertSame($event1, $retult[0]);
338         $this->assertSame($event2, $retult[1]);
340         $sink->clear();
341         $this->assertSame(0, $sink->count());
342         $this->assertSame(array(), $sink->get_events());
344         $event3 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>3, 'xx'=>10)));
345         $event3->trigger();
346         $this->assertSame(1, $sink->count());
347         $retult = $sink->get_events();
348         $this->assertSame($event3, $retult[0]);
350         $sink->close();
351         $event4 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>4, 'xx'=>10)));
352         $event4->trigger();
353         $this->assertSame(1, $sink->count());
354         $retult = $sink->get_events();
355         $this->assertSame($event3, $retult[0]);
356     }
358     public function test_ignore_exceptions() {
359         $observers = array(
361             array(
362                 'eventname'   => '\core_tests\event\unittest_executed',
363                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
364             ),
366             array(
367                 'eventname'   => '\core_tests\event\unittest_executed',
368                 'callback'    => '\core_tests\event\unittest_observer::broken_observer',
369                 'priority'    => 100,
370             ),
371         );
373         \core\event\manager::phpunit_replace_observers($observers);
374         \core_tests\event\unittest_observer::reset();
376         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
377         $event1->trigger();
378         $this->assertDebuggingCalled();
380         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
381         $event1->trigger();
382         $this->assertDebuggingCalled();
384         $this->assertSame(
385             array('broken_observer-1', 'observe_one-1', 'broken_observer-2', 'observe_one-2'),
386             \core_tests\event\unittest_observer::$info);
387     }
389     public function test_external_buffer() {
390         global $DB;
392         $this->preventResetByRollback();
394         $observers = array(
396             array(
397                 'eventname'   => '\core_tests\event\unittest_executed',
398                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
399             ),
401             array(
402                 'eventname'   => '\core_tests\event\unittest_executed',
403                 'callback'    => '\core_tests\event\unittest_observer::external_observer',
404                 'priority'    => 200,
405                 'internal'    => 0,
406             ),
407         );
409         \core\event\manager::phpunit_replace_observers($observers);
410         \core_tests\event\unittest_observer::reset();
412         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
413         $event1->trigger();
414         $event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
415         $event2->trigger();
417         $this->assertSame(
418             array('external_observer-1', 'observe_one-1', 'external_observer-2', 'observe_one-2'),
419             \core_tests\event\unittest_observer::$info);
421         \core\event\manager::phpunit_replace_observers($observers);
422         \core_tests\event\unittest_observer::reset();
424         $this->assertSame(array(), \core_tests\event\unittest_observer::$info);
426         $trans = $DB->start_delegated_transaction();
428         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
429         $event1->trigger();
430         $event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
431         $event2->trigger();
433         $this->assertSame(
434             array('observe_one-1', 'observe_one-2'),
435             \core_tests\event\unittest_observer::$info);
437         $trans->allow_commit();
439         $this->assertSame(
440             array('observe_one-1', 'observe_one-2', 'external_observer-1', 'external_observer-2'),
441             \core_tests\event\unittest_observer::$info);
443         \core\event\manager::phpunit_replace_observers($observers);
444         \core_tests\event\unittest_observer::reset();
446         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
447         $event1->trigger();
448         $trans = $DB->start_delegated_transaction();
449         $event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
450         $event2->trigger();
451         try {
452             $trans->rollback(new \moodle_exception('xxx'));
453             $this->fail('Expecting exception');
454         } catch (\moodle_exception $e) {
455             $this->assertInstanceOf('moodle_exception', $e);
456         }
458         $this->assertSame(
459             array('external_observer-1', 'observe_one-1', 'observe_one-2'),
460             \core_tests\event\unittest_observer::$info);
461     }
463     public function test_rollback() {
464         global $DB;
466         $this->resetAfterTest();
467         $this->preventResetByRollback();
469         $observers = array(
470             array(
471                 'eventname'   => '\core_tests\event\unittest_executed',
472                 'callback'    => '\core_tests\event\unittest_observer::external_observer',
473                 'internal'    => 0,
474             ),
475         );
477         \core\event\manager::phpunit_replace_observers($observers);
478         \core_tests\event\unittest_observer::reset();
480         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
482         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
483         $this->assertCount(1, \core_tests\event\unittest_observer::$event);
484         \core_tests\event\unittest_observer::reset();
486         $transaction1 = $DB->start_delegated_transaction();
488         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
489         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
491         $transaction2 = $DB->start_delegated_transaction();
493         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
494         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
496         try {
497             $transaction2->rollback(new Exception('x'));
498             $this->fail('Expecting exception');
499         } catch (Exception $e) {}
500         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
502         $this->assertTrue($DB->is_transaction_started());
504         try {
505             $transaction1->rollback(new Exception('x'));
506             $this->fail('Expecting exception');
507         } catch (Exception $e) {}
508         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
510         $this->assertFalse($DB->is_transaction_started());
512         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
513         $this->assertCount(1, \core_tests\event\unittest_observer::$event);
514     }
516     public function test_forced_rollback() {
517         global $DB;
519         $this->resetAfterTest();
520         $this->preventResetByRollback();
522         $observers = array(
523             array(
524                 'eventname'   => '\core_tests\event\unittest_executed',
525                 'callback'    => '\core_tests\event\unittest_observer::external_observer',
526                 'internal'    => 0,
527             ),
528         );
530         \core\event\manager::phpunit_replace_observers($observers);
531         \core_tests\event\unittest_observer::reset();
533         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
535         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
536         $this->assertCount(1, \core_tests\event\unittest_observer::$event);
537         \core_tests\event\unittest_observer::reset();
539         $transaction1 = $DB->start_delegated_transaction();
541         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
542         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
544         $transaction2 = $DB->start_delegated_transaction();
546         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
547         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
549         $DB->force_transaction_rollback();
550         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
552         $this->assertFalse($DB->is_transaction_started());
554         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
555         $this->assertCount(1, \core_tests\event\unittest_observer::$event);
556     }
558     public function test_deprecated() {
559         global $DB;
561         $this->resetAfterTest(true);
563         $event = \core_tests\event\deprecated_event1::create();
564         $this->assertDebuggingCalled('level property is deprecated, use edulevel property instead');
566         $this->assertSame($event::LEVEL_TEACHING, $event->level);
567         $this->assertDebuggingCalled('level property is deprecated, use edulevel property instead');
569         $this->assertTrue(isset($event->level));
570         $this->assertDebuggingCalled('level property is deprecated, use edulevel property instead');
572         $this->assertSame($event::LEVEL_TEACHING, $event->edulevel);
573     }
575     public function test_legacy() {
576         global $DB, $CFG;
578         $this->resetAfterTest(true);
580         $observers = array(
581             array(
582                 'eventname'   => '\core_tests\event\unittest_executed',
583                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
584             ),
585             array(
586                 'eventname'   => '*',
587                 'callback'    => '\core_tests\event\unittest_observer::observe_all',
588                 'includefile' => null,
589                 'internal'    => 1,
590                 'priority'    => 9999,
591             ),
592         );
594         $DB->delete_records('log', array());
595         events_update_definition('unittest');
596         $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
597         $DB->delete_records_select('events_handlers', "component <> 'unittest'");
598         events_get_handlers('reset');
599         $this->assertEquals(3, $DB->count_records('events_handlers'));
600         set_config('loglifetime', 60*60*24*5);
602         \core\event\manager::phpunit_replace_observers($observers);
603         \core_tests\event\unittest_observer::reset();
605         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
606         $event1->trigger();
607         $this->assertDebuggingCalled(self::DEBUGGING_MSG, DEBUG_DEVELOPER);
609         $event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>6, 'xx'=>11)));
610         $event2->nest = true;
611         $event2->trigger();
612         $this->assertDebuggingCalledCount(2, array(self::DEBUGGING_MSG, self::DEBUGGING_MSG), array(DEBUG_DEVELOPER, DEBUG_DEVELOPER));
614         $this->assertSame(
615             array('observe_all-5', 'observe_one-5', 'legacy_handler-0', 'observe_all-nesting-6', 'legacy_handler-0', 'observe_one-6', 'observe_all-666', 'observe_one-666', 'legacy_handler-0'),
616             \core_tests\event\unittest_observer::$info);
618         $this->assertSame($event1, \core_tests\event\unittest_observer::$event[0]);
619         $this->assertSame($event1, \core_tests\event\unittest_observer::$event[1]);
620         $this->assertSame(array(0, 5), \core_tests\event\unittest_observer::$event[2]);
622         $logs = $DB->get_records('log', array(), 'id ASC');
623         $this->assertCount(0, $logs);
624     }
626     public function test_restore_event() {
627         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
628         $data1 = $event1->get_data();
630         $event2 = \core\event\base::restore($data1, array('origin'=>'clid'));
631         $data2 = $event2->get_data();
633         $this->assertTrue($event2->is_triggered());
634         $this->assertTrue($event2->is_restored());
635         $this->assertEquals($data1, $data2);
636         $this->assertInstanceOf('core_tests\event\unittest_executed', $event2);
638         $this->assertEquals($event1->get_context(), $event2->get_context());
640         // Now test problematic data.
641         $data3 = $data1;
642         $data3['eventname'] = '\\a\\b\\c';
643         $event3 = \core\event\base::restore($data3, array());
644         $this->assertFalse($event3, 'Class name must match');
646         $data4 = $data1;
647         unset($data4['userid']);
648         $event4 = \core\event\base::restore($data4, array());
649         $this->assertInstanceOf('core_tests\event\unittest_executed', $event4);
650         $this->assertDebuggingCalled();
652         $data5 = $data1;
653         $data5['xx'] = 'xx';
654         $event5 = \core\event\base::restore($data5, array());
655         $this->assertInstanceOf('core_tests\event\unittest_executed', $event5);
656         $this->assertDebuggingCalled();
658     }
660     public function test_trigger_problems() {
661         $this->resetAfterTest(true);
663         $event = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
664         $event->trigger();
665         try {
666             $event->trigger();
667             $this->fail('Exception expected on double trigger');
668         } catch (\moodle_exception $e) {
669             $this->assertInstanceOf('coding_exception', $e);
670         }
672         $data = $event->get_data();
673         $restored = \core_tests\event\unittest_executed::restore($data, array());
674         $this->assertTrue($restored->is_triggered());
675         $this->assertTrue($restored->is_restored());
677         try {
678             $restored->trigger();
679             $this->fail('Exception expected on triggering of restored event');
680         } catch (\moodle_exception $e) {
681             $this->assertInstanceOf('coding_exception', $e);
682         }
684         $event = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
685         try {
686             \core\event\manager::dispatch($event);
687             $this->fail('Exception expected on manual event dispatching');
688         } catch (\moodle_exception $e) {
689             $this->assertInstanceOf('coding_exception', $e);
690         }
691     }
693     public function test_bad_events() {
694         $this->resetAfterTest(true);
696         try {
697             $event = \core_tests\event\unittest_executed::create(array('other'=>array('sample'=>5, 'xx'=>10)));
698             $this->fail('Exception expected when context and contextid missing');
699         } catch (\moodle_exception $e) {
700             $this->assertInstanceOf('coding_exception', $e);
701         }
703         $event = \core_tests\event\bad_event1::create(array('context'=>\context_system::instance()));
704         try {
705             $event->trigger();
706             $this->fail('Exception expected when $data not valid');
707         } catch (\moodle_exception $e) {
708             $this->assertInstanceOf('\coding_exception', $e);
709         }
711         $event = \core_tests\event\bad_event2::create(array('context'=>\context_system::instance()));
712         try {
713             $event->trigger();
714             $this->fail('Exception expected when $data not valid');
715         } catch (\moodle_exception $e) {
716             $this->assertInstanceOf('\coding_exception', $e);
717         }
719         $event = \core_tests\event\bad_event2b::create(array('context'=>\context_system::instance()));
720         @$event->trigger();
721         $this->assertDebuggingCalled();
723         $event = \core_tests\event\bad_event3::create(array('context'=>\context_system::instance()));
724         @$event->trigger();
725         $this->assertDebuggingCalled();
727         $event = \core_tests\event\bad_event4::create(array('context'=>\context_system::instance()));
728         @$event->trigger();
729         $this->assertDebuggingCalled();
731         $event = \core_tests\event\bad_event5::create(array('context'=>\context_system::instance()));
732         @$event->trigger();
733         $this->assertDebuggingCalled();
735         $event = \core_tests\event\bad_event6::create(array('objectid'=>1, 'context'=>\context_system::instance()));
736         $event->trigger();
737         $this->assertDebuggingCalled('Unknown table specified in objecttable field');
739         $event = \core_tests\event\bad_event7::create(array('objectid'=>1, 'context'=>\context_system::instance()));
740         try {
741             $event->trigger();
742             $this->fail('Exception expected when $data contains objectid but objecttable not specified');
743         } catch (\moodle_exception $e) {
744             $this->assertInstanceOf('\coding_exception', $e);
745         }
747         $event = \core_tests\event\bad_event8::create(array('context'=>\context_system::instance()));
748         $event->trigger();
749         $this->assertDebuggingCalled('Event property objectid must be set when objecttable is defined');
750     }
752     public function test_problematic_events() {
753         $this->resetAfterTest(true);
755         $event1 = \core_tests\event\problematic_event1::create(array('context'=>\context_system::instance()));
756         $this->assertDebuggingNotCalled();
757         $this->assertNull($event1->xxx);
758         $this->assertDebuggingCalled();
760         $event2 = \core_tests\event\problematic_event1::create(array('xxx'=>0, 'context'=>\context_system::instance()));
761         $this->assertDebuggingCalled();
763         set_debugging(DEBUG_NONE);
764         $event3 = \core_tests\event\problematic_event1::create(array('xxx'=>0, 'context'=>\context_system::instance()));
765         $this->assertDebuggingNotCalled();
766         set_debugging(DEBUG_DEVELOPER);
768         $event4 = \core_tests\event\problematic_event1::create(array('context'=>\context_system::instance(), 'other'=>array('a'=>1)));
769         $event4->trigger();
770         $this->assertDebuggingNotCalled();
772         $event5 = \core_tests\event\problematic_event1::create(array('context'=>\context_system::instance(), 'other'=>(object)array('a'=>1)));
773         $this->assertDebuggingNotCalled();
774         $event5->trigger();
775         $this->assertDebuggingCalled();
777         $url = new moodle_url('/admin/');
778         $event6 = \core_tests\event\problematic_event1::create(array('context'=>\context_system::instance(), 'other'=>array('a'=>$url)));
779         $this->assertDebuggingNotCalled();
780         $event6->trigger();
781         $this->assertDebuggingCalled();
783         // Check that whole float numbers do not trigger debugging messages.
784         $event7 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(),
785             'other' => array('wholenumber' => 90.0000, 'numberwithdecimals' => 54.7656, 'sample' => 1)));
786         $event7->trigger();
787         $this->assertDebuggingNotCalled();
789         $event = \core_tests\event\problematic_event2::create(array());
790         $this->assertDebuggingNotCalled();
791         $event = \core_tests\event\problematic_event2::create(array('context'=>\context_system::instance()));
792         $this->assertDebuggingCalled();
794         $event = \core_tests\event\problematic_event3::create(array('other'=>1));
795         $this->assertDebuggingNotCalled();
796         $event = \core_tests\event\problematic_event3::create(array());
797         $this->assertDebuggingCalled();
798     }
800     public function test_record_snapshots() {
801         global $DB;
803         $this->resetAfterTest(true);
805         $event = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
806         $course1 = $DB->get_record('course', array('id'=>1));
807         $this->assertNotEmpty($course1);
809         $event->add_record_snapshot('course', $course1);
811         $result = $event->get_record_snapshot('course', $course1->id);
812         // Convert to arrays because record snapshot returns a clone of the object.
813         $this->assertSame((array)$course1, (array)$result);
815         $user = $event->get_record_snapshot('user', 1);
816         $this->assertEquals(1, $user->id);
817         $this->assertSame('guest', $user->username);
819         $event->add_record_snapshot('course', $course1);
820         $event->trigger();
821         try {
822             $event->add_record_snapshot('course', $course1);
823             $this->fail('Updating of snapshots after trigger is not ok');;
824         } catch (\moodle_exception $e) {
825             $this->assertInstanceOf('\coding_exception', $e);
826         }
828         $event2 = \core_tests\event\unittest_executed::restore($event->get_data(), array());
829         try {
830             $event2->get_record_snapshot('course', $course1->id);
831             $this->fail('Reading of snapshots from restored events is not ok');;
832         } catch (\moodle_exception $e) {
833             $this->assertInstanceOf('\coding_exception', $e);
834         }
835     }
837     public function test_get_name() {
838         $event = \core_tests\event\noname_event::create(array('other' => array('sample' => 1, 'xx' => 10)));
839         $this->assertEquals("core_tests: noname event", $event->get_name());
840     }
842     public function test_iteration() {
843         $event = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
845         $data = array();
846         foreach ($event as $k => $v) {
847             $data[$k] = $v;
848         }
850         $this->assertSame($event->get_data(), $data);
851     }
853     /**
854      * @expectedException PHPUnit\Framework\Error\Notice
855      */
856     public function test_context_not_used() {
857         $event = \core_tests\event\context_used_in_event::create(array('other' => array('sample' => 1, 'xx' => 10)));
858         $this->assertEventContextNotUsed($event);
860         $eventcontext = phpunit_event_mock::testable_get_event_context($event);
861         phpunit_event_mock::testable_set_event_context($event, null);
862         $this->assertEventContextNotUsed($event);
863     }
865     /**
866      * Test that all observer information is returned correctly.
867      */
868     public function test_get_all_observers() {
869         // Retrieve all observers.
870         $observers = \core\event\manager::get_all_observers();
872         // Expected information from the workshop allocation scheduled observer.
873         $expected = new stdClass();
874         $expected->callable = '\workshopallocation_scheduled\observer::workshop_viewed';
875         $expected->priority = 0;
876         $expected->internal = true;
877         $expected->includefile = null;
878         $expected->plugintype = 'workshopallocation';
879         $expected->plugin = 'scheduled';
881         // May be more than one observer for the mod_workshop event.
882         $found = false;
883         foreach ($observers['\mod_workshop\event\course_module_viewed'] as $observer) {
884             if ($expected == $observer) {
885                 $found = true;
886                 break;
887             }
888         }
889         $this->assertTrue($found);
890     }
892     /**
893      * Test formatting of the get_explanation method.
894      * This formats the information from an events class docblock.
895      */
896     public function test_get_explanation() {
897         $explanation = \core_tests\event\full_docblock::get_explanation();
899         $expected = "This is an explanation of the event.
900      - I'm making a point here.
901      - I have a second {@link something}  point here.
902      - whitespace is intentional to test it's removal.
903 I have something else *Yeah* that.";
905         $this->assertEquals($explanation, $expected);
907         $explanation = \core_tests\event\docblock_test2::get_explanation();
909         $expected = "We have only the description in the docblock
910 and nothing else.";
912         $this->assertEquals($explanation, $expected);
914         $explanation = \core_tests\event\docblock_test3::get_explanation();
915         $expected = "Calendar event created event.";
916         $this->assertEquals($explanation, $expected);
918     }
920     /**
921      * Test that general information about an event is returned
922      * by the get_static_info() method.
923      */
924     public function test_get_static_info() {
925         $staticinfo = \core_tests\event\static_info_viewing::get_static_info();
927         $expected = array(
928             'eventname'   => '\\core_tests\\event\\static_info_viewing',
929             'component'   => 'core_tests',
930             'target'      => 'static_info',
931             'action'      => 'viewing',
932             'crud'        => 'r',
933             'edulevel'    => 0,
934             'objecttable' => 'mod_unittest'
935         );
936         $this->assertEquals($staticinfo, $expected);
937     }
939     /**
940      * This tests the internal method of \core\event\manager::get_observing_classes.
941      *
942      * What we are testing is if we can subscribe to a parent event class, instead of only
943      * the base event class or the final, implemented event class.  This enables us to subscribe
944      * to things like all course module view events, all comment created events, etc.
945      */
946     public function test_observe_parent_event() {
947         $this->resetAfterTest();
949         // Ensure this has been reset prior to using it.
950         \core_tests\event\unittest_observer::reset();
952         $course  = $this->getDataGenerator()->create_course();
953         $feed    = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
954         $context = context_module::instance($feed->cmid);
955         $data    = [
956             'context'  => $context,
957             'courseid' => $course->id,
958             'objectid' => $feed->id
959         ];
961         // This assertion ensures that basic observe use case did not break.
962         \core\event\manager::phpunit_replace_observers([[
963             'eventname' => '\core_tests\event\course_module_viewed',
964             'callback'  => ['\core_tests\event\unittest_observer', 'observe_all_alt'],
965         ]]);
967         $pageevent = \core_tests\event\course_module_viewed::create($data);
968         $pageevent->trigger();
970         $this->assertSame(['observe_all_alt'], \core_tests\event\unittest_observer::$info, 'Error observing triggered event');
972         \core_tests\event\unittest_observer::reset();
974         // This assertion tests that we can observe an abstract (parent) class instead of the implemented class.
975         \core\event\manager::phpunit_replace_observers([[
976             'eventname' => '\core\event\course_module_viewed',
977             'callback'  => ['\core_tests\event\unittest_observer', 'observe_all_alt'],
978         ]]);
980         $pageevent = \core_tests\event\course_module_viewed::create($data);
981         $pageevent->trigger();
983         $this->assertSame(['observe_all_alt'], \core_tests\event\unittest_observer::$info, 'Error observing parent class event');
985         \core_tests\event\unittest_observer::reset();
986     }