Exemplo n.º 1
3
 /**
  * Reset contents of all database tables to initial values, reset caches, etc.
  *
  * Note: this is relatively slow (cca 2 seconds for pg and 7 for mysql) - please use with care!
  *
  * @static
  * @param bool $detectchanges
  *      true  - changes in global state and database are reported as errors
  *      false - no errors reported
  *      null  - only critical problems are reported as errors
  * @return void
  */
 public static function reset_all_data($detectchanges = false)
 {
     global $DB, $CFG, $USER, $SITE, $COURSE, $PAGE, $OUTPUT, $SESSION;
     // Stop any message redirection.
     phpunit_util::stop_message_redirection();
     // Stop any message redirection.
     phpunit_util::stop_phpmailer_redirection();
     // Stop any message redirection.
     phpunit_util::stop_event_redirection();
     // We used to call gc_collect_cycles here to ensure desctructors were called between tests.
     // This accounted for 25% of the total time running phpunit - so we removed it.
     // Show any unhandled debugging messages, the runbare() could already reset it.
     self::display_debugging_messages();
     self::reset_debugging();
     // reset global $DB in case somebody mocked it
     $DB = self::get_global_backup('DB');
     if ($DB->is_transaction_started()) {
         // we can not reset inside transaction
         $DB->force_transaction_rollback();
     }
     $resetdb = self::reset_database();
     $warnings = array();
     if ($detectchanges === true) {
         if ($resetdb) {
             $warnings[] = 'Warning: unexpected database modification, resetting DB state';
         }
         $oldcfg = self::get_global_backup('CFG');
         $oldsite = self::get_global_backup('SITE');
         foreach ($CFG as $k => $v) {
             if (!property_exists($oldcfg, $k)) {
                 $warnings[] = 'Warning: unexpected new $CFG->' . $k . ' value';
             } else {
                 if ($oldcfg->{$k} !== $CFG->{$k}) {
                     $warnings[] = 'Warning: unexpected change of $CFG->' . $k . ' value';
                 }
             }
             unset($oldcfg->{$k});
         }
         if ($oldcfg) {
             foreach ($oldcfg as $k => $v) {
                 $warnings[] = 'Warning: unexpected removal of $CFG->' . $k;
             }
         }
         if ($USER->id != 0) {
             $warnings[] = 'Warning: unexpected change of $USER';
         }
         if ($COURSE->id != $oldsite->id) {
             $warnings[] = 'Warning: unexpected change of $COURSE';
         }
     }
     if (ini_get('max_execution_time') != 0) {
         // This is special warning for all resets because we do not want any
         // libraries to mess with timeouts unintentionally.
         // Our PHPUnit integration is not supposed to change it either.
         if ($detectchanges !== false) {
             $warnings[] = 'Warning: max_execution_time was changed to ' . ini_get('max_execution_time');
         }
         set_time_limit(0);
     }
     // restore original globals
     $_SERVER = self::get_global_backup('_SERVER');
     $CFG = self::get_global_backup('CFG');
     $SITE = self::get_global_backup('SITE');
     $_GET = array();
     $_POST = array();
     $_FILES = array();
     $_REQUEST = array();
     $COURSE = $SITE;
     // reinitialise following globals
     $OUTPUT = new bootstrap_renderer();
     $PAGE = new moodle_page();
     $FULLME = null;
     $ME = null;
     $SCRIPT = null;
     // Empty sessison and set fresh new not-logged-in user.
     \core\session\manager::init_empty_session();
     // reset all static caches
     \core\event\manager::phpunit_reset();
     accesslib_clear_all_caches(true);
     get_string_manager()->reset_caches(true);
     reset_text_filters_cache(true);
     events_get_handlers('reset');
     core_text::reset_caches();
     get_message_processors(false, true);
     filter_manager::reset_caches();
     // Reset internal users.
     core_user::reset_internal_users();
     //TODO MDL-25290: add more resets here and probably refactor them to new core function
     // Reset course and module caches.
     if (class_exists('format_base')) {
         // If file containing class is not loaded, there is no cache there anyway.
         format_base::reset_course_cache(0);
     }
     get_fast_modinfo(0, 0, true);
     // Reset other singletons.
     if (class_exists('core_plugin_manager')) {
         core_plugin_manager::reset_caches(true);
     }
     if (class_exists('\\core\\update\\checker')) {
         \core\update\checker::reset_caches(true);
     }
     if (class_exists('\\core\\update\\deployer')) {
         \core\update\deployer::reset_caches(true);
     }
     // purge dataroot directory
     self::reset_dataroot();
     // restore original config once more in case resetting of caches changed CFG
     $CFG = self::get_global_backup('CFG');
     // inform data generator
     self::get_data_generator()->reset();
     // fix PHP settings
     error_reporting($CFG->debug);
     // verify db writes just in case something goes wrong in reset
     if (self::$lastdbwrites != $DB->perf_get_writes()) {
         error_log('Unexpected DB writes in phpunit_util::reset_all_data()');
         self::$lastdbwrites = $DB->perf_get_writes();
     }
     if ($warnings) {
         $warnings = implode("\n", $warnings);
         trigger_error($warnings, E_USER_WARNING);
     }
 }
