Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

Differences Between: [Versions 311 and 403] [Versions 400 and 403] [Versions 401 and 403]

   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/>.
  16  
  17  /**
  18   * Events tests.
  19   *
  20   * @package   core
  21   * @category  test
  22   * @copyright 2014 Mark Nelson <markn@moodle.com>
  23   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  namespace core\event;
  27  
  28  defined('MOODLE_INTERNAL') || die();
  29  
  30  require_once (__DIR__.'/../fixtures/event_fixtures.php');
  31  
  32  class events_test extends \advanced_testcase {
  33  
  34      /**
  35       * Test set up.
  36       *
  37       * This is executed before running any test in this file.
  38       */
  39      public function setUp(): void {
  40          $this->resetAfterTest();
  41      }
  42  
  43      /**
  44       * Test the course category created event.
  45       */
  46      public function test_course_category_created() {
  47          // Trigger and capture the event.
  48          $sink = $this->redirectEvents();
  49          $category = $this->getDataGenerator()->create_category();
  50          $events = $sink->get_events();
  51          $event = reset($events);
  52  
  53          // Check that the event data is valid.
  54          $this->assertInstanceOf('\core\event\course_category_created', $event);
  55          $this->assertEquals(\context_coursecat::instance($category->id), $event->get_context());
  56          $url = new \moodle_url('/course/management.php', array('categoryid' => $event->objectid));
  57          $this->assertEquals($url, $event->get_url());
  58          $this->assertEventContextNotUsed($event);
  59      }
  60  
  61      /**
  62       * Test the course category updated event.
  63       */
  64      public function test_course_category_updated() {
  65          // Create a category.
  66          $category = $this->getDataGenerator()->create_category();
  67  
  68          // Create some data we are going to use to update this category.
  69          $data = new \stdClass();
  70          $data->name = 'Category name change';
  71  
  72          // Trigger and capture the event for updating a category.
  73          $sink = $this->redirectEvents();
  74          $category->update($data);
  75          $events = $sink->get_events();
  76          $event = reset($events);
  77  
  78          // Check that the event data is valid.
  79          $this->assertInstanceOf('\core\event\course_category_updated', $event);
  80          $this->assertEquals(\context_coursecat::instance($category->id), $event->get_context());
  81          $url = new \moodle_url('/course/editcategory.php', array('id' => $event->objectid));
  82          $this->assertEquals($url, $event->get_url());
  83  
  84          // Create another category and a child category.
  85          $category2 = $this->getDataGenerator()->create_category();
  86          $childcat = $this->getDataGenerator()->create_category(array('parent' => $category2->id));
  87  
  88          // Trigger and capture the event for changing the parent of a category.
  89          $sink = $this->redirectEvents();
  90          $childcat->change_parent($category);
  91          $events = $sink->get_events();
  92          $event = reset($events);
  93  
  94          // Check that the event data is valid.
  95          $this->assertInstanceOf('\core\event\course_category_updated', $event);
  96          $this->assertEquals(\context_coursecat::instance($childcat->id), $event->get_context());
  97  
  98          // Trigger and capture the event for changing the sortorder of a category.
  99          $sink = $this->redirectEvents();
 100          $category2->change_sortorder_by_one(true);
 101          $events = $sink->get_events();
 102          $event = reset($events);
 103  
 104          // Check that the event data is valid.
 105          $this->assertInstanceOf('\core\event\course_category_updated', $event);
 106          $this->assertEquals(\context_coursecat::instance($category2->id), $event->get_context());
 107  
 108          // Trigger and capture the event for deleting a category and moving it's children to another.
 109          $sink = $this->redirectEvents();
 110          $category->delete_move($category->id);
 111          $events = $sink->get_events();
 112          $event = reset($events);
 113  
 114          // Check that the event data is valid.
 115          $this->assertInstanceOf('\core\event\course_category_updated', $event);
 116          $this->assertEquals(\context_coursecat::instance($childcat->id), $event->get_context());
 117  
 118          // Trigger and capture the event for hiding a category.
 119          $sink = $this->redirectEvents();
 120          $category2->hide();
 121          $events = $sink->get_events();
 122          $event = reset($events);
 123  
 124          // Check that the event data is valid.
 125          $this->assertInstanceOf('\core\event\course_category_updated', $event);
 126          $this->assertEquals(\context_coursecat::instance($category2->id), $event->get_context());
 127  
 128          // Trigger and capture the event for unhiding a category.
 129          $sink = $this->redirectEvents();
 130          $category2->show();
 131          $events = $sink->get_events();
 132          $event = reset($events);
 133  
 134          // Check that the event data is valid.
 135          $this->assertInstanceOf('\core\event\course_category_updated', $event);
 136          $this->assertEquals(\context_coursecat::instance($category2->id), $event->get_context());
 137          $this->assertEventContextNotUsed($event);
 138      }
 139  
 140      /**
 141       * Test the email failed event.
 142       *
 143       * It's not possible to use the moodle API to simulate the failure of sending
 144       * an email, so here we simply create the event and trigger it.
 145       */
 146      public function test_email_failed() {
 147          // Trigger event for failing to send email.
 148          $event = \core\event\email_failed::create(array(
 149              'context' => \context_system::instance(),
 150              'userid' => 1,
 151              'relateduserid' => 2,
 152              'other' => array(
 153                  'subject' => 'This is a subject',
 154                  'message' => 'This is a message',
 155                  'errorinfo' => 'The email failed to send!'
 156              )
 157          ));
 158  
 159          // Trigger and capture the event.
 160          $sink = $this->redirectEvents();
 161          $event->trigger();
 162          $events = $sink->get_events();
 163          $event = reset($events);
 164  
 165          $this->assertInstanceOf('\core\event\email_failed', $event);
 166          $this->assertEquals(\context_system::instance(), $event->get_context());
 167          $this->assertEventContextNotUsed($event);
 168      }
 169  
 170      /**
 171       * There is no api involved so the best we can do is test legacy data by triggering event manually.
 172       */
 173      public function test_course_user_report_viewed() {
 174  
 175          $user = $this->getDataGenerator()->create_user();
 176          $course = $this->getDataGenerator()->create_course();
 177          $context = \context_course::instance($course->id);
 178  
 179          $eventparams = array();
 180          $eventparams['context'] = $context;
 181          $eventparams['relateduserid'] = $user->id;
 182          $eventparams['other'] = array();
 183          $eventparams['other']['mode'] = 'grade';
 184          $event = \core\event\course_user_report_viewed::create($eventparams);
 185  
 186          // Trigger and capture the event.
 187          $sink = $this->redirectEvents();
 188          $event->trigger();
 189          $events = $sink->get_events();
 190          $event = reset($events);
 191  
 192          $this->assertInstanceOf('\core\event\course_user_report_viewed', $event);
 193          $this->assertEquals(\context_course::instance($course->id), $event->get_context());
 194          $this->assertEventContextNotUsed($event);
 195      }
 196  
 197      /**
 198       * There is no api involved so the best we can do is test legacy data by triggering event manually.
 199       */
 200      public function test_course_viewed() {
 201  
 202          $user = $this->getDataGenerator()->create_user();
 203          $course = $this->getDataGenerator()->create_course();
 204          $context = \context_course::instance($course->id);
 205  
 206          // First try with no optional parameters.
 207          $eventparams = array();
 208          $eventparams['context'] = $context;
 209          $event = \core\event\course_viewed::create($eventparams);
 210  
 211          // Trigger and capture the event.
 212          $sink = $this->redirectEvents();
 213          $event->trigger();
 214          $events = $sink->get_events();
 215          $event = reset($events);
 216  
 217          $this->assertInstanceOf('\core\event\course_viewed', $event);
 218          $this->assertEquals(\context_course::instance($course->id), $event->get_context());
 219          $this->assertEventContextNotUsed($event);
 220  
 221          // Now try with optional parameters.
 222          $sectionnumber = 7;
 223          $eventparams = array();
 224          $eventparams['context'] = $context;
 225          $eventparams['other'] = array('coursesectionnumber' => $sectionnumber);
 226          $event = \core\event\course_viewed::create($eventparams);
 227  
 228          // Trigger and capture the event.
 229          $sink = $this->redirectEvents();
 230          $event->trigger();
 231          $loggeddata = $event->get_data();
 232          $events = $sink->get_events();
 233          $event = reset($events);
 234  
 235  
 236          $this->assertInstanceOf('\core\event\course_viewed', $event);
 237          $this->assertEquals(\context_course::instance($course->id), $event->get_context());
 238          $this->assertEventContextNotUsed($event);
 239  
 240          delete_course($course->id, false);
 241          $restored = \core\event\base::restore($loggeddata, array('origin' => 'web', 'ip' => '127.0.0.1'));
 242          $this->assertInstanceOf('\core\event\course_viewed', $restored);
 243          $this->assertNull($restored->get_url());
 244      }
 245  
 246      public function test_recent_capability_viewed() {
 247          $this->resetAfterTest();
 248  
 249          $this->setAdminUser();
 250          $course = $this->getDataGenerator()->create_course();
 251          $context = \context_course::instance($course->id);
 252  
 253          $event = \core\event\recent_activity_viewed::create(array('context' => $context));
 254  
 255          // Trigger and capture the event.
 256          $sink = $this->redirectEvents();
 257          $event->trigger();
 258          $events = $sink->get_events();
 259          $event = reset($events);
 260  
 261          $this->assertInstanceOf('\core\event\recent_activity_viewed', $event);
 262          $this->assertEquals($context, $event->get_context());
 263          $this->assertEventContextNotUsed($event);
 264          $url = new \moodle_url('/course/recent.php', array('id' => $course->id));
 265          $this->assertEquals($url, $event->get_url());
 266          $event->get_name();
 267      }
 268  
 269      public function test_user_profile_viewed() {
 270          $this->resetAfterTest();
 271          $this->setAdminUser();
 272  
 273          $user = $this->getDataGenerator()->create_user();
 274          $course = $this->getDataGenerator()->create_course();
 275          $coursecontext = \context_course::instance($course->id);
 276  
 277          // User profile viewed in course context.
 278          $eventparams = array(
 279              'objectid' => $user->id,
 280              'relateduserid' => $user->id,
 281              'courseid' => $course->id,
 282              'context' => $coursecontext,
 283              'other' => array(
 284                  'courseid' => $course->id,
 285                  'courseshortname' => $course->shortname,
 286                  'coursefullname' => $course->fullname
 287              )
 288          );
 289          $event = \core\event\user_profile_viewed::create($eventparams);
 290  
 291          // Trigger and capture the event.
 292          $sink = $this->redirectEvents();
 293          $event->trigger();
 294          $events = $sink->get_events();
 295          $event = reset($events);
 296  
 297          $this->assertInstanceOf('\core\event\user_profile_viewed', $event);
 298          $this->assertEventContextNotUsed($event);
 299  
 300          // User profile viewed in user context.
 301          $usercontext = \context_user::instance($user->id);
 302          $eventparams['context'] = $usercontext;
 303          unset($eventparams['courseid'], $eventparams['other']);
 304          $event = \core\event\user_profile_viewed::create($eventparams);
 305  
 306          // Trigger and capture the event.
 307          $sink = $this->redirectEvents();
 308          $event->trigger();
 309          $events = $sink->get_events();
 310          $event = reset($events);
 311  
 312          $this->assertInstanceOf('\core\event\user_profile_viewed', $event);
 313          $this->assertEventContextNotUsed($event);
 314      }
 315  
 316      /**
 317       * There is no API associated with this event, so we will just test standard features.
 318       */
 319      public function test_grade_viewed() {
 320          $this->resetAfterTest();
 321          $this->setAdminUser();
 322  
 323          $user = $this->getDataGenerator()->create_user();
 324          $course = $this->getDataGenerator()->create_course();
 325          $coursecontext = \context_course::instance($course->id);
 326  
 327          $event = \core_tests\event\grade_report_viewed::create(
 328              array(
 329                  'context' => $coursecontext,
 330                  'courseid' => $course->id,
 331                  'userid' => $user->id,
 332              )
 333          );
 334  
 335          // Trigger and capture the event.
 336          $sink = $this->redirectEvents();
 337          $event->trigger();
 338          $events = $sink->get_events();
 339          $event = reset($events);
 340  
 341          $this->assertInstanceOf('\core\event\grade_report_viewed', $event);
 342          $this->assertEquals($event->courseid, $course->id);
 343          $this->assertEquals($event->userid, $user->id);
 344          $this->assertEventContextNotUsed($event);
 345      }
 346  
 347      /**
 348       * Test the database text field content replaced event.
 349       */
 350      public function test_database_text_field_content_replaced() {
 351          global $CFG;
 352  
 353          require_once($CFG->dirroot . '/lib/adminlib.php');
 354  
 355          // Trigger and capture the event for finding and replacing strings in the database.
 356          $sink = $this->redirectEvents();
 357          ob_start();
 358          db_replace('searchstring', 'replacestring');
 359          ob_end_clean();
 360          $events = $sink->get_events();
 361          $event = reset($events);
 362  
 363          // Check that the event data is valid.
 364          $this->assertInstanceOf('\core\event\database_text_field_content_replaced', $event);
 365          $this->assertEquals(\context_system::instance(), $event->get_context());
 366          $this->assertEquals('searchstring', $event->other['search']);
 367          $this->assertEquals('replacestring', $event->other['replace']);
 368      }
 369  }