Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace mod_forum;
18
 
19
use mod_forum_tests_generator_trait;
20
 
21
defined('MOODLE_INTERNAL') || die();
22
 
23
global $CFG;
24
require_once(__DIR__ . '/generator_trait.php');
25
require_once("{$CFG->dirroot}/mod/forum/lib.php");
26
 
27
/**
28
 * The module forums tests
29
 *
30
 * @package    mod_forum
31
 * @copyright  2013 Frédéric Massart
32
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
33
 */
34
class subscriptions_test extends \advanced_testcase {
35
    // Include the mod_forum test helpers.
36
    // This includes functions to create forums, users, discussions, and posts.
37
    use mod_forum_tests_generator_trait;
38
 
39
    /**
40
     * Test setUp.
41
     */
42
    public function setUp(): void {
43
        global $DB;
44
 
45
        // We must clear the subscription caches. This has to be done both before each test, and after in case of other
46
        // tests using these functions.
47
        \mod_forum\subscriptions::reset_forum_cache();
48
        \mod_forum\subscriptions::reset_discussion_cache();
49
    }
50
 
51
    /**
52
     * Test tearDown.
53
     */
54
    public function tearDown(): void {
55
        // We must clear the subscription caches. This has to be done both before each test, and after in case of other
56
        // tests using these functions.
57
        \mod_forum\subscriptions::reset_forum_cache();
58
        \mod_forum\subscriptions::reset_discussion_cache();
59
    }
60
 
61
    /**
62
     * Test subscription modes modifications.
63
     *
64
     * @covers \mod_forum\event\subscription_mode_updated
65
     */
11 efrain 66
    public function test_subscription_modes(): void {
1 efrain 67
        global $DB;
68
 
69
        $this->resetAfterTest(true);
70
 
71
        // Create a course, with a forum.
72
        $course = $this->getDataGenerator()->create_course();
73
 
74
        $options = array('course' => $course->id);
75
        $forum = $this->getDataGenerator()->create_module('forum', $options);
76
        $context = \context_module::instance($forum->cmid);
77
 
78
        // Create a user enrolled in the course as a student.
79
        list($user) = $this->helper_create_users($course, 1);
80
 
81
        // Must be logged in as the current user.
82
        $this->setUser($user);
83
 
84
        $sink = $this->redirectEvents(); // Capturing the event.
85
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_FORCESUBSCRIBE);
86
        $forum = $DB->get_record('forum', array('id' => $forum->id));
87
        $this->assertEquals(FORUM_FORCESUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
88
        $this->assertTrue(\mod_forum\subscriptions::is_forcesubscribed($forum));
89
        $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
90
        $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
91
 
92
        $events = $sink->get_events();
93
        $this->assertCount(1, $events);
94
        $event = reset($events);
95
        $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event);
96
        $this->assertEquals($context, $event->get_context());
97
        $this->assertEventContextNotUsed($event);
98
        $this->assertNotEmpty($event->get_name());
99
 
100
        $sink = $this->redirectEvents(); // Capturing the event.
101
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_DISALLOWSUBSCRIBE);
102
        $forum = $DB->get_record('forum', array('id' => $forum->id));
103
        $this->assertEquals(FORUM_DISALLOWSUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
104
        $this->assertTrue(\mod_forum\subscriptions::subscription_disabled($forum));
105
        $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
106
        $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
107
 
108
        $events = $sink->get_events();
109
        $this->assertCount(1, $events);
110
        $event = reset($events);
111
        $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event);
112
        $this->assertEquals($context, $event->get_context());
113
        $this->assertEventContextNotUsed($event);
114
        $this->assertNotEmpty($event->get_name());
115
 
116
        $sink = $this->redirectEvents(); // Capturing the event.
117
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_INITIALSUBSCRIBE);
118
        $forum = $DB->get_record('forum', array('id' => $forum->id));
119
        $this->assertEquals(FORUM_INITIALSUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
120
        $this->assertTrue(\mod_forum\subscriptions::is_subscribable($forum));
121
        $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
122
        $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
123
 
124
        $events = $sink->get_events();
125
        $this->assertCount(1, $events);
126
        $event = reset($events);
127
        $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event);
128
        $this->assertEquals($context, $event->get_context());
129
        $this->assertEventContextNotUsed($event);
130
        $this->assertNotEmpty($event->get_name());
131
 
132
        $sink = $this->redirectEvents(); // Capturing the event.
133
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_CHOOSESUBSCRIBE);
134
        $forum = $DB->get_record('forum', array('id' => $forum->id));
135
        $this->assertEquals(FORUM_CHOOSESUBSCRIBE, \mod_forum\subscriptions::get_subscription_mode($forum));
136
        $this->assertTrue(\mod_forum\subscriptions::is_subscribable($forum));
137
        $this->assertFalse(\mod_forum\subscriptions::subscription_disabled($forum));
138
        $this->assertFalse(\mod_forum\subscriptions::is_forcesubscribed($forum));
139
 
140
        $events = $sink->get_events();
141
        $this->assertCount(1, $events);
142
        $event = reset($events);
143
        $this->assertInstanceOf('\mod_forum\event\subscription_mode_updated', $event);
144
        $this->assertEquals($context, $event->get_context());
145
        $this->assertEventContextNotUsed($event);
146
        $this->assertNotEmpty($event->get_name());
147
    }
148
 
149
    /**
150
     * Test fetching unsubscribable forums.
151
     */
