MDL-1626 mod_forum: Add functions to change user discussion subscription state
[moodle.git] / mod / forum / tests / mail_test.php
CommitLineData
a7a84903
AN
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 * The forum module mail generation tests.
19 *
20 * @package mod_forum
21 * @category external
22 * @copyright 2013 Andrew Nicols
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24 */
25
26defined('MOODLE_INTERNAL') || die();
27
28global $CFG;
29
30class mod_forum_mail_testcase extends advanced_testcase {
31
32 protected $helper;
33
34 public function setUp() {
59075a43
AN
35 // We must clear the subscription caches. This has to be done both before each test, and after in case of other
36 // tests using these functions.
37 \mod_forum\subscriptions::reset_forum_cache();
38
a7a84903
AN
39 global $CFG;
40 require_once($CFG->dirroot . '/mod/forum/lib.php');
41
42 $helper = new stdClass();
43
44 // Messaging is not compatible with transactions...
45 $this->preventResetByRollback();
46
47 // Catch all messages.
48 $helper->messagesink = $this->redirectMessages();
49 $helper->mailsink = $this->redirectEmails();
50
51 // Confirm that we have an empty message sink so far.
52 $messages = $helper->messagesink->get_messages();
53 $this->assertEquals(0, count($messages));
54
55 $messages = $helper->mailsink->get_messages();
56 $this->assertEquals(0, count($messages));
57
58 // Forcibly reduce the maxeditingtime to a one second to ensure that
59 // messages are sent out.
60 $CFG->maxeditingtime = 1;
61
62 // Ensure that we don't prevent e-mail as this will cause unit test failures.
63 $CFG->noemailever = false;
64
65 $this->helper = $helper;
66 }
67
68 public function tearDown() {
59075a43
AN
69 // We must clear the subscription caches. This has to be done both before each test, and after in case of other
70 // tests using these functions.
71 \mod_forum\subscriptions::reset_forum_cache();
72
a7a84903
AN
73 $this->helper->messagesink->clear();
74 $this->helper->messagesink->close();
75
76 $this->helper->mailsink->clear();
77 $this->helper->mailsink->close();
78 }
79
80 /**
81 * Helper to create the required number of users in the specified
82 * course.
83 * Users are enrolled as students.
84 *
85 * @param stdClass $course The course object
86 * @param integer $count The number of users to create
87 * @return array The users created
88 */
89 protected function helper_create_users($course, $count) {
90 $users = array();
91
92 for ($i = 0; $i < $count; $i++) {
93 $user = $this->getDataGenerator()->create_user();
94 $this->getDataGenerator()->enrol_user($user->id, $course->id);
95 $users[] = $user;
96 }
97
98 return $users;
99 }
100
101 /**
102 * Create a new discussion and post within the specified forum, as the
103 * specified author.
104 *
105 * @param stdClass $forum The forum to post in
106 * @param stdClass $author The author to post as
107 * @param array An array containing the discussion object, and the post object
108 */
109 protected function helper_post_to_forum($forum, $author) {
110 $generator = $this->getDataGenerator()->get_plugin_generator('mod_forum');
111
112 // Create a discussion in the forum, and then add a post to that discussion.
113 $record = new stdClass();
114 $record->course = $forum->course;
115 $record->userid = $author->id;
116 $record->forum = $forum->id;
117 $discussion = $generator->create_discussion($record);
118
119 $record = new stdClass();
120 $record->course = $forum->course;
121 $record->userid = $author->id;
122 $record->forum = $forum->id;
123 $record->discussion = $discussion->id;
124 $record->mailnow = 1;
125 $post = $generator->create_post($record);
126
127 return array($discussion, $post);
128 }
129
130 /**
131 * Run the forum cron, and check that the specified post was sent the
132 * specified number of times.
133 *
134 * @param stdClass $post The forum post object
135 * @param integer $expected The number of times that the post should have been sent
136 * @return array An array of the messages caught by the message sink
137 */
138 protected function helper_run_cron_check_count($post, $expected) {
139 // Clear the sinks before running cron.
140 $this->helper->messagesink->clear();
141 $this->helper->mailsink->clear();
142
143 // Cron daily uses mtrace, turn on buffering to silence output.
144 $this->expectOutputRegex("/{$expected} users were sent post {$post->id}, '{$post->subject}'/");
145 forum_cron();
146
147 // Now check the results in the message sink.
148 $messages = $this->helper->messagesink->get_messages();
149
150 // There should be the expected number of messages.
151 $this->assertEquals($expected, count($messages));
152
153 return $messages;
154 }
155
156 public function test_forced_subscription() {
157 $this->resetAfterTest(true);
158
159 // Create a course, with a forum.
160 $course = $this->getDataGenerator()->create_course();
161
162 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
163 $forum = $this->getDataGenerator()->create_module('forum', $options);
164
165 // Create two users enrolled in the course as students.
166 list($author, $recipient) = $this->helper_create_users($course, 2);
167
168 // Post a discussion to the forum.
169 list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
170
171 // We expect both users to receive this post.
172 $expected = 2;
173
174 // Run cron and check that the expected number of users received the notification.
175 $messages = $this->helper_run_cron_check_count($post, $expected);
176
177 $seenauthor = false;
178 $seenrecipient = false;
179 foreach ($messages as $message) {
180 // They should both be from our user.
181 $this->assertEquals($author->id, $message->useridfrom);
182
183 if ($message->useridto == $author->id) {
184 $seenauthor = true;
185 } else if ($message->useridto = $recipient->id) {
186 $seenrecipient = true;
187 }
188 }
189
190 // Check we saw messages for both users.
191 $this->assertTrue($seenauthor);
192 $this->assertTrue($seenrecipient);
193 }
194
195 public function test_subscription_disabled() {
196 global $DB;
197
198 $this->resetAfterTest(true);
199
200 // Create a course, with a forum.
201 $course = $this->getDataGenerator()->create_course();
202
203 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
204 $forum = $this->getDataGenerator()->create_module('forum', $options);
205
206 // Create two users enrolled in the course as students.
207 list($author, $recipient) = $this->helper_create_users($course, 2);
208
209 // Post a discussion to the forum.
210 list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
211
212 // We expect both users to receive this post.
213 $expected = 0;
214
215 // Run cron and check that the expected number of users received the notification.
216 $messages = $this->helper_run_cron_check_count($post, $expected);
217
218 // A user with the manageactivities capability within the course can subscribe.
219 $expected = 1;
220 $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
221 assign_capability('moodle/course:manageactivities', CAP_ALLOW, $roleids['student'], context_course::instance($course->id));
222 \mod_forum\subscriptions::subscribe_user($author->id, $forum);
223
224 $this->assertEquals($expected, $DB->count_records('forum_subscriptions', array(
225 'userid' => $author->id,
226 'forum' => $forum->id,
227 )));
228
229 // Run cron and check that the expected number of users received the notification.
230 list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
231 $messages = $this->helper_run_cron_check_count($post, $expected);
232
233 // Unsubscribe the user again.
234 \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
235
236 $expected = 0;
237 $this->assertEquals($expected, $DB->count_records('forum_subscriptions', array(
238 'userid' => $author->id,
239 'forum' => $forum->id,
240 )));
241
242 // Run cron and check that the expected number of users received the notification.
243 list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
244 $messages = $this->helper_run_cron_check_count($post, $expected);
245
246 // And unsubscribe the user from a new discussion
247 $expected = 1;
248 list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
249 \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
250 $messages = $this->helper_run_cron_check_count($post, $expected);
251 }
252
253 public function test_automatic() {
254 $this->resetAfterTest(true);
255
256 // Create a course, with a forum.
257 $course = $this->getDataGenerator()->create_course();
258
259 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
260 $forum = $this->getDataGenerator()->create_module('forum', $options);
261
262 // Create two users enrolled in the course as students.
263 list($author, $recipient) = $this->helper_create_users($course, 2);
264
265 // Post a discussion to the forum.
266 list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
267
268 // We expect both users to receive this post.
269 $expected = 2;
270
271 // Run cron and check that the expected number of users received the notification.
272 $messages = $this->helper_run_cron_check_count($post, $expected);
273
274 $seenauthor = false;
275 $seenrecipient = false;
276 foreach ($messages as $message) {
277 // They should both be from our user.
278 $this->assertEquals($author->id, $message->useridfrom);
279
280 if ($message->useridto == $author->id) {
281 $seenauthor = true;
282 } else if ($message->useridto = $recipient->id) {
283 $seenrecipient = true;
284 }
285 }
286
287 // Check we saw messages for both users.
288 $this->assertTrue($seenauthor);
289 $this->assertTrue($seenrecipient);
290 }
291
292 public function test_optional() {
293 $this->resetAfterTest(true);
294
295 // Create a course, with a forum.
296 $course = $this->getDataGenerator()->create_course();
297
298 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
299 $forum = $this->getDataGenerator()->create_module('forum', $options);
300
301 // Create two users enrolled in the course as students.
302 list($author, $recipient) = $this->helper_create_users($course, 2);
303
304 // Post a discussion to the forum.
305 list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
306
307 // We expect both users to receive this post.
308 $expected = 0;
309
310 // Run cron and check that the expected number of users received the notification.
311 $messages = $this->helper_run_cron_check_count($post, $expected);
312 }
313
314 public function test_automatic_with_unsubscribed_user() {
315 $this->resetAfterTest(true);
316
317 // Create a course, with a forum.
318 $course = $this->getDataGenerator()->create_course();
319
320 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
321 $forum = $this->getDataGenerator()->create_module('forum', $options);
322
323 // Create two users enrolled in the course as students.
324 list($author, $recipient) = $this->helper_create_users($course, 2);
325
326 // Unsubscribe the 'author' user from the forum.
59075a43 327 \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
a7a84903
AN
328
329 // Post a discussion to the forum.
330 list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
331
332 // We expect only one user to receive this post.
333 $expected = 1;
334
335 // Run cron and check that the expected number of users received the notification.
336 $messages = $this->helper_run_cron_check_count($post, $expected);
337
338 $seenauthor = false;
339 $seenrecipient = false;
340 foreach ($messages as $message) {
341 // They should both be from our user.
342 $this->assertEquals($author->id, $message->useridfrom);
343
344 if ($message->useridto == $author->id) {
345 $seenauthor = true;
346 } else if ($message->useridto = $recipient->id) {
347 $seenrecipient = true;
348 }
349 }
350
351 // Check we only saw one user.
352 $this->assertFalse($seenauthor);
353 $this->assertTrue($seenrecipient);
354 }
355
356 public function test_optional_with_subscribed_user() {
357 $this->resetAfterTest(true);
358
359 // Create a course, with a forum.
360 $course = $this->getDataGenerator()->create_course();
361
362 $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
363 $forum = $this->getDataGenerator()->create_module('forum', $options);
364
365 // Create two users enrolled in the course as students.
366 list($author, $recipient) = $this->helper_create_users($course, 2);
367
368 // Subscribe the 'recipient' user from the forum.
59075a43 369 \mod_forum\subscriptions::subscribe_user($recipient->id, $forum);
a7a84903
AN
370
371 // Post a discussion to the forum.
372 list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
373
374 // We expect only one user to receive this post.
375 $expected = 1;
376
377 // Run cron and check that the expected number of users received the notification.
378 $messages = $this->helper_run_cron_check_count($post, $expected);
379
380 $seenauthor = false;
381 $seenrecipient = false;
382 foreach ($messages as $message) {
383 // They should both be from our user.
384 $this->assertEquals($author->id, $message->useridfrom);
385
386 if ($message->useridto == $author->id) {
387 $seenauthor = true;
388 } else if ($message->useridto = $recipient->id) {
389 $seenrecipient = true;
390 }
391 }
392
393 // Check we only saw one user.
394 $this->assertFalse($seenauthor);
395 $this->assertTrue($seenrecipient);
396 }
397
398}