MDL-63097 phpunit: decouple user lastping and session start in tests
[moodle.git] / mod / chat / tests / lib_test.php
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/>.
17 /**
18  * Contains class containing unit tests for mod/chat/lib.php.
19  *
20  * @package mod_chat
21  * @category test
22  * @copyright 2017 Mark Nelson <markn@moodle.com>
23  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 /**
29  * Class containing unit tests for mod/chat/lib.php.
30  *
31  * @package mod_chat
32  * @category test
33  * @copyright 2017 Mark Nelson <markn@moodle.com>
34  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35  */
36 class mod_chat_lib_testcase extends advanced_testcase {
38     public function setUp() {
39         $this->resetAfterTest();
40     }
42     public function test_chat_core_calendar_provide_event_action_chattime_event_yesterday() {
43         $this->setAdminUser();
45         // Create a course.
46         $course = $this->getDataGenerator()->create_course();
48         // Create a chat.
49         $chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
50             'chattime' => time() - DAYSECS));
52         // Create a calendar event.
53         $event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
55         // Create an action factory.
56         $factory = new \core_calendar\action_factory();
58         // Decorate action event.
59         $actionevent = mod_chat_core_calendar_provide_event_action($event, $factory);
61         // Confirm the event is not shown at all.
62         $this->assertNull($actionevent);
63     }
65     public function test_chat_core_calendar_provide_event_action_chattime_event_today() {
66         $this->setAdminUser();
68         // Create a course.
69         $course = $this->getDataGenerator()->create_course();
71         // Create a chat.
72         $chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
73             'chattime' => usergetmidnight(time())));
75         // Create a calendar event.
76         $event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
78         // Create an action factory.
79         $factory = new \core_calendar\action_factory();
81         // Decorate action event.
82         $actionevent = mod_chat_core_calendar_provide_event_action($event, $factory);
84         // Confirm the event was decorated.
85         $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
86         $this->assertEquals(get_string('enterchat', 'chat'), $actionevent->get_name());
87         $this->assertInstanceOf('moodle_url', $actionevent->get_url());
88         $this->assertEquals(1, $actionevent->get_item_count());
89         $this->assertTrue($actionevent->is_actionable());
90     }
92     public function test_chat_core_calendar_provide_event_action_chattime_event_tonight() {
93         $this->setAdminUser();
95         // Create a course.
96         $course = $this->getDataGenerator()->create_course();
98         // Create a chat.
99         $chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
100             'chattime' => usergetmidnight(time()) + (23 * HOURSECS)));
102         // Create a calendar event.
103         $event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
105         // Create an action factory.
106         $factory = new \core_calendar\action_factory();
108         // Decorate action event.
109         $actionevent = mod_chat_core_calendar_provide_event_action($event, $factory);
111         // Confirm the event was decorated.
112         $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
113         $this->assertEquals(get_string('enterchat', 'chat'), $actionevent->get_name());
114         $this->assertInstanceOf('moodle_url', $actionevent->get_url());
115         $this->assertEquals(1, $actionevent->get_item_count());
116         $this->assertTrue($actionevent->is_actionable());
117     }
119     public function test_chat_core_calendar_provide_event_action_chattime_event_tomorrow() {
120         $this->setAdminUser();
122         // Create a course.
123         $course = $this->getDataGenerator()->create_course();
125         // Create a chat.
126         $chat = $this->getDataGenerator()->create_module('chat', array('course' => $course->id,
127             'chattime' => time() + DAYSECS));
129         // Create a calendar event.
130         $event = $this->create_action_event($course->id, $chat->id, CHAT_EVENT_TYPE_CHATTIME);
132         // Create an action factory.
133         $factory = new \core_calendar\action_factory();
135         // Decorate action event.
136         $actionevent = mod_chat_core_calendar_provide_event_action($event, $factory);
138         // Confirm the event was decorated.
139         $this->assertInstanceOf('\core_calendar\local\event\value_objects\action', $actionevent);
140         $this->assertEquals(get_string('enterchat', 'chat'), $actionevent->get_name());
141         $this->assertInstanceOf('moodle_url', $actionevent->get_url());
142         $this->assertEquals(1, $actionevent->get_item_count());
143         $this->assertFalse($actionevent->is_actionable());
144     }
146     /**
147      * Test for chat_get_sessions().
148      */
149     public function test_chat_get_sessions() {
150         global $DB;
152         $this->resetAfterTest();
154         $generator = $this->getDataGenerator();
156         // Setup test data.
157         $this->setAdminUser();
158         $course = $generator->create_course();
159         $chat = $generator->create_module('chat', ['course' => $course->id]);
161         $user1 = $generator->create_user();
162         $user2 = $generator->create_user();
163         $studentrole = $DB->get_record('role', ['shortname' => 'student']);
164         $generator->enrol_user($user1->id, $course->id, $studentrole->id);
165         $generator->enrol_user($user2->id, $course->id, $studentrole->id);
167         // Login as user 1.
168         $this->setUser($user1);
169         $chatsid = chat_login_user($chat->id, 'ajax', 0, $course);
170         $chatuser = $DB->get_record('chat_users', ['sid' => $chatsid]);
172         // Get the messages for this chat session.
173         $messages = chat_get_session_messages($chat->id, false, 0, 0, 'timestamp DESC');
175         // We should have just 1 system (enter) messages.
176         $this->assertCount(1, $messages);
178         // This is when the session starts (when the first message - enter - has been sent).
179         $sessionstart = reset($messages)->timestamp;
181         // Send some messages.
182         chat_send_chatmessage($chatuser, 'hello!');
183         chat_send_chatmessage($chatuser, 'bye bye!');
185         // Login as user 2.
186         $this->setUser($user2);
187         $chatsid = chat_login_user($chat->id, 'ajax', 0, $course);
188         $chatuser = $DB->get_record('chat_users', ['sid' => $chatsid]);
190         // Send a message and take note of this message ID.
191         $messageid = chat_send_chatmessage($chatuser, 'greetings!');
193         // This is when the session ends (timestamp of the last message sent to the chat).
194         $sessionend = $DB->get_field('chat_messages', 'timestamp', ['id' => $messageid]);
196         // Get the messages for this chat session.
197         $messages = chat_get_session_messages($chat->id, false, 0, 0, 'timestamp DESC');
199         // We should have 3 user and 2 system (enter) messages.
200         $this->assertCount(5, $messages);
202         // Fetch the chat sessions from the messages we retrieved.
203         $sessions = chat_get_sessions($messages, true);
205         // There should be only one session.
206         $this->assertCount(1, $sessions);
208         // Get this session.
209         $session = reset($sessions);
211         // Confirm that the start and end times of the session matches.
212         $this->assertEquals($sessionstart, $session->sessionstart);
213         $this->assertEquals($sessionend, $session->sessionend);
214         // Confirm we have 2 participants in the chat.
215         $this->assertCount(2, $session->sessionusers);
216     }
218     /**
219      * Test for chat_get_sessions with messages belonging to multiple sessions.
220      */
221     public function test_chat_get_sessions_multiple() {
222         $messages = [];
223         $gap = 5; // 5 secs.
225         $now = time();
226         $timestamp = $now;
228         // Messages belonging to 3 sessions. Session 1 has 10 messages, 2 has 15, 3 has 25.
229         $sessionusers = [];
230         $sessiontimes = [];
231         $session = 0; // Incomplete session.
232         for ($i = 1; $i <= 50; $i++) {
233             // Take note of expected session times as we go through.
234             switch ($i) {
235                 case 1:
236                     // Session 1 start time.
237                     $sessiontimes[0]['start'] = $timestamp;
238                     break;
239                 case 10:
240                     // Session 1 end time.
241                     $sessiontimes[0]['end'] = $timestamp;
242                     break;
243                 case 11:
244                     // Session 2 start time.
245                     $sessiontimes[1]['start'] = $timestamp;
246                     break;
247                 case 25:
248                     // Session 2 end time.
249                     $sessiontimes[1]['end'] = $timestamp;
250                     break;
251                 case 26:
252                     // Session 3 start time.
253                     $sessiontimes[2]['start'] = $timestamp;
254                     break;
255                 case 50:
256                     // Session 3 end time.
257                     $sessiontimes[2]['end'] = $timestamp;
258                     break;
259             }
261             // User 1 to 5.
262             $user = rand(1, 5);
264             // Let's also include system messages as well. Give them to pop in 1-in-10 chance.
265             $issystem = rand(1, 10) == 10;
267             if ($issystem) {
268                 $message = 'enter';
269             } else {
270                 $message = 'Message ' . $i;
271                 if (!isset($sessionusers[$session][$user])) {
272                     $sessionusers[$session][$user] = 1;
273                 } else {
274                     $sessionusers[$session][$user]++;
275                 }
276             }
277             $messages[] = (object)[
278                 'id' => $i,
279                 'chatid' => 1,
280                 'userid' => $user,
281                 'message' => $message,
282                 'issystem' => $issystem,
283                 'timestamp' => $timestamp,
284             ];
286             // Set the next timestamp.
287             if ($i == 10 || $i == 25) {
288                 // New session.
289                 $session++;
290                 $timestamp += CHAT_SESSION_GAP + 1;
291             } else {
292                 $timestamp += $gap;
293             }
294         }
295         // Reverse sort the messages so they're in descending order.
296         rsort($messages);
298         // Get chat sessions showing only complete ones.
299         $completesessions = chat_get_sessions($messages);
300         // Session 1 is incomplete, so there should only be 2 sessions when $showall is false.
301         $this->assertCount(2, $completesessions);
303         // Reverse sort sessions so they are in ascending order matching our expected session times and users.
304         $completesessions = array_reverse($completesessions);
305         foreach ($completesessions as $index => $session) {
306             // We increment index by 1 because the incomplete expected session (index=0) is not included.
307             $expectedindex = $index + 1;
309             // Check the session users.
310             $users = $sessionusers[$expectedindex];
311             $this->assertCount(count($users), $session->sessionusers);
312             // Check the message counts for each user in this session.
313             foreach ($users as $userid => $messagecount) {
314                 $this->assertEquals($messagecount, $session->sessionusers[$userid]);
315             }
317             $sessionstart = $sessiontimes[$expectedindex]['start'];
318             $sessionend = $sessiontimes[$expectedindex]['end'];
319             $this->assertEquals($sessionstart, $session->sessionstart);
320             $this->assertEquals($sessionend, $session->sessionend);
321         }
323         // Get all the chat sessions.
324         $allsessions = chat_get_sessions($messages, true);
325         // When showall is true, we should get 3 sessions.
326         $this->assertCount(3, $allsessions);
328         // Reverse sort sessions so they are in ascending order matching our expected session times and users.
329         $allsessions = array_reverse($allsessions);
330         foreach ($allsessions as $index => $session) {
331             // Check the session users.
332             $users = $sessionusers[$index];
333             $this->assertCount(count($users), $session->sessionusers);
334             // Check the message counts for each user in this session.
335             foreach ($users as $userid => $messagecount) {
336                 $this->assertEquals($messagecount, $session->sessionusers[$userid]);
337             }
339             $sessionstart = $sessiontimes[$index]['start'];
340             $sessionend = $sessiontimes[$index]['end'];
341             $this->assertEquals($sessionstart, $session->sessionstart);
342             $this->assertEquals($sessionend, $session->sessionend);
343         }
344     }
346     /**
347      * Creates an action event.
348      *
349      * @param int $courseid
350      * @param int $instanceid The chat id.
351      * @param string $eventtype The event type. eg. ASSIGN_EVENT_TYPE_DUE.
352      * @return bool|calendar_event
353      */
354     private function create_action_event($courseid, $instanceid, $eventtype) {
355         $event = new stdClass();
356         $event->name = 'Calendar event';
357         $event->modulename  = 'chat';
358         $event->courseid = $courseid;
359         $event->instance = $instanceid;
360         $event->type = CALENDAR_EVENT_TYPE_ACTION;
361         $event->eventtype = $eventtype;
362         $event->timestart = time();
364         return calendar_event::create($event);
365     }