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   * Tests for feedback events.
  19   *
  20   * @package    mod_feedback
  21   * @copyright  2013 Ankit Agarwal
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
  23   */
  24  
  25  namespace mod_feedback\event;
  26  
  27  /**
  28   * Class mod_feedback_events_testcase
  29   *
  30   * Class for tests related to feedback events.
  31   *
  32   * @package    mod_feedback
  33   * @copyright  2013 Ankit Agarwal
  34   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
  35   */
  36  class events_test extends \advanced_testcase {
  37  
  38      /** @var  stdClass A user who likes to interact with feedback activity. */
  39      private $eventuser;
  40  
  41      /** @var  stdClass A course used to hold feedback activities for testing. */
  42      private $eventcourse;
  43  
  44      /** @var  stdClass A feedback activity used for feedback event testing. */
  45      private $eventfeedback;
  46  
  47      /** @var  stdClass course module object . */
  48      private $eventcm;
  49  
  50      /** @var  stdClass A feedback item. */
  51      private $eventfeedbackitem;
  52  
  53      /** @var  stdClass A feedback activity response submitted by user. */
  54      private $eventfeedbackcompleted;
  55  
  56      /** @var  stdClass value associated with $eventfeedbackitem . */
  57      private $eventfeedbackvalue;
  58  
  59      public function setUp(): void {
  60          global $DB;
  61  
  62          $this->setAdminUser();
  63          $gen = $this->getDataGenerator();
  64          $this->eventuser = $gen->create_user(); // Create a user.
  65          $course = $gen->create_course(); // Create a course.
  66          // Assign manager role, so user can see reports.
  67          role_assign(1, $this->eventuser->id, \context_course::instance($course->id));
  68  
  69          // Add a feedback activity to the created course.
  70          $record = new \stdClass();
  71          $record->course = $course->id;
  72          $feedback = $gen->create_module('feedback', $record);
  73          $this->eventfeedback = $DB->get_record('feedback', array('id' => $feedback->id), '*', MUST_EXIST); // Get exact copy.
  74          $this->eventcm = get_coursemodule_from_instance('feedback', $this->eventfeedback->id, false, MUST_EXIST);
  75  
  76          // Create a feedback item.
  77          $item = new \stdClass();
  78          $item->feedback = $this->eventfeedback->id;
  79          $item->type = 'numeric';
  80          $item->presentation = '0|0';
  81          $itemid = $DB->insert_record('feedback_item', $item);
  82          $this->eventfeedbackitem = $DB->get_record('feedback_item', array('id' => $itemid), '*', MUST_EXIST);
  83  
  84          // Create a response from a user.
  85          $response = new \stdClass();
  86          $response->feedback = $this->eventfeedback->id;
  87          $response->userid = $this->eventuser->id;
  88          $response->anonymous_response = FEEDBACK_ANONYMOUS_YES;
  89          $completedid = $DB->insert_record('feedback_completed', $response);
  90          $this->eventfeedbackcompleted = $DB->get_record('feedback_completed', array('id' => $completedid), '*', MUST_EXIST);
  91  
  92          $value = new \stdClass();
  93          $value->course_id = $course->id;
  94          $value->item = $this->eventfeedbackitem->id;
  95          $value->completed = $this->eventfeedbackcompleted->id;
  96          $value->value = 25; // User response value.
  97          $valueid = $DB->insert_record('feedback_value', $value);
  98          $this->eventfeedbackvalue = $DB->get_record('feedback_value', array('id' => $valueid), '*', MUST_EXIST);
  99          // Do this in the end to get correct sortorder and cacherev values.
 100          $this->eventcourse = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST);
 101  
 102      }
 103  
 104      /**
 105       * Tests for event response_deleted.
 106       */
 107      public function test_response_deleted_event() {
 108          global $USER, $DB;
 109          $this->resetAfterTest();
 110  
 111          // Create and delete a module.
 112          $sink = $this->redirectEvents();
 113          feedback_delete_completed($this->eventfeedbackcompleted->id);
 114          $events = $sink->get_events();
 115          $event = array_pop($events); // Delete feedback event.
 116          $sink->close();
 117  
 118          // Validate event data.
 119          $this->assertInstanceOf('\mod_feedback\event\response_deleted', $event);
 120          $this->assertEquals($this->eventfeedbackcompleted->id, $event->objectid);
 121          $this->assertEquals($USER->id, $event->userid);
 122          $this->assertEquals($this->eventuser->id, $event->relateduserid);
 123          $this->assertEquals('feedback_completed', $event->objecttable);
 124          $this->assertEquals(null, $event->get_url());
 125          $this->assertEquals($this->eventfeedbackcompleted, $event->get_record_snapshot('feedback_completed', $event->objectid));
 126          $this->assertEquals($this->eventcourse, $event->get_record_snapshot('course', $event->courseid));
 127          $this->assertEquals($this->eventfeedback, $event->get_record_snapshot('feedback', $event->other['instanceid']));
 128  
 129          // Test legacy data.
 130          $arr = array($this->eventcourse->id, 'feedback', 'delete', 'view.php?id=' . $this->eventcm->id, $this->eventfeedback->id,
 131                  $this->eventfeedback->id);
 132          $this->assertEventLegacyLogData($arr, $event);
 133          $this->assertEventContextNotUsed($event);
 134  
 135          // Test can_view() .
 136          $this->setUser($this->eventuser);
 137          $this->assertFalse($event->can_view());
 138          $this->assertDebuggingCalled();
 139          $this->setAdminUser();
 140          $this->assertTrue($event->can_view());
 141          $this->assertDebuggingCalled();
 142  
 143          // Create a response, with anonymous set to no and test can_view().
 144          $response = new \stdClass();
 145          $response->feedback = $this->eventcm->instance;
 146          $response->userid = $this->eventuser->id;
 147          $response->anonymous_response = FEEDBACK_ANONYMOUS_NO;
 148          $completedid = $DB->insert_record('feedback_completed', $response);
 149          $DB->get_record('feedback_completed', array('id' => $completedid), '*', MUST_EXIST);
 150          $value = new \stdClass();
 151          $value->course_id = $this->eventcourse->id;
 152          $value->item = $this->eventfeedbackitem->id;
 153          $value->completed = $completedid;
 154          $value->value = 25; // User response value.
 155          $DB->insert_record('feedback_valuetmp', $value);
 156  
 157          // Save the feedback.
 158          $sink = $this->redirectEvents();
 159          feedback_delete_completed($completedid);
 160          $events = $sink->get_events();
 161          $event = array_pop($events); // Response submitted feedback event.
 162          $sink->close();
 163  
 164          // Test can_view() .
 165          $this->setUser($this->eventuser);
 166          $this->assertTrue($event->can_view());
 167          $this->assertDebuggingCalled();
 168          $this->setAdminUser();
 169          $this->assertTrue($event->can_view());
 170          $this->assertDebuggingCalled();
 171          $this->assertEventContextNotUsed($event);
 172      }
 173  
 174      /**
 175       * Tests for event validations related to feedback response deletion.
 176       */
 177      public function test_response_deleted_event_exceptions() {
 178  
 179          $this->resetAfterTest();
 180  
 181          $context = \context_module::instance($this->eventcm->id);
 182  
 183          // Test not setting other['anonymous'].
 184          try {
 185              \mod_feedback\event\response_submitted::create(array(
 186                  'context'  => $context,
 187                  'objectid' => $this->eventfeedbackcompleted->id,
 188                  'relateduserid' => 2,
 189              ));
 190              $this->fail("Event validation should not allow \\mod_feedback\\event\\response_deleted to be triggered without
 191                      other['anonymous']");
 192          } catch (\coding_exception $e) {
 193              $this->assertStringContainsString("The 'anonymous' value must be set in other.", $e->getMessage());
 194          }
 195      }
 196  
 197      /**
 198       * Tests for event response_submitted.
 199       */
 200      public function test_response_submitted_event() {
 201          global $USER, $DB;
 202          $this->resetAfterTest();
 203          $this->setUser($this->eventuser);
 204  
 205          // Create a temporary response, with anonymous set to yes.
 206          $response = new \stdClass();
 207          $response->feedback = $this->eventcm->instance;
 208          $response->userid = $this->eventuser->id;
 209          $response->anonymous_response = FEEDBACK_ANONYMOUS_YES;
 210          $completedid = $DB->insert_record('feedback_completedtmp', $response);
 211          $completed = $DB->get_record('feedback_completedtmp', array('id' => $completedid), '*', MUST_EXIST);
 212          $value = new \stdClass();
 213          $value->course_id = $this->eventcourse->id;
 214          $value->item = $this->eventfeedbackitem->id;
 215          $value->completed = $completedid;
 216          $value->value = 25; // User response value.
 217          $DB->insert_record('feedback_valuetmp', $value);
 218  
 219          // Save the feedback.
 220          $sink = $this->redirectEvents();
 221          $id = feedback_save_tmp_values($completed, false);
 222          $events = $sink->get_events();
 223          $event = array_pop($events); // Response submitted feedback event.
 224          $sink->close();
 225  
 226          // Validate event data. Feedback is anonymous.
 227          $this->assertInstanceOf('\mod_feedback\event\response_submitted', $event);
 228          $this->assertEquals($id, $event->objectid);
 229          $this->assertEquals($USER->id, $event->userid);
 230          $this->assertEquals($USER->id, $event->relateduserid);
 231          $this->assertEquals('feedback_completed', $event->objecttable);
 232          $this->assertEquals(1, $event->anonymous);
 233          $this->assertEquals(FEEDBACK_ANONYMOUS_YES, $event->other['anonymous']);
 234          $this->setUser($this->eventuser);
 235          $this->assertFalse($event->can_view());
 236          $this->assertDebuggingCalled();
 237          $this->setAdminUser();
 238          $this->assertTrue($event->can_view());
 239          $this->assertDebuggingCalled();
 240  
 241          // Test legacy data.
 242          $this->assertEventLegacyLogData(null, $event);
 243  
 244          // Create a temporary response, with anonymous set to no.
 245          $response = new \stdClass();
 246          $response->feedback = $this->eventcm->instance;
 247          $response->userid = $this->eventuser->id;
 248          $response->anonymous_response = FEEDBACK_ANONYMOUS_NO;
 249          $completedid = $DB->insert_record('feedback_completedtmp', $response);
 250          $completed = $DB->get_record('feedback_completedtmp', array('id' => $completedid), '*', MUST_EXIST);
 251          $value = new \stdClass();
 252          $value->course_id = $this->eventcourse->id;
 253          $value->item = $this->eventfeedbackitem->id;
 254          $value->completed = $completedid;
 255          $value->value = 25; // User response value.
 256          $DB->insert_record('feedback_valuetmp', $value);
 257  
 258          // Save the feedback.
 259          $sink = $this->redirectEvents();
 260          feedback_save_tmp_values($completed, false);
 261          $events = $sink->get_events();
 262          $event = array_pop($events); // Response submitted feedback event.
 263          $sink->close();
 264  
 265          // Test legacy data.
 266          $arr = array($this->eventcourse->id, 'feedback', 'submit', 'view.php?id=' . $this->eventcm->id, $this->eventfeedback->id,
 267                       $this->eventcm->id, $this->eventuser->id);
 268          $this->assertEventLegacyLogData($arr, $event);
 269  
 270          // Test can_view().
 271          $this->assertTrue($event->can_view());
 272          $this->assertDebuggingCalled();
 273          $this->setAdminUser();
 274          $this->assertTrue($event->can_view());
 275          $this->assertDebuggingCalled();
 276          $this->assertEventContextNotUsed($event);
 277      }
 278  
 279      /**
 280       * Tests for event validations related to feedback response submission.
 281       */
 282      public function test_response_submitted_event_exceptions() {
 283  
 284          $this->resetAfterTest();
 285  
 286          $context = \context_module::instance($this->eventcm->id);
 287  
 288          // Test not setting instanceid.
 289          try {
 290              \mod_feedback\event\response_submitted::create(array(
 291                  'context'  => $context,
 292                  'objectid' => $this->eventfeedbackcompleted->id,
 293                  'relateduserid' => 2,
 294                  'anonymous' => 0,
 295                  'other'    => array('cmid' => $this->eventcm->id, 'anonymous' => 2)
 296              ));
 297              $this->fail("Event validation should not allow \\mod_feedback\\event\\response_deleted to be triggered without
 298                      other['instanceid']");
 299          } catch (\coding_exception $e) {
 300              $this->assertStringContainsString("The 'instanceid' value must be set in other.", $e->getMessage());
 301          }
 302  
 303          // Test not setting cmid.
 304          try {
 305              \mod_feedback\event\response_submitted::create(array(
 306                  'context'  => $context,
 307                  'objectid' => $this->eventfeedbackcompleted->id,
 308                  'relateduserid' => 2,
 309                  'anonymous' => 0,
 310                  'other'    => array('instanceid' => $this->eventfeedback->id, 'anonymous' => 2)
 311              ));
 312              $this->fail("Event validation should not allow \\mod_feedback\\event\\response_deleted to be triggered without
 313                      other['cmid']");
 314          } catch (\coding_exception $e) {
 315              $this->assertStringContainsString("The 'cmid' value must be set in other.", $e->getMessage());
 316          }
 317  
 318          // Test not setting anonymous.
 319          try {
 320              \mod_feedback\event\response_submitted::create(array(
 321                   'context'  => $context,
 322                   'objectid' => $this->eventfeedbackcompleted->id,
 323                   'relateduserid' => 2,
 324                   'other'    => array('cmid' => $this->eventcm->id, 'instanceid' => $this->eventfeedback->id)
 325              ));
 326              $this->fail("Event validation should not allow \\mod_feedback\\event\\response_deleted to be triggered without
 327                      other['anonymous']");
 328          } catch (\coding_exception $e) {
 329              $this->assertStringContainsString("The 'anonymous' value must be set in other.", $e->getMessage());
 330          }
 331      }
 332  
 333      /**
 334       * Test that event observer is executed on course deletion and the templates are removed.
 335       */
 336      public function test_delete_course() {
 337          global $DB;
 338          $this->resetAfterTest();
 339          feedback_save_as_template($this->eventfeedback, 'my template', 0);
 340          $courseid = $this->eventcourse->id;
 341          $this->assertNotEmpty($DB->get_records('feedback_template', array('course' => $courseid)));
 342          delete_course($this->eventcourse, false);
 343          $this->assertEmpty($DB->get_records('feedback_template', array('course' => $courseid)));
 344      }
 345  }