MDL-55173 mod_forum: Perform final deprecations
[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 that the user is unsubscribed from the discussion too.
224         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
226         // Check that we have no records in either of the subscription tables.
227         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
228             'userid'        => $author->id,
229             'forum'         => $forum->id,
230         )));
231         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
232             'userid'        => $author->id,
233             'discussion'    => $discussion->id,
234         )));
236         // Subscribing to the forum should create a record in the subscriptions table, but not the forum discussion
237         // subscriptions table.
238         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
239         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
240             'userid'        => $author->id,
241             'forum'         => $forum->id,
242         )));
243         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
244             'userid'        => $author->id,
245             'discussion'    => $discussion->id,
246         )));
248         // Unsubscribing should remove the record from the forum subscriptions table, and not modify the forum
249         // discussion subscriptions table.
250         \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
251         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
252             'userid'        => $author->id,
253             'forum'         => $forum->id,
254         )));
255         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
256             'userid'        => $author->id,
257             'discussion'    => $discussion->id,
258         )));
260         // Enroling the user in the discussion should add one record to the forum discussion table without modifying the
261         // form subscriptions.
262         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
263         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
264             'userid'        => $author->id,
265             'forum'         => $forum->id,
266         )));
267         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
268             'userid'        => $author->id,
269             'discussion'    => $discussion->id,
270         )));
272         // Unsubscribing should remove the record from the forum subscriptions table, and not modify the forum
273         // discussion subscriptions table.
274         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
275         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
276             'userid'        => $author->id,
277             'forum'         => $forum->id,
278         )));
279         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
280             'userid'        => $author->id,
281             'discussion'    => $discussion->id,
282         )));
284         // Re-subscribe to the discussion so that we can check the effect of forum-level subscriptions.
285         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
286         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
287             'userid'        => $author->id,
288             'forum'         => $forum->id,
289         )));
290         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
291             'userid'        => $author->id,
292             'discussion'    => $discussion->id,
293         )));
295         // Subscribing to the forum should have no effect on the forum discussion subscriptions table if the user did
296         // not request the change themself.
297         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
298         $this->assertEquals(1, $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 from the forum should have no effect on the forum discussion subscriptions table if the user
308         // did not request the change themself.
309         \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
310         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
311             'userid'        => $author->id,
312             'forum'         => $forum->id,
313         )));
314         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
315             'userid'        => $author->id,
316             'discussion'    => $discussion->id,
317         )));
319         // Subscribing to the forum should remove the per-discussion subscription preference if the user requested the
320         // change themself.
321         \mod_forum\subscriptions::subscribe_user($author->id, $forum, null, true);
322         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
323             'userid'        => $author->id,
324             'forum'         => $forum->id,
325         )));
326         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
327             'userid'        => $author->id,
328             'discussion'    => $discussion->id,
329         )));
331         // Now unsubscribe from the current discussion whilst being subscribed to the forum as a whole.
332         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
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 remove the per-discussion subscription preference if the user requested the
343         // change themself.
344         \mod_forum\subscriptions::unsubscribe_user($author->id, $forum, null, true);
345         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
346             'userid'        => $author->id,
347             'forum'         => $forum->id,
348         )));
349         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
350             'userid'        => $author->id,
351             'discussion'    => $discussion->id,
352         )));
354         // Subscribe to the discussion.
355         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
356         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
357             'userid'        => $author->id,
358             'forum'         => $forum->id,
359         )));
360         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
361             'userid'        => $author->id,
362             'discussion'    => $discussion->id,
363         )));
365         // Subscribe to the forum without removing the discussion preferences.
366         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
367         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
368             'userid'        => $author->id,
369             'forum'         => $forum->id,
370         )));
371         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
372             'userid'        => $author->id,
373             'discussion'    => $discussion->id,
374         )));
376         // Unsubscribing from the discussion should result in a change.
377         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
378         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
379             'userid'        => $author->id,
380             'forum'         => $forum->id,
381         )));
382         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
383             'userid'        => $author->id,
384             'discussion'    => $discussion->id,
385         )));
387     }
389     /**
390      * Test that a user unsubscribed from a forum is not subscribed to it's discussions by default.
391      */
392     public function test_forum_discussion_subscription_forum_unsubscribed() {
393         $this->resetAfterTest(true);
395         // Create a course, with a forum.
396         $course = $this->getDataGenerator()->create_course();
398         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
399         $forum = $this->getDataGenerator()->create_module('forum', $options);
401         // Create users enrolled in the course as students.
402         list($author) = $this->helper_create_users($course, 1);
404         // Check that the user is currently not subscribed to the forum.
405         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
407         // Post a discussion to the forum.
408         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
410         // Check that the user is unsubscribed from the discussion too.
411         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
412     }
414     /**
415      * Test that the act of subscribing to a forum subscribes the user to it's discussions by default.
416      */
417     public function test_forum_discussion_subscription_forum_subscribed() {
418         $this->resetAfterTest(true);
420         // Create a course, with a forum.
421         $course = $this->getDataGenerator()->create_course();
423         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
424         $forum = $this->getDataGenerator()->create_module('forum', $options);
426         // Create users enrolled in the course as students.
427         list($author) = $this->helper_create_users($course, 1);
429         // Enrol the user in the forum.
430         // If a subscription was added, we get the record ID.
431         $this->assertInternalType('int', \mod_forum\subscriptions::subscribe_user($author->id, $forum));
433         // If we already have a subscription when subscribing the user, we get a boolean (true).
434         $this->assertTrue(\mod_forum\subscriptions::subscribe_user($author->id, $forum));
436         // Check that the user is currently subscribed to the forum.
437         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
439         // Post a discussion to the forum.
440         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
442         // Check that the user is subscribed to the discussion too.
443         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
444     }
446     /**
447      * Test that a user unsubscribed from a forum can be subscribed to a discussion.
448      */
449     public function test_forum_discussion_subscription_forum_unsubscribed_discussion_subscribed() {
450         $this->resetAfterTest(true);
452         // Create a course, with a forum.
453         $course = $this->getDataGenerator()->create_course();
455         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
456         $forum = $this->getDataGenerator()->create_module('forum', $options);
458         // Create a user enrolled in the course as a student.
459         list($author) = $this->helper_create_users($course, 1);
461         // Check that the user is currently not subscribed to the forum.
462         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
464         // Post a discussion to the forum.
465         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
467         // Attempting to unsubscribe from the discussion should not make a change.
468         $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion));
470         // Then subscribe them to the discussion.
471         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
473         // Check that the user is still unsubscribed from the forum.
474         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
476         // But subscribed to the discussion.
477         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
478     }
480     /**
481      * Test that a user subscribed to a forum can be unsubscribed from a discussion.
482      */
483     public function test_forum_discussion_subscription_forum_subscribed_discussion_unsubscribed() {
484         $this->resetAfterTest(true);
486         // Create a course, with a forum.
487         $course = $this->getDataGenerator()->create_course();
489         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
490         $forum = $this->getDataGenerator()->create_module('forum', $options);
492         // Create two users enrolled in the course as students.
493         list($author) = $this->helper_create_users($course, 2);
495         // Enrol the student in the forum.
496         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
498         // Check that the user is currently subscribed to the forum.
499         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
501         // Post a discussion to the forum.
502         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
504         // Then unsubscribe them from the discussion.
505         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
507         // Check that the user is still subscribed to the forum.
508         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
510         // But unsubscribed from the discussion.
511         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
512     }
514     /**
515      * Test the effect of toggling the discussion subscription status when subscribed to the forum.
516      */
517     public function test_forum_discussion_toggle_forum_subscribed() {
518         global $DB;
520         $this->resetAfterTest(true);
522         // Create a course, with a forum.
523         $course = $this->getDataGenerator()->create_course();
525         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
526         $forum = $this->getDataGenerator()->create_module('forum', $options);
528         // Create two users enrolled in the course as students.
529         list($author) = $this->helper_create_users($course, 2);
531         // Enrol the student in the forum.
532         \mod_forum\subscriptions::subscribe_user($author->id, $forum);
534         // Check that the user is currently subscribed to the forum.
535         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
537         // Post a discussion to the forum.
538         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
540         // Check that the user is initially subscribed to that discussion.
541         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
543         // An attempt to subscribe again should result in a falsey return to indicate that no change was made.
544         $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
546         // And there should be no discussion subscriptions (and one forum subscription).
547         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
548             'userid'        => $author->id,
549             'discussion'    => $discussion->id,
550         )));
551         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
552             'userid'        => $author->id,
553             'forum'         => $forum->id,
554         )));
556         // Then unsubscribe them from the discussion.
557         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
559         // Check that the user is still subscribed to the forum.
560         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
562         // An attempt to unsubscribe again should result in a falsey return to indicate that no change was made.
563         $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion));
565         // And there should be a discussion subscriptions (and one forum subscription).
566         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
567             'userid'        => $author->id,
568             'discussion'    => $discussion->id,
569         )));
570         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
571             'userid'        => $author->id,
572             'forum'         => $forum->id,
573         )));
575         // But unsubscribed from the discussion.
576         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
578         // There should be a record in the discussion subscription tracking table.
579         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
580             'userid'        => $author->id,
581             'discussion'    => $discussion->id,
582         )));
584         // And one in the forum subscription tracking table.
585         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
586             'userid'        => $author->id,
587             'forum'         => $forum->id,
588         )));
590         // Now subscribe the user again to the discussion.
591         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
593         // Check that the user is still subscribed to the forum.
594         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
596         // And is subscribed to the discussion again.
597         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
599         // There should be no record in the discussion subscription tracking table.
600         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
601             'userid'        => $author->id,
602             'discussion'    => $discussion->id,
603         )));
605         // And one in the forum subscription tracking table.
606         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
607             'userid'        => $author->id,
608             'forum'         => $forum->id,
609         )));
611         // And unsubscribe again.
612         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
614         // Check that the user is still subscribed to the forum.
615         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
617         // But unsubscribed from the discussion.
618         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
620         // There should be a record in the discussion subscription tracking table.
621         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
622             'userid'        => $author->id,
623             'discussion'    => $discussion->id,
624         )));
626         // And one in the forum subscription tracking table.
627         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
628             'userid'        => $author->id,
629             'forum'         => $forum->id,
630         )));
632         // And subscribe the user again to the discussion.
633         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
635         // Check that the user is still subscribed to the forum.
636         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
637         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
639         // And is subscribed to the discussion again.
640         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
642         // There should be no record in the discussion subscription tracking table.
643         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
644             'userid'        => $author->id,
645             'discussion'    => $discussion->id,
646         )));
648         // And one in the forum subscription tracking table.
649         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
650             'userid'        => $author->id,
651             'forum'         => $forum->id,
652         )));
654         // And unsubscribe again.
655         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
657         // Check that the user is still subscribed to the forum.
658         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
660         // But unsubscribed from the discussion.
661         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
663         // There should be a record in the discussion subscription tracking table.
664         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
665             'userid'        => $author->id,
666             'discussion'    => $discussion->id,
667         )));
669         // And one in the forum subscription tracking table.
670         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
671             'userid'        => $author->id,
672             'forum'         => $forum->id,
673         )));
675         // Now unsubscribe the user from the forum.
676         $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user($author->id, $forum, null, true));
678         // This removes both the forum_subscriptions, and the forum_discussion_subs records.
679         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
680             'userid'        => $author->id,
681             'discussion'    => $discussion->id,
682         )));
683         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
684             'userid'        => $author->id,
685             'forum'         => $forum->id,
686         )));
688         // And should have reset the discussion cache value.
689         $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $author->id);
690         $this->assertInternalType('array', $result);
691         $this->assertFalse(isset($result[$discussion->id]));
692     }
694     /**
695      * Test the effect of toggling the discussion subscription status when unsubscribed from the forum.
696      */
697     public function test_forum_discussion_toggle_forum_unsubscribed() {
698         global $DB;
700         $this->resetAfterTest(true);
702         // Create a course, with a forum.
703         $course = $this->getDataGenerator()->create_course();
705         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
706         $forum = $this->getDataGenerator()->create_module('forum', $options);
708         // Create two users enrolled in the course as students.
709         list($author) = $this->helper_create_users($course, 2);
711         // Check that the user is currently unsubscribed to the forum.
712         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
714         // Post a discussion to the forum.
715         list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
717         // Check that the user is initially unsubscribed to that discussion.
718         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
720         // Then subscribe them to the discussion.
721         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
723         // An attempt to subscribe again should result in a falsey return to indicate that no change was made.
724         $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
726         // Check that the user is still unsubscribed from the forum.
727         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
729         // But subscribed to the discussion.
730         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
732         // There should be a record in the discussion subscription tracking table.
733         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
734             'userid'        => $author->id,
735             'discussion'    => $discussion->id,
736         )));
738         // Now unsubscribe the user again from the discussion.
739         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
741         // Check that the user is still unsubscribed from the forum.
742         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
744         // And is unsubscribed from the discussion again.
745         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
747         // There should be no record in the discussion subscription tracking table.
748         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
749             'userid'        => $author->id,
750             'discussion'    => $discussion->id,
751         )));
753         // And subscribe the user again to the discussion.
754         \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
756         // Check that the user is still unsubscribed from the forum.
757         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
759         // And is subscribed to the discussion again.
760         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
762         // There should be a record in the discussion subscription tracking table.
763         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
764             'userid'        => $author->id,
765             'discussion'    => $discussion->id,
766         )));
768         // And unsubscribe again.
769         \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
771         // Check that the user is still unsubscribed from the forum.
772         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
774         // But unsubscribed from the discussion.
775         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
777         // There should be no record in the discussion subscription tracking table.
778         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
779             'userid'        => $author->id,
780             'discussion'    => $discussion->id,
781         )));
782     }
784     /**
785      * Test that the correct users are returned when fetching subscribed users from a forum where users can choose to
786      * subscribe and unsubscribe.
787      */
788     public function test_fetch_subscribed_users_subscriptions() {
789         global $DB, $CFG;
791         $this->resetAfterTest(true);
793         // Create a course, with a forum. where users are initially subscribed.
794         $course = $this->getDataGenerator()->create_course();
795         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
796         $forum = $this->getDataGenerator()->create_module('forum', $options);
798         // Create some user enrolled in the course as a student.
799         $usercount = 5;
800         $users = $this->helper_create_users($course, $usercount);
802         // All users should be subscribed.
803         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
804         $this->assertEquals($usercount, count($subscribers));
806         // Subscribe the guest user too to the forum - they should never be returned by this function.
807         $this->getDataGenerator()->enrol_user($CFG->siteguest, $course->id);
808         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
809         $this->assertEquals($usercount, count($subscribers));
811         // Unsubscribe 2 users.
812         $unsubscribedcount = 2;
813         for ($i = 0; $i < $unsubscribedcount; $i++) {
814             \mod_forum\subscriptions::unsubscribe_user($users[$i]->id, $forum);
815         }
817         // The subscription count should now take into account those users who have been unsubscribed.
818         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
819         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
820     }
822     /**
823      * Test that the correct users are returned hwen fetching subscribed users from a forum where users are forcibly
824      * subscribed.
825      */
826     public function test_fetch_subscribed_users_forced() {
827         global $DB;
829         $this->resetAfterTest(true);
831         // Create a course, with a forum. where users are initially subscribed.
832         $course = $this->getDataGenerator()->create_course();
833         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
834         $forum = $this->getDataGenerator()->create_module('forum', $options);
836         // Create some user enrolled in the course as a student.
837         $usercount = 5;
838         $users = $this->helper_create_users($course, $usercount);
840         // All users should be subscribed.
841         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
842         $this->assertEquals($usercount, count($subscribers));
843     }
845     /**
846      * Test that unusual combinations of discussion subscriptions do not affect the subscribed user list.
847      */
848     public function test_fetch_subscribed_users_discussion_subscriptions() {
849         global $DB;
851         $this->resetAfterTest(true);
853         // Create a course, with a forum. where users are initially subscribed.
854         $course = $this->getDataGenerator()->create_course();
855         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
856         $forum = $this->getDataGenerator()->create_module('forum', $options);
858         // Create some user enrolled in the course as a student.
859         $usercount = 5;
860         $users = $this->helper_create_users($course, $usercount);
862         list($discussion, $post) = $this->helper_post_to_forum($forum, $users[0]);
864         // All users should be subscribed.
865         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
866         $this->assertEquals($usercount, count($subscribers));
867         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
868         $this->assertEquals($usercount, count($subscribers));
870         \mod_forum\subscriptions::unsubscribe_user_from_discussion($users[0]->id, $discussion);
872         // All users should be subscribed.
873         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
874         $this->assertEquals($usercount, count($subscribers));
876         // All users should be subscribed.
877         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
878         $this->assertEquals($usercount, count($subscribers));
880         // Manually insert an extra subscription for one of the users.
881         $record = new stdClass();
882         $record->userid = $users[2]->id;
883         $record->forum = $forum->id;
884         $record->discussion = $discussion->id;
885         $record->preference = time();
886         $DB->insert_record('forum_discussion_subs', $record);
888         // The discussion count should not have changed.
889         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
890         $this->assertEquals($usercount, count($subscribers));
891         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
892         $this->assertEquals($usercount, count($subscribers));
894         // Unsubscribe 2 users.
895         $unsubscribedcount = 2;
896         for ($i = 0; $i < $unsubscribedcount; $i++) {
897             \mod_forum\subscriptions::unsubscribe_user($users[$i]->id, $forum);
898         }
900         // The subscription count should now take into account those users who have been unsubscribed.
901         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
902         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
903         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
904         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
906         // Now subscribe one of those users back to the discussion.
907         $subscribeddiscussionusers = 1;
908         for ($i = 0; $i < $subscribeddiscussionusers; $i++) {
909             \mod_forum\subscriptions::subscribe_user_to_discussion($users[$i]->id, $discussion);
910         }
911         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
912         $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
913         $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
914         $this->assertEquals($usercount - $unsubscribedcount + $subscribeddiscussionusers, count($subscribers));
915     }
917     /**
918      * Test whether a user is force-subscribed to a forum.
919      */
920     public function test_force_subscribed_to_forum() {
921         global $DB;
923         $this->resetAfterTest(true);
925         // Create a course, with a forum.
926         $course = $this->getDataGenerator()->create_course();
928         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
929         $forum = $this->getDataGenerator()->create_module('forum', $options);
931         // Create a user enrolled in the course as a student.
932         $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
933         $user = $this->getDataGenerator()->create_user();
934         $this->getDataGenerator()->enrol_user($user->id, $course->id, $roleids['student']);
936         // Check that the user is currently subscribed to the forum.
937         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
939         // Remove the allowforcesubscribe capability from the user.
940         $cm = get_coursemodule_from_instance('forum', $forum->id);
941         $context = \context_module::instance($cm->id);
942         assign_capability('mod/forum:allowforcesubscribe', CAP_PROHIBIT, $roleids['student'], $context);
943         $context->mark_dirty();
944         $this->assertFalse(has_capability('mod/forum:allowforcesubscribe', $context, $user->id));
946         // Check that the user is no longer subscribed to the forum.
947         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
948     }
950     /**
951      * Test that the subscription cache can be pre-filled.
952      */
953     public function test_subscription_cache_prefill() {
954         global $DB;
956         $this->resetAfterTest(true);
958         // Create a course, with a forum.
959         $course = $this->getDataGenerator()->create_course();
961         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
962         $forum = $this->getDataGenerator()->create_module('forum', $options);
964         // Create some users.
965         $users = $this->helper_create_users($course, 20);
967         // Reset the subscription cache.
968         \mod_forum\subscriptions::reset_forum_cache();
970         // Filling the subscription cache should only use a single query.
971         $startcount = $DB->perf_get_reads();
972         $this->assertNull(\mod_forum\subscriptions::fill_subscription_cache($forum->id));
973         $postfillcount = $DB->perf_get_reads();
974         $this->assertEquals(1, $postfillcount - $startcount);
976         // Now fetch some subscriptions from that forum - these should use
977         // the cache and not perform additional queries.
978         foreach ($users as $user) {
979             $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($forum->id, $user->id));
980         }
981         $finalcount = $DB->perf_get_reads();
982         $this->assertEquals(0, $finalcount - $postfillcount);
983     }
985     /**
986      * Test that the subscription cache can filled user-at-a-time.
987      */
988     public function test_subscription_cache_fill() {
989         global $DB;
991         $this->resetAfterTest(true);
993         // Create a course, with a forum.
994         $course = $this->getDataGenerator()->create_course();
996         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
997         $forum = $this->getDataGenerator()->create_module('forum', $options);
999         // Create some users.
1000         $users = $this->helper_create_users($course, 20);
1002         // Reset the subscription cache.
1003         \mod_forum\subscriptions::reset_forum_cache();
1005         // Filling the subscription cache should only use a single query.
1006         $startcount = $DB->perf_get_reads();
1008         // Fetch some subscriptions from that forum - these should not use the cache and will perform additional queries.
1009         foreach ($users as $user) {
1010             $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($forum->id, $user->id));
1011         }
1012         $finalcount = $DB->perf_get_reads();
1013         $this->assertEquals(20, $finalcount - $startcount);
1014     }
1016     /**
1017      * Test that the discussion subscription cache can filled course-at-a-time.
1018      */
1019     public function test_discussion_subscription_cache_fill_for_course() {
1020         global $DB;
1022         $this->resetAfterTest(true);
1024         // Create a course, with a forum.
1025         $course = $this->getDataGenerator()->create_course();
1027         // Create the forums.
1028         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
1029         $disallowforum = $this->getDataGenerator()->create_module('forum', $options);
1030         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
1031         $chooseforum = $this->getDataGenerator()->create_module('forum', $options);
1032         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1033         $initialforum = $this->getDataGenerator()->create_module('forum', $options);
1035         // Create some users and keep a reference to the first user.
1036         $users = $this->helper_create_users($course, 20);
1037         $user = reset($users);
1039         // Reset the subscription caches.
1040         \mod_forum\subscriptions::reset_forum_cache();
1042         $startcount = $DB->perf_get_reads();
1043         $result = \mod_forum\subscriptions::fill_subscription_cache_for_course($course->id, $user->id);
1044         $this->assertNull($result);
1045         $postfillcount = $DB->perf_get_reads();
1046         $this->assertEquals(1, $postfillcount - $startcount);
1047         $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($disallowforum->id, $user->id));
1048         $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($chooseforum->id, $user->id));
1049         $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($initialforum->id, $user->id));
1050         $finalcount = $DB->perf_get_reads();
1051         $this->assertEquals(0, $finalcount - $postfillcount);
1053         // Test for all users.
1054         foreach ($users as $user) {
1055             $result = \mod_forum\subscriptions::fill_subscription_cache_for_course($course->id, $user->id);
1056             $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($disallowforum->id, $user->id));
1057             $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($chooseforum->id, $user->id));
1058             $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($initialforum->id, $user->id));
1059         }
1060         $finalcount = $DB->perf_get_reads();
1061         $this->assertEquals(count($users), $finalcount - $postfillcount);
1062     }
1064     /**
1065      * Test that the discussion subscription cache can be forcibly updated for a user.
1066      */
1067     public function test_discussion_subscription_cache_prefill() {
1068         global $DB;
1070         $this->resetAfterTest(true);
1072         // Create a course, with a forum.
1073         $course = $this->getDataGenerator()->create_course();
1075         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1076         $forum = $this->getDataGenerator()->create_module('forum', $options);
1078         // Create some users.
1079         $users = $this->helper_create_users($course, 20);
1081         // Post some discussions to the forum.
1082         $discussions = array();
1083         $author = $users[0];
1084         for ($i = 0; $i < 20; $i++) {
1085             list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1086             $discussions[] = $discussion;
1087         }
1089         // Unsubscribe half the users from the half the discussions.
1090         $forumcount = 0;
1091         $usercount = 0;
1092         foreach ($discussions as $data) {
1093             if ($forumcount % 2) {
1094                 continue;
1095             }
1096             foreach ($users as $user) {
1097                 if ($usercount % 2) {
1098                     continue;
1099                 }
1100                 \mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion);
1101                 $usercount++;
1102             }
1103             $forumcount++;
1104         }
1106         // Reset the subscription caches.
1107         \mod_forum\subscriptions::reset_forum_cache();
1108         \mod_forum\subscriptions::reset_discussion_cache();
1110         // Filling the discussion subscription cache should only use a single query.
1111         $startcount = $DB->perf_get_reads();
1112         $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id));
1113         $postfillcount = $DB->perf_get_reads();
1114         $this->assertEquals(1, $postfillcount - $startcount);
1116         // Now fetch some subscriptions from that forum - these should use
1117         // the cache and not perform additional queries.
1118         foreach ($users as $user) {
1119             $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $user->id);
1120             $this->assertInternalType('array', $result);
1121         }
1122         $finalcount = $DB->perf_get_reads();
1123         $this->assertEquals(0, $finalcount - $postfillcount);
1124     }
1126     /**
1127      * Test that the discussion subscription cache can filled user-at-a-time.
1128      */
1129     public function test_discussion_subscription_cache_fill() {
1130         global $DB;
1132         $this->resetAfterTest(true);
1134         // Create a course, with a forum.
1135         $course = $this->getDataGenerator()->create_course();
1137         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1138         $forum = $this->getDataGenerator()->create_module('forum', $options);
1140         // Create some users.
1141         $users = $this->helper_create_users($course, 20);
1143         // Post some discussions to the forum.
1144         $discussions = array();
1145         $author = $users[0];
1146         for ($i = 0; $i < 20; $i++) {
1147             list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1148             $discussions[] = $discussion;
1149         }
1151         // Unsubscribe half the users from the half the discussions.
1152         $forumcount = 0;
1153         $usercount = 0;
1154         foreach ($discussions as $data) {
1155             if ($forumcount % 2) {
1156                 continue;
1157             }
1158             foreach ($users as $user) {
1159                 if ($usercount % 2) {
1160                     continue;
1161                 }
1162                 \mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion);
1163                 $usercount++;
1164             }
1165             $forumcount++;
1166         }
1168         // Reset the subscription caches.
1169         \mod_forum\subscriptions::reset_forum_cache();
1170         \mod_forum\subscriptions::reset_discussion_cache();
1172         $startcount = $DB->perf_get_reads();
1174         // Now fetch some subscriptions from that forum - these should use
1175         // the cache and not perform additional queries.
1176         foreach ($users as $user) {
1177             $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $user->id);
1178             $this->assertInternalType('array', $result);
1179         }
1180         $finalcount = $DB->perf_get_reads();
1181         $this->assertEquals(20, $finalcount - $startcount);
1182     }
1184     /**
1185      * Test that after toggling the forum subscription as another user,
1186      * the discussion subscription functionality works as expected.
1187      */
1188     public function test_forum_subscribe_toggle_as_other_repeat_subscriptions() {
1189         global $DB;
1191         $this->resetAfterTest(true);
1193         // Create a course, with a forum.
1194         $course = $this->getDataGenerator()->create_course();
1196         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
1197         $forum = $this->getDataGenerator()->create_module('forum', $options);
1199         // Create a user enrolled in the course as a student.
1200         list($user) = $this->helper_create_users($course, 1);
1202         // Post a discussion to the forum.
1203         list($discussion, $post) = $this->helper_post_to_forum($forum, $user);
1205         // Confirm that the user is currently not subscribed to the forum.
1206         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1208         // Confirm that the user is unsubscribed from the discussion too.
1209         $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum, $discussion->id));
1211         // Confirm that we have no records in either of the subscription tables.
1212         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1213             'userid'        => $user->id,
1214             'forum'         => $forum->id,
1215         )));
1216         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
1217             'userid'        => $user->id,
1218             'discussion'    => $discussion->id,
1219         )));
1221         // Subscribing to the forum should create a record in the subscriptions table, but not the forum discussion
1222         // subscriptions table.
1223         \mod_forum\subscriptions::subscribe_user($user->id, $forum);
1224         $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
1225             'userid'        => $user->id,
1226             'forum'         => $forum->id,
1227         )));
1228         $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
1229             'userid'        => $user->id,
1230             'discussion'    => $discussion->id,
1231         )));
1233         // Now unsubscribe from the discussion. This should return true.
1234         $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1236         // Attempting to unsubscribe again should return false because no change was made.
1237         $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1239         // Subscribing to the discussion again should return truthfully as the subscription preference was removed.
1240         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1242         // Attempting to subscribe again should return false because no change was made.
1243         $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1245         // Now unsubscribe from the discussion. This should return true once more.
1246         $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1248         // And unsubscribing from the forum but not as a request from the user should maintain their preference.
1249         \mod_forum\subscriptions::unsubscribe_user($user->id, $forum);
1251         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1252             'userid'        => $user->id,
1253             'forum'         => $forum->id,
1254         )));
1255         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
1256             'userid'        => $user->id,
1257             'discussion'    => $discussion->id,
1258         )));
1260         // Subscribing to the discussion should return truthfully because a change was made.
1261         $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1262         $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1263             'userid'        => $user->id,
1264             'forum'         => $forum->id,
1265         )));
1266         $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
1267             'userid'        => $user->id,
1268             'discussion'    => $discussion->id,
1269         )));
1270     }
1272     /**
1273      * Test that providing a context_module instance to is_subscribed does not result in additional lookups to retrieve
1274      * the context_module.
1275      */
1276     public function test_is_subscribed_cm() {
1277         global $DB;
1279         $this->resetAfterTest(true);
1281         // Create a course, with a forum.
1282         $course = $this->getDataGenerator()->create_course();
1284         $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
1285         $forum = $this->getDataGenerator()->create_module('forum', $options);
1287         // Create a user enrolled in the course as a student.
1288         list($user) = $this->helper_create_users($course, 1);
1290         // Retrieve the $cm now.
1291         $cm = get_fast_modinfo($forum->course)->instances['forum'][$forum->id];
1293         // Reset get_fast_modinfo.
1294         get_fast_modinfo(0, 0, true);
1296         // Call is_subscribed without passing the $cmid - this should result in a lookup and filling of some of the
1297         // caches. This provides us with consistent data to start from.
1298         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1299         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1301         // Make a note of the number of DB calls.
1302         $basecount = $DB->perf_get_reads();
1304         // Call is_subscribed - it should give return the correct result (False), and result in no additional queries.
1305         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum, null, $cm));
1307         // The capability check does require some queries, so we don't test it directly.
1308         // We don't assert here because this is dependant upon linked code which could change at any time.
1309         $suppliedcmcount = $DB->perf_get_reads() - $basecount;
1311         // Call is_subscribed without passing the $cmid now - this should result in a lookup.
1312         get_fast_modinfo(0, 0, true);
1313         $basecount = $DB->perf_get_reads();
1314         $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1315         $calculatedcmcount = $DB->perf_get_reads() - $basecount;
1317         // There should be more queries than when we performed the same check a moment ago.
1318         $this->assertGreaterThan($suppliedcmcount, $calculatedcmcount);
1319     }