From a7a849038a91efc8acd0b0ac4ba3d393538fe9cd Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Thu, 5 Jun 2014 20:59:18 +0800 Subject: [PATCH] MDL-1626 mod_forum: Add unit tests for forum cron mail behaviour --- mod/forum/tests/mail_test.php | 390 ++++++++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) create mode 100644 mod/forum/tests/mail_test.php diff --git a/mod/forum/tests/mail_test.php b/mod/forum/tests/mail_test.php new file mode 100644 index 00000000000..909ed6f79c4 --- /dev/null +++ b/mod/forum/tests/mail_test.php @@ -0,0 +1,390 @@ +. + +/** + * The forum module mail generation tests. + * + * @package mod_forum + * @category external + * @copyright 2013 Andrew Nicols + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; + +class mod_forum_mail_testcase extends advanced_testcase { + + protected $helper; + + public function setUp() { + global $CFG; + require_once($CFG->dirroot . '/mod/forum/lib.php'); + + $helper = new stdClass(); + + // Messaging is not compatible with transactions... + $this->preventResetByRollback(); + + // Catch all messages. + $helper->messagesink = $this->redirectMessages(); + $helper->mailsink = $this->redirectEmails(); + + // Confirm that we have an empty message sink so far. + $messages = $helper->messagesink->get_messages(); + $this->assertEquals(0, count($messages)); + + $messages = $helper->mailsink->get_messages(); + $this->assertEquals(0, count($messages)); + + // Forcibly reduce the maxeditingtime to a one second to ensure that + // messages are sent out. + $CFG->maxeditingtime = 1; + + // Ensure that we don't prevent e-mail as this will cause unit test failures. + $CFG->noemailever = false; + + $this->helper = $helper; + } + + public function tearDown() { + $this->helper->messagesink->clear(); + $this->helper->messagesink->close(); + + $this->helper->mailsink->clear(); + $this->helper->mailsink->close(); + } + + /** + * Helper to create the required number of users in the specified + * course. + * Users are enrolled as students. + * + * @param stdClass $course The course object + * @param integer $count The number of users to create + * @return array The users created + */ + protected function helper_create_users($course, $count) { + $users = array(); + + for ($i = 0; $i < $count; $i++) { + $user = $this->getDataGenerator()->create_user(); + $this->getDataGenerator()->enrol_user($user->id, $course->id); + $users[] = $user; + } + + return $users; + } + + /** + * Create a new discussion and post within the specified forum, as the + * specified author. + * + * @param stdClass $forum The forum to post in + * @param stdClass $author The author to post as + * @param array An array containing the discussion object, and the post object + */ + protected function helper_post_to_forum($forum, $author) { + $generator = $this->getDataGenerator()->get_plugin_generator('mod_forum'); + + // Create a discussion in the forum, and then add a post to that discussion. + $record = new stdClass(); + $record->course = $forum->course; + $record->userid = $author->id; + $record->forum = $forum->id; + $discussion = $generator->create_discussion($record); + + $record = new stdClass(); + $record->course = $forum->course; + $record->userid = $author->id; + $record->forum = $forum->id; + $record->discussion = $discussion->id; + $record->mailnow = 1; + $post = $generator->create_post($record); + + return array($discussion, $post); + } + + /** + * Run the forum cron, and check that the specified post was sent the + * specified number of times. + * + * @param stdClass $post The forum post object + * @param integer $expected The number of times that the post should have been sent + * @return array An array of the messages caught by the message sink + */ + protected function helper_run_cron_check_count($post, $expected) { + // Clear the sinks before running cron. + $this->helper->messagesink->clear(); + $this->helper->mailsink->clear(); + + // Cron daily uses mtrace, turn on buffering to silence output. + $this->expectOutputRegex("/{$expected} users were sent post {$post->id}, '{$post->subject}'/"); + forum_cron(); + + // Now check the results in the message sink. + $messages = $this->helper->messagesink->get_messages(); + + // There should be the expected number of messages. + $this->assertEquals($expected, count($messages)); + + return $messages; + } + + public function test_forced_subscription() { + $this->resetAfterTest(true); + + // Create a course, with a forum. + $course = $this->getDataGenerator()->create_course(); + + $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE); + $forum = $this->getDataGenerator()->create_module('forum', $options); + + // Create two users enrolled in the course as students. + list($author, $recipient) = $this->helper_create_users($course, 2); + + // Post a discussion to the forum. + list($discussion, $post) = $this->helper_post_to_forum($forum, $author); + + // We expect both users to receive this post. + $expected = 2; + + // Run cron and check that the expected number of users received the notification. + $messages = $this->helper_run_cron_check_count($post, $expected); + + $seenauthor = false; + $seenrecipient = false; + foreach ($messages as $message) { + // They should both be from our user. + $this->assertEquals($author->id, $message->useridfrom); + + if ($message->useridto == $author->id) { + $seenauthor = true; + } else if ($message->useridto = $recipient->id) { + $seenrecipient = true; + } + } + + // Check we saw messages for both users. + $this->assertTrue($seenauthor); + $this->assertTrue($seenrecipient); + } + + public function test_subscription_disabled() { + global $DB; + + $this->resetAfterTest(true); + + // Create a course, with a forum. + $course = $this->getDataGenerator()->create_course(); + + $options = array('course' => $course->id, 'forcesubscribe' => FORUM_DISALLOWSUBSCRIBE); + $forum = $this->getDataGenerator()->create_module('forum', $options); + + // Create two users enrolled in the course as students. + list($author, $recipient) = $this->helper_create_users($course, 2); + + // Post a discussion to the forum. + list($discussion, $post) = $this->helper_post_to_forum($forum, $author); + + // We expect both users to receive this post. + $expected = 0; + + // Run cron and check that the expected number of users received the notification. + $messages = $this->helper_run_cron_check_count($post, $expected); + + // A user with the manageactivities capability within the course can subscribe. + $expected = 1; + $roleids = $DB->get_records_menu('role', null, '', 'shortname, id'); + assign_capability('moodle/course:manageactivities', CAP_ALLOW, $roleids['student'], context_course::instance($course->id)); + \mod_forum\subscriptions::subscribe_user($author->id, $forum); + + $this->assertEquals($expected, $DB->count_records('forum_subscriptions', array( + 'userid' => $author->id, + 'forum' => $forum->id, + ))); + + // Run cron and check that the expected number of users received the notification. + list($discussion, $post) = $this->helper_post_to_forum($forum, $author); + $messages = $this->helper_run_cron_check_count($post, $expected); + + // Unsubscribe the user again. + \mod_forum\subscriptions::unsubscribe_user($author->id, $forum); + + $expected = 0; + $this->assertEquals($expected, $DB->count_records('forum_subscriptions', array( + 'userid' => $author->id, + 'forum' => $forum->id, + ))); + + // Run cron and check that the expected number of users received the notification. + list($discussion, $post) = $this->helper_post_to_forum($forum, $author); + $messages = $this->helper_run_cron_check_count($post, $expected); + + // And unsubscribe the user from a new discussion + $expected = 1; + list($discussion, $post) = $this->helper_post_to_forum($forum, $author); + \mod_forum\subscriptions::subscribe_user_to_discussion($author->id, $discussion); + $messages = $this->helper_run_cron_check_count($post, $expected); + } + + public function test_automatic() { + $this->resetAfterTest(true); + + // Create a course, with a forum. + $course = $this->getDataGenerator()->create_course(); + + $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); + $forum = $this->getDataGenerator()->create_module('forum', $options); + + // Create two users enrolled in the course as students. + list($author, $recipient) = $this->helper_create_users($course, 2); + + // Post a discussion to the forum. + list($discussion, $post) = $this->helper_post_to_forum($forum, $author); + + // We expect both users to receive this post. + $expected = 2; + + // Run cron and check that the expected number of users received the notification. + $messages = $this->helper_run_cron_check_count($post, $expected); + + $seenauthor = false; + $seenrecipient = false; + foreach ($messages as $message) { + // They should both be from our user. + $this->assertEquals($author->id, $message->useridfrom); + + if ($message->useridto == $author->id) { + $seenauthor = true; + } else if ($message->useridto = $recipient->id) { + $seenrecipient = true; + } + } + + // Check we saw messages for both users. + $this->assertTrue($seenauthor); + $this->assertTrue($seenrecipient); + } + + public function test_optional() { + $this->resetAfterTest(true); + + // Create a course, with a forum. + $course = $this->getDataGenerator()->create_course(); + + $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); + $forum = $this->getDataGenerator()->create_module('forum', $options); + + // Create two users enrolled in the course as students. + list($author, $recipient) = $this->helper_create_users($course, 2); + + // Post a discussion to the forum. + list($discussion, $post) = $this->helper_post_to_forum($forum, $author); + + // We expect both users to receive this post. + $expected = 0; + + // Run cron and check that the expected number of users received the notification. + $messages = $this->helper_run_cron_check_count($post, $expected); + } + + public function test_automatic_with_unsubscribed_user() { + $this->resetAfterTest(true); + + // Create a course, with a forum. + $course = $this->getDataGenerator()->create_course(); + + $options = array('course' => $course->id, 'forcesubscribe' => FORUM_INITIALSUBSCRIBE); + $forum = $this->getDataGenerator()->create_module('forum', $options); + + // Create two users enrolled in the course as students. + list($author, $recipient) = $this->helper_create_users($course, 2); + + // Unsubscribe the 'author' user from the forum. + forum_unsubscribe($author->id, $forum->id); + + // Post a discussion to the forum. + list($discussion, $post) = $this->helper_post_to_forum($forum, $author); + + // We expect only one user to receive this post. + $expected = 1; + + // Run cron and check that the expected number of users received the notification. + $messages = $this->helper_run_cron_check_count($post, $expected); + + $seenauthor = false; + $seenrecipient = false; + foreach ($messages as $message) { + // They should both be from our user. + $this->assertEquals($author->id, $message->useridfrom); + + if ($message->useridto == $author->id) { + $seenauthor = true; + } else if ($message->useridto = $recipient->id) { + $seenrecipient = true; + } + } + + // Check we only saw one user. + $this->assertFalse($seenauthor); + $this->assertTrue($seenrecipient); + } + + public function test_optional_with_subscribed_user() { + $this->resetAfterTest(true); + + // Create a course, with a forum. + $course = $this->getDataGenerator()->create_course(); + + $options = array('course' => $course->id, 'forcesubscribe' => FORUM_CHOOSESUBSCRIBE); + $forum = $this->getDataGenerator()->create_module('forum', $options); + + // Create two users enrolled in the course as students. + list($author, $recipient) = $this->helper_create_users($course, 2); + + // Subscribe the 'recipient' user from the forum. + forum_subscribe($recipient->id, $forum->id); + + // Post a discussion to the forum. + list($discussion, $post) = $this->helper_post_to_forum($forum, $author); + + // We expect only one user to receive this post. + $expected = 1; + + // Run cron and check that the expected number of users received the notification. + $messages = $this->helper_run_cron_check_count($post, $expected); + + $seenauthor = false; + $seenrecipient = false; + foreach ($messages as $message) { + // They should both be from our user. + $this->assertEquals($author->id, $message->useridfrom); + + if ($message->useridto == $author->id) { + $seenauthor = true; + } else if ($message->useridto = $recipient->id) { + $seenrecipient = true; + } + } + + // Check we only saw one user. + $this->assertFalse($seenauthor); + $this->assertTrue($seenrecipient); + } + +}