Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310]

   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 the migrate message data task.
  19   *
  20   * @package core_message
  21   * @category test
  22   * @copyright 2018 Mark Nelson <markn@moodle.com>
  23   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  global $CFG;
  29  
  30  require_once($CFG->dirroot . '/message/tests/messagelib_test.php');
  31  
  32  /**
  33   * Class for testing the migrate message data task.
  34   *
  35   * @package core_message
  36   * @category test
  37   * @copyright 2018 Mark Nelson <markn@moodle.com>
  38   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   */
  40  class core_message_migrate_message_data_task_testcase extends advanced_testcase {
  41  
  42      /**
  43       * Test set up.
  44       *
  45       * This is executed before running any test in this file.
  46       */
  47      public function setUp(): void {
  48          $this->resetAfterTest();
  49      }
  50  
  51      /**
  52       * Test migrating legacy messages.
  53       */
  54      public function test_migrating_messages() {
  55          global $DB;
  56  
  57          // Create users to test with.
  58          $user1 = $this->getDataGenerator()->create_user();
  59          $user2 = $this->getDataGenerator()->create_user();
  60          $user3 = $this->getDataGenerator()->create_user();
  61  
  62          // Get the current time minus some, to make sure our data is migrated accurately and just not using the current timestamp.
  63          $now = time();
  64          $timedeleted1 = $now - (2 * DAYSECS);
  65          $timedeleted2 = $now - (2 * DAYSECS) + 1;
  66          $timeread1 = $now - DAYSECS;
  67          $timeread2 = $now - DAYSECS + 1;
  68          $timeread3 = $now - DAYSECS + 2;
  69  
  70          // Send messages from user 1 to user 2.
  71          $m1 = $this->create_legacy_message_or_notification($user1->id, $user2->id, 1, false, $timeread1);
  72          $m2 = $this->create_legacy_message_or_notification($user1->id, $user2->id, 2);
  73          $m3 = $this->create_legacy_message_or_notification($user1->id, $user2->id, 3);
  74  
  75          // Send messages from user 3 to user 1.
  76          $m4 = $this->create_legacy_message_or_notification($user3->id, $user1->id, 4, false, $timeread2);
  77          $m5 = $this->create_legacy_message_or_notification($user3->id, $user1->id, 5);
  78          $m6 = $this->create_legacy_message_or_notification($user3->id, $user1->id, 6);
  79  
  80          // Send messages from user 3 to user 2.
  81          $m7 = $this->create_legacy_message_or_notification($user3->id, $user2->id, 7, false, $timeread3);
  82          $m8 = $this->create_legacy_message_or_notification($user3->id, $user2->id, 8);
  83          $m9 = $this->create_legacy_message_or_notification($user3->id, $user2->id, 9);
  84  
  85          // Let's delete some messages, not using API here as it does not use the legacy tables.
  86          $messageupdate = new stdClass();
  87          $messageupdate->id = $m1;
  88          $messageupdate->timeusertodeleted = $timedeleted1;
  89          $DB->update_record('message_read', $messageupdate);
  90  
  91          $messageupdate = new stdClass();
  92          $messageupdate->id = $m5;
  93          $messageupdate->timeuserfromdeleted = $timedeleted2;
  94          $DB->update_record('message', $messageupdate);
  95  
  96          // Now, let's execute the task for user 1.
  97          $task = new \core_message\task\migrate_message_data();
  98          $task->set_custom_data(
  99              [
 100                  'userid' => $user1->id
 101              ]
 102          );
 103          $task->execute();
 104  
 105          // Ok, now we need to confirm all is good.
 106          // Remember - we are only converting the messages related to user 1.
 107          $this->assertEquals(2, $DB->count_records('message'));
 108          $this->assertEquals(1, $DB->count_records('message_read'));
 109          $this->assertEquals(6, $DB->count_records('messages'));
 110          $this->assertEquals(0, $DB->count_records('notifications'));
 111          $this->assertEquals(0, $DB->count_records('message_popup_notifications'));
 112  
 113          // Get the conversations.
 114          $conversation1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
 115          $conversation2 = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
 116  
 117          // Confirm what we have in the messages table is correct.
 118          $messages = $DB->get_records('messages', [], 'timecreated ASC');
 119          $i = 1;
 120          foreach ($messages as $message) {
 121              $useridfrom = $user1->id;
 122              $conversationid = $conversation1;
 123              if ($i > 3) {
 124                  $useridfrom = $user3->id;
 125                  $conversationid = $conversation2;
 126              }
 127  
 128              if ($i == 1) {
 129                  $messagereadid1 = $message->id;
 130                  $messagedeletedid1 = $message->id;
 131              } else if ($i == 4) {
 132                  $messagereadid2 = $message->id;
 133              } else if ($i == 5) {
 134                  $messagedeletedid2 = $message->id;
 135              }
 136  
 137              $this->assertEquals($useridfrom, $message->useridfrom);
 138              $this->assertEquals($conversationid, $message->conversationid);
 139              $this->assertEquals('Subject ' . $i, $message->subject);
 140              $this->assertEquals('Full message ' . $i, $message->fullmessage);
 141              $this->assertEquals(FORMAT_PLAIN, $message->fullmessageformat);
 142              $this->assertEquals('Full message HTML '. $i, $message->fullmessagehtml);
 143              $this->assertEquals('Small message ' . $i, $message->smallmessage);
 144              $this->assertEquals($i, $message->timecreated);
 145              $i++;
 146          }
 147  
 148          // Confirm there are 4 actions.
 149          $this->assertEquals(4, $DB->count_records('message_user_actions'));
 150  
 151          // Confirm the messages that were marked as read have actions associated with them.
 152          $muas = $DB->get_records('message_user_actions', ['action' => \core_message\api::MESSAGE_ACTION_READ], 'timecreated DESC');
 153          $this->assertCount(2, $muas);
 154  
 155          // Message user action for message read by user 1 (referring to $m4).
 156          $mua1 = array_shift($muas);
 157          // Message user action for message read by user 2 (referring to $m1).
 158          $mua2 = array_shift($muas);
 159  
 160          $this->assertEquals($user1->id, $mua1->userid);
 161          $this->assertEquals($messagereadid2, $mua1->messageid);
 162          $this->assertEquals($timeread2, $mua1->timecreated);
 163  
 164          $this->assertEquals($user2->id, $mua2->userid);
 165          $this->assertEquals($messagereadid1, $mua2->messageid);
 166          $this->assertEquals($timeread1, $mua2->timecreated);
 167  
 168          // Confirm the messages that were deleted have actions associated with them.
 169          $muas = $DB->get_records('message_user_actions', ['action' => \core_message\api::MESSAGE_ACTION_DELETED],
 170              'timecreated DESC');
 171          $this->assertCount(2, $muas);
 172  
 173          // Message user action for message deleted by user 3 (referring to $m5).
 174          $mua1 = array_shift($muas);
 175          // Message user action for message deleted by user 2 (referring to $m1).
 176          $mua2 = array_shift($muas);
 177  
 178          $this->assertEquals($user3->id, $mua1->userid);
 179          $this->assertEquals($messagedeletedid2, $mua1->messageid);
 180          $this->assertEquals($timedeleted2, $mua1->timecreated);
 181  
 182          $this->assertEquals($user2->id, $mua2->userid);
 183          $this->assertEquals($messagedeletedid1, $mua2->messageid);
 184          $this->assertEquals($timedeleted1, $mua2->timecreated);
 185      }
 186  
 187      /**
 188       * Test migrating legacy notifications.
 189       */
 190      public function test_migrating_notifications() {
 191          global $DB;
 192  
 193          // Create users to test with.
 194          $user1 = $this->getDataGenerator()->create_user();
 195          $user2 = $this->getDataGenerator()->create_user();
 196          $user3 = $this->getDataGenerator()->create_user();
 197  
 198          // Get the current time minus some, to make sure our data is migrated accurately and just not using the current timestamp.
 199          $timeread = time() - DAYSECS;
 200  
 201          // Send notifications from user 1 to user 2.
 202          $this->create_legacy_message_or_notification($user1->id, $user2->id, 1, true, $timeread);
 203          $this->create_legacy_message_or_notification($user1->id, $user2->id, 2, true);
 204          $this->create_legacy_message_or_notification($user1->id, $user2->id, 3, true);
 205  
 206          // Send notifications from user 3 to user 1.
 207          $this->create_legacy_message_or_notification($user3->id, $user1->id, 4, true, $timeread);
 208          $this->create_legacy_message_or_notification($user3->id, $user1->id, 5, true);
 209          $this->create_legacy_message_or_notification($user3->id, $user1->id, 6, true);
 210  
 211          // Send notifications from user 3 to user 2.
 212          $this->create_legacy_message_or_notification($user3->id, $user2->id, 7, true, $timeread);
 213          $this->create_legacy_message_or_notification($user3->id, $user2->id, 8, true);
 214          $this->create_legacy_message_or_notification($user3->id, $user2->id, 9, true);
 215  
 216          // Now, let's execute the task for user 1.
 217          $task = new \core_message\task\migrate_message_data();
 218          $task->set_custom_data(
 219              [
 220                  'userid' => $user1->id
 221              ]
 222          );
 223          $task->execute();
 224  
 225          // Ok, now we need to confirm all is good.
 226          // Remember - we are only converting the notifications related to user 1.
 227          $this->assertEquals(2, $DB->count_records('message'));
 228          $this->assertEquals(1, $DB->count_records('message_read'));
 229          $this->assertEquals(3, $DB->count_records('message_popup'));
 230          $this->assertEquals(6, $DB->count_records('notifications'));
 231          $this->assertEquals(6, $DB->count_records('message_popup_notifications'));
 232  
 233          // Confirm what we have in the notifications table is correct.
 234          $notifications = $DB->get_records('notifications', [], 'timecreated ASC');
 235          $popupnotifications = $DB->get_records('message_popup_notifications', [], 'notificationid ASC', 'notificationid');
 236          $i = 1;
 237          foreach ($notifications as $notification) {
 238              // Assert the correct id is stored in the 'message_popup_notifications' table.
 239              $this->assertArrayHasKey($notification->id, $popupnotifications);
 240  
 241              $useridfrom = $user1->id;
 242              $useridto = $user2->id;
 243              if ($i > 3) {
 244                  $useridfrom = $user3->id;
 245                  $useridto = $user1->id;
 246              }
 247  
 248              $this->assertEquals($useridfrom, $notification->useridfrom);
 249              $this->assertEquals($useridto, $notification->useridto);
 250              $this->assertEquals('Subject ' . $i, $notification->subject);
 251              $this->assertEquals('Full message ' . $i, $notification->fullmessage);
 252              $this->assertEquals(FORMAT_PLAIN, $notification->fullmessageformat);
 253              $this->assertEquals('Full message HTML '. $i, $notification->fullmessagehtml);
 254              $this->assertEquals('Small message ' . $i, $notification->smallmessage);
 255              $this->assertEquals('mod_assign', $notification->component);
 256              $this->assertEquals('assign_notification', $notification->eventtype);
 257              $this->assertEquals('https://www.google.com', $notification->contexturl);
 258              $this->assertEquals('google', $notification->contexturlname);
 259              $this->assertEquals($i, $notification->timecreated);
 260  
 261              if (($i == 1) || ($i == 4)) {
 262                  $this->assertEquals($timeread, $notification->timeread);
 263              } else {
 264                  $this->assertNull($notification->timeread);
 265              }
 266  
 267              $i++;
 268          }
 269      }
 270  
 271      /**
 272       * Test migrating a legacy message that contains null as the format.
 273       */
 274      public function test_migrating_message_null_format() {
 275          global $DB;
 276  
 277          // Create users to test with.
 278          $user1 = $this->getDataGenerator()->create_user();
 279          $user2 = $this->getDataGenerator()->create_user();
 280  
 281          $this->create_legacy_message_or_notification($user1->id, $user2->id, null, false, null, null);
 282  
 283          // Now, let's execute the task for user 1.
 284          $task = new \core_message\task\migrate_message_data();
 285          $task->set_custom_data(
 286              [
 287                  'userid' => $user1->id
 288              ]
 289          );
 290          $task->execute();
 291  
 292          $messages = $DB->get_records('messages');
 293          $this->assertCount(1, $messages);
 294  
 295          $message = reset($messages);
 296          $this->assertEquals(FORMAT_MOODLE, $message->fullmessageformat);
 297      }
 298  
 299      /**
 300       * Test migrating a legacy notification that contains null as the format.
 301       */
 302      public function test_migrating_notification_null_format() {
 303          global $DB;
 304  
 305          // Create users to test with.
 306          $user1 = $this->getDataGenerator()->create_user();
 307          $user2 = $this->getDataGenerator()->create_user();
 308  
 309          $this->create_legacy_message_or_notification($user1->id, $user2->id, null, true, null, null);
 310  
 311          // Now, let's execute the task for user 1.
 312          $task = new \core_message\task\migrate_message_data();
 313          $task->set_custom_data(
 314              [
 315                  'userid' => $user1->id
 316              ]
 317          );
 318          $task->execute();
 319  
 320          $notifications = $DB->get_records('notifications');
 321          $this->assertCount(1, $notifications);
 322  
 323          $notification = reset($notifications);
 324          $this->assertEquals(FORMAT_MOODLE, $notification->fullmessageformat);
 325      }
 326  
 327      /**
 328       * Test migrating a legacy message that a user sent to themselves then deleted.
 329       */
 330      public function test_migrating_message_deleted_message_sent_to_self() {
 331          global $DB;
 332  
 333          // Create user to test with.
 334          $user1 = $this->getDataGenerator()->create_user();
 335  
 336          $m1 = $this->create_legacy_message_or_notification($user1->id, $user1->id, null, false, null, null);
 337  
 338          // Let's delete the message for the 'user to' and 'user from' which in this case is the same user.
 339          $messageupdate = new stdClass();
 340          $messageupdate->id = $m1;
 341          $messageupdate->timeuserfromdeleted = time();
 342          $messageupdate->timeusertodeleted = time();
 343          $DB->update_record('message', $messageupdate);
 344  
 345          // Now, let's execute the task for the user.
 346          $task = new \core_message\task\migrate_message_data();
 347          $task->set_custom_data(
 348              [
 349                  'userid' => $user1->id
 350              ]
 351          );
 352          $task->execute();
 353  
 354          $this->assertEquals(0, $DB->count_records('message'));
 355          $this->assertEquals(1, $DB->count_records('message_user_actions'));
 356      }
 357  
 358      /**
 359       * Creates a legacy message or notification to be used for testing.
 360       *
 361       * @param int $useridfrom The user id from
 362       * @param int $useridto The user id to
 363       * @param int $timecreated
 364       * @param bool $notification
 365       * @param int|null $timeread The time the message/notification was read, null if it hasn't been.
 366       * @param string|int|null $format The format of the message.
 367       * @return int The id of the message (in either the message or message_read table)
 368       * @throws dml_exception
 369       */
 370      private function create_legacy_message_or_notification($useridfrom, $useridto, $timecreated = null,
 371              $notification = false, $timeread = null, $format = FORMAT_PLAIN) {
 372          global $DB;
 373  
 374          $tabledata = new \stdClass();
 375  
 376          if (is_null($timecreated)) {
 377              $timecreated = time();
 378          }
 379  
 380          if (!is_null($timeread)) {
 381              $table = 'message_read';
 382              $tabledata->timeread = $timeread;
 383          } else {
 384              $table = 'message';
 385          }
 386  
 387          if ($notification) {
 388              $tabledata->eventtype = 'assign_notification';
 389              $tabledata->component = 'mod_assign';
 390              $tabledata->notification = 1;
 391              $tabledata->contexturl = 'https://www.google.com';
 392              $tabledata->contexturlname = 'google';
 393          } else {
 394              $tabledata->eventtype = 'instantmessage';
 395              $tabledata->component = 'moodle';
 396              $tabledata->notification = 0;
 397          }
 398  
 399          $tabledata->useridfrom = $useridfrom;
 400          $tabledata->useridto = $useridto;
 401          $tabledata->subject = 'Subject ' . $timecreated;
 402          $tabledata->fullmessage = 'Full message ' . $timecreated;
 403          $tabledata->fullmessageformat = $format;
 404          $tabledata->fullmessagehtml = 'Full message HTML ' . $timecreated;
 405          $tabledata->smallmessage = 'Small message ' . $timecreated;
 406          $tabledata->timecreated = $timecreated;
 407  
 408          $id = $DB->insert_record($table, $tabledata);
 409  
 410          // Insert into the legacy 'message_popup' table if it is a notification.
 411          if ($notification) {
 412              $mp = new stdClass();
 413              $mp->messageid = $id;
 414              $mp->isread = (!is_null($timeread)) ? 1 : 0;
 415  
 416              $DB->insert_record('message_popup', $mp);
 417          }
 418  
 419          return $id;
 420      }
 421  }