Exemplo n.º 2
0
 /**
  * Force rollback of all delegated transaction.
  * Does not throw any exceptions and does not log anything.
  *
  * This method should be used only from default exception handlers and other
  * core code.
  *
  * @return void
  */
 public function force_transaction_rollback()
 {
     if ($this->transactions) {
         try {
             $this->rollback_transaction();
         } catch (dml_exception $e) {
             // ignore any sql errors here, the connection might be broken
         }
     }
     // now enable transactions again
     $this->transactions = array();
     $this->force_rollback = false;
     \core\event\manager::database_transaction_rolledback();
     \core\message\manager::database_transaction_rolledback();
 }
Exemplo n.º 3
0
 /**
  * Trigger event.
  */
 public final function trigger()
 {
     global $CFG;
     if ($this->restored) {
         throw new \coding_exception('Can not trigger restored event');
     }
     if ($this->triggered or $this->dispatched) {
         throw new \coding_exception('Can not trigger event twice');
     }
     $this->validate_before_trigger();
     $this->triggered = true;
     if (isset($CFG->loglifetime) and $CFG->loglifetime != -1) {
         if ($data = $this->get_legacy_logdata()) {
             $manager = get_log_manager();
             if (method_exists($manager, 'legacy_add_to_log')) {
                 if (is_array($data[0])) {
                     // Some events require several entries in 'log' table.
                     foreach ($data as $d) {
                         call_user_func_array(array($manager, 'legacy_add_to_log'), $d);
                     }
                 } else {
                     call_user_func_array(array($manager, 'legacy_add_to_log'), $data);
                 }
             }
         }
     }
     if (PHPUNIT_TEST and \phpunit_util::is_redirecting_events()) {
         $this->dispatched = true;
         \phpunit_util::event_triggered($this);
         return;
     }
     \core\event\manager::dispatch($this);
     $this->dispatched = true;
     if ($legacyeventname = static::get_legacy_eventname()) {
         events_trigger_legacy($legacyeventname, $this->get_legacy_eventdata());
     }
 }
Exemplo n.º 4
0
 /**
  * Get the full list of observers for the system.
  *
  * @return array An array of observers in the system.
  */
 public static function get_observer_list()
 {
     $events = \core\event\manager::get_all_observers();
     foreach ($events as $key => $observers) {
         foreach ($observers as $observerskey => $observer) {
             $events[$key][$observerskey]->parentplugin = \core_plugin_manager::instance()->get_parent_of_subplugin($observer->plugintype);
         }
     }
     return $events;
 }
Exemplo n.º 5
0
 /**
  * Trigger event.
  */
 public final function trigger()
 {
     global $CFG;
     if ($this->restored) {
         throw new \coding_exception('Can not trigger restored event');
     }
     if ($this->triggered or $this->dispatched) {
         throw new \coding_exception('Can not trigger event twice');
     }
     $this->validate_before_trigger();
     $this->triggered = true;
     if (isset($CFG->loglifetime) and $CFG->loglifetime != -1) {
         if ($data = $this->get_legacy_logdata()) {
             call_user_func_array('add_to_log', $data);
         }
     }
     if (PHPUNIT_TEST and \phpunit_util::is_redirecting_events()) {
         $this->dispatched = true;
         \phpunit_util::event_triggered($this);
         return;
     }
     \core\event\manager::dispatch($this);
     $this->dispatched = true;
     if ($legacyeventname = static::get_legacy_eventname()) {
         events_trigger_legacy($legacyeventname, $this->get_legacy_eventdata());
     }
 }
