Merge branch 'MDL-53166' of https://github.com/eugeneventer/moodle-fixes
[moodle.git] / mod / forum / tests / subscriptions_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  * The module forums tests
19  *
20  * @package    mod_forum
21  * @copyright  2013 Frédéric Massart
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 defined('MOODLE_INTERNAL') || die();
27 global $CFG;
28 require_once($CFG->dirroot . '/mod/forum/lib.php');
30 class mod_forum_subscriptions_testcase extends advanced_testcase {
32     /**
33      * Test setUp.
34      */
35     public function setUp() {
36         // We must clear the subscription caches. This has to be done both before each test, and after in case of other
37         // tests using these functions.
38         \mod_forum\subscriptions::reset_forum_cache();
39         \mod_forum\subscriptions::reset_discussion_cache();
40     }
42     /**
43      * Test tearDown.
44      */
45     public function tearDown() {
46         // We must clear the subscription caches. This has to be done both before each test, and after in case of other
47         // tests using these functions.
48         \mod_forum\subscriptions::reset_forum_cache();
49         \mod_forum\subscriptions::reset_discussion_cache();
50     }
52     /**
53      * Helper to create the required number of users in the specified
54      * course.
55      * Users are enrolled as students.
56      *
57      * @param stdClass $course The course object
58      * @param integer $count The number of users to create
59      * @return array The users created
60      */
61     protected function helper_create_users($course, $count) {
62         $users = array();
64         for ($i = 0; $i < $count; $i++) {
65             $user = $this->getDataGenerator()->create_user();
66             $this->getDataGenerator()->enrol_user($user->id, $course->id);
67             $users[] = $user;
68         }
70         return $users;
71     }
73     /**
74      * Create a new discussion and post within the specified forum, as the
75      * specified author.
76      *
77      * @param stdClass $forum The forum to post in
78      * @param stdClass $author The author to post as
79      * @param array An array containing the discussion object, and the post object
80      */
81     protected function helper_post_to_forum($forum, $author) {
82         global $DB;
83         $generator = $this->getDataGenerator()->get_plugin_generator('mod_forum');
85         // Create a discussion in the forum, and then add a post to that discussion.
86         $record = new stdClass();
87         $record->course = $forum->course;
88         $record->userid = $author->id;
89         $record->forum = $forum->id;
90         $discussion = $generator->create_discussion($record);
92         // Retrieve the post which was created by create_discussion.
93         $post = $DB->get_record('forum_posts', array('discussion' => $discussion->id));
95         return array($discussion, $post);
96     }
98     public function test_subscription_modes() {
99         global $DB;
101         $this->resetAfterTest(true);
103         // Create a course, with a forum.
104         $course = $this->getDataGenerator()->create_course();
106         $options = array('course' => $course->id);
107         $forum = $this->getDataGenerator()->create_module('forum', $options);
109         \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_FORCESUBSCRIBE);
110         $forum = $DB->get_record('forum', array('id' => $forum->id));
111         $this->assertEquals(FORUM_FORCESUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
112         $this->assertTrue(\mod_forum\subscriptions::is_forcesubscribed($forum));
113         $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
114         $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
116         \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_DISALLOWSUBSCRIBE);
117         $forum = $DB->get_record('forum', array('id' => $forum->id));
118         $this->assertEquals(FORUM_DISALLOWSUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
119         $this->assertTrue(\mod_forum\subscriptions::subscription_disabled($forum));
120         $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
121         $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
123         \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_INITIALSUBSCRIBE);
124         $forum = $DB->get_record('forum', array('id' => $forum->id));
125         $this->assertEquals(FORUM_INITIALSUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
126         $this->assertTrue(\mod_forum\subscriptions::is_subscribable($forum));
127         $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
128         $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
130         \mod_forum\subscriptions::set_subscription_mode($forum->id, FORUM_CHOOSESUBSCRIBE);
131         $forum = $DB->get_record('forum', array('id' => $forum->id));
132         $this->assertEquals(FORUM_CHOOSESUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
133         $this->assertTrue(\mod_forum\subscriptions::is_subscribable($forum));
134         $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
135         $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
136     }
138     /**
139      * Test fetching unsubscribable forums.
140      */
141     public function test_unsubscribable_forums() {
142         global $DB;
144         $this->resetAfterTest(true);
146         // Create a course, with a forum.
147         $course = $this->getDataGenerator()->create_course();
149         // Create a user enrolled in the course as a student.
150         list($user) = $this->helper_create_users($course, 1);
152         // Must be logged in as the current user.
153         $this->setUser($user);
155         // Without any subscriptions, there should be nothing returned.
156         $result = \mod_forum\subscriptions::get_unsubscribable_forums();
157         $this->assertEquals(0, count($result));
159         // Create the forums.
160         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
161         $forceforum = $this->getDataGenerator()->create_module('forum', $options);
162         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
163         $disallowforum = $this->getDataGenerator()->create_module('forum', $options);
164         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
165         $chooseforum = $this->getDataGenerator()->create_module('forum', $options);
166         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
167         $initialforum = $this->getDataGenerator()->create_module('forum', $options);
169         // At present the user is only subscribed to the initial forum.
170         $result = \mod_forum\subscriptions::get_unsubscribable_forums();
171         $this->assertEquals(1, count($result));
173         // Ensure that the user is enrolled in all of the forums except force subscribed.
174         \mod_forum\subscriptions::subscribe_user($user->id, $disallowforum);
175         \mod_forum\subscriptions::subscribe_user($user->id, $chooseforum);
177         $result = \mod_forum\subscriptions::get_unsubscribable_forums();
178         $this->assertEquals(3, count($result));
180         // Hide the forums.
181         set_coursemodule_visible($forceforum->cmid, 0);
182         set_coursemodule_visible($disallowforum->cmid, 0);
183         set_coursemodule_visible($chooseforum->cmid, 0);
184         set_coursemodule_visible($initialforum->cmid, 0);
185         $result = \mod_forum\subscriptions::get_unsubscribable_forums();
186         $this->assertEquals(0, count($result));
188         // Add the moodle/course:viewhiddenactivities capability to the student user.
189         $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
190         $context = \context_course::instance($course->id);
191         assign_capability('moodle/course:viewhiddenactivities', CAP_ALLOW, $roleids['student'], $context);
192         $context->mark_dirty();
194         // All of the unsubscribable forums should now be listed.
195         $result = \mod_forum\subscriptions::get_unsubscribable_forums();
196         $this->assertEquals(3, count($result));
197     }
199     /**
200      * Test that toggling the forum-level subscription for a different user does not affect their discussion-level
201      * subscriptions.
202      */
203     public function test_forum_subscribe_toggle_as_other() {
204         global $DB;
206         $this->resetAfterTest(true);
208         // Create a course, with a forum.
209         $course = $this->getDataGenerator()->create_course();
211         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
212         $forum = $this->getDataGenerator()->create_module('forum', $options);
214         // Create a user enrolled in the course as a student.
215         list($author) = $this->helper_create_users($course, 1);
217         // Post a discussion to the forum.
218         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
220         // Check that the user is currently not subscribed to the forum.
221         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
223         // Check the deprecated function too.
224         $this->assertFalse(forum_is_subscribed($author->id, $forum));
225         $this->assertEquals(1, count($this->getDebuggingMessages()));
226         $this->resetDebugging();
228         // Check that the user is unsubscribed from the discussion too.
229         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
231         // Check that we have no records in either of the subscription tables.
232         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
233             'userid'        => $author->id,
234             'forum'         => $forum->id,
235         )));
236         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
237             'userid'        => $author->id,
238             'discussion'    => $discussion->id,
239         )));
241         // Subscribing to the forum should create a record in the subscriptions table, but not the forum discussion
242         // subscriptions table.
243         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
244         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
245             'userid'        => $author->id,
246             'forum'         => $forum->id,
247         )));
248         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
249             'userid'        => $author->id,
250             'discussion'    => $discussion->id,
251         )));
253         // Unsubscribing should remove the record from the forum subscriptions table, and not modify the forum
254         // discussion subscriptions table.
255         \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
256         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
257             'userid'        => $author->id,
258             'forum'         => $forum->id,
259         )));
260         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
261             'userid'        => $author->id,
262             'discussion'    => $discussion->id,
263         )));
265         // The same thing should happen calling the deprecated versions of
266         // these functions.
267         // Subscribing to the forum should create a record in the subscriptions table, but not the forum discussion
268         // subscriptions table.
269         forum_subscribe($author->id, $forum->id);
270         $this->assertEquals(1, count($this->getDebuggingMessages()));
271         $this->resetDebugging();
272         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
273             'userid'        => $author->id,
274             'forum'         => $forum->id,
275         )));
276         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
277             'userid'        => $author->id,
278             'discussion'    => $discussion->id,
279         )));
281         // Unsubscribing should remove the record from the forum subscriptions table, and not modify the forum
282         // discussion subscriptions table.
283         forum_unsubscribe($author->id, $forum->id);
284         $this->assertEquals(1, count($this->getDebuggingMessages()));
285         $this->resetDebugging();
286         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
287             'userid'        => $author->id,
288             'forum'         => $forum->id,
289         )));
290         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
291             'userid'        => $author->id,
292             'discussion'    => $discussion->id,
293         )));
295         // Enroling the user in the discussion should add one record to the forum discussion table without modifying the
296         // form subscriptions.
297         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
298         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
299             'userid'        => $author->id,
300             'forum'         => $forum->id,
301         )));
302         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
303             'userid'        => $author->id,
304             'discussion'    => $discussion->id,
305         )));
307         // Unsubscribing should remove the record from the forum subscriptions table, and not modify the forum
308         // discussion subscriptions table.
309         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
310         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
311             'userid'        => $author->id,
312             'forum'         => $forum->id,
313         )));
314         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
315             'userid'        => $author->id,
316             'discussion'    => $discussion->id,
317         )));
319         // Re-subscribe to the discussion so that we can check the effect of forum-level subscriptions.
320         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
321         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
322             'userid'        => $author->id,
323             'forum'         => $forum->id,
324         )));
325         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
326             'userid'        => $author->id,
327             'discussion'    => $discussion->id,
328         )));
330         // Subscribing to the forum should have no effect on the forum discussion subscriptions table if the user did
331         // not request the change themself.
332         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
333         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
334             'userid'        => $author->id,
335             'forum'         => $forum->id,
336         )));
337         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
338             'userid'        => $author->id,
339             'discussion'    => $discussion->id,
340         )));
342         // Unsubscribing from the forum should have no effect on the forum discussion subscriptions table if the user
343         // did not request the change themself.
344         \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
345         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
346             'userid'        => $author->id,
347             'forum'         => $forum->id,
348         )));
349         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
350             'userid'        => $author->id,
351             'discussion'    => $discussion->id,
352         )));
354         // Subscribing to the forum should remove the per-discussion subscription preference if the user requested the
355         // change themself.
356         \mod_forum\subscriptions::subscribe_user($author->id, $forum, null, true);
357         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
358             'userid'        => $author->id,
359             'forum'         => $forum->id,
360         )));
361         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
362             'userid'        => $author->id,
363             'discussion'    => $discussion->id,
364         )));
366         // Now unsubscribe from the current discussion whilst being subscribed to the forum as a whole.
367         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
368         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
369             'userid'        => $author->id,
370             'forum'         => $forum->id,
371         )));
372         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
373             'userid'        => $author->id,
374             'discussion'    => $discussion->id,
375         )));
377         // Unsubscribing from the forum should remove the per-discussion subscription preference if the user requested the
378         // change themself.
379         \mod_forum\subscriptions::unsubscribe_user($author->id, $forum, null, true);
380         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
381             'userid'        => $author->id,
382             'forum'         => $forum->id,
383         )));
384         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
385             'userid'        => $author->id,
386             'discussion'    => $discussion->id,
387         )));
389         // Subscribe to the discussion.
390         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
391         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
392             'userid'        => $author->id,
393             'forum'         => $forum->id,
394         )));
395         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
396             'userid'        => $author->id,
397             'discussion'    => $discussion->id,
398         )));
400         // Subscribe to the forum without removing the discussion preferences.
401         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
402         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
403             'userid'        => $author->id,
404             'forum'         => $forum->id,
405         )));
406         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
407             'userid'        => $author->id,
408             'discussion'    => $discussion->id,
409         )));
411         // Unsubscribing from the discussion should result in a change.
412         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
413         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
414             'userid'        => $author->id,
415             'forum'         => $forum->id,
416         )));
417         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
418             'userid'        => $author->id,
419             'discussion'    => $discussion->id,
420         )));
422     }
424     /**
425      * Test that a user unsubscribed from a forum is not subscribed to it's discussions by default.
426      */
427     public function test_forum_discussion_subscription_forum_unsubscribed() {
428         $this->resetAfterTest(true);
430         // Create a course, with a forum.
431         $course = $this->getDataGenerator()->create_course();
433         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
434         $forum = $this->getDataGenerator()->create_module('forum', $options);
436         // Create users enrolled in the course as students.
437         list($author) = $this->helper_create_users($course, 1);
439         // Check that the user is currently not subscribed to the forum.
440         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
442         // Check the deprecated function too.
443         $this->assertFalse(forum_is_subscribed($author->id, $forum));
444         $this->assertEquals(1, count($this->getDebuggingMessages()));
445         $this->resetDebugging();
447         // Post a discussion to the forum.
448         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
450         // Check that the user is unsubscribed from the discussion too.
451         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
452     }
454     /**
455      * Test that the act of subscribing to a forum subscribes the user to it's discussions by default.
456      */
457     public function test_forum_discussion_subscription_forum_subscribed() {
458         $this->resetAfterTest(true);
460         // Create a course, with a forum.
461         $course = $this->getDataGenerator()->create_course();
463         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
464         $forum = $this->getDataGenerator()->create_module('forum', $options);
466         // Create users enrolled in the course as students.
467         list($author) = $this->helper_create_users($course, 1);
469         // Enrol the user in the forum.
470         // If a subscription was added, we get the record ID.
471         $this->assertInternalType('int', \mod_forum\subscriptions::subscribe_user($author->id, $forum));
473         // If we already have a subscription when subscribing the user, we get a boolean (true).
474         $this->assertTrue(\mod_forum\subscriptions::subscribe_user($author->id, $forum));
476         // Check that the user is currently subscribed to the forum.
477         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
479         // Check the deprecated function too.
480         $this->assertTrue(forum_is_subscribed($author->id, $forum));
481         $this->assertEquals(1, count($this->getDebuggingMessages()));
482         $this->resetDebugging();
484         // Post a discussion to the forum.
485         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
487         // Check that the user is subscribed to the discussion too.
488         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
489     }
491     /**
492      * Test that a user unsubscribed from a forum can be subscribed to a discussion.
493      */
494     public function test_forum_discussion_subscription_forum_unsubscribed_discussion_subscribed() {
495         $this->resetAfterTest(true);
497         // Create a course, with a forum.
498         $course = $this->getDataGenerator()->create_course();
500         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
501         $forum = $this->getDataGenerator()->create_module('forum', $options);
503         // Create a user enrolled in the course as a student.
504         list($author) = $this->helper_create_users($course, 1);
506         // Check that the user is currently not subscribed to the forum.
507         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
509         // Check the deprecated function too.
510         $this->assertFalse(forum_is_subscribed($author->id, $forum));
511         $this->assertEquals(1, count($this->getDebuggingMessages()));
512         $this->resetDebugging();
514         // Post a discussion to the forum.
515         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
517         // Attempting to unsubscribe from the discussion should not make a change.
518         $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion));
520         // Then subscribe them to the discussion.
521         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
523         // Check that the user is still unsubscribed from the forum.
524         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
526         // Check the deprecated function too.
527         $this->assertFalse(forum_is_subscribed($author->id, $forum));
528         $this->assertEquals(1, count($this->getDebuggingMessages()));
529         $this->resetDebugging();
531         // But subscribed to the discussion.
532         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
533     }
535     /**
536      * Test that a user subscribed to a forum can be unsubscribed from a discussion.
537      */
538     public function test_forum_discussion_subscription_forum_subscribed_discussion_unsubscribed() {
539         $this->resetAfterTest(true);
541         // Create a course, with a forum.
542         $course = $this->getDataGenerator()->create_course();
544         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
545         $forum = $this->getDataGenerator()->create_module('forum', $options);
547         // Create two users enrolled in the course as students.
548         list($author) = $this->helper_create_users($course, 2);
550         // Enrol the student in the forum.
551         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
553         // Check that the user is currently subscribed to the forum.
554         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
556         // Check the deprecated function too.
557         $this->assertTrue(forum_is_subscribed($author->id, $forum));
558         $this->assertEquals(1, count($this->getDebuggingMessages()));
559         $this->resetDebugging();
561         // Post a discussion to the forum.
562         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
564         // Then unsubscribe them from the discussion.
565         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
567         // Check that the user is still subscribed to the forum.
568         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
570         // Check the deprecated function too.
571         $this->assertTrue(forum_is_subscribed($author->id, $forum));
572         $this->assertEquals(1, count($this->getDebuggingMessages()));
573         $this->resetDebugging();
575         // But unsubscribed from the discussion.
576         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
577     }
579     /**
580      * Test the effect of toggling the discussion subscription status when subscribed to the forum.
581      */
582     public function test_forum_discussion_toggle_forum_subscribed() {
583         global $DB;
585         $this->resetAfterTest(true);
587         // Create a course, with a forum.
588         $course = $this->getDataGenerator()->create_course();
590         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
591         $forum = $this->getDataGenerator()->create_module('forum', $options);
593         // Create two users enrolled in the course as students.
594         list($author) = $this->helper_create_users($course, 2);
596         // Enrol the student in the forum.
597         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
599         // Check that the user is currently subscribed to the forum.
600         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
602         // Check the deprecated function too.
603         $this->assertTrue(forum_is_subscribed($author->id, $forum));
604         $this->assertEquals(1, count($this->getDebuggingMessages()));
605         $this->resetDebugging();
607         // Post a discussion to the forum.
608         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
610         // Check that the user is initially subscribed to that discussion.
611         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
613         // An attempt to subscribe again should result in a falsey return to indicate that no change was made.
614         $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
616         // And there should be no discussion subscriptions (and one forum subscription).
617         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
618             'userid'        => $author->id,
619             'discussion'    => $discussion->id,
620         )));
621         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
622             'userid'        => $author->id,
623             'forum'         => $forum->id,
624         )));
626         // Then unsubscribe them from the discussion.
627         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
629         // Check that the user is still subscribed to the forum.
630         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
632         // Check the deprecated function too.
633         $this->assertTrue(forum_is_subscribed($author->id, $forum));
634         $this->assertEquals(1, count($this->getDebuggingMessages()));
635         $this->resetDebugging();
637         // An attempt to unsubscribe again should result in a falsey return to indicate that no change was made.
638         $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion));
640         // And there should be a discussion subscriptions (and one forum subscription).
641         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
642             'userid'        => $author->id,
643             'discussion'    => $discussion->id,
644         )));
645         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
646             'userid'        => $author->id,
647             'forum'         => $forum->id,
648         )));
650         // But unsubscribed from the discussion.
651         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
653         // There should be a record in the discussion subscription tracking table.
654         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
655             'userid'        => $author->id,
656             'discussion'    => $discussion->id,
657         )));
659         // And one in the forum subscription tracking table.
660         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
661             'userid'        => $author->id,
662             'forum'         => $forum->id,
663         )));
665         // Now subscribe the user again to the discussion.
666         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
668         // Check that the user is still subscribed to the forum.
669         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
671         // Check the deprecated function too.
672         $this->assertTrue(forum_is_subscribed($author->id, $forum));
673         $this->assertEquals(1, count($this->getDebuggingMessages()));
674         $this->resetDebugging();
676         // Check the deprecated function too.
677         $this->assertTrue(forum_is_subscribed($author->id, $forum));
678         $this->assertEquals(1, count($this->getDebuggingMessages()));
679         $this->resetDebugging();
681         // And is subscribed to the discussion again.
682         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
684         // There should be no record in the discussion subscription tracking table.
685         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
686             'userid'        => $author->id,
687             'discussion'    => $discussion->id,
688         )));
690         // And one in the forum subscription tracking table.
691         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
692             'userid'        => $author->id,
693             'forum'         => $forum->id,
694         )));
696         // And unsubscribe again.
697         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
699         // Check that the user is still subscribed to the forum.
700         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
702         // Check the deprecated function too.
703         $this->assertTrue(forum_is_subscribed($author->id, $forum));
704         $this->assertEquals(1, count($this->getDebuggingMessages()));
705         $this->resetDebugging();
707         // But unsubscribed from the discussion.
708         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
710         // There should be a record in the discussion subscription tracking table.
711         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
712             'userid'        => $author->id,
713             'discussion'    => $discussion->id,
714         )));
716         // And one in the forum subscription tracking table.
717         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
718             'userid'        => $author->id,
719             'forum'         => $forum->id,
720         )));
722         // And subscribe the user again to the discussion.
723         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
725         // Check that the user is still subscribed to the forum.
726         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
727         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
729         // And is subscribed to the discussion again.
730         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
732         // There should be no record in the discussion subscription tracking table.
733         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
734             'userid'        => $author->id,
735             'discussion'    => $discussion->id,
736         )));
738         // And one in the forum subscription tracking table.
739         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
740             'userid'        => $author->id,
741             'forum'         => $forum->id,
742         )));
744         // And unsubscribe again.
745         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
747         // Check that the user is still subscribed to the forum.
748         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
750         // Check the deprecated function too.
751         $this->assertTrue(forum_is_subscribed($author->id, $forum));
752         $this->assertEquals(1, count($this->getDebuggingMessages()));
753         $this->resetDebugging();
755         // But unsubscribed from the discussion.
756         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
758         // There should be a record in the discussion subscription tracking table.
759         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
760             'userid'        => $author->id,
761             'discussion'    => $discussion->id,
762         )));
764         // And one in the forum subscription tracking table.
765         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
766             'userid'        => $author->id,
767             'forum'         => $forum->id,
768         )));
770         // Now unsubscribe the user from the forum.
771         $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user($author->id, $forum, null, true));
773         // This removes both the forum_subscriptions, and the forum_discussion_subs records.
774         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
775             'userid'        => $author->id,
776             'discussion'    => $discussion->id,
777         )));
778         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
779             'userid'        => $author->id,
780             'forum'         => $forum->id,
781         )));
783         // And should have reset the discussion cache value.
784         $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $author->id);
785         $this->assertInternalType('array', $result);
786         $this->assertFalse(isset($result[$discussion->id]));
787     }
789     /**
790      * Test the effect of toggling the discussion subscription status when unsubscribed from the forum.
791      */
792     public function test_forum_discussion_toggle_forum_unsubscribed() {
793         global $DB;
795         $this->resetAfterTest(true);
797         // Create a course, with a forum.
798         $course = $this->getDataGenerator()->create_course();
800         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
801         $forum = $this->getDataGenerator()->create_module('forum', $options);
803         // Create two users enrolled in the course as students.
804         list($author) = $this->helper_create_users($course, 2);
806         // Check that the user is currently unsubscribed to the forum.
807         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
809         // Check the deprecated function too.
810         $this->assertFalse(forum_is_subscribed($author->id, $forum));
811         $this->assertEquals(1, count($this->getDebuggingMessages()));
812         $this->resetDebugging();
814         // Post a discussion to the forum.
815         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
817         // Check that the user is initially unsubscribed to that discussion.
818         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
820         // Then subscribe them to the discussion.
821         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
823         // An attempt to subscribe again should result in a falsey return to indicate that no change was made.
824         $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
826         // Check that the user is still unsubscribed from the forum.
827         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
829         // Check the deprecated function too.
830         $this->assertFalse(forum_is_subscribed($author->id, $forum));
831         $this->assertEquals(1, count($this->getDebuggingMessages()));
832         $this->resetDebugging();
834         // But subscribed to the discussion.
835         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
837         // There should be a record in the discussion subscription tracking table.
838         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
839             'userid'        => $author->id,
840             'discussion'    => $discussion->id,
841         )));
843         // Now unsubscribe the user again from the discussion.
844         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
846         // Check that the user is still unsubscribed from the forum.
847         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
849         // Check the deprecated function too.
850         $this->assertFalse(forum_is_subscribed($author->id, $forum));
851         $this->assertEquals(1, count($this->getDebuggingMessages()));
852         $this->resetDebugging();
854         // And is unsubscribed from the discussion again.
855         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
857         // There should be no record in the discussion subscription tracking table.
858         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
859             'userid'        => $author->id,
860             'discussion'    => $discussion->id,
861         )));
863         // And subscribe the user again to the discussion.
864         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
866         // Check that the user is still unsubscribed from the forum.
867         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
869         // Check the deprecated function too.
870         $this->assertFalse(forum_is_subscribed($author->id, $forum));
871         $this->assertEquals(1, count($this->getDebuggingMessages()));
872         $this->resetDebugging();
874         // And is subscribed to the discussion again.
875         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
877         // There should be a record in the discussion subscription tracking table.
878         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
879             'userid'        => $author->id,
880             'discussion'    => $discussion->id,
881         )));
883         // And unsubscribe again.
884         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
886         // Check that the user is still unsubscribed from the forum.
887         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
889         // Check the deprecated function too.
890         $this->assertFalse(forum_is_subscribed($author->id, $forum));
891         $this->assertEquals(1, count($this->getDebuggingMessages()));
892         $this->resetDebugging();
894         // But unsubscribed from the discussion.
895         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
897         // There should be no record in the discussion subscription tracking table.
898         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
899             'userid'        => $author->id,
900             'discussion'    => $discussion->id,
901         )));
902     }
904     /**
905      * Test that the deprecated forum_is_subscribed accepts numeric forum IDs.
906      */
907     public function test_forum_is_subscribed_numeric() {
908         global $DB;
910         $this->resetAfterTest(true);
912         // Create a course, with a forum.
913         $course = $this->getDataGenerator()->create_course();
915         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
916         $forum = $this->getDataGenerator()->create_module('forum', $options);
918         // Create a user enrolled in the course as a students.
919         list($author) = $this->helper_create_users($course, 1);
921         // Check that the user is currently unsubscribed to the forum.
922         $this->assertFalse(forum_is_subscribed($author->id, $forum->id));
923         $this->assertEquals(1, count($this->getDebuggingMessages()));
924         $this->resetDebugging();
926         // It should match the result of when it's called with the forum object.
927         $this->assertFalse(forum_is_subscribed($author->id, $forum));
928         $this->assertEquals(1, count($this->getDebuggingMessages()));
929         $this->resetDebugging();
931         // And when the user is subscribed, we should also get the correct result.
932         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
934         $this->assertTrue(forum_is_subscribed($author->id, $forum->id));
935         $this->assertEquals(1, count($this->getDebuggingMessages()));
936         $this->resetDebugging();
938         // It should match the result of when it's called with the forum object.
939         $this->assertTrue(forum_is_subscribed($author->id, $forum));
940         $this->assertEquals(1, count($this->getDebuggingMessages()));
941         $this->resetDebugging();
942     }
944     /**
945      * Test that the correct users are returned when fetching subscribed users from a forum where users can choose to
946      * subscribe and unsubscribe.
947      */
948     public function test_fetch_subscribed_users_subscriptions() {
949         global $DB, $CFG;
951         $this->resetAfterTest(true);
953         // Create a course, with a forum. where users are initially subscribed.
954         $course = $this->getDataGenerator()->create_course();
955         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
956         $forum = $this->getDataGenerator()->create_module('forum', $options);
958         // Create some user enrolled in the course as a student.
959         $usercount = 5;
960         $users = $this->helper_create_users($course, $usercount);
962         // All users should be subscribed.
963         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
964         $this->assertEquals($usercount, count($subscribers));
966         // Subscribe the guest user too to the forum - they should never be returned by this function.
967         $this->getDataGenerator()->enrol_user($CFG->siteguest, $course->id);
968         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
969         $this->assertEquals($usercount, count($subscribers));
971         // Unsubscribe 2 users.
972         $unsubscribedcount = 2;
973         for ($i = 0; $i < $unsubscribedcount; $i++) {
974             \mod_forum\subscriptions::unsubscribe_user($users[$i]->id, $forum);
975         }
977         // The subscription count should now take into account those users who have been unsubscribed.
978         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
979         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
980     }
982     /**
983      * Test that the correct users are returned hwen fetching subscribed users from a forum where users are forcibly
984      * subscribed.
985      */
986     public function test_fetch_subscribed_users_forced() {
987         global $DB;
989         $this->resetAfterTest(true);
991         // Create a course, with a forum. where users are initially subscribed.
992         $course = $this->getDataGenerator()->create_course();
993         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
994         $forum = $this->getDataGenerator()->create_module('forum', $options);
996         // Create some user enrolled in the course as a student.
997         $usercount = 5;
998         $users = $this->helper_create_users($course, $usercount);
1000         // All users should be subscribed.
1001         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
1002         $this->assertEquals($usercount, count($subscribers));
1003     }
1005     /**
1006      * Test that unusual combinations of discussion subscriptions do not affect the subscribed user list.
1007      */
1008     public function test_fetch_subscribed_users_discussion_subscriptions() {
1009         global $DB;
1011         $this->resetAfterTest(true);
1013         // Create a course, with a forum. where users are initially subscribed.
1014         $course = $this->getDataGenerator()->create_course();
1015         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1016         $forum = $this->getDataGenerator()->create_module('forum', $options);
1018         // Create some user enrolled in the course as a student.
1019         $usercount = 5;
1020         $users = $this->helper_create_users($course, $usercount);
1022         list($discussion, $post) = $this->helper_post_to_forum($forum, $users[0]);
1024         // All users should be subscribed.
1025         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
1026         $this->assertEquals($usercount, count($subscribers));
1027         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
1028         $this->assertEquals($usercount, count($subscribers));
1030         \mod_forum\subscriptions::unsubscribe_user_from_discussion($users[0]->id, $discussion);
1032         // All users should be subscribed.
1033         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
1034         $this->assertEquals($usercount, count($subscribers));
1036         // All users should be subscribed.
1037         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
1038         $this->assertEquals($usercount, count($subscribers));
1040         // Manually insert an extra subscription for one of the users.
1041         $record = new stdClass();
1042         $record->userid = $users[2]->id;
1043         $record->forum = $forum->id;
1044         $record->discussion = $discussion->id;
1045         $record->preference = time();
1046         $DB->insert_record('forum_discussion_subs', $record);
1048         // The discussion count should not have changed.
1049         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
1050         $this->assertEquals($usercount, count($subscribers));
1051         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
1052         $this->assertEquals($usercount, count($subscribers));
1054         // Unsubscribe 2 users.
1055         $unsubscribedcount = 2;
1056         for ($i = 0; $i < $unsubscribedcount; $i++) {
1057             \mod_forum\subscriptions::unsubscribe_user($users[$i]->id, $forum);
1058         }
1060         // The subscription count should now take into account those users who have been unsubscribed.
1061         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
1062         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
1063         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
1064         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
1066         // Now subscribe one of those users back to the discussion.
1067         $subscribeddiscussionusers = 1;
1068         for ($i = 0; $i < $subscribeddiscussionusers; $i++) {
1069             \mod_forum\subscriptions::subscribe_user_to_discussion($users[$i]->id, $discussion);
1070         }
1071         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
1072         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
1073         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
1074         $this->assertEquals($usercount - $unsubscribedcount + $subscribeddiscussionusers, count($subscribers));
1075     }
1077     /**
1078      * Test whether a user is force-subscribed to a forum.
1079      */
1080     public function test_force_subscribed_to_forum() {
1081         global $DB;
1083         $this->resetAfterTest(true);
1085         // Create a course, with a forum.
1086         $course = $this->getDataGenerator()->create_course();
1088         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
1089         $forum = $this->getDataGenerator()->create_module('forum', $options);
1091         // Create a user enrolled in the course as a student.
1092         $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
1093         $user = $this->getDataGenerator()->create_user();
1094         $this->getDataGenerator()->enrol_user($user->id, $course->id, $roleids['student']);
1096         // Check that the user is currently subscribed to the forum.
1097         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1099         // Remove the allowforcesubscribe capability from the user.
1100         $cm = get_coursemodule_from_instance('forum', $forum->id);
1101         $context = \context_module::instance($cm->id);
1102         assign_capability('mod/forum:allowforcesubscribe', CAP_PROHIBIT, $roleids['student'], $context);
1103         $context->mark_dirty();
1104         $this->assertFalse(has_capability('mod/forum:allowforcesubscribe', $context, $user->id));
1106         // Check that the user is no longer subscribed to the forum.
1107         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1108     }
1110     /**
1111      * Test that the subscription cache can be pre-filled.
1112      */
1113     public function test_subscription_cache_prefill() {
1114         global $DB;
1116         $this->resetAfterTest(true);
1118         // Create a course, with a forum.
1119         $course = $this->getDataGenerator()->create_course();
1121         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1122         $forum = $this->getDataGenerator()->create_module('forum', $options);
1124         // Create some users.
1125         $users = $this->helper_create_users($course, 20);
1127         // Reset the subscription cache.
1128         \mod_forum\subscriptions::reset_forum_cache();
1130         // Filling the subscription cache should only use a single query.
1131         $startcount = $DB->perf_get_reads();
1132         $this->assertNull(\mod_forum\subscriptions::fill_subscription_cache($forum->id));
1133         $postfillcount = $DB->perf_get_reads();
1134         $this->assertEquals(1, $postfillcount - $startcount);
1136         // Now fetch some subscriptions from that forum - these should use
1137         // the cache and not perform additional queries.
1138         foreach ($users as $user) {
1139             $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($forum->id, $user->id));
1140         }
1141         $finalcount = $DB->perf_get_reads();
1142         $this->assertEquals(0, $finalcount - $postfillcount);
1143     }
1145     /**
1146      * Test that the subscription cache can filled user-at-a-time.
1147      */
1148     public function test_subscription_cache_fill() {
1149         global $DB;
1151         $this->resetAfterTest(true);
1153         // Create a course, with a forum.
1154         $course = $this->getDataGenerator()->create_course();
1156         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1157         $forum = $this->getDataGenerator()->create_module('forum', $options);
1159         // Create some users.
1160         $users = $this->helper_create_users($course, 20);
1162         // Reset the subscription cache.
1163         \mod_forum\subscriptions::reset_forum_cache();
1165         // Filling the subscription cache should only use a single query.
1166         $startcount = $DB->perf_get_reads();
1168         // Fetch some subscriptions from that forum - these should not use the cache and will perform additional queries.
1169         foreach ($users as $user) {
1170             $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($forum->id, $user->id));
1171         }
1172         $finalcount = $DB->perf_get_reads();
1173         $this->assertEquals(20, $finalcount - $startcount);
1174     }
1176     /**
1177      * Test that the discussion subscription cache can filled course-at-a-time.
1178      */
1179     public function test_discussion_subscription_cache_fill_for_course() {
1180         global $DB;
1182         $this->resetAfterTest(true);
1184         // Create a course, with a forum.
1185         $course = $this->getDataGenerator()->create_course();
1187         // Create the forums.
1188         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
1189         $disallowforum = $this->getDataGenerator()->create_module('forum', $options);
1190         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
1191         $chooseforum = $this->getDataGenerator()->create_module('forum', $options);
1192         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1193         $initialforum = $this->getDataGenerator()->create_module('forum', $options);
1195         // Create some users and keep a reference to the first user.
1196         $users = $this->helper_create_users($course, 20);
1197         $user = reset($users);
1199         // Reset the subscription caches.
1200         \mod_forum\subscriptions::reset_forum_cache();
1202         $startcount = $DB->perf_get_reads();
1203         $result = \mod_forum\subscriptions::fill_subscription_cache_for_course($course->id, $user->id);
1204         $this->assertNull($result);
1205         $postfillcount = $DB->perf_get_reads();
1206         $this->assertEquals(1, $postfillcount - $startcount);
1207         $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($disallowforum->id, $user->id));
1208         $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($chooseforum->id, $user->id));
1209         $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($initialforum->id, $user->id));
1210         $finalcount = $DB->perf_get_reads();
1211         $this->assertEquals(0, $finalcount - $postfillcount);
1213         // Test for all users.
1214         foreach ($users as $user) {
1215             $result = \mod_forum\subscriptions::fill_subscription_cache_for_course($course->id, $user->id);
1216             $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($disallowforum->id, $user->id));
1217             $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($chooseforum->id, $user->id));
1218             $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($initialforum->id, $user->id));
1219         }
1220         $finalcount = $DB->perf_get_reads();
1221         $this->assertEquals(count($users), $finalcount - $postfillcount);
1222     }
1224     /**
1225      * Test that the discussion subscription cache can be forcibly updated for a user.
1226      */
1227     public function test_discussion_subscription_cache_prefill() {
1228         global $DB;
1230         $this->resetAfterTest(true);
1232         // Create a course, with a forum.
1233         $course = $this->getDataGenerator()->create_course();
1235         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1236         $forum = $this->getDataGenerator()->create_module('forum', $options);
1238         // Create some users.
1239         $users = $this->helper_create_users($course, 20);
1241         // Post some discussions to the forum.
1242         $discussions = array();
1243         $author = $users[0];
1244         for ($i = 0; $i < 20; $i++) {
1245             list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1246             $discussions[] = $discussion;
1247         }
1249         // Unsubscribe half the users from the half the discussions.
1250         $forumcount = 0;
1251         $usercount = 0;
1252         foreach ($discussions as $data) {
1253             if ($forumcount % 2) {
1254                 continue;
1255             }
1256             foreach ($users as $user) {
1257                 if ($usercount % 2) {
1258                     continue;
1259                 }
1260                 \mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion);
1261                 $usercount++;
1262             }
1263             $forumcount++;
1264         }
1266         // Reset the subscription caches.
1267         \mod_forum\subscriptions::reset_forum_cache();
1268         \mod_forum\subscriptions::reset_discussion_cache();
1270         // Filling the discussion subscription cache should only use a single query.
1271         $startcount = $DB->perf_get_reads();
1272         $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id));
1273         $postfillcount = $DB->perf_get_reads();
1274         $this->assertEquals(1, $postfillcount - $startcount);
1276         // Now fetch some subscriptions from that forum - these should use
1277         // the cache and not perform additional queries.
1278         foreach ($users as $user) {
1279             $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $user->id);
1280             $this->assertInternalType('array', $result);
1281         }
1282         $finalcount = $DB->perf_get_reads();
1283         $this->assertEquals(0, $finalcount - $postfillcount);
1284     }
1286     /**
1287      * Test that the discussion subscription cache can filled user-at-a-time.
1288      */
1289     public function test_discussion_subscription_cache_fill() {
1290         global $DB;
1292         $this->resetAfterTest(true);
1294         // Create a course, with a forum.
1295         $course = $this->getDataGenerator()->create_course();
1297         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1298         $forum = $this->getDataGenerator()->create_module('forum', $options);
1300         // Create some users.
1301         $users = $this->helper_create_users($course, 20);
1303         // Post some discussions to the forum.
1304         $discussions = array();
1305         $author = $users[0];
1306         for ($i = 0; $i < 20; $i++) {
1307             list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1308             $discussions[] = $discussion;
1309         }
1311         // Unsubscribe half the users from the half the discussions.
1312         $forumcount = 0;
1313         $usercount = 0;
1314         foreach ($discussions as $data) {
1315             if ($forumcount % 2) {
1316                 continue;
1317             }
1318             foreach ($users as $user) {
1319                 if ($usercount % 2) {
1320                     continue;
1321                 }
1322                 \mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion);
1323                 $usercount++;
1324             }
1325             $forumcount++;
1326         }
1328         // Reset the subscription caches.
1329         \mod_forum\subscriptions::reset_forum_cache();
1330         \mod_forum\subscriptions::reset_discussion_cache();
1332         $startcount = $DB->perf_get_reads();
1334         // Now fetch some subscriptions from that forum - these should use
1335         // the cache and not perform additional queries.
1336         foreach ($users as $user) {
1337             $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $user->id);
1338             $this->assertInternalType('array', $result);
1339         }
1340         $finalcount = $DB->perf_get_reads();
1341         $this->assertEquals(20, $finalcount - $startcount);
1342     }
1344     /**
1345      * Test that after toggling the forum subscription as another user,
1346      * the discussion subscription functionality works as expected.
1347      */
1348     public function test_forum_subscribe_toggle_as_other_repeat_subscriptions() {
1349         global $DB;
1351         $this->resetAfterTest(true);
1353         // Create a course, with a forum.
1354         $course = $this->getDataGenerator()->create_course();
1356         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
1357         $forum = $this->getDataGenerator()->create_module('forum', $options);
1359         // Create a user enrolled in the course as a student.
1360         list($user) = $this->helper_create_users($course, 1);
1362         // Post a discussion to the forum.
1363         list($discussion, $post) = $this->helper_post_to_forum($forum, $user);
1365         // Confirm that the user is currently not subscribed to the forum.
1366         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1368         // Confirm that the user is unsubscribed from the discussion too.
1369         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum, $discussion->id));
1371         // Confirm that we have no records in either of the subscription tables.
1372         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1373             'userid'        => $user->id,
1374             'forum'         => $forum->id,
1375         )));
1376         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
1377             'userid'        => $user->id,
1378             'discussion'    => $discussion->id,
1379         )));
1381         // Subscribing to the forum should create a record in the subscriptions table, but not the forum discussion
1382         // subscriptions table.
1383         \mod_forum\subscriptions::subscribe_user($user->id, $forum);
1384         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
1385             'userid'        => $user->id,
1386             'forum'         => $forum->id,
1387         )));
1388         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
1389             'userid'        => $user->id,
1390             'discussion'    => $discussion->id,
1391         )));
1393         // Now unsubscribe from the discussion. This should return true.
1394         $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1396         // Attempting to unsubscribe again should return false because no change was made.
1397         $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1399         // Subscribing to the discussion again should return truthfully as the subscription preference was removed.
1400         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1402         // Attempting to subscribe again should return false because no change was made.
1403         $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1405         // Now unsubscribe from the discussion. This should return true once more.
1406         $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1408         // And unsubscribing from the forum but not as a request from the user should maintain their preference.
1409         \mod_forum\subscriptions::unsubscribe_user($user->id, $forum);
1411         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1412             'userid'        => $user->id,
1413             'forum'         => $forum->id,
1414         )));
1415         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
1416             'userid'        => $user->id,
1417             'discussion'    => $discussion->id,
1418         )));
1420         // Subscribing to the discussion should return truthfully because a change was made.
1421         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1422         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1423             'userid'        => $user->id,
1424             'forum'         => $forum->id,
1425         )));
1426         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
1427             'userid'        => $user->id,
1428             'discussion'    => $discussion->id,
1429         )));
1430     }
1432     /**
1433      * Test that providing a context_module instance to is_subscribed does not result in additional lookups to retrieve
1434      * the context_module.
1435      */
1436     public function test_is_subscribed_cm() {
1437         global $DB;
1439         $this->resetAfterTest(true);
1441         // Create a course, with a forum.
1442         $course = $this->getDataGenerator()->create_course();
1444         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
1445         $forum = $this->getDataGenerator()->create_module('forum', $options);
1447         // Create a user enrolled in the course as a student.
1448         list($user) = $this->helper_create_users($course, 1);
1450         // Retrieve the $cm now.
1451         $cm = get_fast_modinfo($forum->course)->instances['forum'][$forum->id];
1453         // Reset get_fast_modinfo.
1454         get_fast_modinfo(0, 0, true);
1456         // Call is_subscribed without passing the $cmid - this should result in a lookup and filling of some of the
1457         // caches. This provides us with consistent data to start from.
1458         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1459         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1461         // Make a note of the number of DB calls.
1462         $basecount = $DB->perf_get_reads();
1464         // Call is_subscribed - it should give return the correct result (False), and result in no additional queries.
1465         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum, null, $cm));
1467         // The capability check does require some queries, so we don't test it directly.
1468         // We don't assert here because this is dependant upon linked code which could change at any time.
1469         $suppliedcmcount = $DB->perf_get_reads() - $basecount;
1471         // Call is_subscribed without passing the $cmid now - this should result in a lookup.
1472         get_fast_modinfo(0, 0, true);
1473         $basecount = $DB->perf_get_reads();
1474         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1475         $calculatedcmcount = $DB->perf_get_reads() - $basecount;
1477         // There should be more queries than when we performed the same check a moment ago.
1478         $this->assertGreaterThan($suppliedcmcount, $calculatedcmcount);
1479     }