11 efrain 152
    public function test_unsubscribable_forums(): void {
1 efrain 153
        global $DB;
154
 
155
        $this->resetAfterTest(true);
156
 
157
        // Create a course, with a forum.
158
        $course = $this->getDataGenerator()->create_course();
159
 
160
        // Create a user enrolled in the course as a student.
161
        list($user) = $this->helper_create_users($course, 1);
162
 
163
        // Must be logged in as the current user.
164
        $this->setUser($user);
165
 
166
        // Without any subscriptions, there should be nothing returned.
167
        $result = \mod_forum\subscriptions::get_unsubscribable_forums();
168
        $this->assertEquals(0, count($result));
169
 
170
        // Create the forums.
171
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
172
        $forceforum = $this->getDataGenerator()->create_module('forum', $options);
173
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
174
        $disallowforum = $this->getDataGenerator()->create_module('forum', $options);
175
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
176
        $chooseforum = $this->getDataGenerator()->create_module('forum', $options);
177
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
178
        $initialforum = $this->getDataGenerator()->create_module('forum', $options);
179
 
180
        // At present the user is only subscribed to the initial forum.
181
        $result = \mod_forum\subscriptions::get_unsubscribable_forums();
182
        $this->assertEquals(1, count($result));
183
 
184
        // Ensure that the user is enrolled in all of the forums except force subscribed.
185
        \mod_forum\subscriptions::subscribe_user($user->id, $disallowforum);
186
        \mod_forum\subscriptions::subscribe_user($user->id, $chooseforum);
187
 
188
        $result = \mod_forum\subscriptions::get_unsubscribable_forums();
189
        $this->assertEquals(3, count($result));
190
 
191
        // Hide the forums.
192
        set_coursemodule_visible($forceforum->cmid, 0);
193
        set_coursemodule_visible($disallowforum->cmid, 0);
194
        set_coursemodule_visible($chooseforum->cmid, 0);
195
        set_coursemodule_visible($initialforum->cmid, 0);
196
        $result = \mod_forum\subscriptions::get_unsubscribable_forums();
197
        $this->assertEquals(0, count($result));
198
 
199
        // Add the moodle/course:viewhiddenactivities capability to the student user.
200
        $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
201
        $context = \context_course::instance($course->id);
202
        assign_capability('moodle/course:viewhiddenactivities', CAP_ALLOW, $roleids['student'], $context);
203
 
204
        // All of the unsubscribable forums should now be listed.
205
        $result = \mod_forum\subscriptions::get_unsubscribable_forums();
206
        $this->assertEquals(3, count($result));
207
    }
208
 
209
    /**
210
     * Test that toggling the forum-level subscription for a different user does not affect their discussion-level
211
     * subscriptions.
212
     */
11 efrain 213
    public function test_forum_subscribe_toggle_as_other(): void {
1 efrain 214
        global $DB;
215
 
216
        $this->resetAfterTest(true);
217
 
218
        // Create a course, with a forum.
219
        $course = $this->getDataGenerator()->create_course();
220
 
221
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
222
        $forum = $this->getDataGenerator()->create_module('forum', $options);
223
 
224
        // Create a user enrolled in the course as a student.
225
        list($author) = $this->helper_create_users($course, 1);
226
 
227
        // Post a discussion to the forum.
228
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
229
 
230
        // Check that the user is currently not subscribed to the forum.
231
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
232
 
233
        // Check that the user is unsubscribed from the discussion too.
234
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
235
 
236
        // Check that we have no records in either of the subscription tables.
237
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
238
            'userid'        => $author->id,
239
            'forum'         => $forum->id,
240
        )));
241
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
242
            'userid'        => $author->id,
243
            'discussion'    => $discussion->id,
244
        )));
245
 
246
        // Subscribing to the forum should create a record in the subscriptions table, but not the forum discussion
247
        // subscriptions table.
248
        \mod_forum\subscriptions::subscribe_user($author->id, $forum);
249
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
250
            'userid'        => $author->id,
251
            'forum'         => $forum->id,
252
        )));
253
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
254
            'userid'        => $author->id,
255
            'discussion'    => $discussion->id,
256
        )));
257
 
258
        // Unsubscribing should remove the record from the forum subscriptions table, and not modify the forum
259
        // discussion subscriptions table.
260
        \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
261
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
262
            'userid'        => $author->id,
263
            'forum'         => $forum->id,
264
        )));
265
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
266
            'userid'        => $author->id,
267
            'discussion'    => $discussion->id,
268
        )));
269
 
270
        // Enroling the user in the discussion should add one record to the forum discussion table without modifying the
271
        // form subscriptions.
272
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
273
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
274
            'userid'        => $author->id,
275
            'forum'         => $forum->id,
276
        )));
277
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
278
            'userid'        => $author->id,
279
            'discussion'    => $discussion->id,
280
        )));
281
 
282
        // Unsubscribing should remove the record from the forum subscriptions table, and not modify the forum
283
        // discussion subscriptions table.
284
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
285
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
286
            'userid'        => $author->id,
287
            'forum'         => $forum->id,
288
        )));
289
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
290
            'userid'        => $author->id,
291
            'discussion'    => $discussion->id,
292
        )));
293
 
294
        // Re-subscribe to the discussion so that we can check the effect of forum-level subscriptions.
295
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
296
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
297
            'userid'        => $author->id,
298
            'forum'         => $forum->id,
299
        )));
300
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
301
            'userid'        => $author->id,
302
            'discussion'    => $discussion->id,
303
        )));
304
 
305
        // Subscribing to the forum should have no effect on the forum discussion subscriptions table if the user did
306
        // not request the change themself.
307
        \mod_forum\subscriptions::subscribe_user($author->id, $forum);
308
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
309
            'userid'        => $author->id,
310
            'forum'         => $forum->id,
311
        )));
312
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
313
            'userid'        => $author->id,
314
            'discussion'    => $discussion->id,
315
        )));
316
 
317
        // Unsubscribing from the forum should have no effect on the forum discussion subscriptions table if the user
318
        // did not request the change themself.
319
        \mod_forum\subscriptions::unsubscribe_user($author->id, $forum);
320
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
321
            'userid'        => $author->id,
322
            'forum'         => $forum->id,
323
        )));
324
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
325
            'userid'        => $author->id,
326
            'discussion'    => $discussion->id,
327
        )));
328
 
329
        // Subscribing to the forum should remove the per-discussion subscription preference if the user requested the
330
        // change themself.
331
        \mod_forum\subscriptions::subscribe_user($author->id, $forum, null, true);
332
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
333
            'userid'        => $author->id,
334
            'forum'         => $forum->id,
335
        )));
336
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
337
            'userid'        => $author->id,
338
            'discussion'    => $discussion->id,
339
        )));
340
 
341
        // Now unsubscribe from the current discussion whilst being subscribed to the forum as a whole.
342
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
343
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
344
            'userid'        => $author->id,
345
            'forum'         => $forum->id,
346
        )));
347
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
348
            'userid'        => $author->id,
349
            'discussion'    => $discussion->id,
350
        )));
351
 
352
        // Unsubscribing from the forum should remove the per-discussion subscription preference if the user requested the
353
        // change themself.
354
        \mod_forum\subscriptions::unsubscribe_user($author->id, $forum, null, true);
355
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
356
            'userid'        => $author->id,
357
            'forum'         => $forum->id,
358
        )));
359
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
360
            'userid'        => $author->id,
361
            'discussion'    => $discussion->id,
362
        )));
363
 
364
        // Subscribe to the discussion.
365
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
366
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
367
            'userid'        => $author->id,
368
            'forum'         => $forum->id,
369
        )));
370
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
371
            'userid'        => $author->id,
372
            'discussion'    => $discussion->id,
373
        )));
374
 
375
        // Subscribe to the forum without removing the discussion preferences.
