From 163d280053740c4723e4a973f66b5de35e80fdfb Mon Sep 17 00:00:00 2001 From: sam marshall Date: Wed, 20 Sep 2017 17:45:25 +0100 Subject: [PATCH] MDL-58885 core_search: Group support unit tests --- search/engine/solr/tests/engine_test.php | 113 ++++++++++++++++- search/tests/manager_test.php | 150 +++++++++++++++++++---- 2 files changed, 233 insertions(+), 30 deletions(-) diff --git a/search/engine/solr/tests/engine_test.php b/search/engine/solr/tests/engine_test.php index 6d3d1179423..7a4bcde943d 100644 --- a/search/engine/solr/tests/engine_test.php +++ b/search/engine/solr/tests/engine_test.php @@ -54,7 +54,7 @@ require_once($CFG->dirroot . '/search/engine/solr/tests/fixtures/testable_engine class search_solr_engine_testcase extends advanced_testcase { /** - * @var \core_search::manager + * @var \core_search\manager */ protected $search = null; @@ -707,18 +707,18 @@ class search_solr_engine_testcase extends advanced_testcase { $querydata->q = 'Something1 Something2 Something3 Something4'; // In this first set, it should have determined the first 10 of 40 are bad, so there could be up to 30 left. - $results = $this->engine->execute_query($querydata, true, 5); + $results = $this->engine->execute_query($querydata, (object)['everything' => true], 5); $this->assertEquals(30, $this->engine->get_query_total_count()); $this->assertCount(5, $results); // To get to 15, it has to process the first 10 that are bad, 10 that are good, 10 that are bad, then 5 that are good. // So we now know 20 are bad out of 40. - $results = $this->engine->execute_query($querydata, true, 15); + $results = $this->engine->execute_query($querydata, (object)['everything' => true], 15); $this->assertEquals(20, $this->engine->get_query_total_count()); $this->assertCount(15, $results); // Try to get more then all, make sure we still see 20 count and 20 returned. - $results = $this->engine->execute_query($querydata, true, 30); + $results = $this->engine->execute_query($querydata, (object)['everything' => true], 30); $this->assertEquals(20, $this->engine->get_query_total_count()); $this->assertCount(20, $results); } @@ -830,6 +830,111 @@ class search_solr_engine_testcase extends advanced_testcase { $this->assert_result_titles([], $results); } + /** + * Tests searching for results in groups, either by specified group ids or based on user + * access permissions. + */ + public function test_groups() { + global $USER; + + // Use real search areas. + $this->search->clear_static(); + $this->search->add_core_search_areas(); + + // Create 2 courses and a selection of forums with different group mode. + $generator = $this->getDataGenerator(); + $course1 = $generator->create_course(['fullname' => 'Course 1']); + $forum1nogroups = $generator->create_module('forum', ['course' => $course1, 'groupmode' => NOGROUPS]); + $forum1separategroups = $generator->create_module('forum', ['course' => $course1, 'groupmode' => SEPARATEGROUPS]); + $forum1visiblegroups = $generator->create_module('forum', ['course' => $course1, 'groupmode' => VISIBLEGROUPS]); + $course2 = $generator->create_course(['fullname' => 'Course 2']); + $forum2separategroups = $generator->create_module('forum', ['course' => $course2, 'groupmode' => SEPARATEGROUPS]); + + // Create two groups on each course. + $group1a = $generator->create_group(['courseid' => $course1->id]); + $group1b = $generator->create_group(['courseid' => $course1->id]); + $group2a = $generator->create_group(['courseid' => $course2->id]); + $group2b = $generator->create_group(['courseid' => $course2->id]); + + // Create search records in each activity and (where relevant) in each group. + $forumgenerator = $generator->get_plugin_generator('mod_forum'); + $forumgenerator->create_discussion(['course' => $course1->id, 'userid' => $USER->id, + 'forum' => $forum1nogroups->id, 'name' => 'F1NG', 'message' => 'xyzzy']); + $forumgenerator->create_discussion(['course' => $course1->id, 'userid' => $USER->id, + 'forum' => $forum1separategroups->id, 'name' => 'F1SG-A', 'message' => 'xyzzy', + 'groupid' => $group1a->id]); + $forumgenerator->create_discussion(['course' => $course1->id, 'userid' => $USER->id, + 'forum' => $forum1separategroups->id, 'name' => 'F1SG-B', 'message' => 'xyzzy', + 'groupid' => $group1b->id]); + $forumgenerator->create_discussion(['course' => $course1->id, 'userid' => $USER->id, + 'forum' => $forum1visiblegroups->id, 'name' => 'F1VG-A', 'message' => 'xyzzy', + 'groupid' => $group1a->id]); + $forumgenerator->create_discussion(['course' => $course1->id, 'userid' => $USER->id, + 'forum' => $forum1visiblegroups->id, 'name' => 'F1VG-B', 'message' => 'xyzzy', + 'groupid' => $group1b->id]); + $forumgenerator->create_discussion(['course' => $course2->id, 'userid' => $USER->id, + 'forum' => $forum2separategroups->id, 'name' => 'F2SG-A', 'message' => 'xyzzy', + 'groupid' => $group2a->id]); + $forumgenerator->create_discussion(['course' => $course2->id, 'userid' => $USER->id, + 'forum' => $forum2separategroups->id, 'name' => 'F2SG-B', 'message' => 'xyzzy', + 'groupid' => $group2b->id]); + + $this->search->index(); + + // Search as admin user should find everything. + $querydata = new stdClass(); + $querydata->q = 'xyzzy'; + $results = $this->search->search($querydata); + $this->assert_result_titles( + ['F1NG', 'F1SG-A', 'F1SG-B', 'F1VG-A', 'F1VG-B', 'F2SG-A', 'F2SG-B'], $results); + + // Admin user manually restricts results by groups. + $querydata->groupids = [$group1b->id, $group2a->id]; + $results = $this->search->search($querydata); + $this->assert_result_titles(['F1SG-B', 'F1VG-B', 'F2SG-A'], $results); + + // Student enrolled in both courses but no groups. + $student1 = $generator->create_user(); + $generator->enrol_user($student1->id, $course1->id, 'student'); + $generator->enrol_user($student1->id, $course2->id, 'student'); + $this->setUser($student1); + + unset($querydata->groupids); + $results = $this->search->search($querydata); + $this->assert_result_titles(['F1NG', 'F1VG-A', 'F1VG-B'], $results); + + // Student enrolled in both courses and group A in both cases. + $student2 = $generator->create_user(); + $generator->enrol_user($student2->id, $course1->id, 'student'); + $generator->enrol_user($student2->id, $course2->id, 'student'); + groups_add_member($group1a, $student2); + groups_add_member($group2a, $student2); + $this->setUser($student2); + + $results = $this->search->search($querydata); + $this->assert_result_titles(['F1NG', 'F1SG-A', 'F1VG-A', 'F1VG-B', 'F2SG-A'], $results); + + // Manually restrict results to group B in course 1. + $querydata->groupids = [$group1b->id]; + $results = $this->search->search($querydata); + $this->assert_result_titles(['F1VG-B'], $results); + + // Manually restrict results to group A in course 1. + $querydata->groupids = [$group1a->id]; + $results = $this->search->search($querydata); + $this->assert_result_titles(['F1SG-A', 'F1VG-A'], $results); + + // Manager enrolled in both courses (has access all groups). + $manager = $generator->create_user(); + $generator->enrol_user($manager->id, $course1->id, 'manager'); + $generator->enrol_user($manager->id, $course2->id, 'manager'); + $this->setUser($manager); + unset($querydata->groupids); + $results = $this->search->search($querydata); + $this->assert_result_titles( + ['F1NG', 'F1SG-A', 'F1SG-B', 'F1VG-A', 'F1VG-B', 'F2SG-A', 'F2SG-B'], $results); + } + /** * Asserts that the returned documents have the expected titles (regardless of order). * diff --git a/search/tests/manager_test.php b/search/tests/manager_test.php index b64cb159929..675bc6f0718 100644 --- a/search/tests/manager_test.php +++ b/search/tests/manager_test.php @@ -555,20 +555,20 @@ class search_manager_testcase extends advanced_testcase { $search->add_search_area($mockareaid, new core_mocksearch\search\mock_search_area()); $this->setAdminUser(); - $this->assertTrue($search->get_areas_user_accesses()); + $this->assertEquals((object)['everything' => true], $search->get_areas_user_accesses()); $sitectx = \context_course::instance(SITEID); // Can access the frontpage ones. $this->setUser($noaccess); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $this->assertEquals(array($frontpageforumcontext->id => $frontpageforumcontext->id), $contexts[$this->forumpostareaid]); $this->assertEquals(array($sitectx->id => $sitectx->id), $contexts[$this->mycoursesareaid]); $mockctxs = array($noaccessctx->id => $noaccessctx->id, $frontpagectx->id => $frontpagectx->id); $this->assertEquals($mockctxs, $contexts[$mockareaid]); $this->setUser($teacher); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $frontpageandcourse1 = array($frontpageforumcontext->id => $frontpageforumcontext->id, $context1->id => $context1->id, $context2->id => $context2->id); $this->assertEquals($frontpageandcourse1, $contexts[$this->forumpostareaid]); @@ -579,7 +579,7 @@ class search_manager_testcase extends advanced_testcase { $this->assertEquals($mockctxs, $contexts[$mockareaid]); $this->setUser($student); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $this->assertEquals($frontpageandcourse1, $contexts[$this->forumpostareaid]); $this->assertEquals(array($sitectx->id => $sitectx->id, $course1ctx->id => $course1ctx->id), $contexts[$this->mycoursesareaid]); @@ -589,39 +589,39 @@ class search_manager_testcase extends advanced_testcase { // Hide the activity. set_coursemodule_visible($forum2->cmid, 0); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $this->assertEquals(array($frontpageforumcontext->id => $frontpageforumcontext->id, $context1->id => $context1->id), $contexts[$this->forumpostareaid]); // Now test course limited searches. set_coursemodule_visible($forum2->cmid, 1); $this->getDataGenerator()->enrol_user($student->id, $course2->id, 'student'); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $allcontexts = array($frontpageforumcontext->id => $frontpageforumcontext->id, $context1->id => $context1->id, $context2->id => $context2->id, $context3->id => $context3->id); $this->assertEquals($allcontexts, $contexts[$this->forumpostareaid]); $this->assertEquals(array($sitectx->id => $sitectx->id, $course1ctx->id => $course1ctx->id, $course2ctx->id => $course2ctx->id), $contexts[$this->mycoursesareaid]); - $contexts = $search->get_areas_user_accesses(array($course1->id, $course2->id)); + $contexts = $search->get_areas_user_accesses(array($course1->id, $course2->id))->usercontexts; $allcontexts = array($context1->id => $context1->id, $context2->id => $context2->id, $context3->id => $context3->id); $this->assertEquals($allcontexts, $contexts[$this->forumpostareaid]); $this->assertEquals(array($course1ctx->id => $course1ctx->id, $course2ctx->id => $course2ctx->id), $contexts[$this->mycoursesareaid]); - $contexts = $search->get_areas_user_accesses(array($course2->id)); + $contexts = $search->get_areas_user_accesses(array($course2->id))->usercontexts; $allcontexts = array($context3->id => $context3->id); $this->assertEquals($allcontexts, $contexts[$this->forumpostareaid]); $this->assertEquals(array($course2ctx->id => $course2ctx->id), $contexts[$this->mycoursesareaid]); - $contexts = $search->get_areas_user_accesses(array($course1->id)); + $contexts = $search->get_areas_user_accesses(array($course1->id))->usercontexts; $allcontexts = array($context1->id => $context1->id, $context2->id => $context2->id); $this->assertEquals($allcontexts, $contexts[$this->forumpostareaid]); $this->assertEquals(array($course1ctx->id => $course1ctx->id), $contexts[$this->mycoursesareaid]); // Test context limited search with no course limit. $contexts = $search->get_areas_user_accesses(false, - [$frontpageforumcontext->id, $course2ctx->id]); + [$frontpageforumcontext->id, $course2ctx->id])->usercontexts; $this->assertEquals([$frontpageforumcontext->id => $frontpageforumcontext->id], $contexts[$this->forumpostareaid]); $this->assertEquals([$course2ctx->id => $course2ctx->id], @@ -629,19 +629,19 @@ class search_manager_testcase extends advanced_testcase { // Test context limited search with course limit. $contexts = $search->get_areas_user_accesses([$course1->id, $course2->id], - [$frontpageforumcontext->id, $course2ctx->id]); + [$frontpageforumcontext->id, $course2ctx->id])->usercontexts; $this->assertArrayNotHasKey($this->forumpostareaid, $contexts); $this->assertEquals([$course2ctx->id => $course2ctx->id], $contexts[$this->mycoursesareaid]); // Single context and course. - $contexts = $search->get_areas_user_accesses([$course1->id], [$context1->id]); + $contexts = $search->get_areas_user_accesses([$course1->id], [$context1->id])->usercontexts; $this->assertEquals([$context1->id => $context1->id], $contexts[$this->forumpostareaid]); $this->assertArrayNotHasKey($this->mycoursesareaid, $contexts); // For admins, this is still limited only if we specify the things, so it should be same. $this->setAdminUser(); - $contexts = $search->get_areas_user_accesses([$course1->id], [$context1->id]); + $contexts = $search->get_areas_user_accesses([$course1->id], [$context1->id])->usercontexts; $this->assertEquals([$context1->id => $context1->id], $contexts[$this->forumpostareaid]); $this->assertArrayNotHasKey($this->mycoursesareaid, $contexts); } @@ -722,28 +722,28 @@ class search_manager_testcase extends advanced_testcase { // Admin gets 'true' result to function regardless of blocks. $this->setAdminUser(); - $this->assertTrue($search->get_areas_user_accesses()); + $this->assertEquals((object)['everything' => true], $search->get_areas_user_accesses()); // Student 1 gets all 3 block contexts. $this->setUser($student1); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $this->assertArrayHasKey('block_html-content', $contexts); $this->assertCount(3, $contexts['block_html-content']); // Student 2 does not get any blocks. $this->setUser($student2); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $this->assertArrayNotHasKey('block_html-content', $contexts); // Student 3 gets only two of them. $this->setUser($student3); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $this->assertArrayHasKey('block_html-content', $contexts); $this->assertCount(2, $contexts['block_html-content']); // A course limited search for student 1 is the same as the student 3 search. $this->setUser($student1); - $limitedcontexts = $search->get_areas_user_accesses([$course3->id]); + $limitedcontexts = $search->get_areas_user_accesses([$course3->id])->usercontexts; $this->assertEquals($contexts['block_html-content'], $limitedcontexts['block_html-content']); // Get block context ids for the blocks that appear. @@ -758,12 +758,12 @@ class search_manager_testcase extends advanced_testcase { // Context limited search (no course). $contexts = $search->get_areas_user_accesses(false, - [$blockcontextids[0], $blockcontextids[2]]); + [$blockcontextids[0], $blockcontextids[2]])->usercontexts; $this->assertCount(2, $contexts['block_html-content']); // Context limited search (with course 3). $contexts = $search->get_areas_user_accesses([$course2->id, $course3->id], - [$blockcontextids[0], $blockcontextids[2]]); + [$blockcontextids[0], $blockcontextids[2]])->usercontexts; $this->assertCount(1, $contexts['block_html-content']); } @@ -817,16 +817,16 @@ class search_manager_testcase extends advanced_testcase { // Admin user can access everything. $this->setAdminUser(); - $this->assertTrue($search->get_areas_user_accesses()); + $this->assertEquals((object)['everything' => true], $search->get_areas_user_accesses()); // No-access user can access only the front page forum. $this->setUser($noaccess); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $this->assertEquals([$forumfrontctx->id], array_keys($contexts[$this->forumpostareaid])); // Student can access the front page forum plus the enrolled one. $this->setUser($student); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $this->assertEquals([$forum1ctx->id, $forumfrontctx->id], array_keys($contexts[$this->forumpostareaid])); @@ -835,21 +835,119 @@ class search_manager_testcase extends advanced_testcase { // Admin user can access everything. $this->setAdminUser(); - $this->assertTrue($search->get_areas_user_accesses()); + $this->assertEquals((object)['everything' => true], $search->get_areas_user_accesses()); // No-access user can access the front page forum and course 2, 3. $this->setUser($noaccess); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $this->assertEquals([$forum2ctx->id, $forum3ctx->id, $forumfrontctx->id], array_keys($contexts[$this->forumpostareaid])); // Student can access the front page forum plus the enrolled one plus courses 2, 3. $this->setUser($student); - $contexts = $search->get_areas_user_accesses(); + $contexts = $search->get_areas_user_accesses()->usercontexts; $this->assertEquals([$forum1ctx->id, $forum2ctx->id, $forum3ctx->id, $forumfrontctx->id], array_keys($contexts[$this->forumpostareaid])); } + /** + * Tests group-related aspects of the get_areas_user_accesses function. + */ + public function test_search_user_accesses_groups() { + global $DB; + + $this->resetAfterTest(); + $this->setAdminUser(); + + // Create 2 courses each with 2 groups and 2 forums (separate/visible groups). + $generator = $this->getDataGenerator(); + $course1 = $generator->create_course(); + $course2 = $generator->create_course(); + $group1 = $generator->create_group(['courseid' => $course1->id]); + $group2 = $generator->create_group(['courseid' => $course1->id]); + $group3 = $generator->create_group(['courseid' => $course2->id]); + $group4 = $generator->create_group(['courseid' => $course2->id]); + $forum1s = $generator->create_module('forum', ['course' => $course1->id, 'groupmode' => SEPARATEGROUPS]); + $id1s = context_module::instance($forum1s->cmid)->id; + $forum1v = $generator->create_module('forum', ['course' => $course1->id, 'groupmode' => VISIBLEGROUPS]); + $id1v = context_module::instance($forum1v->cmid)->id; + $forum2s = $generator->create_module('forum', ['course' => $course2->id, 'groupmode' => SEPARATEGROUPS]); + $id2s = context_module::instance($forum2s->cmid)->id; + $forum2n = $generator->create_module('forum', ['course' => $course2->id, 'groupmode' => NOGROUPS]); + $id2n = context_module::instance($forum2n->cmid)->id; + + // Get search instance. + $search = testable_core_search::instance(); + $search->add_core_search_areas(); + + // User 1 is a manager in one course and a student in the other one. They belong to + // all of the groups 1, 2, 3, and 4. + $user1 = $generator->create_user(); + $generator->enrol_user($user1->id, $course1->id, 'manager'); + $generator->enrol_user($user1->id, $course2->id, 'student'); + groups_add_member($group1, $user1); + groups_add_member($group2, $user1); + groups_add_member($group3, $user1); + groups_add_member($group4, $user1); + + $this->setUser($user1); + $accessinfo = $search->get_areas_user_accesses(); + $contexts = $accessinfo->usercontexts; + + // Double-check all the forum contexts. + $postcontexts = $contexts['mod_forum-post']; + sort($postcontexts); + $this->assertEquals([$id1s, $id1v, $id2s, $id2n], $postcontexts); + + // Only the context in the second course (no accessallgroups) is restricted. + $restrictedcontexts = $accessinfo->separategroupscontexts; + sort($restrictedcontexts); + $this->assertEquals([$id2s], $restrictedcontexts); + + // Only the groups from the second course (no accessallgroups) are included. + $groupids = $accessinfo->usergroups; + sort($groupids); + $this->assertEquals([$group3->id, $group4->id], $groupids); + + // User 2 is a student in each course and belongs to groups 2 and 4. + $user2 = $generator->create_user(); + $generator->enrol_user($user2->id, $course1->id, 'student'); + $generator->enrol_user($user2->id, $course2->id, 'student'); + groups_add_member($group2, $user2); + groups_add_member($group4, $user2); + + $this->setUser($user2); + $accessinfo = $search->get_areas_user_accesses(); + $contexts = $accessinfo->usercontexts; + + // Double-check all the forum contexts. + $postcontexts = $contexts['mod_forum-post']; + sort($postcontexts); + $this->assertEquals([$id1s, $id1v, $id2s, $id2n], $postcontexts); + + // Both separate groups forums are restricted. + $restrictedcontexts = $accessinfo->separategroupscontexts; + sort($restrictedcontexts); + $this->assertEquals([$id1s, $id2s], $restrictedcontexts); + + // Groups from both courses are included. + $groupids = $accessinfo->usergroups; + sort($groupids); + $this->assertEquals([$group2->id, $group4->id], $groupids); + + // User 3 is a manager at system level. + $user3 = $generator->create_user(); + role_assign($DB->get_field('role', 'id', ['shortname' => 'manager'], MUST_EXIST), $user3->id, + \context_system::instance()); + + $this->setUser($user3); + $accessinfo = $search->get_areas_user_accesses(); + + // Nothing is restricted and no groups are relevant. + $this->assertEquals([], $accessinfo->separategroupscontexts); + $this->assertEquals([], $accessinfo->usergroups); + } + /** * test_is_search_area *