Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 401 and 402] [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    mod_lesson
  21   * @category   test
  22   * @copyright  2013 Mark Nelson <markn@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  namespace mod_lesson\event;
  27  
  28  use lesson;
  29  
  30  defined('MOODLE_INTERNAL') || die();
  31  
  32  global $CFG;
  33  
  34  require_once($CFG->dirroot.'/mod/lesson/locallib.php');
  35  
  36  class events_test extends \advanced_testcase {
  37  
  38      /** @var stdClass the course used for testing */
  39      private $course;
  40  
  41      /** @var lesson the lesson used for testing */
  42      private $lesson;
  43  
  44      /**
  45       * Test set up.
  46       *
  47       * This is executed before running any test in this file.
  48       */
  49      public function setUp(): void {
  50          $this->resetAfterTest();
  51  
  52          $this->setAdminUser();
  53          $this->course = $this->getDataGenerator()->create_course();
  54          $lesson = $this->getDataGenerator()->create_module('lesson', array('course' => $this->course->id));
  55  
  56          // Convert to a lesson object.
  57          $this->lesson = new lesson($lesson);
  58      }
  59  
  60      /**
  61       * Test the page created event.
  62       *
  63       */
  64      public function test_page_created() {
  65  
  66          // Set up a generator to create content.
  67          $generator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
  68          // Trigger and capture the event.
  69          $sink = $this->redirectEvents();
  70          $pagerecord = $generator->create_content($this->lesson);
  71          $page = $this->lesson->load_page($pagerecord->id);
  72  
  73          // Get our event event.
  74          $events = $sink->get_events();
  75          $event = reset($events);
  76  
  77          // Check that the event data is valid.
  78          $this->assertInstanceOf('\mod_lesson\event\page_created', $event);
  79          $this->assertEquals($page->id, $event->objectid);
  80          $this->assertEventContextNotUsed($event);
  81          $this->assertDebuggingNotCalled();
  82      }
  83  
  84      /**
  85       * Test the page created event.
  86       *
  87       */
  88      public function test_page_moved() {
  89  
  90          // Set up a generator to create content.
  91          // paga3 is the first one and page1 the last one.
  92          $generator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
  93          $pagerecord1 = $generator->create_content($this->lesson);
  94          $page1 = $this->lesson->load_page($pagerecord1->id);
  95          $pagerecord2 = $generator->create_content($this->lesson);
  96          $page2 = $this->lesson->load_page($pagerecord2->id);
  97          $pagerecord3 = $generator->create_content($this->lesson);
  98          $page3 = $this->lesson->load_page($pagerecord3->id);
  99          // Trigger and capture the event.
 100          $sink = $this->redirectEvents();
 101          $this->lesson->resort_pages($page3->id, $pagerecord2->id);
 102          // Get our event event.
 103          $events = $sink->get_events();
 104          $event = reset($events);
 105  
 106          $this->assertCount(1, $events);
 107          // Check that the event data is valid.
 108          $this->assertInstanceOf('\mod_lesson\event\page_moved', $event);
 109          $this->assertEquals($page3->id, $event->objectid);
 110          $this->assertEquals($pagerecord1->id, $event->other['nextpageid']);
 111          $this->assertEquals($pagerecord2->id, $event->other['prevpageid']);
 112          $this->assertEventContextNotUsed($event);
 113          $this->assertDebuggingNotCalled();
 114      }
 115  
 116      /**
 117       * Test the page deleted event.
 118       *
 119       */
 120      public function test_page_deleted() {
 121  
 122          // Set up a generator to create content.
 123          $generator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 124          // Create a content page.
 125          $pagerecord = $generator->create_content($this->lesson);
 126          // Get the lesson page information.
 127          $page = $this->lesson->load_page($pagerecord->id);
 128          // Trigger and capture the event.
 129          $sink = $this->redirectEvents();
 130          $page->delete();
 131  
 132          // Get our event event.
 133          $events = $sink->get_events();
 134          $event = reset($events);
 135  
 136          // Check that the event data is valid.
 137          $this->assertInstanceOf('\mod_lesson\event\page_deleted', $event);
 138          $this->assertEquals($page->id, $event->objectid);
 139          $this->assertEventContextNotUsed($event);
 140          $this->assertDebuggingNotCalled();
 141      }
 142  
 143      /**
 144       * Test the page updated event.
 145       *
 146       * There is no external API for updateing a page, so the unit test will simply
 147       * create and trigger the event and ensure data is returned as expected.
 148       */
 149      public function test_page_updated() {
 150  
 151          // Trigger an event: page updated.
 152          $eventparams = array(
 153              'context' => \context_module::instance($this->lesson->properties()->cmid),
 154              'objectid' => 25,
 155              'other' => array(
 156                  'pagetype' => 'True/false'
 157                  )
 158          );
 159  
 160          $event = \mod_lesson\event\page_updated::create($eventparams);
 161  
 162          // Trigger and capture the event.
 163          $sink = $this->redirectEvents();
 164          $event->trigger();
 165          $events = $sink->get_events();
 166          $event = reset($events);
 167  
 168          // Check that the event data is valid.
 169          $this->assertInstanceOf('\mod_lesson\event\page_updated', $event);
 170          $this->assertEquals(25, $event->objectid);
 171          $this->assertEquals('True/false', $event->other['pagetype']);
 172          $this->assertEventContextNotUsed($event);
 173          $this->assertDebuggingNotCalled();
 174      }
 175  
 176      /**
 177       * Test the essay attempt viewed event.
 178       *
 179       * There is no external API for viewing an essay attempt, so the unit test will simply
 180       * create and trigger the event and ensure the legacy log data is returned as expected.
 181       */
 182      public function test_essay_attempt_viewed() {
 183          // Create a essays list viewed event
 184          $event = \mod_lesson\event\essay_attempt_viewed::create(array(
 185              'objectid' => $this->lesson->id,
 186              'relateduserid' => 3,
 187              'context' => \context_module::instance($this->lesson->properties()->cmid),
 188              'courseid' => $this->course->id
 189          ));
 190  
 191          // Trigger and capture the event.
 192          $sink = $this->redirectEvents();
 193          $event->trigger();
 194          $events = $sink->get_events();
 195          $event = reset($events);
 196  
 197          // Check that the event data is valid.
 198          $this->assertInstanceOf('\mod_lesson\event\essay_attempt_viewed', $event);
 199          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 200          $expected = array($this->course->id, 'lesson', 'view grade', 'essay.php?id=' . $this->lesson->properties()->cmid .
 201              '&mode=grade&attemptid='.$this->lesson->id, get_string('manualgrading', 'lesson'), $this->lesson->properties()->cmid);
 202          $this->assertEventLegacyLogData($expected, $event);
 203          $this->assertEventContextNotUsed($event);
 204      }
 205  
 206      /**
 207       * Test the lesson started event.
 208       */
 209      public function test_lesson_started() {
 210          // Trigger and capture the event.
 211          $sink = $this->redirectEvents();
 212          $this->lesson->start_timer();
 213          $events = $sink->get_events();
 214          $event = reset($events);
 215  
 216          // Check that the event data is valid.
 217          $this->assertInstanceOf('\mod_lesson\event\lesson_started', $event);
 218          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 219          $expected = array($this->course->id, 'lesson', 'start', 'view.php?id=' . $this->lesson->properties()->cmid,
 220              $this->lesson->properties()->id, $this->lesson->properties()->cmid);
 221          $this->assertEventLegacyLogData($expected, $event);
 222          $this->assertEventContextNotUsed($event);
 223      }
 224  
 225      /**
 226       * Test the lesson restarted event.
 227       */
 228      public function test_lesson_restarted() {
 229  
 230          // Initialize timer.
 231          $this->lesson->start_timer();
 232          // Trigger and capture the event.
 233          $sink = $this->redirectEvents();
 234          $this->lesson->update_timer(true);
 235          $events = $sink->get_events();
 236          $event = reset($events);
 237  
 238          // Check that the event data is valid.
 239          $this->assertInstanceOf('\mod_lesson\event\lesson_restarted', $event);
 240          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 241          $expected = array($this->course->id, 'lesson', 'start', 'view.php?id=' . $this->lesson->properties()->cmid,
 242              $this->lesson->properties()->id, $this->lesson->properties()->cmid);
 243          $this->assertEventContextNotUsed($event);
 244          $this->assertDebuggingNotCalled();
 245  
 246      }
 247  
 248      /**
 249       * Test the lesson restarted event.
 250       */
 251      public function test_lesson_resumed() {
 252  
 253          // Initialize timer.
 254          $this->lesson->start_timer();
 255          // Trigger and capture the event.
 256          $sink = $this->redirectEvents();
 257          $this->lesson->update_timer(true, true);
 258          $events = $sink->get_events();
 259          $event = reset($events);
 260  
 261          // Check that the event data is valid.
 262          $this->assertInstanceOf('\mod_lesson\event\lesson_resumed', $event);
 263          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 264          $expected = array($this->course->id, 'lesson', 'start', 'view.php?id=' . $this->lesson->properties()->cmid,
 265              $this->lesson->properties()->id, $this->lesson->properties()->cmid);
 266          $this->assertEventContextNotUsed($event);
 267          $this->assertDebuggingNotCalled();
 268  
 269      }
 270      /**
 271       * Test the lesson ended event.
 272       */
 273      public function test_lesson_ended() {
 274          global $DB, $USER;
 275  
 276          // Add a lesson timer so that stop_timer() does not complain.
 277          $lessontimer = new \stdClass();
 278          $lessontimer->lessonid = $this->lesson->properties()->id;
 279          $lessontimer->userid = $USER->id;
 280          $lessontimer->startime = time();
 281          $lessontimer->lessontime = time();
 282          $DB->insert_record('lesson_timer', $lessontimer);
 283  
 284          // Trigger and capture the event.
 285          $sink = $this->redirectEvents();
 286          $this->lesson->stop_timer();
 287          $events = $sink->get_events();
 288          $event = reset($events);
 289  
 290          // Check that the event data is valid.
 291          $this->assertInstanceOf('\mod_lesson\event\lesson_ended', $event);
 292          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 293          $expected = array($this->course->id, 'lesson', 'end', 'view.php?id=' . $this->lesson->properties()->cmid,
 294              $this->lesson->properties()->id, $this->lesson->properties()->cmid);
 295          $this->assertEventLegacyLogData($expected, $event);
 296          $this->assertEventContextNotUsed($event);
 297      }
 298  
 299      /**
 300       * Test the essay assessed event.
 301       *
 302       * There is no external API for assessing an essay, so the unit test will simply
 303       * create and trigger the event and ensure the legacy log data is returned as expected.
 304       */
 305      public function test_essay_assessed() {
 306          // Create an essay assessed event
 307          $gradeid = 5;
 308          $attemptid = 7;
 309          $event = \mod_lesson\event\essay_assessed::create(array(
 310              'objectid' => $gradeid,
 311              'relateduserid' => 3,
 312              'context' => \context_module::instance($this->lesson->properties()->cmid),
 313              'courseid' => $this->course->id,
 314              'other' => array(
 315                  'lessonid' => $this->lesson->id,
 316                  'attemptid' => $attemptid
 317              )
 318          ));
 319  
 320          // Trigger and capture the event.
 321          $sink = $this->redirectEvents();
 322          $event->trigger();
 323          $events = $sink->get_events();
 324          $event = reset($events);
 325  
 326          // Check that the event data is valid.
 327          $this->assertInstanceOf('\mod_lesson\event\essay_assessed', $event);
 328          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 329          $expected = array($this->course->id, 'lesson', 'update grade', 'essay.php?id=' . $this->lesson->properties()->cmid,
 330                  $this->lesson->name, $this->lesson->properties()->cmid);
 331          $this->assertEventLegacyLogData($expected, $event);
 332          $this->assertEventContextNotUsed($event);
 333      }
 334  
 335      /**
 336       * Test the content page viewed event.
 337       *
 338       */
 339      public function test_content_page_viewed() {
 340          global $DB, $PAGE;
 341  
 342          // Set up a generator to create content.
 343          $generator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 344          // Create a content page.
 345          $pagerecord = $generator->create_content($this->lesson);
 346          // Get the lesson page information.
 347          $page = $this->lesson->load_page($pagerecord->id);
 348          // Get the coursemodule record to setup the $PAGE->cm.
 349          $coursemodule = $DB->get_record('course_modules', array('id' => $this->lesson->properties()->cmid));
 350          // Set the $PAGE->cm.
 351          $PAGE->set_cm($coursemodule);
 352          // Get the appropriate renderer.
 353          $lessonoutput = $PAGE->get_renderer('mod_lesson');
 354  
 355          // Trigger and capture the event.
 356          $sink = $this->redirectEvents();
 357          // Fire the function that leads to the triggering of our event.
 358          $lessonoutput->display_page($this->lesson, $page, false);
 359          $events = $sink->get_events();
 360          $event = reset($events);
 361  
 362          // Check that the event data is valid.
 363          $this->assertInstanceOf('\mod_lesson\event\content_page_viewed', $event);
 364          $this->assertEquals($page->id, $event->objectid);
 365          $this->assertEventContextNotUsed($event);
 366          $this->assertDebuggingNotCalled();
 367      }
 368  
 369      /**
 370       * Test the question viewed event.
 371       *
 372       */
 373      public function test_question_viewed() {
 374          global $DB, $PAGE;
 375  
 376          // Set up a generator to create content.
 377          $generator = $this->getDataGenerator()->get_plugin_generator('mod_lesson');
 378          // Create a question page.
 379          $pagerecord = $generator->create_question_truefalse($this->lesson);
 380          // Get the lesson page information.
 381          $page = $this->lesson->load_page($pagerecord->id);
 382          // Get the coursemodule record to setup the $PAGE->cm.
 383          $coursemodule = $DB->get_record('course_modules', array('id' => $this->lesson->properties()->cmid));
 384          // Set the $PAGE->cm.
 385          $PAGE->set_cm($coursemodule);
 386          // Get the appropriate renderer.
 387          $lessonoutput = $PAGE->get_renderer('mod_lesson');
 388  
 389          // Trigger and capture the event.
 390          $sink = $this->redirectEvents();
 391          // Fire the function that leads to the triggering of our event.
 392          $lessonoutput->display_page($this->lesson, $page, false);
 393          $events = $sink->get_events();
 394          $event = reset($events);
 395  
 396          // Check that the event data is valid.
 397          $this->assertInstanceOf('\mod_lesson\event\question_viewed', $event);
 398          $this->assertEquals($page->id, $event->objectid);
 399          $this->assertEquals('True/false', $event->other['pagetype']);
 400          $this->assertEventContextNotUsed($event);
 401          $this->assertDebuggingNotCalled();
 402      }
 403  
 404      /**
 405       * Test the question answered event.
 406       *
 407       * There is no external API for answering an truefalse question, so the unit test will simply
 408       * create and trigger the event and ensure data is returned as expected.
 409       */
 410      public function test_question_answered() {
 411  
 412          // Trigger an event: truefalse question answered.
 413          $eventparams = array(
 414              'context' => \context_module::instance($this->lesson->properties()->cmid),
 415              'objectid' => 25,
 416              'other' => array(
 417                  'pagetype' => 'True/false'
 418                  )
 419          );
 420  
 421          $event = \mod_lesson\event\question_answered::create($eventparams);
 422  
 423          // Trigger and capture the event.
 424          $sink = $this->redirectEvents();
 425          $event->trigger();
 426          $events = $sink->get_events();
 427          $event = reset($events);
 428  
 429          // Check that the event data is valid.
 430          $this->assertInstanceOf('\mod_lesson\event\question_answered', $event);
 431          $this->assertEquals(25, $event->objectid);
 432          $this->assertEquals('True/false', $event->other['pagetype']);
 433          $this->assertEventContextNotUsed($event);
 434          $this->assertDebuggingNotCalled();
 435      }
 436  
 437      /**
 438       * Test the user override created event.
 439       *
 440       * There is no external API for creating a user override, so the unit test will simply
 441       * create and trigger the event and ensure the event data is returned as expected.
 442       */
 443      public function test_user_override_created() {
 444  
 445          $params = array(
 446              'objectid' => 1,
 447              'relateduserid' => 2,
 448              'context' => \context_module::instance($this->lesson->properties()->cmid),
 449              'other' => array(
 450                  'lessonid' => $this->lesson->id
 451              )
 452          );
 453          $event = \mod_lesson\event\user_override_created::create($params);
 454  
 455          // Trigger and capture the event.
 456          $sink = $this->redirectEvents();
 457          $event->trigger();
 458          $events = $sink->get_events();
 459          $event = reset($events);
 460  
 461          // Check that the event data is valid.
 462          $this->assertInstanceOf('\mod_lesson\event\user_override_created', $event);
 463          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 464          $this->assertEventContextNotUsed($event);
 465      }
 466  
 467      /**
 468       * Test the group override created event.
 469       *
 470       * There is no external API for creating a group override, so the unit test will simply
 471       * create and trigger the event and ensure the event data is returned as expected.
 472       */
 473      public function test_group_override_created() {
 474  
 475          $params = array(
 476              'objectid' => 1,
 477              'context' => \context_module::instance($this->lesson->properties()->cmid),
 478              'other' => array(
 479                  'lessonid' => $this->lesson->id,
 480                  'groupid' => 2
 481              )
 482          );
 483          $event = \mod_lesson\event\group_override_created::create($params);
 484  
 485          // Trigger and capture the event.
 486          $sink = $this->redirectEvents();
 487          $event->trigger();
 488          $events = $sink->get_events();
 489          $event = reset($events);
 490  
 491          // Check that the event data is valid.
 492          $this->assertInstanceOf('\mod_lesson\event\group_override_created', $event);
 493          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 494          $this->assertEventContextNotUsed($event);
 495      }
 496  
 497      /**
 498       * Test the user override updated event.
 499       *
 500       * There is no external API for updating a user override, so the unit test will simply
 501       * create and trigger the event and ensure the event data is returned as expected.
 502       */
 503      public function test_user_override_updated() {
 504  
 505          $params = array(
 506              'objectid' => 1,
 507              'relateduserid' => 2,
 508              'context' => \context_module::instance($this->lesson->properties()->cmid),
 509              'other' => array(
 510                  'lessonid' => $this->lesson->id
 511              )
 512          );
 513          $event = \mod_lesson\event\user_override_updated::create($params);
 514  
 515          // Trigger and capture the event.
 516          $sink = $this->redirectEvents();
 517          $event->trigger();
 518          $events = $sink->get_events();
 519          $event = reset($events);
 520  
 521          // Check that the event data is valid.
 522          $this->assertInstanceOf('\mod_lesson\event\user_override_updated', $event);
 523          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 524          $this->assertEventContextNotUsed($event);
 525      }
 526  
 527      /**
 528       * Test the group override updated event.
 529       *
 530       * There is no external API for updating a group override, so the unit test will simply
 531       * create and trigger the event and ensure the event data is returned as expected.
 532       */
 533      public function test_group_override_updated() {
 534  
 535          $params = array(
 536              'objectid' => 1,
 537              'context' => \context_module::instance($this->lesson->properties()->cmid),
 538              'other' => array(
 539                  'lessonid' => $this->lesson->id,
 540                  'groupid' => 2
 541              )
 542          );
 543          $event = \mod_lesson\event\group_override_updated::create($params);
 544  
 545          // Trigger and capture the event.
 546          $sink = $this->redirectEvents();
 547          $event->trigger();
 548          $events = $sink->get_events();
 549          $event = reset($events);
 550  
 551          // Check that the event data is valid.
 552          $this->assertInstanceOf('\mod_lesson\event\group_override_updated', $event);
 553          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 554          $this->assertEventContextNotUsed($event);
 555      }
 556  
 557      /**
 558       * Test the user override deleted event.
 559       */
 560      public function test_user_override_deleted() {
 561          global $DB;
 562  
 563          // Create an override.
 564          $override = new \stdClass();
 565          $override->lesson = $this->lesson->id;
 566          $override->userid = 2;
 567          $override->id = $DB->insert_record('lesson_overrides', $override);
 568  
 569          // Trigger and capture the event.
 570          $sink = $this->redirectEvents();
 571          $this->lesson->delete_override($override->id);
 572          $events = $sink->get_events();
 573          $event = reset($events);
 574  
 575          // Check that the event data is valid.
 576          $this->assertInstanceOf('\mod_lesson\event\user_override_deleted', $event);
 577          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 578          $this->assertEventContextNotUsed($event);
 579      }
 580  
 581      /**
 582       * Test the group override deleted event.
 583       */
 584      public function test_group_override_deleted() {
 585          global $DB;
 586  
 587          // Create an override.
 588          $override = new \stdClass();
 589          $override->lesson = $this->lesson->id;
 590          $override->groupid = 2;
 591          $override->id = $DB->insert_record('lesson_overrides', $override);
 592  
 593          // Trigger and capture the event.
 594          $sink = $this->redirectEvents();
 595          $this->lesson->delete_override($override->id);
 596          $events = $sink->get_events();
 597          $event = reset($events);
 598  
 599          // Check that the event data is valid.
 600          $this->assertInstanceOf('\mod_lesson\event\group_override_deleted', $event);
 601          $this->assertEquals(\context_module::instance($this->lesson->properties()->cmid), $event->get_context());
 602          $this->assertEventContextNotUsed($event);
 603      }
 604  }