weekly release 3.6dev
[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         // This is when the session starts (when the user enters the chat).
173         $sessionstart = $chatuser->lastping;
175         // Send some messages.
176         chat_send_chatmessage($chatuser, 'hello!');
177         chat_send_chatmessage($chatuser, 'bye bye!');
179         // Login as user 2.
180         $this->setUser($user2);
181         $chatsid = chat_login_user($chat->id, 'ajax', 0, $course);
182         $chatuser = $DB->get_record('chat_users', ['sid' => $chatsid]);
184         // Send a message and take note of this message ID.
185         $messageid = chat_send_chatmessage($chatuser, 'greetings!');
187         // This is when the session ends (timestamp of the last message sent to the chat).
188         $sessionend = $DB->get_field('chat_messages', 'timestamp', ['id' => $messageid]);
190         // Get the messages for this chat session.
191         $messages = chat_get_session_messages($chat->id, false, 0, 0, 'timestamp DESC');
193         // We should have 3 user and 2 system (enter) messages.
194         $this->assertCount(5, $messages);
196         // Fetch the chat sessions from the messages we retrieved.
197         $sessions = chat_get_sessions($messages, true);
199         // There should be only one session.
200         $this->assertCount(1, $sessions);
202         // Get this session.
203         $session = reset($sessions);
205         // Confirm that the start and end times of the session matches.
206         $this->assertEquals($sessionstart, $session->sessionstart);
207         $this->assertEquals($sessionend, $session->sessionend);
208         // Confirm we have 2 participants in the chat.
209         $this->assertCount(2, $session->sessionusers);
210     }
212     /**
213      * Test for chat_get_sessions with messages belonging to multiple sessions.
214      */
215     public function test_chat_get_sessions_multiple() {
216         $messages = [];
217         $gap = 5; // 5 secs.
219         $now = time();
220         $timestamp = $now;
222         // Messages belonging to 3 sessions. Session 1 has 10 messages, 2 has 15, 3 has 25.
223         $sessionusers = [];
224         $sessiontimes = [];
225         $session = 0; // Incomplete session.
226         for ($i = 1; $i <= 50; $i++) {
227             // Take note of expected session times as we go through.
228             switch ($i) {
229                 case 1:
230                     // Session 1 start time.
231                     $sessiontimes[0]['start'] = $timestamp;
232                     break;
233                 case 10:
234                     // Session 1 end time.
235                     $sessiontimes[0]['end'] = $timestamp;
236                     break;
237                 case 11:
238                     // Session 2 start time.
239                     $sessiontimes[1]['start'] = $timestamp;
240                     break;
241                 case 25:
242                     // Session 2 end time.
243                     $sessiontimes[1]['end'] = $timestamp;
244                     break;
245                 case 26:
246                     // Session 3 start time.
247                     $sessiontimes[2]['start'] = $timestamp;
248                     break;
249                 case 50:
250                     // Session 3 end time.
251                     $sessiontimes[2]['end'] = $timestamp;
252                     break;
253             }
255             // User 1 to 5.
256             $user = rand(1, 5);
258             // Let's also include system messages as well. Give them to pop in 1-in-10 chance.
259             $issystem = rand(1, 10) == 10;
261             if ($issystem) {
262                 $message = 'enter';
263             } else {
264                 $message = 'Message ' . $i;
265                 if (!isset($sessionusers[$session][$user])) {
266                     $sessionusers[$session][$user] = 1;
267                 } else {
268                     $sessionusers[$session][$user]++;
269                 }
270             }
271             $messages[] = (object)[
272                 'id' => $i,
273                 'chatid' => 1,
274                 'userid' => $user,
275                 'message' => $message,
276                 'issystem' => $issystem,
277                 'timestamp' => $timestamp,
278             ];
280             // Set the next timestamp.
281             if ($i == 10 || $i == 25) {
282                 // New session.
283                 $session++;
284                 $timestamp += CHAT_SESSION_GAP + 1;
285             } else {
286                 $timestamp += $gap;
287             }
288         }
289         // Reverse sort the messages so they're in descending order.
290         rsort($messages);
292         // Get chat sessions showing only complete ones.
293         $completesessions = chat_get_sessions($messages);
294         // Session 1 is incomplete, so there should only be 2 sessions when $showall is false.
295         $this->assertCount(2, $completesessions);
297         // Reverse sort sessions so they are in ascending order matching our expected session times and users.
298         $completesessions = array_reverse($completesessions);
299         foreach ($completesessions as $index => $session) {
300             // We increment index by 1 because the incomplete expected session (index=0) is not included.
301             $expectedindex = $index + 1;
303             // Check the session users.
304             $users = $sessionusers[$expectedindex];
305             $this->assertCount(count($users), $session->sessionusers);
306             // Check the message counts for each user in this session.
307             foreach ($users as $userid => $messagecount) {
308                 $this->assertEquals($messagecount, $session->sessionusers[$userid]);
309             }
311             $sessionstart = $sessiontimes[$expectedindex]['start'];
312             $sessionend = $sessiontimes[$expectedindex]['end'];
313             $this->assertEquals($sessionstart, $session->sessionstart);
314             $this->assertEquals($sessionend, $session->sessionend);
315         }
317         // Get all the chat sessions.
318         $allsessions = chat_get_sessions($messages, true);
319         // When showall is true, we should get 3 sessions.
320         $this->assertCount(3, $allsessions);
322         // Reverse sort sessions so they are in ascending order matching our expected session times and users.
323         $allsessions = array_reverse($allsessions);
324         foreach ($allsessions as $index => $session) {
325             // Check the session users.
326             $users = $sessionusers[$index];
327             $this->assertCount(count($users), $session->sessionusers);
328             // Check the message counts for each user in this session.
329             foreach ($users as $userid => $messagecount) {
330                 $this->assertEquals($messagecount, $session->sessionusers[$userid]);
331             }
333             $sessionstart = $sessiontimes[$index]['start'];
334             $sessionend = $sessiontimes[$index]['end'];
335             $this->assertEquals($sessionstart, $session->sessionstart);
336             $this->assertEquals($sessionend, $session->sessionend);
337         }
338     }
340     /**
341      * Creates an action event.
342      *
343      * @param int $courseid
344      * @param int $instanceid The chat id.
345      * @param string $eventtype The event type. eg. ASSIGN_EVENT_TYPE_DUE.
346      * @return bool|calendar_event
347      */
348     private function create_action_event($courseid, $instanceid, $eventtype) {
349         $event = new stdClass();
350         $event->name = 'Calendar event';
351         $event->modulename  = 'chat';
352         $event->courseid = $courseid;
353         $event->instance = $instanceid;
354         $event->type = CALENDAR_EVENT_TYPE_ACTION;
355         $event->eventtype = $eventtype;
356         $event->timestart = time();
358         return calendar_event::create($event);
359     }