376
        \mod_forum\subscriptions::subscribe_user($author->id, $forum);
377
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
378
            'userid'        => $author->id,
379
            'forum'         => $forum->id,
380
        )));
381
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
382
            'userid'        => $author->id,
383
            'discussion'    => $discussion->id,
384
        )));
385
 
386
        // Unsubscribing from the discussion should result in a change.
387
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
388
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
389
            'userid'        => $author->id,
390
            'forum'         => $forum->id,
391
        )));
392
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
393
            'userid'        => $author->id,
394
            'discussion'    => $discussion->id,
395
        )));
396
 
397
    }
398
 
399
    /**
400
     * Test that a user unsubscribed from a forum is not subscribed to it's discussions by default.
401
     */
11 efrain 402
    public function test_forum_discussion_subscription_forum_unsubscribed(): void {
1 efrain 403
        $this->resetAfterTest(true);
404
 
405
        // Create a course, with a forum.
406
        $course = $this->getDataGenerator()->create_course();
407
 
408
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
409
        $forum = $this->getDataGenerator()->create_module('forum', $options);
410
 
411
        // Create users enrolled in the course as students.
412
        list($author) = $this->helper_create_users($course, 1);
413
 
414
        // Check that the user is currently not subscribed to the forum.
415
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
416
 
417
        // Post a discussion to the forum.
418
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
419
 
420
        // Check that the user is unsubscribed from the discussion too.
421
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
422
    }
423
 
424
    /**
425
     * Test that the act of subscribing to a forum subscribes the user to it's discussions by default.
426
     */
11 efrain 427
    public function test_forum_discussion_subscription_forum_subscribed(): void {
1 efrain 428
        $this->resetAfterTest(true);
429
 
430
        // Create a course, with a forum.
431
        $course = $this->getDataGenerator()->create_course();
432
 
433
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
434
        $forum = $this->getDataGenerator()->create_module('forum', $options);
435
 
436
        // Create users enrolled in the course as students.
437
        list($author) = $this->helper_create_users($course, 1);
438
 
439
        // Enrol the user in the forum.
440
        // If a subscription was added, we get the record ID.
441
        $this->assertIsInt(\mod_forum\subscriptions::subscribe_user($author->id, $forum));
442
 
443
        // If we already have a subscription when subscribing the user, we get a boolean (true).
444
        $this->assertTrue(\mod_forum\subscriptions::subscribe_user($author->id, $forum));
445
 
446
        // Check that the user is currently subscribed to the forum.
447
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
448
 
449
        // Post a discussion to the forum.
450
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
451
 
452
        // Check that the user is subscribed to the discussion too.
453
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
454
    }
455
 
456
    /**
457
     * Test that a user unsubscribed from a forum can be subscribed to a discussion.
458
     */
11 efrain 459
    public function test_forum_discussion_subscription_forum_unsubscribed_discussion_subscribed(): void {
1 efrain 460
        $this->resetAfterTest(true);
461
 
462
        // Create a course, with a forum.
463
        $course = $this->getDataGenerator()->create_course();
464
 
465
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
466
        $forum = $this->getDataGenerator()->create_module('forum', $options);
467
 
468
        // Create a user enrolled in the course as a student.
469
        list($author) = $this->helper_create_users($course, 1);
470
 
471
        // Check that the user is currently not subscribed to the forum.
472
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
473
 
474
        // Post a discussion to the forum.
475
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
476
 
477
        // Attempting to unsubscribe from the discussion should not make a change.
478
        $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion));
479
 
480
        // Then subscribe them to the discussion.
481
        $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
482
 
483
        // Check that the user is still unsubscribed from the forum.
484
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
485
 
486
        // But subscribed to the discussion.
487
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
488
    }
489
 
490
    /**
491
     * Test that a user subscribed to a forum can be unsubscribed from a discussion.
492
     */
11 efrain 493
    public function test_forum_discussion_subscription_forum_subscribed_discussion_unsubscribed(): void {
1 efrain 494
        $this->resetAfterTest(true);
495
 
496
        // Create a course, with a forum.
497
        $course = $this->getDataGenerator()->create_course();
498
 
499
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
500
        $forum = $this->getDataGenerator()->create_module('forum', $options);
501
 
502
        // Create two users enrolled in the course as students.
503
        list($author) = $this->helper_create_users($course, 2);
504
 
505
        // Enrol the student in the forum.
506
        \mod_forum\subscriptions::subscribe_user($author->id, $forum);
507
 
508
        // Check that the user is currently subscribed to the forum.
509
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
510
 
511
        // Post a discussion to the forum.
512
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
513
 
514
        // Then unsubscribe them from the discussion.
515
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
516
 
517
        // Check that the user is still subscribed to the forum.
518
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
519
 
520
        // But unsubscribed from the discussion.
521
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
522
    }
523
 
524
    /**
525
     * Test the effect of toggling the discussion subscription status when subscribed to the forum.
526
     */
11 efrain 527
    public function test_forum_discussion_toggle_forum_subscribed(): void {
1 efrain 528
        global $DB;
529
 
530
        $this->resetAfterTest(true);
531
 
532
        // Create a course, with a forum.
533
        $course = $this->getDataGenerator()->create_course();
534
 
535
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
536
        $forum = $this->getDataGenerator()->create_module('forum', $options);
537
 
538
        // Create two users enrolled in the course as students.
539
        list($author) = $this->helper_create_users($course, 2);
540
 
541
        // Enrol the student in the forum.
542
        \mod_forum\subscriptions::subscribe_user($author->id, $forum);
543
 
544
        // Check that the user is currently subscribed to the forum.
545
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
546
 
547
        // Post a discussion to the forum.
548
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
549
 
550
        // Check that the user is initially subscribed to that discussion.
551
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
552
 
553
        // An attempt to subscribe again should result in a falsey return to indicate that no change was made.
554
        $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
555
 
556
        // And there should be no discussion subscriptions (and one forum subscription).
557
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
558
            'userid'        => $author->id,
559
            'discussion'    => $discussion->id,
560
        )));
561
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
562
            'userid'        => $author->id,
563
            'forum'         => $forum->id,
564
        )));
565
 
566
        // Then unsubscribe them from the discussion.
567
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
568
 
569
        // Check that the user is still subscribed to the forum.
570
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
571
 
572
        // An attempt to unsubscribe again should result in a falsey return to indicate that no change was made.
573
        $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion));
574
 
575
        // And there should be a discussion subscriptions (and one forum subscription).
576
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
577
            'userid'        => $author->id,
578
            'discussion'    => $discussion->id,
579
        )));
