2 // This file is part of Moodle - http://moodle.org/
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.
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 * Tests for event manager, base event and observers.
22 * @copyright 2013 Petr Skoda {@link http://skodak.org}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
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() {
35 $system = \context_system
::instance();
36 $event = \core_tests\event\unittest_executed
::create(array('courseid'=>1, '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->object);
42 $this->assertSame(5, $event->objectid
);
43 $this->assertSame('u', $event->crud
);
44 $this->assertSame(10, $event->level
);
46 $this->assertSame($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(1, $event->courseid
);
54 $this->assertNull($event->relateduserid
);
55 $this->assertFalse(isset($event->relateduserid
));
57 $this->assertSame(array('sample'=>null, 'xx'=>10), $event->other
);
58 $this->assertTrue(isset($event->other
['xx']));
59 $this->assertFalse(isset($event->other
['sample']));
61 $this->assertLessThanOrEqual(time(), $event->timecreated
);
65 $this->fail('Exception expected on event modification');
66 } catch (\moodle_exception
$e) {
67 $this->assertInstanceOf('coding_exception', $e);
72 $this->fail('Exception expected on event modification');
73 } catch (\moodle_exception
$e) {
74 $this->assertInstanceOf('coding_exception', $e);
78 public function test_observers_parsing() {
82 'eventname' => '\core_tests\event\unittest_executed',
83 'callback' => '\core_tests\event\unittest_observer::observe_one',
84 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
88 'callback' => array('\core_tests\event\unittest_observer', 'observe_all'),
89 'includefile' => null,
94 'eventname' => '\core\event\unknown_executed',
95 'callback' => '\core_tests\event\unittest_observer::broken_observer',
99 'eventname' => '\core_tests\event\unittest_executed',
100 'callback' => '\core_tests\event\unittest_observer::external_observer',
106 $result = \core\event\manager
::phpunit_replace_observers($observers);
108 $this->assertCount(3, $result);
110 $this->assertSame('*', key($result));
113 $observer = new stdClass();
114 $observer->callable
= array('\core_tests\event\unittest_observer', 'observe_all');
115 $observer->priority
= 9999;
116 $observer->internal
= true;
117 $observer->includefile
= null;
118 $expected[0] = $observer;
119 $observer = new stdClass();
120 $observer->callable
= '\core_tests\event\unittest_observer::external_observer';
121 $observer->priority
= 200;
122 $observer->internal
= false;
123 $observer->includefile
= null;
124 $expected[1] = $observer;
125 $observer = new stdClass();
126 $observer->callable
= '\core_tests\event\unittest_observer::observe_one';
127 $observer->priority
= 0;
128 $observer->internal
= true;
129 $observer->includefile
= 'lib/tests/fixtures/event_fixtures.php';
130 $expected[2] = $observer;
132 $this->assertEquals($expected, $result['\core_tests\event\unittest_executed']);
135 $observer = new stdClass();
136 $observer->callable
= array('\core_tests\event\unittest_observer', 'observe_all');
137 $observer->priority
= 9999;
138 $observer->internal
= true;
139 $observer->includefile
= null;
140 $expected[0] = $observer;
141 $observer = new stdClass();
142 $observer->callable
= '\core_tests\event\unittest_observer::broken_observer';
143 $observer->priority
= 100;
144 $observer->internal
= true;
145 $observer->includefile
= null;
146 $expected[1] = $observer;
148 $this->assertEquals($expected, $result['\core\event\unknown_executed']);
151 $observer = new stdClass();
152 $observer->callable
= array('\core_tests\event\unittest_observer', 'observe_all');
153 $observer->priority
= 9999;
154 $observer->internal
= true;
155 $observer->includefile
= null;
156 $expected[0] = $observer;
158 $this->assertEquals($expected, $result['*']);
161 // Now test broken stuff...
165 'eventname' => 'core_tests\event\unittest_executed', // Fix leading backslash.
166 'callback' => '\core_tests\event\unittest_observer::observe_one',
167 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
168 'internal' => 1, // Cast to bool.
171 $result = \core\event\manager
::phpunit_replace_observers($observers);
172 $this->assertCount(1, $result);
174 $observer = new stdClass();
175 $observer->callable
= '\core_tests\event\unittest_observer::observe_one';
176 $observer->priority
= 0;
177 $observer->internal
= true;
178 $observer->includefile
= 'lib/tests/fixtures/event_fixtures.php';
179 $expected[0] = $observer;
180 $this->assertEquals($expected, $result['\core_tests\event\unittest_executed']);
184 // Missing eventclass.
185 'callback' => '\core_tests\event\unittest_observer::observe_one',
186 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
189 $result = \core\event\manager
::phpunit_replace_observers($observers);
190 $this->assertCount(0, $result);
191 $this->assertDebuggingCalled();
195 'eventname' => '', // Empty eventclass.
196 'callback' => '\core_tests\event\unittest_observer::observe_one',
197 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
200 $result = \core\event\manager
::phpunit_replace_observers($observers);
201 $this->assertCount(0, $result);
202 $this->assertDebuggingCalled();
206 'eventname' => '\core_tests\event\unittest_executed',
208 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
211 $result = \core\event\manager
::phpunit_replace_observers($observers);
212 $this->assertCount(0, $result);
213 $this->assertDebuggingCalled();
217 'eventname' => '\core_tests\event\unittest_executed',
218 'callback' => '', // empty callable
219 'includefile' => 'lib/tests/fixtures/event_fixtures.php',
222 $result = \core\event\manager
::phpunit_replace_observers($observers);
223 $this->assertCount(0, $result);
224 $this->assertDebuggingCalled();
228 'eventname' => '\core_tests\event\unittest_executed',
229 'callback' => '\core_tests\event\unittest_observer::observe_one',
230 'includefile' => 'lib/tests/fixtures/event_fixtures.php_xxx', // Missing file.
233 $result = \core\event\manager
::phpunit_replace_observers($observers);
234 $this->assertCount(0, $result);
235 $this->assertDebuggingCalled();
238 public function test_normal_dispatching() {
241 'eventname' => '\core_tests\event\unittest_executed',
242 'callback' => '\core_tests\event\unittest_observer::observe_one',
246 'callback' => '\core_tests\event\unittest_observer::observe_all',
247 'includefile' => null,
253 \core\event\manager
::phpunit_replace_observers($observers);
254 \core_tests\event\unittest_observer
::reset();
256 $event1 = \core_tests\event\unittest_executed
::create(array('courseid'=>1, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
258 $this->assertFalse($event1->is_triggered());
259 $this->assertFalse($event1->is_dispatched());
260 $this->assertFalse($event1->is_restored());
262 $this->assertTrue($event1->is_triggered());
263 $this->assertTrue($event1->is_dispatched());
264 $this->assertFalse($event1->is_restored());
266 $event1 = \core_tests\event\unittest_executed
::create(array('courseid'=>2, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
270 array('observe_all-nesting-1', 'observe_one-1', 'observe_all-3', 'observe_one-3', 'observe_all-2', 'observe_one-2'),
271 \core_tests\event\unittest_observer
::$info);
274 public function test_ignore_exceptions() {
278 'eventname' => '\core_tests\event\unittest_executed',
279 'callback' => '\core_tests\event\unittest_observer::observe_one',
283 'eventname' => '\core_tests\event\unittest_executed',
284 'callback' => '\core_tests\event\unittest_observer::broken_observer',
289 \core\event\manager
::phpunit_replace_observers($observers);
290 \core_tests\event\unittest_observer
::reset();
292 $event1 = \core_tests\event\unittest_executed
::create(array('courseid'=>1, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
294 $this->assertDebuggingCalled();
296 $event1 = \core_tests\event\unittest_executed
::create(array('courseid'=>2, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
298 $this->assertDebuggingCalled();
301 array('broken_observer-1', 'observe_one-1', 'broken_observer-2', 'observe_one-2'),
302 \core_tests\event\unittest_observer
::$info);
305 public function test_external_buffer() {
308 $this->preventResetByRollback();
313 'eventname' => '\core_tests\event\unittest_executed',
314 'callback' => '\core_tests\event\unittest_observer::observe_one',
318 'eventname' => '\core_tests\event\unittest_executed',
319 'callback' => '\core_tests\event\unittest_observer::external_observer',
325 \core\event\manager
::phpunit_replace_observers($observers);
326 \core_tests\event\unittest_observer
::reset();
328 $event1 = \core_tests\event\unittest_executed
::create(array('courseid'=>1, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
330 $event2 = \core_tests\event\unittest_executed
::create(array('courseid'=>2, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
334 array('external_observer-1', 'observe_one-1', 'external_observer-2', 'observe_one-2'),
335 \core_tests\event\unittest_observer
::$info);
337 \core\event\manager
::phpunit_replace_observers($observers);
338 \core_tests\event\unittest_observer
::reset();
340 $this->assertSame(array(), \core_tests\event\unittest_observer
::$info);
342 $trans = $DB->start_delegated_transaction();
344 $event1 = \core_tests\event\unittest_executed
::create(array('courseid'=>1, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
346 $event2 = \core_tests\event\unittest_executed
::create(array('courseid'=>2, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
350 array('observe_one-1', 'observe_one-2'),
351 \core_tests\event\unittest_observer
::$info);
353 $trans->allow_commit();
356 array('observe_one-1', 'observe_one-2', 'external_observer-1', 'external_observer-2'),
357 \core_tests\event\unittest_observer
::$info);
359 \core\event\manager
::phpunit_replace_observers($observers);
360 \core_tests\event\unittest_observer
::reset();
362 $event1 = \core_tests\event\unittest_executed
::create(array('courseid'=>1, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
364 $trans = $DB->start_delegated_transaction();
365 $event2 = \core_tests\event\unittest_executed
::create(array('courseid'=>2, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>2, 'xx'=>10)));
368 $trans->rollback(new \
moodle_exception('xxx'));
369 $this->fail('Expecting exception');
370 } catch (\moodle_exception
$e) {
374 array('external_observer-1', 'observe_one-1', 'observe_one-2'),
375 \core_tests\event\unittest_observer
::$info);
378 public function test_legacy() {
381 $this->resetAfterTest(true);
385 'eventname' => '\core_tests\event\unittest_executed',
386 'callback' => '\core_tests\event\unittest_observer::observe_one',
390 'callback' => '\core_tests\event\unittest_observer::observe_all',
391 'includefile' => null,
397 $DB->delete_records('log', array());
398 events_update_definition('unittest');
399 $DB->delete_records_select('events_handlers', "component <> 'unittest'");
400 events_get_handlers('reset');
401 $this->assertEquals(3, $DB->count_records('events_handlers'));
402 set_config('loglifetime', 60*60*24*5);
404 \core\event\manager
::phpunit_replace_observers($observers);
405 \core_tests\event\unittest_observer
::reset();
407 $event1 = \core_tests\event\unittest_executed
::create(array('courseid'=>1, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
410 $event2 = \core_tests\event\unittest_executed
::create(array('courseid'=>2, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>6, 'xx'=>11)));
411 $event2->nest
= true;
416 array('observe_all-1', 'observe_one-1', 'legacy_handler-1', 'observe_all-nesting-2', 'legacy_handler-3', 'observe_one-2', 'observe_all-3', 'observe_one-3', 'legacy_handler-2'),
417 \core_tests\event\unittest_observer
::$info);
419 $this->assertSame($event1, \core_tests\event\unittest_observer
::$event[0]);
420 $this->assertSame($event1, \core_tests\event\unittest_observer
::$event[1]);
421 $this->assertSame(array(1, 5), \core_tests\event\unittest_observer
::$event[2]);
424 $logs = $DB->get_records('log', array(), 'id ASC');
425 $this->assertCount(3, $logs);
427 $log = array_shift($logs);
428 $this->assertEquals(1, $log->course
);
429 $this->assertSame('core_unittest', $log->module
);
430 $this->assertSame('view', $log->action
);
432 $log = array_shift($logs);
433 $this->assertEquals(2, $log->course
);
434 $this->assertSame('core_unittest', $log->module
);
435 $this->assertSame('view', $log->action
);
437 $log = array_shift($logs);
438 $this->assertEquals(3, $log->course
);
439 $this->assertSame('core_unittest', $log->module
);
440 $this->assertSame('view', $log->action
);
443 public function test_restore_event() {
444 $event1 = \core_tests\event\unittest_executed
::create(array('courseid'=>1, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
445 $data1 = $event1->get_data();
447 $event2 = \core\event\base
::restore($data1, array('origin'=>'clid'));
448 $data2 = $event2->get_data();
450 $this->assertTrue($event2->is_triggered());
451 $this->assertTrue($event2->is_restored());
452 $this->assertEquals($data1, $data2);
453 $this->assertInstanceOf('core_tests\event\unittest_executed', $event2);
455 $this->assertEquals($event1->get_context(), $event2->get_context());
457 // Now test problematic data.
459 $data3['eventname'] = '\\a\\b\\c';
460 $event3 = \core\event\base
::restore($data3, array());
461 $this->assertFalse($event3, 'Class name must match');
464 unset($data4['userid']);
465 $event4 = \core\event\base
::restore($data4, array());
466 $this->assertInstanceOf('core_tests\event\unittest_executed', $event4);
467 $this->assertDebuggingCalled();
471 $event5 = \core\event\base
::restore($data5, array());
472 $this->assertInstanceOf('core_tests\event\unittest_executed', $event5);
473 $this->assertDebuggingCalled();
477 public function test_trigger_problems() {
478 $event = \core_tests\event\unittest_executed
::create(array('courseid'=>1, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
482 $this->fail('Exception expected on double trigger');
483 } catch (Exception
$e) {
484 $this->assertInstanceOf('coding_exception', $e);
487 $data = $event->get_data();
488 $restored = \core_tests\event\unittest_executed
::restore($data, array());
489 $this->assertTrue($restored->is_triggered());
490 $this->assertTrue($restored->is_restored());
493 $restored->trigger();
494 $this->fail('Exception expected on triggering of restored event');
495 } catch (\moodle_exception
$e) {
496 $this->assertInstanceOf('coding_exception', $e);
499 $event = \core_tests\event\unittest_executed
::create(array('courseid'=>1, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>5, 'xx'=>10)));
501 \core\event\manager
::dispatch($event);
502 $this->fail('Exception expected on manual event dispatching');
503 } catch (\moodle_exception
$e) {
504 $this->assertInstanceOf('coding_exception', $e);
508 public function test_bad_events() {
509 $event = \core_tests\event\bad_event
1::create();
512 $this->fail('Exception expected when $data not valid');
513 } catch (\moodle_exception
$e) {
514 $this->assertInstanceOf('\coding_exception', $e);
517 $event = \core_tests\event\bad_event
2::create();
520 $this->fail('Exception expected when $data not valid');
521 } catch (\moodle_exception
$e) {
522 $this->assertInstanceOf('\coding_exception', $e);
525 $event = \core_tests\event\bad_event
3::create();
527 $this->assertDebuggingCalled();
529 $event = \core_tests\event\bad_event
4::create();
531 $this->assertDebuggingCalled();
533 $event = \core_tests\event\bad_event
5::create();
535 $this->assertDebuggingCalled();
538 public function test_problematic_events() {
540 $event1 = \core_tests\event\problematic_event1
::create();
541 $this->assertDebuggingNotCalled();
542 $this->assertNull($event1->xxx
);
543 $this->assertDebuggingCalled();
545 $event2 = \core_tests\event\problematic_event1
::create(array('xxx'=>0));
546 $this->assertDebuggingCalled();
549 $event3 = \core_tests\event\problematic_event1
::create(array('xxx'=>0));
550 $this->assertDebuggingNotCalled();
551 $CFG->debug
= E_ALL | E_STRICT
;
553 $event4 = \core_tests\event\problematic_event1
::create(array('other'=>array('a'=>1)));
555 $this->assertDebuggingNotCalled();
557 $event5 = \core_tests\event\problematic_event1
::create(array('other'=>(object)array('a'=>1)));
558 $this->assertDebuggingNotCalled();
560 $this->assertDebuggingCalled();
562 $url = new moodle_url('/admin/');
563 $event6 = \core_tests\event\problematic_event1
::create(array('other'=>array('a'=>$url)));
564 $this->assertDebuggingNotCalled();
566 $this->assertDebuggingCalled();
569 public function test_record_cache() {
572 $event = \core_tests\event\unittest_executed
::create(array('courseid'=>1, 'context'=>\context_system
::instance(), 'other'=>array('sample'=>1, 'xx'=>10)));
573 $course1 = $DB->get_record('course', array('id'=>1));
574 $this->assertNotEmpty($course1);
576 $event->add_cached_record('course', $course1);
578 $result = $event->get_cached_record('course', 1, $course1);
579 $this->assertSame($course1, $result);
581 $user = $event->get_cached_record('user', 1);
582 $this->assertEquals(1, $user->id
);
583 $this->assertSame('guest', $user->username
);