diff --git a/mod/forum/tests/externallib_test.php b/mod/forum/tests/externallib_test.php index 786f350c8cc..8a1df829d43 100644 --- a/mod/forum/tests/externallib_test.php +++ b/mod/forum/tests/externallib_test.php @@ -35,7 +35,7 @@ require_once($CFG->dirroot . '/mod/forum/lib.php'); * @copyright 2012 Mark Nelson * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class externallib_test extends externallib_advanced_testcase { +final class externallib_test extends externallib_advanced_testcase { /** * Tests set up @@ -1056,6 +1056,8 @@ class externallib_test extends externallib_advanced_testcase { $this->resetAfterTest(true); + $clock = $this->mock_clock_with_frozen(); + // Set the CFG variable to allow track forums. $CFG->forum_trackreadposts = true; @@ -1105,7 +1107,7 @@ class externallib_test extends externallib_advanced_testcase { $record->userid = $user1->id; $record->forum = $forum1->id; $discussion1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); - sleep(1); + $clock->bump(); // Add three replies to the discussion 1 from different users. $record = new \stdClass(); @@ -1113,16 +1115,16 @@ class externallib_test extends externallib_advanced_testcase { $record->parent = $discussion1->firstpost; $record->userid = $user2->id; $discussion1reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); - sleep(1); + $clock->bump(); $record->parent = $discussion1reply1->id; $record->userid = $user3->id; $discussion1reply2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); - sleep(1); + $clock->bump(); $record->userid = $user4->id; $discussion1reply3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); - sleep(1); + $clock->bump(); // Create discussion2. $record2 = new \stdClass(); @@ -1130,7 +1132,7 @@ class externallib_test extends externallib_advanced_testcase { $record2->userid = $user1->id; $record2->forum = $forum1->id; $discussion2 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record2); - sleep(1); + $clock->bump(); // Add one reply to the discussion 2. $record2 = new \stdClass(); @@ -1138,7 +1140,7 @@ class externallib_test extends externallib_advanced_testcase { $record2->parent = $discussion2->firstpost; $record2->userid = $user2->id; $discussion2reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record2); - sleep(1); + $clock->bump(); // Create discussion 3. $record3 = new \stdClass(); @@ -1146,7 +1148,7 @@ class externallib_test extends externallib_advanced_testcase { $record3->userid = $user1->id; $record3->forum = $forum1->id; $discussion3 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record3); - sleep(1); + $clock->bump(); // Add two replies to the discussion 3. $record3 = new \stdClass(); @@ -1154,7 +1156,7 @@ class externallib_test extends externallib_advanced_testcase { $record3->parent = $discussion3->firstpost; $record3->userid = $user2->id; $discussion3reply1 = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record3); - sleep(1); + $clock->bump(); $record3->parent = $discussion3reply1->id; $record3->userid = $user3->id; diff --git a/mod/forum/tests/generator/lib.php b/mod/forum/tests/generator/lib.php index 2a078c1b9a4..de276702cc5 100644 --- a/mod/forum/tests/generator/lib.php +++ b/mod/forum/tests/generator/lib.php @@ -14,17 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . -/** - * mod_forum data generator - * - * @package mod_forum - * @category test - * @copyright 2012 Petr Skoda {@link http://skodak.org} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - /** * Forum module data generator class @@ -35,7 +24,6 @@ defined('MOODLE_INTERNAL') || die(); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class mod_forum_generator extends testing_module_generator { - /** * @var int keep track of how many forum discussions have been created. */ @@ -51,6 +39,15 @@ class mod_forum_generator extends testing_module_generator { */ protected $forumsubscriptionscount = 0; + /** + * Get the clock implementation to use when generating data. + * + * @return \core\clock + */ + protected function get_clock(): \core\clock { + return \core\di::get(\core\clock::class); + } + /** * To be called from data reset code only, * do not use in tests. @@ -188,8 +185,14 @@ class mod_forum_generator extends testing_module_generator { $record['mailnow'] = "0"; } + if (!isset($record['timecreated'])) { + $record['timecreated'] = $this->get_clock()->now()->getTimestamp(); + } + if (isset($record['timemodified'])) { $timemodified = $record['timemodified']; + } else { + $timemodified = $record['timecreated']; } if (!isset($record['pinned'])) { @@ -276,11 +279,19 @@ class mod_forum_generator extends testing_module_generator { } if (!isset($record['created'])) { - $record['created'] = $time; + // If we are using the system clock, then revert to the time + count approach. + // Unfortunately a lot of Forum code relies on things not happening at the same time. + // See MDL-80838 for more information on this issue. + + if ($this->get_clock() instanceof \core\system_clock) { + $record['created'] = $time; + } else { + $record['created'] = $this->get_clock()->now()->getTimestamp(); + } } if (!isset($record['modified'])) { - $record['modified'] = $time; + $record['modified'] = $record['created']; } if (!isset($record['mailed'])) { diff --git a/mod/forum/tests/generator_test.php b/mod/forum/tests/generator_test.php index ba190831095..daf9c01009d 100644 --- a/mod/forum/tests/generator_test.php +++ b/mod/forum/tests/generator_test.php @@ -20,12 +20,12 @@ namespace mod_forum; * PHPUnit data generator testcase * * @package mod_forum - * @category phpunit + * @category test * @copyright 2012 Petr Skoda {@link http://skodak.org} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @covers \mod_forum_generator */ -class generator_test extends \advanced_testcase { - +final class generator_test extends \advanced_testcase { public function setUp(): void { // We must clear the subscription caches. This has to be done both before each test, and after in case of other // tests using these functions. @@ -38,7 +38,7 @@ class generator_test extends \advanced_testcase { \mod_forum\subscriptions::reset_forum_cache(); } - public function test_generator() { + public function test_generator(): void { global $DB; $this->resetAfterTest(true); @@ -52,9 +52,9 @@ class generator_test extends \advanced_testcase { $this->assertInstanceOf('mod_forum_generator', $generator); $this->assertEquals('forum', $generator->get_modulename()); - $generator->create_instance(array('course'=>$course->id)); - $generator->create_instance(array('course'=>$course->id)); - $forum = $generator->create_instance(array('course'=>$course->id)); + $generator->create_instance(['course' => $course->id]); + $generator->create_instance(['course' => $course->id]); + $forum = $generator->create_instance(['course' => $course->id]); $this->assertEquals(3, $DB->count_records('forum')); $cm = get_coursemodule_from_instance('forum', $forum->id); @@ -65,9 +65,12 @@ class generator_test extends \advanced_testcase { $context = \context_module::instance($cm->id); $this->assertEquals($forum->cmid, $context->instanceid); - // test gradebook integration using low level DB access - DO NOT USE IN PLUGIN CODE! - $forum = $generator->create_instance(array('course'=>$course->id, 'assessed'=>1, 'scale'=>100)); - $gitem = $DB->get_record('grade_items', array('courseid'=>$course->id, 'itemtype'=>'mod', 'itemmodule'=>'forum', 'iteminstance'=>$forum->id)); + // Test gradebook integration using low level DB access - DO NOT USE IN PLUGIN CODE. + $forum = $generator->create_instance(['course' => $course->id, 'assessed' => 1, 'scale' => 100]); + $gitem = $DB->get_record( + 'grade_items', + ['courseid' => $course->id, 'itemtype' => 'mod', 'itemmodule' => 'forum', 'iteminstance' => $forum->id] + ); $this->assertNotEmpty($gitem); $this->assertEquals(100, $gitem->grademax); $this->assertEquals(0, $gitem->grademin); @@ -77,7 +80,7 @@ class generator_test extends \advanced_testcase { /** * Test create_discussion. */ - public function test_create_discussion() { + public function test_create_discussion(): void { global $DB; $this->resetAfterTest(true); @@ -94,7 +97,7 @@ class generator_test extends \advanced_testcase { $forum = self::getDataGenerator()->create_module('forum', $record); // Add a few discussions. - $record = array(); + $record = []; $record['course'] = $course->id; $record['forum'] = $forum->id; $record['userid'] = $user->id; @@ -105,24 +108,29 @@ class generator_test extends \advanced_testcase { self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); // Check the discussions were correctly created. - $this->assertEquals(3, $DB->count_records_select('forum_discussions', 'forum = :forum', - array('forum' => $forum->id))); + $this->assertEquals(3, $DB->count_records_select( + 'forum_discussions', + 'forum = :forum', + ['forum' => $forum->id] + )); - $record['tags'] = array('Cats', 'mice'); + $record['tags'] = ['Cats', 'mice']; $record = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion($record); - $this->assertEquals(array('Cats', 'mice'), - array_values(\core_tag_tag::get_item_tags_array('mod_forum', 'forum_posts', $record->firstpost))); + $this->assertEquals( + ['Cats', 'mice'], + array_values(\core_tag_tag::get_item_tags_array('mod_forum', 'forum_posts', $record->firstpost)) + ); } /** * Test create_post. */ - public function test_create_post() { + public function test_create_post(): void { global $DB; $this->resetAfterTest(true); - // Create a bunch of users + // Create a bunch of users. $user1 = self::getDataGenerator()->create_user(); $user2 = self::getDataGenerator()->create_user(); $user3 = self::getDataGenerator()->create_user(); @@ -153,21 +161,26 @@ class generator_test extends \advanced_testcase { // Check the posts were correctly created, remember, when creating a discussion a post // is generated as well, so we should have 4 posts, not 3. - $this->assertEquals(4, $DB->count_records_select('forum_posts', 'discussion = :discussion', - array('discussion' => $discussion->id))); + $this->assertEquals(4, $DB->count_records_select( + 'forum_posts', + 'discussion = :discussion', + ['discussion' => $discussion->id] + )); - $record->tags = array('Cats', 'mice'); + $record->tags = ['Cats', 'mice']; $record = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post($record); - $this->assertEquals(array('Cats', 'mice'), - array_values(\core_tag_tag::get_item_tags_array('mod_forum', 'forum_posts', $record->id))); + $this->assertEquals( + ['Cats', 'mice'], + array_values(\core_tag_tag::get_item_tags_array('mod_forum', 'forum_posts', $record->id)) + ); } - public function test_create_content() { + public function test_create_content(): void { global $DB; $this->resetAfterTest(true); - // Create a bunch of users + // Create a bunch of users. $user1 = self::getDataGenerator()->create_user(); $user2 = self::getDataGenerator()->create_user(); $user3 = self::getDataGenerator()->create_user(); @@ -177,22 +190,22 @@ class generator_test extends \advanced_testcase { // Create course and forum. $course = self::getDataGenerator()->create_course(); - $forum = self::getDataGenerator()->create_module('forum', array('course' => $course)); + $forum = self::getDataGenerator()->create_module('forum', ['course' => $course]); $generator = self::getDataGenerator()->get_plugin_generator('mod_forum'); // This should create discussion. $post1 = $generator->create_content($forum); // This should create posts in the discussion. - $post2 = $generator->create_content($forum, array('parent' => $post1->id)); - $post3 = $generator->create_content($forum, array('discussion' => $post1->discussion)); + $post2 = $generator->create_content($forum, ['parent' => $post1->id]); + $post3 = $generator->create_content($forum, ['discussion' => $post1->discussion]); // This should create posts answering another post. - $post4 = $generator->create_content($forum, array('parent' => $post2->id)); + $post4 = $generator->create_content($forum, ['parent' => $post2->id]); // This should create post with tags. - $post5 = $generator->create_content($forum, array('parent' => $post2->id, 'tags' => array('Cats', 'mice'))); + $post5 = $generator->create_content($forum, ['parent' => $post2->id, 'tags' => ['Cats', 'mice']]); - $discussionrecords = $DB->get_records('forum_discussions', array('forum' => $forum->id)); + $discussionrecords = $DB->get_records('forum_discussions', ['forum' => $forum->id]); $postrecords = $DB->get_records('forum_posts'); - $postrecords2 = $DB->get_records('forum_posts', array('discussion' => $post1->discussion)); + $postrecords2 = $DB->get_records('forum_posts', ['discussion' => $post1->discussion]); $this->assertEquals(1, count($discussionrecords)); $this->assertEquals(5, count($postrecords)); $this->assertEquals(5, count($postrecords2)); @@ -201,7 +214,72 @@ class generator_test extends \advanced_testcase { $this->assertEquals($post1->id, $postrecords[$post3->id]->parent); $this->assertEquals($post2->id, $postrecords[$post4->id]->parent); - $this->assertEquals(array('Cats', 'mice'), - array_values(\core_tag_tag::get_item_tags_array('mod_forum', 'forum_posts', $post5->id))); + $this->assertEquals( + ['Cats', 'mice'], + array_values(\core_tag_tag::get_item_tags_array('mod_forum', 'forum_posts', $post5->id)) + ); + } + + public function test_create_post_time_system(): void { + $this->resetAfterTest(true); + + $user = self::getDataGenerator()->create_user(); + $course = $this->getDataGenerator()->create_course(); + $forum = self::getDataGenerator()->create_module('forum', (object) [ + 'course' => $course->id, + ]); + + $starttime = time(); + + // Add a discussion. + $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion((object) [ + 'course' => $course->id, + 'forum' => $forum->id, + 'userid' => $user->id, + ]); + + // Add a post. + $post = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post((object) [ + 'discussion' => $discussion->id, + 'userid' => $user->id, + ]); + + $this->assertGreaterThanOrEqual($starttime, $discussion->timemodified); + $this->assertGreaterThanOrEqual($starttime, $post->created); + + // The fallback behavior is to add the number of created posts to the current time to avoid duplicates. + $this->assertLessThanOrEqual(time() + 1, $discussion->timemodified); + $this->assertLessThanOrEqual(time() + 2, $post->created); + } + + public function test_create_post_time_frozen(): void { + $this->resetAfterTest(true); + + $clock = $this->mock_clock_with_frozen(100); + + $user = self::getDataGenerator()->create_user(); + $course = $this->getDataGenerator()->create_course(); + $forum = self::getDataGenerator()->create_module('forum', (object) [ + 'course' => $course->id, + ]); + + $starttime = time(); + + // Add a discussion. + $discussion = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_discussion((object) [ + 'course' => $course->id, + 'forum' => $forum->id, + 'userid' => $user->id, + ]); + $this->assertEquals(100, $discussion->timemodified); + + // Add a post. + $clock->set_to(200); + $post = self::getDataGenerator()->get_plugin_generator('mod_forum')->create_post((object) [ + 'discussion' => $discussion->id, + 'userid' => $user->id, + ]); + + $this->assertEquals(200, $post->created); } }