580
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
581
            'userid'        => $author->id,
582
            'forum'         => $forum->id,
583
        )));
584
 
585
        // But unsubscribed from the discussion.
586
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
587
 
588
        // There should be a record in the discussion subscription tracking table.
589
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
590
            'userid'        => $author->id,
591
            'discussion'    => $discussion->id,
592
        )));
593
 
594
        // And one in the forum subscription tracking table.
595
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
596
            'userid'        => $author->id,
597
            'forum'         => $forum->id,
598
        )));
599
 
600
        // Now subscribe the user again to the discussion.
601
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
602
 
603
        // Check that the user is still subscribed to the forum.
604
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
605
 
606
        // And is subscribed to the discussion again.
607
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
608
 
609
        // There should be no record in the discussion subscription tracking table.
610
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
611
            'userid'        => $author->id,
612
            'discussion'    => $discussion->id,
613
        )));
614
 
615
        // And one in the forum subscription tracking table.
616
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
617
            'userid'        => $author->id,
618
            'forum'         => $forum->id,
619
        )));
620
 
621
        // And unsubscribe again.
622
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
623
 
624
        // Check that the user is still subscribed to the forum.
625
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
626
 
627
        // But unsubscribed from the discussion.
628
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
629
 
630
        // There should be a record in the discussion subscription tracking table.
631
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
632
            'userid'        => $author->id,
633
            'discussion'    => $discussion->id,
634
        )));
635
 
636
        // And one in the forum subscription tracking table.
637
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
638
            'userid'        => $author->id,
639
            'forum'         => $forum->id,
640
        )));
641
 
642
        // And subscribe the user again to the discussion.
643
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
644
 
645
        // Check that the user is still subscribed to the forum.
646
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
647
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
648
 
649
        // And is subscribed to the discussion again.
650
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
651
 
652
        // There should be no record in the discussion subscription tracking table.
653
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
654
            'userid'        => $author->id,
655
            'discussion'    => $discussion->id,
656
        )));
657
 
658
        // And one in the forum subscription tracking table.
659
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
660
            'userid'        => $author->id,
661
            'forum'         => $forum->id,
662
        )));
663
 
664
        // And unsubscribe again.
665
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
666
 
667
        // Check that the user is still subscribed to the forum.
668
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
669
 
670
        // But unsubscribed from the discussion.
671
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
672
 
673
        // There should be a record in the discussion subscription tracking table.
674
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
675
            'userid'        => $author->id,
676
            'discussion'    => $discussion->id,
677
        )));
678
 
679
        // And one in the forum subscription tracking table.
680
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
681
            'userid'        => $author->id,
682
            'forum'         => $forum->id,
683
        )));
684
 
685
        // Now unsubscribe the user from the forum.
686
        $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user($author->id, $forum, null, true));
687
 
688
        // This removes both the forum_subscriptions, and the forum_discussion_subs records.
689
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
690
            'userid'        => $author->id,
691
            'discussion'    => $discussion->id,
692
        )));
693
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
694
            'userid'        => $author->id,
695
            'forum'         => $forum->id,
696
        )));
697
 
698
        // And should have reset the discussion cache value.
699
        $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $author->id);
700
        $this->assertIsArray($result);
701
        $this->assertFalse(isset($result[$discussion->id]));
702
    }
703
 
704
    /**
705
     * Test the effect of toggling the discussion subscription status when unsubscribed from the forum.
706
     */
11 efrain 707
    public function test_forum_discussion_toggle_forum_unsubscribed(): void {
1 efrain 708
        global $DB;
709
 
710
        $this->resetAfterTest(true);
711
 
712
        // Create a course, with a forum.
713
        $course = $this->getDataGenerator()->create_course();
714
 
715
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
716
        $forum = $this->getDataGenerator()->create_module('forum', $options);
717
 
718
        // Create two users enrolled in the course as students.
719
        list($author) = $this->helper_create_users($course, 2);
720
 
721
        // Check that the user is currently unsubscribed to the forum.
722
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
723
 
724
        // Post a discussion to the forum.
725
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
726
 
727
        // Check that the user is initially unsubscribed to that discussion.
728
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
729
 
730
        // Then subscribe them to the discussion.
731
        $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
732
 
733
        // An attempt to subscribe again should result in a falsey return to indicate that no change was made.
734
        $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion));
735
 
736
        // Check that the user is still unsubscribed from the forum.
737
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
738
 
739
        // But subscribed to the discussion.
740
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
741
 
742
        // There should be a record in the discussion subscription tracking table.
743
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
744
            'userid'        => $author->id,
745
            'discussion'    => $discussion->id,
746
        )));
747
 
748
        // Now unsubscribe the user again from the discussion.
749
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
750
 
751
        // Check that the user is still unsubscribed from the forum.
752
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
753
 
754
        // And is unsubscribed from the discussion again.
755
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
756
 
757
        // There should be no record in the discussion subscription tracking table.
758
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
759
            'userid'        => $author->id,
760
            'discussion'    => $discussion->id,
761
        )));
762
 
763
        // And subscribe the user again to the discussion.
764
        \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion);
765
 
766
        // Check that the user is still unsubscribed from the forum.
767
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
768
 
769
        // And is subscribed to the discussion again.
770
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
771
 
772
        // There should be a record in the discussion subscription tracking table.
773
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
774
            'userid'        => $author->id,
775
            'discussion'    => $discussion->id,
776
        )));
777
 
778
        // And unsubscribe again.
779
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($author->id, $discussion);
780
 
781
        // Check that the user is still unsubscribed from the forum.
782
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum));
783
 
784
        // But unsubscribed from the discussion.
785
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($author->id, $forum, $discussion->id));
786
 
787
        // There should be no record in the discussion subscription tracking table.
788
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
789
            'userid'        => $author->id,
790
            'discussion'    => $discussion->id,
791
        )));
792
    }
793
 
794
    /**
795
     * Test that the correct users are returned when fetching subscribed users from a forum where users can choose to
796
     * subscribe and unsubscribe.
797
     */