Exemplo n.º 6
0
 public function test_trigger_problems()
 {
     $event = \core_tests\event\unittest_executed::create(array('courseid' => 1, 'context' => \context_system::instance(), 'other' => array('sample' => 5, 'xx' => 10)));
     $event->trigger();
     try {
         $event->trigger();
         $this->fail('Exception expected on double trigger');
     } catch (\moodle_exception $e) {
         $this->assertInstanceOf('coding_exception', $e);
     }
     $data = $event->get_data();
     $restored = \core_tests\event\unittest_executed::restore($data, array());
     $this->assertTrue($restored->is_triggered());
     $this->assertTrue($restored->is_restored());
     try {
         $restored->trigger();
         $this->fail('Exception expected on triggering of restored event');
     } catch (\moodle_exception $e) {
         $this->assertInstanceOf('coding_exception', $e);
     }
     $event = \core_tests\event\unittest_executed::create(array('courseid' => 1, 'context' => \context_system::instance(), 'other' => array('sample' => 5, 'xx' => 10)));
     try {
         \core\event\manager::dispatch($event);
         $this->fail('Exception expected on manual event dispatching');
     } catch (\moodle_exception $e) {
         $this->assertInstanceOf('coding_exception', $e);
     }
 }
Exemplo n.º 7
0
 /**
  * Call when delegated transaction failed, this rolls back
  * all delegated transactions up to the top most level.
  *
  * In many cases you do not need to call this method manually,
  * because all open delegated transactions are rolled back
  * automatically if exceptions not caught.
  *
  * @param moodle_transaction $transaction An instance of a moodle_transaction.
  * @param Exception $e The related exception to this transaction rollback.
  * @return void This does not return, instead the exception passed in will be rethrown.
  */
 public function rollback_delegated_transaction(moodle_transaction $transaction, Exception $e)
 {
     if ($transaction->is_disposed()) {
         throw new dml_transaction_exception('Transactions already disposed', $transaction);
     }
     // mark as disposed so that it can not be used again
     $transaction->dispose();
     // one rollback at any level rollbacks everything
     $this->force_rollback = true;
     if (empty($this->transactions) or $transaction !== $this->transactions[count($this->transactions) - 1]) {
         // this may or may not be a coding problem, better just rethrow the exception,
         // because we do not want to loose the original $e
         throw $e;
     }
     if (count($this->transactions) == 1) {
         // only rollback the top most level
         $this->rollback_transaction();
     }
     array_pop($this->transactions);
     if (empty($this->transactions)) {
         // finally top most level rolled back
         $this->force_rollback = false;
         \core\event\manager::database_transaction_rolledback();
     }
     throw $e;
 }
Exemplo n.º 8
0
 /**
  * This tests the internal method of \core\event\manager::get_observing_classes.
  *
  * What we are testing is if we can subscribe to a parent event class, instead of only
  * the base event class or the final, implemented event class.  This enables us to subscribe
  * to things like all course module view events, all comment created events, etc.
  */
 public function test_observe_parent_event()
 {
     $this->resetAfterTest();
     // Ensure this has been reset prior to using it.
     \core_tests\event\unittest_observer::reset();
     $course = $this->getDataGenerator()->create_course();
     $feed = $this->getDataGenerator()->create_module('feedback', ['course' => $course->id]);
     $context = context_module::instance($feed->cmid);
     $data = ['context' => $context, 'courseid' => $course->id, 'objectid' => $feed->id];
     // This assertion ensures that basic observe use case did not break.
     \core\event\manager::phpunit_replace_observers([['eventname' => '\\core_tests\\event\\course_module_viewed', 'callback' => ['\\core_tests\\event\\unittest_observer', 'observe_all_alt']]]);
     $pageevent = \core_tests\event\course_module_viewed::create($data);
     $pageevent->trigger();
     $this->assertSame(['observe_all_alt'], \core_tests\event\unittest_observer::$info, 'Error observing triggered event');
     \core_tests\event\unittest_observer::reset();
     // This assertion tests that we can observe an abstract (parent) class instead of the implemented class.
     \core\event\manager::phpunit_replace_observers([['eventname' => '\\core\\event\\course_module_viewed', 'callback' => ['\\core_tests\\event\\unittest_observer', 'observe_all_alt']]]);
     $pageevent = \core_tests\event\course_module_viewed::create($data);
     $pageevent->trigger();
     $this->assertSame(['observe_all_alt'], \core_tests\event\unittest_observer::$info, 'Error observing parent class event');
     \core_tests\event\unittest_observer::reset();
 }
Exemplo n.º 9
0
 /**
  * Test that all observer information is returned correctly.
  */
 public function test_get_all_observers()
 {
     // Retrieve all observers.
     $observers = \core\event\manager::get_all_observers();
     // Expected information from the workshop allocation scheduled observer.
     $expected = array();
     $observer = new stdClass();
     $observer->callable = '\\workshopallocation_scheduled\\observer::workshop_viewed';
     $observer->priority = 0;
     $observer->internal = true;
     $observer->includefile = null;
     $observer->plugintype = 'workshopallocation';
     $observer->plugin = 'scheduled';
     $expected[0] = $observer;
     $this->assertEquals($expected, $observers['\\mod_workshop\\event\\course_module_viewed']);
 }