556d4ff5167ec7388a9ce1d2fd0a89595503048b
[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     public function test_event_properties() {
33         global $USER;
35         $system = \context_system::instance();
36         $event = \core_tests\event\unittest_executed::create(array('context'=>$system, 'objectid'=>5, 'other'=>array('sample'=>null, 'xx'=>10)));
38         $this->assertSame('\core_tests\event\unittest_executed', $event->eventname);
39         $this->assertSame('core_tests', $event->component);
40         $this->assertSame('executed', $event->action);
41         $this->assertSame('unittest', $event->target);
42         $this->assertSame(5, $event->objectid);
43         $this->assertSame('u', $event->crud);
44         $this->assertSame(\core\event\base::LEVEL_PARTICIPATING, $event->edulevel);
46         $this->assertEquals($system, $event->get_context());
47         $this->assertSame($system->id, $event->contextid);
48         $this->assertSame($system->contextlevel, $event->contextlevel);
49         $this->assertSame($system->instanceid, $event->contextinstanceid);
51         $this->assertSame($USER->id, $event->userid);
52         $this->assertSame(0, $event->courseid);
54         $this->assertNull($event->relateduserid);
55         $this->assertFalse(isset($event->relateduserid));
57         $this->assertSame(0, $event->anonymous);
59         $this->assertSame(array('sample'=>null, 'xx'=>10), $event->other);
60         $this->assertTrue(isset($event->other['xx']));
61         $this->assertFalse(isset($event->other['sample']));
63         $this->assertLessThanOrEqual(time(), $event->timecreated);
65         try {
66             $event->courseid = 2;
67             $this->fail('Exception expected on event modification');
68         } catch (\moodle_exception $e) {
69             $this->assertInstanceOf('coding_exception', $e);
70         }
72         try {
73             $event->xxxx = 1;
74             $this->fail('Exception expected on event modification');
75         } catch (\moodle_exception $e) {
76             $this->assertInstanceOf('coding_exception', $e);
77         }
79         $event2 = \core_tests\event\unittest_executed::create(array('contextid'=>$system->id, 'objectid'=>5, 'anonymous'=>1, 'other'=>array('sample'=>null, 'xx'=>10)));
80         $this->assertEquals($event->get_context(), $event2->get_context());
81         $this->assertSame(1, $event2->anonymous);
83         $event3 = \core_tests\event\unittest_executed::create(array('contextid'=>$system->id, 'objectid'=>5, 'anonymous'=>true, 'other'=>array('sample'=>null, 'xx'=>10)));
84         $this->assertSame(1, $event3->anonymous);
85     }
87     public function test_event_properties_guessing() {
88         global $USER;
89         $this->resetAfterTest();
91         $course = $this->getDataGenerator()->create_course();
92         $forum = $this->getDataGenerator()->create_module('forum', array('course' => $course->id));
93         $context = context_module::instance($forum->cmid);
94         $event = \core_tests\event\unittest_executed::create(array('context' => $context, 'objectid' => 5));
96         // Check guessed course ID, and default properties.
97         $this->assertSame('\core_tests\event\unittest_executed', $event->eventname);
98         $this->assertSame('core_tests', $event->component);
99         $this->assertSame('executed', $event->action);
100         $this->assertSame('unittest', $event->target);
101         $this->assertSame(5, $event->objectid);
102         $this->assertEquals($context, $event->get_context());
103         $this->assertEquals($course->id, $event->courseid);
104         $this->assertSame($USER->id, $event->userid);
105         $this->assertNull($event->relateduserid);
107         $user = $this->getDataGenerator()->create_user();
108         $context = context_user::instance($user->id);
109         $event = \core_tests\event\unittest_executed::create(array('contextid' => $context->id, 'objectid' => 5));
111         // Check guessing on contextid, and user context level.
112         $this->assertEquals($context, $event->get_context());
113         $this->assertEquals($context->id, $event->contextid);
114         $this->assertEquals($context->contextlevel, $event->contextlevel);
115         $this->assertSame(0, $event->courseid);
116         $this->assertSame($USER->id, $event->userid);
117         $this->assertSame($user->id, $event->relateduserid);
118     }
120     public function test_observers_parsing() {
121         global $CFG;
123         $observers = array(
124             array(
125                 'eventname'   => '*',
126                 'callback'    => array('\core_tests\event\unittest_observer', 'observe_all_alt'),
127             ),
128             array(
129                 'eventname'   => '\core_tests\event\unittest_executed',
130                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
131                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
132             ),
133             array(
134                 'eventname'   => '*',
135                 'callback'    => array('\core_tests\event\unittest_observer', 'observe_all'),
136                 'includefile' => null,
137                 'internal'    => 1,
138                 'priority'    => 10,
139             ),
140             array(
141                 'eventname'   => '\core\event\unknown_executed',
142                 'callback'    => '\core_tests\event\unittest_observer::broken_observer',
143                 'priority'    => 100,
144             ),
145             array(
146                 'eventname'   => '\core_tests\event\unittest_executed',
147                 'callback'    => '\core_tests\event\unittest_observer::external_observer',
148                 'priority'    => 200,
149                 'internal'    => 0,
150             ),
151         );
153         $result = \core\event\manager::phpunit_replace_observers($observers);
154         $this->assertCount(3, $result);
156         $expected = array();
157         $observer = new stdClass();
158         $observer->callable = '\core_tests\event\unittest_observer::external_observer';
159         $observer->priority = 200;
160         $observer->internal = false;
161         $observer->includefile = null;
162         $observer->plugintype = null;
163         $observer->plugin = null;
164         $expected[0] = $observer;
165         $observer = new stdClass();
166         $observer->callable = '\core_tests\event\unittest_observer::observe_one';
167         $observer->priority = 0;
168         $observer->internal = true;
169         $observer->includefile = $CFG->dirroot.'/lib/tests/fixtures/event_fixtures.php';
170         $observer->plugintype = null;
171         $observer->plugin = null;
172         $expected[1] = $observer;
174         $this->assertEquals($expected, $result['\core_tests\event\unittest_executed']);
176         $expected = array();
177         $observer = new stdClass();
178         $observer->callable = '\core_tests\event\unittest_observer::broken_observer';
179         $observer->priority = 100;
180         $observer->internal = true;
181         $observer->includefile = null;
182         $observer->plugintype = null;
183         $observer->plugin = null;
184         $expected[0] = $observer;
186         $this->assertEquals($expected, $result['\core\event\unknown_executed']);
188         $expected = array();
189         $observer = new stdClass();
190         $observer->callable = array('\core_tests\event\unittest_observer', 'observe_all');
191         $observer->priority = 10;
192         $observer->internal = true;
193         $observer->includefile = null;
194         $observer->plugintype = null;
195         $observer->plugin = null;
196         $expected[0] = $observer;
197         $observer = new stdClass();
198         $observer->callable = array('\core_tests\event\unittest_observer', 'observe_all_alt');
199         $observer->priority = 0;
200         $observer->internal = true;
201         $observer->includefile = null;
202         $observer->plugintype = null;
203         $observer->plugin = null;
204         $expected[1] = $observer;
206         $this->assertEquals($expected, $result['\core\event\base']);
208         // Now test broken stuff...
210         $observers = array(
211             array(
212                 'eventname'   => 'core_tests\event\unittest_executed', // Fix leading backslash.
213                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
214                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
215                 'internal'    => 1, // Cast to bool.
216             ),
217         );
218         $result = \core\event\manager::phpunit_replace_observers($observers);
219         $this->assertCount(1, $result);
220         $expected = array();
221         $observer = new stdClass();
222         $observer->callable = '\core_tests\event\unittest_observer::observe_one';
223         $observer->priority = 0;
224         $observer->internal = true;
225         $observer->includefile = $CFG->dirroot.'/lib/tests/fixtures/event_fixtures.php';
226         $observer->plugintype = null;
227         $observer->plugin = null;
228         $expected[0] = $observer;
229         $this->assertEquals($expected, $result['\core_tests\event\unittest_executed']);
231         $observers = array(
232             array(
233                 // Missing eventclass.
234                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
235                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
236             ),
237         );
238         $result = \core\event\manager::phpunit_replace_observers($observers);
239         $this->assertCount(0, $result);
240         $this->assertDebuggingCalled();
242         $observers = array(
243             array(
244                 'eventname'   => '', // Empty eventclass.
245                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
246                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
247             ),
248         );
249         $result = \core\event\manager::phpunit_replace_observers($observers);
250         $this->assertCount(0, $result);
251         $this->assertDebuggingCalled();
253         $observers = array(
254             array(
255                 'eventname'   => '\core_tests\event\unittest_executed',
256                 // Missing callable.
257                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
258             ),
259         );
260         $result = \core\event\manager::phpunit_replace_observers($observers);
261         $this->assertCount(0, $result);
262         $this->assertDebuggingCalled();
264         $observers = array(
265             array(
266                 'eventname'   => '\core_tests\event\unittest_executed',
267                 'callback'    => '', // Empty callable.
268                 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
269             ),
270         );
271         $result = \core\event\manager::phpunit_replace_observers($observers);
272         $this->assertCount(0, $result);
273         $this->assertDebuggingCalled();
275         $observers = array(
276             array(
277                 'eventname'   => '\core_tests\event\unittest_executed',
278                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
279                 'includefile' => 'lib/tests/fixtures/event_fixtures.php_xxx', // Missing file.
280             ),
281         );
282         $result = \core\event\manager::phpunit_replace_observers($observers);
283         $this->assertCount(0, $result);
284         $this->assertDebuggingCalled();
285     }
287     public function test_normal_dispatching() {
288         $observers = array(
289             array(
290                 'eventname'   => '\core_tests\event\unittest_executed',
291                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
292             ),
293             array(
294                 'eventname'   => '*',
295                 'callback'    => '\core_tests\event\unittest_observer::observe_all',
296                 'includefile' => null,
297                 'internal'    => 1,
298                 'priority'    => 9999,
299             ),
300         );
302         \core\event\manager::phpunit_replace_observers($observers);
303         \core_tests\event\unittest_observer::reset();
305         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
306         $event1->nest = 1;
307         $this->assertFalse($event1->is_triggered());
308         $this->assertFalse($event1->is_dispatched());
309         $this->assertFalse($event1->is_restored());
310         $event1->trigger();
311         $this->assertTrue($event1->is_triggered());
312         $this->assertTrue($event1->is_dispatched());
313         $this->assertFalse($event1->is_restored());
315         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
316         $event1->trigger();
318         $this->assertSame(
319             array('observe_all-nesting-1', 'observe_one-1', 'observe_all-666', 'observe_one-666', 'observe_all-2', 'observe_one-2'),
320             \core_tests\event\unittest_observer::$info);
321     }
323     public function test_event_sink() {
324         $sink = $this->redirectEvents();
325         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
326         $event1->trigger();
327         $this->assertSame(1, $sink->count());
328         $retult = $sink->get_events();
329         $this->assertSame($event1, $retult[0]);
331         $event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
332         $event2->trigger();
333         $this->assertSame(2, $sink->count());
334         $retult = $sink->get_events();
335         $this->assertSame($event1, $retult[0]);
336         $this->assertSame($event2, $retult[1]);
338         $sink->clear();
339         $this->assertSame(0, $sink->count());
340         $this->assertSame(array(), $sink->get_events());
342         $event3 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>3, 'xx'=>10)));
343         $event3->trigger();
344         $this->assertSame(1, $sink->count());
345         $retult = $sink->get_events();
346         $this->assertSame($event3, $retult[0]);
348         $sink->close();
349         $event4 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>4, 'xx'=>10)));
350         $event4->trigger();
351         $this->assertSame(1, $sink->count());
352         $retult = $sink->get_events();
353         $this->assertSame($event3, $retult[0]);
354     }
356     public function test_ignore_exceptions() {
357         $observers = array(
359             array(
360                 'eventname'   => '\core_tests\event\unittest_executed',
361                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
362             ),
364             array(
365                 'eventname'   => '\core_tests\event\unittest_executed',
366                 'callback'    => '\core_tests\event\unittest_observer::broken_observer',
367                 'priority'    => 100,
368             ),
369         );
371         \core\event\manager::phpunit_replace_observers($observers);
372         \core_tests\event\unittest_observer::reset();
374         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
375         $event1->trigger();
376         $this->assertDebuggingCalled();
378         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
379         $event1->trigger();
380         $this->assertDebuggingCalled();
382         $this->assertSame(
383             array('broken_observer-1', 'observe_one-1', 'broken_observer-2', 'observe_one-2'),
384             \core_tests\event\unittest_observer::$info);
385     }
387     public function test_external_buffer() {
388         global $DB;
390         $this->preventResetByRollback();
392         $observers = array(
394             array(
395                 'eventname'   => '\core_tests\event\unittest_executed',
396                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
397             ),
399             array(
400                 'eventname'   => '\core_tests\event\unittest_executed',
401                 'callback'    => '\core_tests\event\unittest_observer::external_observer',
402                 'priority'    => 200,
403                 'internal'    => 0,
404             ),
405         );
407         \core\event\manager::phpunit_replace_observers($observers);
408         \core_tests\event\unittest_observer::reset();
410         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
411         $event1->trigger();
412         $event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
413         $event2->trigger();
415         $this->assertSame(
416             array('external_observer-1', 'observe_one-1', 'external_observer-2', 'observe_one-2'),
417             \core_tests\event\unittest_observer::$info);
419         \core\event\manager::phpunit_replace_observers($observers);
420         \core_tests\event\unittest_observer::reset();
422         $this->assertSame(array(), \core_tests\event\unittest_observer::$info);
424         $trans = $DB->start_delegated_transaction();
426         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
427         $event1->trigger();
428         $event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
429         $event2->trigger();
431         $this->assertSame(
432             array('observe_one-1', 'observe_one-2'),
433             \core_tests\event\unittest_observer::$info);
435         $trans->allow_commit();
437         $this->assertSame(
438             array('observe_one-1', 'observe_one-2', 'external_observer-1', 'external_observer-2'),
439             \core_tests\event\unittest_observer::$info);
441         \core\event\manager::phpunit_replace_observers($observers);
442         \core_tests\event\unittest_observer::reset();
444         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
445         $event1->trigger();
446         $trans = $DB->start_delegated_transaction();
447         $event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
448         $event2->trigger();
449         try {
450             $trans->rollback(new \moodle_exception('xxx'));
451             $this->fail('Expecting exception');
452         } catch (\moodle_exception $e) {
453             $this->assertInstanceOf('moodle_exception', $e);
454         }
456         $this->assertSame(
457             array('external_observer-1', 'observe_one-1', 'observe_one-2'),
458             \core_tests\event\unittest_observer::$info);
459     }
461     public function test_rollback() {
462         global $DB;
464         $this->resetAfterTest();
465         $this->preventResetByRollback();
467         $observers = array(
468             array(
469                 'eventname'   => '\core_tests\event\unittest_executed',
470                 'callback'    => '\core_tests\event\unittest_observer::external_observer',
471                 'internal'    => 0,
472             ),
473         );
475         \core\event\manager::phpunit_replace_observers($observers);
476         \core_tests\event\unittest_observer::reset();
478         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
480         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
481         $this->assertCount(1, \core_tests\event\unittest_observer::$event);
482         \core_tests\event\unittest_observer::reset();
484         $transaction1 = $DB->start_delegated_transaction();
486         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
487         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
489         $transaction2 = $DB->start_delegated_transaction();
491         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
492         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
494         try {
495             $transaction2->rollback(new Exception('x'));
496             $this->fail('Expecting exception');
497         } catch (Exception $e) {}
498         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
500         $this->assertTrue($DB->is_transaction_started());
502         try {
503             $transaction1->rollback(new Exception('x'));
504             $this->fail('Expecting exception');
505         } catch (Exception $e) {}
506         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
508         $this->assertFalse($DB->is_transaction_started());
510         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
511         $this->assertCount(1, \core_tests\event\unittest_observer::$event);
512     }
514     public function test_forced_rollback() {
515         global $DB;
517         $this->resetAfterTest();
518         $this->preventResetByRollback();
520         $observers = array(
521             array(
522                 'eventname'   => '\core_tests\event\unittest_executed',
523                 'callback'    => '\core_tests\event\unittest_observer::external_observer',
524                 'internal'    => 0,
525             ),
526         );
528         \core\event\manager::phpunit_replace_observers($observers);
529         \core_tests\event\unittest_observer::reset();
531         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
533         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
534         $this->assertCount(1, \core_tests\event\unittest_observer::$event);
535         \core_tests\event\unittest_observer::reset();
537         $transaction1 = $DB->start_delegated_transaction();
539         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
540         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
542         $transaction2 = $DB->start_delegated_transaction();
544         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
545         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
547         $DB->force_transaction_rollback();
548         $this->assertCount(0, \core_tests\event\unittest_observer::$event);
550         $this->assertFalse($DB->is_transaction_started());
552         \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)))->trigger();
553         $this->assertCount(1, \core_tests\event\unittest_observer::$event);
554     }
556     public function test_deprecated() {
557         global $DB;
559         $this->resetAfterTest(true);
561         $event = \core_tests\event\deprecated_event1::create();
562         $this->assertDebuggingCalled('level property is deprecated, use edulevel property instead');
564         $this->assertSame($event::LEVEL_TEACHING, $event->level);
565         $this->assertDebuggingCalled('level property is deprecated, use edulevel property instead');
567         $this->assertTrue(isset($event->level));
568         $this->assertDebuggingCalled('level property is deprecated, use edulevel property instead');
570         $this->assertSame($event::LEVEL_TEACHING, $event->edulevel);
571     }
573     public function test_legacy() {
574         global $DB, $CFG;
576         $this->resetAfterTest(true);
578         $observers = array(
579             array(
580                 'eventname'   => '\core_tests\event\unittest_executed',
581                 'callback'    => '\core_tests\event\unittest_observer::observe_one',
582             ),
583             array(
584                 'eventname'   => '*',
585                 'callback'    => '\core_tests\event\unittest_observer::observe_all',
586                 'includefile' => null,
587                 'internal'    => 1,
588                 'priority'    => 9999,
589             ),
590         );
592         $DB->delete_records('log', array());
593         events_update_definition('unittest');
594         $DB->delete_records_select('events_handlers', "component <> 'unittest'");
595         events_get_handlers('reset');
596         $this->assertEquals(3, $DB->count_records('events_handlers'));
597         set_config('loglifetime', 60*60*24*5);
599         \core\event\manager::phpunit_replace_observers($observers);
600         \core_tests\event\unittest_observer::reset();
602         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
603         $event1->trigger();
605         $event2 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>6, 'xx'=>11)));
606         $event2->nest = true;
607         $event2->trigger();
609         $this->assertSame(
610             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'),
611             \core_tests\event\unittest_observer::$info);
613         $this->assertSame($event1, \core_tests\event\unittest_observer::$event[0]);
614         $this->assertSame($event1, \core_tests\event\unittest_observer::$event[1]);
615         $this->assertSame(array(0, 5), \core_tests\event\unittest_observer::$event[2]);
617         $logs = $DB->get_records('log', array(), 'id ASC');
618         $this->assertCount(0, $logs);
619     }
621     public function test_restore_event() {
622         $event1 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
623         $data1 = $event1->get_data();
625         $event2 = \core\event\base::restore($data1, array('origin'=>'clid'));
626         $data2 = $event2->get_data();
628         $this->assertTrue($event2->is_triggered());
629         $this->assertTrue($event2->is_restored());
630         $this->assertEquals($data1, $data2);
631         $this->assertInstanceOf('core_tests\event\unittest_executed', $event2);
633         $this->assertEquals($event1->get_context(), $event2->get_context());
635         // Now test problematic data.
636         $data3 = $data1;
637         $data3['eventname'] = '\\a\\b\\c';
638         $event3 = \core\event\base::restore($data3, array());
639         $this->assertFalse($event3, 'Class name must match');
641         $data4 = $data1;
642         unset($data4['userid']);
643         $event4 = \core\event\base::restore($data4, array());
644         $this->assertInstanceOf('core_tests\event\unittest_executed', $event4);
645         $this->assertDebuggingCalled();
647         $data5 = $data1;
648         $data5['xx'] = 'xx';
649         $event5 = \core\event\base::restore($data5, array());
650         $this->assertInstanceOf('core_tests\event\unittest_executed', $event5);
651         $this->assertDebuggingCalled();
653     }
655     public function test_trigger_problems() {
656         $this->resetAfterTest(true);
658         $event = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
659         $event->trigger();
660         try {
661             $event->trigger();
662             $this->fail('Exception expected on double trigger');
663         } catch (\moodle_exception $e) {
664             $this->assertInstanceOf('coding_exception', $e);
665         }
667         $data = $event->get_data();
668         $restored = \core_tests\event\unittest_executed::restore($data, array());
669         $this->assertTrue($restored->is_triggered());
670         $this->assertTrue($restored->is_restored());
672         try {
673             $restored->trigger();
674             $this->fail('Exception expected on triggering of restored event');
675         } catch (\moodle_exception $e) {
676             $this->assertInstanceOf('coding_exception', $e);
677         }
679         $event = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
680         try {
681             \core\event\manager::dispatch($event);
682             $this->fail('Exception expected on manual event dispatching');
683         } catch (\moodle_exception $e) {
684             $this->assertInstanceOf('coding_exception', $e);
685         }
686     }
688     public function test_bad_events() {
689         $this->resetAfterTest(true);
691         try {
692             $event = \core_tests\event\unittest_executed::create(array('other'=>array('sample'=>5, 'xx'=>10)));
693             $this->fail('Exception expected when context and contextid missing');
694         } catch (\moodle_exception $e) {
695             $this->assertInstanceOf('coding_exception', $e);
696         }
698         $event = \core_tests\event\bad_event1::create(array('context'=>\context_system::instance()));
699         try {
700             $event->trigger();
701             $this->fail('Exception expected when $data not valid');
702         } catch (\moodle_exception $e) {
703             $this->assertInstanceOf('\coding_exception', $e);
704         }
706         $event = \core_tests\event\bad_event2::create(array('context'=>\context_system::instance()));
707         try {
708             $event->trigger();
709             $this->fail('Exception expected when $data not valid');
710         } catch (\moodle_exception $e) {
711             $this->assertInstanceOf('\coding_exception', $e);
712         }
714         $event = \core_tests\event\bad_event2b::create(array('context'=>\context_system::instance()));
715         @$event->trigger();
716         $this->assertDebuggingCalled();
718         $event = \core_tests\event\bad_event3::create(array('context'=>\context_system::instance()));
719         @$event->trigger();
720         $this->assertDebuggingCalled();
722         $event = \core_tests\event\bad_event4::create(array('context'=>\context_system::instance()));
723         @$event->trigger();
724         $this->assertDebuggingCalled();
726         $event = \core_tests\event\bad_event5::create(array('context'=>\context_system::instance()));
727         @$event->trigger();
728         $this->assertDebuggingCalled();
730         $event = \core_tests\event\bad_event6::create(array('objectid'=>1, 'context'=>\context_system::instance()));
731         $event->trigger();
732         $this->assertDebuggingCalled('Unknown table specified in objecttable field');
734         $event = \core_tests\event\bad_event7::create(array('objectid'=>1, 'context'=>\context_system::instance()));
735         try {
736             $event->trigger();
737             $this->fail('Exception expected when $data contains objectid but objecttable not specified');
738         } catch (\moodle_exception $e) {
739             $this->assertInstanceOf('\coding_exception', $e);
740         }
742         $event = \core_tests\event\bad_event8::create(array('context'=>\context_system::instance()));
743         $event->trigger();
744         $this->assertDebuggingCalled('Event property objectid must be set when objecttable is defined');
745     }
747     public function test_problematic_events() {
748         $this->resetAfterTest(true);
750         $event1 = \core_tests\event\problematic_event1::create(array('context'=>\context_system::instance()));
751         $this->assertDebuggingNotCalled();
752         $this->assertNull($event1->xxx);
753         $this->assertDebuggingCalled();
755         $event2 = \core_tests\event\problematic_event1::create(array('xxx'=>0, 'context'=>\context_system::instance()));
756         $this->assertDebuggingCalled();
758         set_debugging(DEBUG_NONE);
759         $event3 = \core_tests\event\problematic_event1::create(array('xxx'=>0, 'context'=>\context_system::instance()));
760         $this->assertDebuggingNotCalled();
761         set_debugging(DEBUG_DEVELOPER);
763         $event4 = \core_tests\event\problematic_event1::create(array('context'=>\context_system::instance(), 'other'=>array('a'=>1)));
764         $event4->trigger();
765         $this->assertDebuggingNotCalled();
767         $event5 = \core_tests\event\problematic_event1::create(array('context'=>\context_system::instance(), 'other'=>(object)array('a'=>1)));
768         $this->assertDebuggingNotCalled();
769         $event5->trigger();
770         $this->assertDebuggingCalled();
772         $url = new moodle_url('/admin/');
773         $event6 = \core_tests\event\problematic_event1::create(array('context'=>\context_system::instance(), 'other'=>array('a'=>$url)));
774         $this->assertDebuggingNotCalled();
775         $event6->trigger();
776         $this->assertDebuggingCalled();
778         // Check that whole float numbers do not trigger debugging messages.
779         $event7 = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(),
780             'other' => array('wholenumber' => 90.0000, 'numberwithdecimals' => 54.7656, 'sample' => 1)));
781         $event7->trigger();
782         $this->assertDebuggingNotCalled();
784         $event = \core_tests\event\problematic_event2::create(array());
785         $this->assertDebuggingNotCalled();
786         $event = \core_tests\event\problematic_event2::create(array('context'=>\context_system::instance()));
787         $this->assertDebuggingCalled();
789         $event = \core_tests\event\problematic_event3::create(array('other'=>1));
790         $this->assertDebuggingNotCalled();
791         $event = \core_tests\event\problematic_event3::create(array());
792         $this->assertDebuggingCalled();
793     }
795     public function test_record_snapshots() {
796         global $DB;
798         $this->resetAfterTest(true);
800         $event = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
801         $course1 = $DB->get_record('course', array('id'=>1));
802         $this->assertNotEmpty($course1);
804         $event->add_record_snapshot('course', $course1);
806         $result = $event->get_record_snapshot('course', $course1->id);
807         // Convert to arrays because record snapshot returns a clone of the object.
808         $this->assertSame((array)$course1, (array)$result);
810         $user = $event->get_record_snapshot('user', 1);
811         $this->assertEquals(1, $user->id);
812         $this->assertSame('guest', $user->username);
814         $event->add_record_snapshot('course', $course1);
815         $event->trigger();
816         try {
817             $event->add_record_snapshot('course', $course1);
818             $this->fail('Updating of snapshots after trigger is not ok');;
819         } catch (\moodle_exception $e) {
820             $this->assertInstanceOf('\coding_exception', $e);
821         }
823         $event2 = \core_tests\event\unittest_executed::restore($event->get_data(), array());
824         try {
825             $event2->get_record_snapshot('course', $course1->id);
826             $this->fail('Reading of snapshots from restored events is not ok');;
827         } catch (\moodle_exception $e) {
828             $this->assertInstanceOf('\coding_exception', $e);
829         }
830     }
832     public function test_get_name() {
833         $event = \core_tests\event\noname_event::create(array('other' => array('sample' => 1, 'xx' => 10)));
834         $this->assertEquals("core_tests: noname event", $event->get_name());
835     }
837     public function test_iteration() {
838         $event = \core_tests\event\unittest_executed::create(array('context'=>\context_system::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
840         $data = array();
841         foreach ($event as $k => $v) {
842             $data[$k] = $v;
843         }
845         $this->assertSame($event->get_data(), $data);
846     }
848     /**
849      * @expectedException PHPUnit_Framework_Error_Notice
850      */
851     public function test_context_not_used() {
852         $event = \core_tests\event\context_used_in_event::create(array('other' => array('sample' => 1, 'xx' => 10)));
853         $this->assertEventContextNotUsed($event);
855         $eventcontext = phpunit_event_mock::testable_get_event_context($event);
856         phpunit_event_mock::testable_set_event_context($event, null);
857         $this->assertEventContextNotUsed($event);
858     }
860     /**
861      * Test that all observer information is returned correctly.
862      */
863     public function test_get_all_observers() {
864         // Retrieve all observers.
865         $observers = \core\event\manager::get_all_observers();
867         // Expected information from the workshop allocation scheduled observer.
868         $expected = array();
869         $observer = new stdClass();
870         $observer->callable = '\workshopallocation_scheduled\observer::workshop_viewed';
871         $observer->priority = 0;
872         $observer->internal = true;
873         $observer->includefile = null;
874         $observer->plugintype = 'workshopallocation';
875         $observer->plugin = 'scheduled';
876         $expected[0] = $observer;
878         $this->assertEquals($expected, $observers['\mod_workshop\event\course_module_viewed']);
879     }
881     /**
882      * Test formatting of the get_explanation method.
883      * This formats the information from an events class docblock.
884      */
885     public function test_get_explanation() {
886         $explanation = \core_tests\event\full_docblock::get_explanation();
888         $expected = "This is an explanation of the event.
889      - I'm making a point here.
890      - I have a second {@link something}  point here.
891      - whitespace is intentional to test it's removal.
892 I have something else *Yeah* that.";
894         $this->assertEquals($explanation, $expected);
896         $explanation = \core_tests\event\docblock_test2::get_explanation();
898         $expected = "We have only the description in the docblock
899 and nothing else.";
901         $this->assertEquals($explanation, $expected);
903         $explanation = \core_tests\event\docblock_test3::get_explanation();
904         $expected = "Calendar event created event.";
905         $this->assertEquals($explanation, $expected);
907     }
909     /**
910      * Test that general information about an event is returned
911      * by the get_static_info() method.
912      */
913     public function test_get_static_info() {
914         $staticinfo = \core_tests\event\static_info_viewing::get_static_info();
916         $expected = array(
917             'eventname'   => '\\core_tests\\event\\static_info_viewing',
918             'component'   => 'core_tests',
919             'target'      => 'static_info',
920             'action'      => 'viewing',
921             'crud'        => 'r',
922             'edulevel'    => 0,
923             'objecttable' => 'mod_unittest'
924         );
925         $this->assertEquals($staticinfo, $expected);
926     }
928     /**
929      * This tests the internal method of \core\event\manager::get_observing_classes.
930      *
931      * What we are testing is if we can subscribe to a parent event class, instead of only
932      * the base event class or the final, implemented event class.  This enables us to subscribe
933      * to things like all course module view events, all comment created events, etc.
934      */
935     public function test_observe_parent_event() {
936         $this->resetAfterTest();
938         // Ensure this has been reset prior to using it.
939         \core_tests\event\unittest_observer::reset();
941         $course  = $this->getDataGenerator()->create_course();
942         $feed    = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
943         $context = context_module::instance($feed->cmid);
944         $data    = [
945             'context'  => $context,
946             'courseid' => $course->id,
947             'objectid' => $feed->id
948         ];
950         // This assertion ensures that basic observe use case did not break.
951         \core\event\manager::phpunit_replace_observers([[
952             'eventname' => '\core_tests\event\course_module_viewed',
953             'callback'  => ['\core_tests\event\unittest_observer', 'observe_all_alt'],
954         ]]);
956         $pageevent = \core_tests\event\course_module_viewed::create($data);
957         $pageevent->trigger();
959         $this->assertSame(['observe_all_alt'], \core_tests\event\unittest_observer::$info, 'Can still subscribe to child event');
961         \core_tests\event\unittest_observer::reset();
963         // This assertion tests that we can observe an abstract (parent) class instead of the implemented class.
964         \core\event\manager::phpunit_replace_observers([[
965             'eventname' => '\core\event\course_module_viewed',
966             'callback'  => ['\core_tests\event\unittest_observer', 'observe_all_alt'],
967         ]]);
969         $pageevent = \core_tests\event\course_module_viewed::create($data);
970         $pageevent->trigger();
972         $this->assertSame(['observe_all_alt'], \core_tests\event\unittest_observer::$info, 'Can subscribe to parent event');
974         \core_tests\event\unittest_observer::reset();
975     }