11 efrain 798
    public function test_fetch_subscribed_users_subscriptions(): void {
1 efrain 799
        global $DB, $CFG;
800
 
801
        $this->resetAfterTest(true);
802
 
803
        // Create a course, with a forum. where users are initially subscribed.
804
        $course = $this->getDataGenerator()->create_course();
805
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
806
        $forum = $this->getDataGenerator()->create_module('forum', $options);
807
 
808
        // Create some user enrolled in the course as a student.
809
        $usercount = 5;
810
        $users = $this->helper_create_users($course, $usercount);
811
 
812
        // All users should be subscribed.
813
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
814
        $this->assertEquals($usercount, count($subscribers));
815
 
816
        // Subscribe the guest user too to the forum - they should never be returned by this function.
817
        $this->getDataGenerator()->enrol_user($CFG->siteguest, $course->id);
818
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
819
        $this->assertEquals($usercount, count($subscribers));
820
 
821
        // Unsubscribe 2 users.
822
        $unsubscribedcount = 2;
823
        for ($i = 0; $i < $unsubscribedcount; $i++) {
824
            \mod_forum\subscriptions::unsubscribe_user($users[$i]->id, $forum);
825
        }
826
 
827
        // The subscription count should now take into account those users who have been unsubscribed.
828
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
829
        $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
830
    }
831
 
832
    /**
833
     * Test that the correct users are returned hwen fetching subscribed users from a forum where users are forcibly
834
     * subscribed.
835
     */
11 efrain 836
    public function test_fetch_subscribed_users_forced(): void {
1 efrain 837
        global $DB;
838
 
839
        $this->resetAfterTest(true);
840
 
841
        // Create a course, with a forum. where users are initially subscribed.
842
        $course = $this->getDataGenerator()->create_course();
843
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
844
        $forum = $this->getDataGenerator()->create_module('forum', $options);
845
 
846
        // Create some user enrolled in the course as a student.
847
        $usercount = 5;
848
        $users = $this->helper_create_users($course, $usercount);
849
 
850
        // All users should be subscribed.
851
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
852
        $this->assertEquals($usercount, count($subscribers));
853
    }
854
 
855
    /**
856
     * Test that unusual combinations of discussion subscriptions do not affect the subscribed user list.
857
     */
11 efrain 858
    public function test_fetch_subscribed_users_discussion_subscriptions(): void {
1 efrain 859
        global $DB;
860
 
861
        $this->resetAfterTest(true);
862
 
863
        // Create a course, with a forum. where users are initially subscribed.
864
        $course = $this->getDataGenerator()->create_course();
865
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
866
        $forum = $this->getDataGenerator()->create_module('forum', $options);
867
 
868
        // Create some user enrolled in the course as a student.
869
        $usercount = 5;
870
        $users = $this->helper_create_users($course, $usercount);
871
 
872
        list($discussion, $post) = $this->helper_post_to_forum($forum, $users[0]);
873
 
874
        // All users should be subscribed.
875
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
876
        $this->assertEquals($usercount, count($subscribers));
877
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
878
        $this->assertEquals($usercount, count($subscribers));
879
 
880
        \mod_forum\subscriptions::unsubscribe_user_from_discussion($users[0]->id, $discussion);
881
 
882
        // All users should be subscribed.
883
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
884
        $this->assertEquals($usercount, count($subscribers));
885
 
886
        // All users should be subscribed.
887
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
888
        $this->assertEquals($usercount, count($subscribers));
889
 
890
        // Manually insert an extra subscription for one of the users.
891
        $record = new \stdClass();
892
        $record->userid = $users[2]->id;
893
        $record->forum = $forum->id;
894
        $record->discussion = $discussion->id;
895
        $record->preference = time();
896
        $DB->insert_record('forum_discussion_subs', $record);
897
 
898
        // The discussion count should not have changed.
899
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
900
        $this->assertEquals($usercount, count($subscribers));
901
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
902
        $this->assertEquals($usercount, count($subscribers));
903
 
904
        // Unsubscribe 2 users.
905
        $unsubscribedcount = 2;
906
        for ($i = 0; $i < $unsubscribedcount; $i++) {
907
            \mod_forum\subscriptions::unsubscribe_user($users[$i]->id, $forum);
908
        }
909
 
910
        // The subscription count should now take into account those users who have been unsubscribed.
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, count($subscribers));
915
 
916
        // Now subscribe one of those users back to the discussion.
917
        $subscribeddiscussionusers = 1;
918
        for ($i = 0; $i < $subscribeddiscussionusers; $i++) {
919
            \mod_forum\subscriptions::subscribe_user_to_discussion($users[$i]->id, $discussion);
920
        }
921
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum);
922
        $this->assertEquals($usercount - $unsubscribedcount, count($subscribers));
923
        $subscribers = \mod_forum\subscriptions::fetch_subscribed_users($forum, 0, null, null, true);
924
        $this->assertEquals($usercount - $unsubscribedcount + $subscribeddiscussionusers, count($subscribers));
925
    }
926
 
927
    /**
928
     * Test whether a user is force-subscribed to a forum.
929
     */
11 efrain 930
    public function test_force_subscribed_to_forum(): void {
1 efrain 931
        global $DB;
932
 
933
        $this->resetAfterTest(true);
934
 
935
        // Create a course, with a forum.
936
        $course = $this->getDataGenerator()->create_course();
937
 
938
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
939
        $forum = $this->getDataGenerator()->create_module('forum', $options);
940
 
941
        // Create a user enrolled in the course as a student.
942
        $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
943
        $user = $this->getDataGenerator()->create_user();
944
        $this->getDataGenerator()->enrol_user($user->id, $course->id, $roleids['student']);
945
 
946
        // Check that the user is currently subscribed to the forum.
947
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
948
 
949
        // Remove the allowforcesubscribe capability from the user.
950
        $cm = get_coursemodule_from_instance('forum', $forum->id);
951
        $context = \context_module::instance($cm->id);
952
        assign_capability('mod/forum:allowforcesubscribe', CAP_PROHIBIT, $roleids['student'], $context);
953
        $this->assertFalse(has_capability('mod/forum:allowforcesubscribe', $context, $user->id));
954
 
955
        // Check that the user is no longer subscribed to the forum.
956
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
957
    }
958
 
959
    /**
960
     * Test that the subscription cache can be pre-filled.
961
     */
11 efrain 962
    public function test_subscription_cache_prefill(): void {
1 efrain 963
        global $DB;
964
 
965
        $this->resetAfterTest(true);
966
 
967
        // Create a course, with a forum.
968
        $course = $this->getDataGenerator()->create_course();
969
 
970
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
971
        $forum = $this->getDataGenerator()->create_module('forum', $options);
972
 
973
        // Create some users.
974
        $users = $this->helper_create_users($course, 20);
975
 
976
        // Reset the subscription cache.
977
        \mod_forum\subscriptions::reset_forum_cache();
978
 
979
        // Filling the subscription cache should use a query.
980
        $startcount = $DB->perf_get_reads();
981
        $this->assertNull(\mod_forum\subscriptions::fill_subscription_cache($forum->id));
982
        $postfillcount = $DB->perf_get_reads();
983
        $this->assertNotEquals($postfillcount, $startcount);
984
 
985
        // Now fetch some subscriptions from that forum - these should use
986
        // the cache and not perform additional queries.
987
        foreach ($users as $user) {
988
            $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($forum->id, $user->id));
989
        }
990
        $finalcount = $DB->perf_get_reads();
991
        $this->assertEquals(0, $finalcount - $postfillcount);
992
    }
993
 
994
    /**
995
     * Test that the subscription cache can filled user-at-a-time.
996
     */
11 efrain 997
    public function test_subscription_cache_fill(): void {
1 efrain 998
        global $DB;
999
 
1000
        $this->resetAfterTest(true);
1001
 
1002
        // Create a course, with a forum.
1003
        $course = $this->getDataGenerator()->create_course();
1004
 
1005
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1006
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1007
 
1008
        // Create some users.
1009
        $users = $this->helper_create_users($course, 20);
1010
 
1011
        // Reset the subscription cache.
1012
        \mod_forum\subscriptions::reset_forum_cache();
1013
 
1014
        // Filling the subscription cache should only use a single query.
1015
        $startcount = $DB->perf_get_reads();
1016
 
1017
        // Fetch some subscriptions from that forum - these should not use the cache and will perform additional queries.
1018
        foreach ($users as $user) {
1019
            $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($forum->id, $user->id));
1020
        }
1021
        $finalcount = $DB->perf_get_reads();
1022
        $this->assertEquals(20, $finalcount - $startcount);
1023
    }
1024
 
1025
    /**
1026
     * Test that the discussion subscription cache can filled course-at-a-time.
1027
     */
11 efrain 1028
    public function test_discussion_subscription_cache_fill_for_course(): void {
1 efrain 1029
        global $DB;
1030
 
1031
        $this->resetAfterTest(true);
1032
 
1033
        // Create a course, with a forum.
1034
        $course = $this->getDataGenerator()->create_course();
1035
 
1036
        // Create the forums.
1037
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE);
1038
        $disallowforum = $this->getDataGenerator()->create_module('forum', $options);
1039
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
1040
        $chooseforum = $this->getDataGenerator()->create_module('forum', $options);
1041
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1042
        $initialforum = $this->getDataGenerator()->create_module('forum', $options);
1043
 
1044
        // Create some users and keep a reference to the first user.
1045
        $users = $this->helper_create_users($course, 20);
1046
        $user = reset($users);
1047
 
1048
        // Reset the subscription caches.
1049
        \mod_forum\subscriptions::reset_forum_cache();
1050
 
1051
        $startcount = $DB->perf_get_reads();
1052
        $result = \mod_forum\subscriptions::fill_subscription_cache_for_course($course->id, $user->id);
1053
        $this->assertNull($result);
1054
        $postfillcount = $DB->perf_get_reads();
1055
        $this->assertNotEquals($postfillcount, $startcount);
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
        $finalcount = $DB->perf_get_reads();
1060
        $this->assertEquals(0, $finalcount - $postfillcount);
1061
 
1062
        // Test for all users.
1063
        foreach ($users as $user) {
1064
            $result = \mod_forum\subscriptions::fill_subscription_cache_for_course($course->id, $user->id);
1065
            $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($disallowforum->id, $user->id));
1066
            $this->assertFalse(\mod_forum\subscriptions::fetch_subscription_cache($chooseforum->id, $user->id));
1067
            $this->assertTrue(\mod_forum\subscriptions::fetch_subscription_cache($initialforum->id, $user->id));
1068
        }
1069
        $finalcount = $DB->perf_get_reads();
1070
        $this->assertNotEquals($finalcount, $postfillcount);
1071
    }
1072
 
1073
    /**
1074
     * Test that the discussion subscription cache can be forcibly updated for a user.
1075
     */
11 efrain 1076
    public function test_discussion_subscription_cache_prefill(): void {
1 efrain 1077
        global $DB;
1078
 
1079
        $this->resetAfterTest(true);
1080
 
1081
        // Create a course, with a forum.
1082
        $course = $this->getDataGenerator()->create_course();
1083
 
1084
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
1085
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1086
 
1087
        // Create some users.
1088
        $users = $this->helper_create_users($course, 20);
1089
 
1090
        // Post some discussions to the forum.
1091
        $discussions = array();
1092
        $author = $users[0];
1093
        $userwithnosubs = $users[1];
1094
 
1095
        for ($i = 0; $i < 20; $i++) {
1096
            list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1097
            $discussions[] = $discussion;
1098
        }
1099
 
1100
        // Unsubscribe half the users from the half the discussions.
1101
        $forumcount = 0;
1102
        $usercount = 0;
1103
        $userwithsubs = null;
1104
        foreach ($discussions as $data) {
1105
            // Unsubscribe user from all discussions.
1106
            \mod_forum\subscriptions::unsubscribe_user_from_discussion($userwithnosubs->id, $data);
1107
 
1108
            if ($forumcount % 2) {
1109
                continue;
1110
            }
1111
            foreach ($users as $user) {
1112
                if ($usercount % 2) {
1113
                    $userwithsubs = $user;
1114
                    continue;
1115
                }
1116
                \mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $data);
1117
                $usercount++;
1118
            }
1119
            $forumcount++;
1120
        }
1121
 
1122
        // Reset the subscription caches.
1123
        \mod_forum\subscriptions::reset_forum_cache();
1124
        \mod_forum\subscriptions::reset_discussion_cache();
1125
 
1126
        // A user with no subscriptions should only be fetched once.
1127
        $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id, $userwithnosubs->id));
1128
        $startcount = $DB->perf_get_reads();
1129
        $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id, $userwithnosubs->id));
1130
        $this->assertEquals($startcount, $DB->perf_get_reads());
1131
 
1132
        // Confirm subsequent calls properly tries to fetch subs.
1133
        $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id, $userwithsubs->id));
1134
        $this->assertNotEquals($startcount, $DB->perf_get_reads());
1135
 
1136
        // Another read should be performed to get all subscriptions for the forum.
1137
        $startcount = $DB->perf_get_reads();
1138
        $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id));
1139
        $this->assertNotEquals($startcount, $DB->perf_get_reads());
1140
 
1141
        // Reset the subscription caches.
1142
        \mod_forum\subscriptions::reset_forum_cache();
1143
        \mod_forum\subscriptions::reset_discussion_cache();
1144
 
1145
        // Filling the discussion subscription cache should only use a single query.
1146
        $startcount = $DB->perf_get_reads();
1147
        $this->assertNull(\mod_forum\subscriptions::fill_discussion_subscription_cache($forum->id));
1148
        $postfillcount = $DB->perf_get_reads();
1149
        $this->assertNotEquals($postfillcount, $startcount);
1150
 
1151
        // Now fetch some subscriptions from that forum - these should use
1152
        // the cache and not perform additional queries.
1153
        foreach ($users as $user) {
1154
            $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $user->id);
1155
            $this->assertIsArray($result);
1156
        }
1157
        $finalcount = $DB->perf_get_reads();
1158
        $this->assertEquals(0, $finalcount - $postfillcount);
1159
    }
1160
 
1161
    /**
1162
     * Test that the discussion subscription cache can filled user-at-a-time.
1163
     */
11 efrain 1164
    public function test_discussion_subscription_cache_fill(): void {
1 efrain 1165
        global $DB;
1166
 
1167
        $this->resetAfterTest(true);
1168
 
1169
        // Create a course, with a forum.
1170
        $course = $this->getDataGenerator()->create_course();
1171
 
1172
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE);
1173
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1174
 
1175
        // Create some users.
1176
        $users = $this->helper_create_users($course, 20);
1177
 
1178
        // Post some discussions to the forum.
1179
        $discussions = array();
1180
        $author = $users[0];
1181
        for ($i = 0; $i < 20; $i++) {
1182
            list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1183
            $discussions[] = $discussion;
1184
        }
1185
 
1186
        // Unsubscribe half the users from the half the discussions.
1187
        $forumcount = 0;
1188
        $usercount = 0;
1189
        foreach ($discussions as $data) {
1190
            if ($forumcount % 2) {
1191
                continue;
1192
            }
1193
            foreach ($users as $user) {
1194
                if ($usercount % 2) {
1195
                    continue;
1196
                }
1197
                \mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion);
1198
                $usercount++;
1199
            }
1200
            $forumcount++;
1201
        }
1202
 
1203
        // Reset the subscription caches.
1204
        \mod_forum\subscriptions::reset_forum_cache();
1205
        \mod_forum\subscriptions::reset_discussion_cache();
1206
 
1207
        $startcount = $DB->perf_get_reads();
1208
 
1209
        // Now fetch some subscriptions from that forum - these should use
1210
        // the cache and not perform additional queries.
1211
        foreach ($users as $user) {
1212
            $result = \mod_forum\subscriptions::fetch_discussion_subscription($forum->id, $user->id);
1213
            $this->assertIsArray($result);
1214
        }
1215
        $finalcount = $DB->perf_get_reads();
1216
        $this->assertNotEquals($finalcount, $startcount);
1217
    }
1218
 
1219
    /**
1220
     * Test that after toggling the forum subscription as another user,
1221
     * the discussion subscription functionality works as expected.
1222
     */
11 efrain 1223
    public function test_forum_subscribe_toggle_as_other_repeat_subscriptions(): void {
1 efrain 1224
        global $DB;
1225
 
1226
        $this->resetAfterTest(true);
1227
 
1228
        // Create a course, with a forum.
1229
        $course = $this->getDataGenerator()->create_course();
1230
 
1231
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE);
1232
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1233
 
1234
        // Create a user enrolled in the course as a student.
1235
        list($user) = $this->helper_create_users($course, 1);
1236
 
1237
        // Post a discussion to the forum.
1238
        list($discussion, $post) = $this->helper_post_to_forum($forum, $user);
1239
 
1240
        // Confirm that the user is currently not subscribed to the forum.
1241
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1242
 
1243
        // Confirm that the user is unsubscribed from the discussion too.
1244
        $this->assertFalse(\mod_forum\subscriptions::is_subscribed($user->id, $forum, $discussion->id));
1245
 
1246
        // Confirm that we have no records in either of the subscription tables.
1247
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1248
            'userid'        => $user->id,
1249
            'forum'         => $forum->id,
1250
        )));
1251
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
1252
            'userid'        => $user->id,
1253
            'discussion'    => $discussion->id,
1254
        )));
1255
 
1256
        // Subscribing to the forum should create a record in the subscriptions table, but not the forum discussion
1257
        // subscriptions table.
1258
        \mod_forum\subscriptions::subscribe_user($user->id, $forum);
1259
        $this->assertEquals(1, $DB->count_records('forum_subscriptions', array(
1260
            'userid'        => $user->id,
1261
            'forum'         => $forum->id,
1262
        )));
1263
        $this->assertEquals(0, $DB->count_records('forum_discussion_subs', array(
1264
            'userid'        => $user->id,
1265
            'discussion'    => $discussion->id,
1266
        )));
1267
 
1268
        // Now unsubscribe from the discussion. This should return true.
1269
        $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1270
 
1271
        // Attempting to unsubscribe again should return false because no change was made.
1272
        $this->assertFalse(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1273
 
1274
        // Subscribing to the discussion again should return truthfully as the subscription preference was removed.
1275
        $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1276
 
1277
        // Attempting to subscribe again should return false because no change was made.
1278
        $this->assertFalse(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1279
 
1280
        // Now unsubscribe from the discussion. This should return true once more.
1281
        $this->assertTrue(\mod_forum\subscriptions::unsubscribe_user_from_discussion($user->id, $discussion));
1282
 
1283
        // And unsubscribing from the forum but not as a request from the user should maintain their preference.
1284
        \mod_forum\subscriptions::unsubscribe_user($user->id, $forum);
1285
 
1286
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1287
            'userid'        => $user->id,
1288
            'forum'         => $forum->id,
1289
        )));
1290
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
1291
            'userid'        => $user->id,
1292
            'discussion'    => $discussion->id,
1293
        )));
1294
 
1295
        // Subscribing to the discussion should return truthfully because a change was made.
1296
        $this->assertTrue(\mod_forum\subscriptions::subscribe_user_to_discussion($user->id, $discussion));
1297
        $this->assertEquals(0, $DB->count_records('forum_subscriptions', array(
1298
            'userid'        => $user->id,
1299
            'forum'         => $forum->id,
1300
        )));
1301
        $this->assertEquals(1, $DB->count_records('forum_discussion_subs', array(
1302
            'userid'        => $user->id,
1303
            'discussion'    => $discussion->id,
1304
        )));
1305
    }
1306
 
1307
    /**
1308
     * Test that providing a context_module instance to is_subscribed does not result in additional lookups to retrieve
1309
     * the context_module.
1310
     */
11 efrain 1311
    public function test_is_subscribed_cm(): void {
1 efrain 1312
        global $DB;
1313
 
1314
        $this->resetAfterTest(true);
1315
 
1316
        // Create a course, with a forum.
1317
        $course = $this->getDataGenerator()->create_course();
1318
 
1319
        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
1320
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1321
 
1322
        // Create a user enrolled in the course as a student.
1323
        list($user) = $this->helper_create_users($course, 1);
1324
 
1325
        // Retrieve the $cm now.
1326
        $cm = get_fast_modinfo($forum->course)->instances['forum'][$forum->id];
1327
 
1328
        // Reset get_fast_modinfo.
1329
        get_fast_modinfo(0, 0, true);
1330
 
1331
        // Call is_subscribed without passing the $cmid - this should result in a lookup and filling of some of the
1332
        // caches. This provides us with consistent data to start from.
1333
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1334
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1335
 
1336
        // Make a note of the number of DB calls.
1337
        $basecount = $DB->perf_get_reads();
1338
 
1339
        // Call is_subscribed - it should give return the correct result (False), and result in no additional queries.
1340
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum, null, $cm));
1341
 
1342
        // The capability check does require some queries, so we don't test it directly.
1343
        // We don't assert here because this is dependant upon linked code which could change at any time.
1344
        $suppliedcmcount = $DB->perf_get_reads() - $basecount;
1345
 
1346
        // Call is_subscribed without passing the $cmid now - this should result in a lookup.
1347
        get_fast_modinfo(0, 0, true);
1348
        $basecount = $DB->perf_get_reads();
1349
        $this->assertTrue(\mod_forum\subscriptions::is_subscribed($user->id, $forum));
1350
        $calculatedcmcount = $DB->perf_get_reads() - $basecount;
1351
 
1352
        // There should be more queries than when we performed the same check a moment ago.
1353
        $this->assertGreaterThan($suppliedcmcount, $calculatedcmcount);
1354
    }
1355
 
1356
    public function is_subscribable_forums() {
1357
        return [
1358
            [
1359
                'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE,
1360
            ],
1361
            [
1362
                'forcesubscribe' => FORUM_CHOOSESUBSCRIBE,
1363
            ],
1364
            [
1365
                'forcesubscribe' => FORUM_INITIALSUBSCRIBE,
1366
            ],
1367
            [
1368
                'forcesubscribe' => FORUM_FORCESUBSCRIBE,
1369
            ],
1370
        ];
1371
    }
1372
 
1373
    public function is_subscribable_provider() {
1374
        $data = [];
1375
        foreach ($this->is_subscribable_forums() as $forum) {
1376
            $data[] = [$forum];
1377
        }
1378
 
1379
        return $data;
1380
    }
1381
 
1382
    /**
1383
     * @dataProvider is_subscribable_provider
1384
     */
11 efrain 1385
    public function test_is_subscribable_logged_out($options): void {
1 efrain 1386
        $this->resetAfterTest(true);
1387
 
1388
        // Create a course, with a forum.
1389
        $course = $this->getDataGenerator()->create_course();
1390
        $options['course'] = $course->id;
1391
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1392
 
1393
        $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
1394
    }
1395
 
1396
    /**
1397
     * @dataProvider is_subscribable_provider
1398
     */
11 efrain 1399
    public function test_is_subscribable_is_guest($options): void {
1 efrain 1400
        global $DB;
1401
        $this->resetAfterTest(true);
1402
 
1403
        $guest = $DB->get_record('user', array('username'=>'guest'));
1404
        $this->setUser($guest);
1405
 
1406
        // Create a course, with a forum.
1407
        $course = $this->getDataGenerator()->create_course();
1408
        $options['course'] = $course->id;
1409
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1410
 
1411
        $this->assertFalse(\mod_forum\subscriptions::is_subscribable($forum));
1412
    }
1413
 
1414
    public function is_subscribable_loggedin_provider() {
1415
        return [
1416
            [
1417
                ['forcesubscribe' => FORUM_DISALLOWSUBSCRIBE],
1418
                false,
1419
            ],
1420
            [
1421
                ['forcesubscribe' => FORUM_CHOOSESUBSCRIBE],
1422
                true,
1423
            ],
1424
            [
1425
                ['forcesubscribe' => FORUM_INITIALSUBSCRIBE],
1426
                true,
1427
            ],
1428
            [
1429
                ['forcesubscribe' => FORUM_FORCESUBSCRIBE],
1430
                false,
1431
            ],
1432
        ];
1433
    }
1434
 
1435
    /**
1436
     * @dataProvider is_subscribable_loggedin_provider
1437
     */
11 efrain 1438
    public function test_is_subscribable_loggedin($options, $expect): void {
1 efrain 1439
        $this->resetAfterTest(true);
1440
 
1441
        // Create a course, with a forum.
1442
        $course = $this->getDataGenerator()->create_course();
1443
        $options['course'] = $course->id;
1444
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1445
 
1446
        $user = $this->getDataGenerator()->create_user();
1447
        $this->getDataGenerator()->enrol_user($user->id, $course->id);
1448
        $this->setUser($user);
1449
 
1450
        $this->assertEquals($expect, \mod_forum\subscriptions::is_subscribable($forum));
1451
    }
1452
 
11 efrain 1453
    public function test_get_user_default_subscription(): void {
1 efrain 1454
        global $DB;
1455
        $this->resetAfterTest(true);
1456
 
1457
        // Create a course, with a forum.
1458
        $course = $this->getDataGenerator()->create_course();
1459
        $context = \context_course::instance($course->id);
1460
        $options['course'] = $course->id;
1461
        $forum = $this->getDataGenerator()->create_module('forum', $options);
1462
        $cm = get_coursemodule_from_instance("forum", $forum->id, $course->id);
1463
 
1464
        // Create a user enrolled in the course as a student.
1465
        list($author, $student) = $this->helper_create_users($course, 2, 'student');
1466
        // Post a discussion to the forum.
1467
        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
1468
 
1469
        // A guest user.
1470
        $this->setUser(0);
1471
        $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1472
        $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1473
 
1474
        // A user enrolled in the course.
1475
        $this->setUser($author->id);
1476
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1477
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1478
 
1479
        // Subscribption disabled.
1480
        $this->setUser($student->id);
1481
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_DISALLOWSUBSCRIBE);
1482
        $forum = $DB->get_record('forum', array('id' => $forum->id));
1483
        $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1484
        $this->assertFalse((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1485
 
1486
        \mod_forum\subscriptions::set_subscription_mode($forum, FORUM_FORCESUBSCRIBE);
1487
        $forum = $DB->get_record('forum', array('id' => $forum->id));
1488
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1489
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1490
 
1491
        // Admin user.
1492
        $this->setAdminUser();
1493
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, $discussion->id));
1494
        $this->assertTrue((boolean)\mod_forum\subscriptions::get_user_default_subscription($forum, $context, $cm, null));
1495
    }
1496
}