You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1219 lines
47 KiB
1219 lines
47 KiB
2 years ago
|
<?php
|
||
|
// This file is part of Moodle - http://moodle.org/
|
||
|
//
|
||
|
// Moodle is free software: you can redistribute it and/or modify
|
||
|
// it under the terms of the GNU General Public License as published by
|
||
|
// the Free Software Foundation, either version 3 of the License, or
|
||
|
// (at your option) any later version.
|
||
|
//
|
||
|
// Moodle is distributed in the hope that it will be useful,
|
||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
// GNU General Public License for more details.
|
||
|
//
|
||
|
// You should have received a copy of the GNU General Public License
|
||
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
/**
|
||
|
* This file contains the class that handles testing of the calendar event vault.
|
||
|
*
|
||
|
* @package core_calendar
|
||
|
* @copyright 2017 Ryan Wyllie <ryan@moodle.com>
|
||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||
|
*/
|
||
|
|
||
|
defined('MOODLE_INTERNAL') || die();
|
||
|
|
||
|
global $CFG;
|
||
|
require_once($CFG->dirroot . '/calendar/tests/helpers.php');
|
||
|
|
||
|
use core_calendar\local\event\data_access\event_vault;
|
||
|
use core_calendar\local\event\strategies\raw_event_retrieval_strategy;
|
||
|
|
||
|
/**
|
||
|
* This file contains the class that handles testing of the calendar event vault.
|
||
|
*
|
||
|
* @package core_calendar
|
||
|
* @copyright 2017 Ryan Wyllie <ryan@moodle.com>
|
||
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||
|
*/
|
||
|
class core_calendar_event_vault_testcase extends advanced_testcase {
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_timesort returns events after the
|
||
|
* provided timesort value.
|
||
|
*/
|
||
|
public function test_get_action_events_by_timesort_after_time() {
|
||
|
$this->resetAfterTest(true);
|
||
|
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
$this->setUser($user);
|
||
|
|
||
|
for ($i = 1; $i < 6; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$events = $vault->get_action_events_by_timesort($user, 3);
|
||
|
|
||
|
$this->assertCount(3, $events);
|
||
|
$this->assertEquals('Event 3', $events[0]->get_name());
|
||
|
$this->assertEquals('Event 4', $events[1]->get_name());
|
||
|
$this->assertEquals('Event 5', $events[2]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_timesort($user, 3, null, null, 1);
|
||
|
|
||
|
$this->assertCount(1, $events);
|
||
|
$this->assertEquals('Event 3', $events[0]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_timesort($user, 6);
|
||
|
|
||
|
$this->assertCount(0, $events);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_timesort returns events before the
|
||
|
* provided timesort value.
|
||
|
*/
|
||
|
public function test_get_action_events_by_timesort_before_time() {
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
for ($i = 1; $i < 6; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => 1
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$events = $vault->get_action_events_by_timesort($user, null, 3);
|
||
|
|
||
|
$this->assertCount(3, $events);
|
||
|
$this->assertEquals('Event 1', $events[0]->get_name());
|
||
|
$this->assertEquals('Event 2', $events[1]->get_name());
|
||
|
$this->assertEquals('Event 3', $events[2]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_timesort($user, null, 3, null, 1);
|
||
|
|
||
|
$this->assertCount(1, $events);
|
||
|
$this->assertEquals('Event 1', $events[0]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_timesort($user, 6);
|
||
|
|
||
|
$this->assertCount(0, $events);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_timesort returns events between the
|
||
|
* provided timesort values.
|
||
|
*/
|
||
|
public function test_get_action_events_by_timesort_between_time() {
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
for ($i = 1; $i < 6; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => 1
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$events = $vault->get_action_events_by_timesort($user, 2, 4);
|
||
|
|
||
|
$this->assertCount(3, $events);
|
||
|
$this->assertEquals('Event 2', $events[0]->get_name());
|
||
|
$this->assertEquals('Event 3', $events[1]->get_name());
|
||
|
$this->assertEquals('Event 4', $events[2]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_timesort($user, 2, 4, null, 1);
|
||
|
|
||
|
$this->assertCount(1, $events);
|
||
|
$this->assertEquals('Event 2', $events[0]->get_name());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_timesort returns events between the
|
||
|
* provided timesort values and after the last seen event when one is
|
||
|
* provided.
|
||
|
*/
|
||
|
public function test_get_action_events_by_timesort_between_time_after_event() {
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
$records = [];
|
||
|
for ($i = 1; $i < 21; $i++) {
|
||
|
$records[] = create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => 1
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$aftereventid = $records[6]->id;
|
||
|
$afterevent = $vault->get_event_by_id($aftereventid);
|
||
|
$events = $vault->get_action_events_by_timesort($user, 3, 15, $afterevent);
|
||
|
|
||
|
$this->assertCount(8, $events);
|
||
|
$this->assertEquals('Event 8', $events[0]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_timesort($user, 3, 15, $afterevent, 3);
|
||
|
|
||
|
$this->assertCount(3, $events);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_timesort returns events between the
|
||
|
* provided timesort values and the last seen event can be provided to
|
||
|
* get paginated results.
|
||
|
*/
|
||
|
public function test_get_action_events_by_timesort_between_time_skip_even_records() {
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
// The factory will return every event that is divisible by 2.
|
||
|
$factory = new action_event_test_factory(function($actionevent) {
|
||
|
static $count = 0;
|
||
|
$count++;
|
||
|
return ($count % 2) ? true : false;
|
||
|
});
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
for ($i = 1; $i < 41; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => 1
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$events = $vault->get_action_events_by_timesort($user, 3, 35, null, 5);
|
||
|
|
||
|
$this->assertCount(5, $events);
|
||
|
$this->assertEquals('Event 3', $events[0]->get_name());
|
||
|
$this->assertEquals('Event 5', $events[1]->get_name());
|
||
|
$this->assertEquals('Event 7', $events[2]->get_name());
|
||
|
$this->assertEquals('Event 9', $events[3]->get_name());
|
||
|
$this->assertEquals('Event 11', $events[4]->get_name());
|
||
|
|
||
|
$afterevent = $events[4];
|
||
|
$events = $vault->get_action_events_by_timesort($user, 3, 35, $afterevent, 5);
|
||
|
|
||
|
$this->assertCount(5, $events);
|
||
|
$this->assertEquals('Event 13', $events[0]->get_name());
|
||
|
$this->assertEquals('Event 15', $events[1]->get_name());
|
||
|
$this->assertEquals('Event 17', $events[2]->get_name());
|
||
|
$this->assertEquals('Event 19', $events[3]->get_name());
|
||
|
$this->assertEquals('Event 21', $events[4]->get_name());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_timesort returns events between the
|
||
|
* provided timesort values. The database will continue to be read until the
|
||
|
* number of events requested has been satisfied. In this case the first
|
||
|
* five events are rejected so it should require two database requests.
|
||
|
*/
|
||
|
public function test_get_action_events_by_timesort_between_time_skip_first_records() {
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$limit = 5;
|
||
|
$seen = 0;
|
||
|
// The factory will skip the first $limit events.
|
||
|
$factory = new action_event_test_factory(function($actionevent) use (&$seen, $limit) {
|
||
|
if ($seen < $limit) {
|
||
|
$seen++;
|
||
|
return false;
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
});
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
for ($i = 1; $i < 21; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => 1
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$events = $vault->get_action_events_by_timesort($user, 1, 20, null, $limit);
|
||
|
|
||
|
$this->assertCount($limit, $events);
|
||
|
$this->assertEquals(sprintf('Event %d', $limit + 1), $events[0]->get_name());
|
||
|
$this->assertEquals(sprintf('Event %d', $limit + 2), $events[1]->get_name());
|
||
|
$this->assertEquals(sprintf('Event %d', $limit + 3), $events[2]->get_name());
|
||
|
$this->assertEquals(sprintf('Event %d', $limit + 4), $events[3]->get_name());
|
||
|
$this->assertEquals(sprintf('Event %d', $limit + 5), $events[4]->get_name());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_timesort returns events between the
|
||
|
* provided timesort values and after the last seen event when one is
|
||
|
* provided. This should work even when the event ids aren't ordered the
|
||
|
* same as the timesort order.
|
||
|
*/
|
||
|
public function test_get_action_events_by_timesort_non_consecutive_ids() {
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
/*
|
||
|
* The events should be ordered by timesort as follows:
|
||
|
*
|
||
|
* 1 event 1
|
||
|
* 2 event 1
|
||
|
* 1 event 2
|
||
|
* 2 event 2
|
||
|
* 1 event 3
|
||
|
* 2 event 3
|
||
|
* 1 event 4
|
||
|
* 2 event 4
|
||
|
* 1 event 5
|
||
|
* 2 event 5
|
||
|
* 1 event 6
|
||
|
* 2 event 6
|
||
|
* 1 event 7
|
||
|
* 2 event 7
|
||
|
* 1 event 8
|
||
|
* 2 event 8
|
||
|
* 1 event 9
|
||
|
* 2 event 9
|
||
|
* 1 event 10
|
||
|
* 2 event 10
|
||
|
*/
|
||
|
$records = [];
|
||
|
for ($i = 1; $i < 11; $i++) {
|
||
|
$records[] = create_event([
|
||
|
'name' => sprintf('1 event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => 1
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
for ($i = 1; $i < 11; $i++) {
|
||
|
$records[] = create_event([
|
||
|
'name' => sprintf('2 event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => 1
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Expected result set:
|
||
|
*
|
||
|
* 2 event 4
|
||
|
* 1 event 5
|
||
|
* 2 event 5
|
||
|
* 1 event 6
|
||
|
* 2 event 6
|
||
|
* 1 event 7
|
||
|
* 2 event 7
|
||
|
* 1 event 8
|
||
|
* 2 event 8
|
||
|
*/
|
||
|
$aftereventid = $records[3]->id;
|
||
|
$afterevent = $vault->get_event_by_id($aftereventid);
|
||
|
// Offset results by event with name "1 event 4" which has the same timesort
|
||
|
// value as the lower boundary of this query (3). Confirm that the given
|
||
|
// $afterevent is used to ignore events with the same timesortfrom values.
|
||
|
$events = $vault->get_action_events_by_timesort($user, 3, 8, $afterevent);
|
||
|
|
||
|
$this->assertCount(9, $events);
|
||
|
$this->assertEquals('2 event 4', $events[0]->get_name());
|
||
|
$this->assertEquals('2 event 8', $events[8]->get_name());
|
||
|
|
||
|
/*
|
||
|
* Expected result set:
|
||
|
*
|
||
|
* 2 event 4
|
||
|
* 1 event 5
|
||
|
*/
|
||
|
$events = $vault->get_action_events_by_timesort($user, 3, 8, $afterevent, 2);
|
||
|
|
||
|
$this->assertCount(2, $events);
|
||
|
$this->assertEquals('2 event 4', $events[0]->get_name());
|
||
|
$this->assertEquals('1 event 5', $events[1]->get_name());
|
||
|
|
||
|
/*
|
||
|
* Expected result set:
|
||
|
*
|
||
|
* 2 event 8
|
||
|
*/
|
||
|
$aftereventid = $records[7]->id;
|
||
|
$afterevent = $vault->get_event_by_id($aftereventid);
|
||
|
// Offset results by event with name "1 event 8" which has the same timesort
|
||
|
// value as the upper boundary of this query (8). Confirm that the given
|
||
|
// $afterevent is used to ignore events with the same timesortto values.
|
||
|
$events = $vault->get_action_events_by_timesort($user, 3, 8, $afterevent);
|
||
|
|
||
|
$this->assertCount(1, $events);
|
||
|
$this->assertEquals('2 event 8', $events[0]->get_name());
|
||
|
|
||
|
/*
|
||
|
* Expected empty result set.
|
||
|
*/
|
||
|
$aftereventid = $records[18]->id;
|
||
|
$afterevent = $vault->get_event_by_id($aftereventid);
|
||
|
// Offset results by event with name "2 event 9" which has a timesort
|
||
|
// value larger than the upper boundary of this query (9 > 8). Confirm
|
||
|
// that the given $afterevent is used for filtering events.
|
||
|
$events = $vault->get_action_events_by_timesort($user, 3, 8, $afterevent);
|
||
|
$this->assertEmpty($events);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* There are subtle cases where the priority of an event override may be identical to another.
|
||
|
* For example, if you duplicate a group override, but make it apply to a different group. Now
|
||
|
* there are two overrides with exactly the same overridden dates. In this case the priority of
|
||
|
* both is 1.
|
||
|
*
|
||
|
* In this situation:
|
||
|
* - A user in group A should see only the A override
|
||
|
* - A user in group B should see only the B override
|
||
|
* - A user in both A and B should see both
|
||
|
*/
|
||
|
public function test_get_action_events_by_timesort_with_identical_group_override_priorities() {
|
||
|
$this->resetAfterTest();
|
||
|
$this->setAdminuser();
|
||
|
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
// Create an assign instance.
|
||
|
$assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
|
||
|
$assigninstance = $assigngenerator->create_instance(['course' => $course->id]);
|
||
|
|
||
|
// Create users.
|
||
|
$users = [
|
||
|
'Only in group A' => $this->getDataGenerator()->create_user(),
|
||
|
'Only in group B' => $this->getDataGenerator()->create_user(),
|
||
|
'In group A and B' => $this->getDataGenerator()->create_user(),
|
||
|
'In no groups' => $this->getDataGenerator()->create_user()
|
||
|
];
|
||
|
|
||
|
// Enrol users.
|
||
|
foreach ($users as $user) {
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course->id);
|
||
|
}
|
||
|
|
||
|
// Create groups.
|
||
|
$groupa = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
|
||
|
$groupb = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
|
||
|
|
||
|
// Add members to groups.
|
||
|
// Group A.
|
||
|
$this->getDataGenerator()->create_group_member(['groupid' => $groupa->id, 'userid' => $users['Only in group A']->id]);
|
||
|
$this->getDataGenerator()->create_group_member(['groupid' => $groupa->id, 'userid' => $users['In group A and B']->id]);
|
||
|
|
||
|
// Group B.
|
||
|
$this->getDataGenerator()->create_group_member(['groupid' => $groupb->id, 'userid' => $users['Only in group B']->id]);
|
||
|
$this->getDataGenerator()->create_group_member(['groupid' => $groupb->id, 'userid' => $users['In group A and B']->id]);
|
||
|
|
||
|
// Events with the same module name, instance and event type.
|
||
|
$events = [
|
||
|
[
|
||
|
'name' => 'Assignment 1 due date - Group A override',
|
||
|
'description' => '',
|
||
|
'format' => 1,
|
||
|
'courseid' => $course->id,
|
||
|
'groupid' => $groupa->id,
|
||
|
'userid' => 2,
|
||
|
'modulename' => 'assign',
|
||
|
'instance' => $assigninstance->id,
|
||
|
'eventtype' => 'due',
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'timestart' => 1,
|
||
|
'timeduration' => 0,
|
||
|
'visible' => 1,
|
||
|
'priority' => 1
|
||
|
],
|
||
|
[
|
||
|
'name' => 'Assignment 1 due date - Group B override',
|
||
|
'description' => '',
|
||
|
'format' => 1,
|
||
|
'courseid' => $course->id,
|
||
|
'groupid' => $groupb->id,
|
||
|
'userid' => 2,
|
||
|
'modulename' => 'assign',
|
||
|
'instance' => $assigninstance->id,
|
||
|
'eventtype' => 'due',
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'timestart' => 1,
|
||
|
'timeduration' => 0,
|
||
|
'visible' => 1,
|
||
|
'priority' => 1
|
||
|
],
|
||
|
[
|
||
|
'name' => 'Assignment 1 due date',
|
||
|
'description' => '',
|
||
|
'format' => 1,
|
||
|
'courseid' => $course->id,
|
||
|
'groupid' => 0,
|
||
|
'userid' => 2,
|
||
|
'modulename' => 'assign',
|
||
|
'instance' => $assigninstance->id,
|
||
|
'eventtype' => 'due',
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'timestart' => 1,
|
||
|
'timeduration' => 0,
|
||
|
'visible' => 1,
|
||
|
'priority' => null,
|
||
|
]
|
||
|
];
|
||
|
|
||
|
foreach ($events as $event) {
|
||
|
calendar_event::create($event, false);
|
||
|
}
|
||
|
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
$usersevents = array_reduce(array_keys($users), function($carry, $description) use ($users, $vault) {
|
||
|
// NB: This is currently needed to make get_action_events_by_timesort return the right thing.
|
||
|
// It needs to be fixed, see MDL-58736.
|
||
|
$this->setUser($users[$description]);
|
||
|
return $carry + ['For user ' . lcfirst($description) => $vault->get_action_events_by_timesort($users[$description])];
|
||
|
}, []);
|
||
|
|
||
|
foreach ($usersevents as $description => $userevents) {
|
||
|
if ($description == 'For user in group A and B') {
|
||
|
// User is in both A and B, so they should see the override for both
|
||
|
// given that the priority is the same.
|
||
|
$this->assertCount(2, $userevents);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Otherwise there should be only one assign event for each user.
|
||
|
$this->assertCount(1, $userevents);
|
||
|
}
|
||
|
|
||
|
// User in only group A should see the group A override.
|
||
|
$this->assertEquals('Assignment 1 due date - Group A override', $usersevents['For user only in group A'][0]->get_name());
|
||
|
|
||
|
// User in only group B should see the group B override.
|
||
|
$this->assertEquals('Assignment 1 due date - Group B override', $usersevents['For user only in group B'][0]->get_name());
|
||
|
|
||
|
// User in group A and B should see see both overrides since the priorities are the same.
|
||
|
$this->assertEquals('Assignment 1 due date - Group A override', $usersevents['For user in group A and B'][0]->get_name());
|
||
|
$this->assertEquals('Assignment 1 due date - Group B override', $usersevents['For user in group A and B'][1]->get_name());
|
||
|
|
||
|
// User in no groups should see the plain assignment event.
|
||
|
$this->assertEquals('Assignment 1 due date', $usersevents['For user in no groups'][0]->get_name());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that if a user is suspended that events related to that course are not shown.
|
||
|
* User 1 is suspended. User 2 is active.
|
||
|
*/
|
||
|
public function test_get_action_events_by_timesort_with_suspended_user() {
|
||
|
$this->resetAfterTest();
|
||
|
$user1 = $this->getDataGenerator()->create_user();
|
||
|
$user2 = $this->getDataGenerator()->create_user();
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
$this->setAdminuser();
|
||
|
$lesson = $this->getDataGenerator()->create_module('lesson', [
|
||
|
'name' => 'Lesson 1',
|
||
|
'course' => $course->id,
|
||
|
'available' => time(),
|
||
|
'deadline' => (time() + (60 * 60 * 24 * 5))
|
||
|
]
|
||
|
);
|
||
|
$this->getDataGenerator()->enrol_user($user1->id, $course->id, null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
|
||
|
$this->getDataGenerator()->enrol_user($user2->id, $course->id);
|
||
|
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
$user1events = $vault->get_action_events_by_timesort($user1, null, null, null, 20, true);
|
||
|
$this->assertEmpty($user1events);
|
||
|
$user2events = $vault->get_action_events_by_timesort($user2, null, null, null, 20, true);
|
||
|
$this->assertCount(1, $user2events);
|
||
|
$this->assertEquals('Lesson 1 closes', $user2events[0]->get_name());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_course returns events after the
|
||
|
* provided timesort value.
|
||
|
*/
|
||
|
public function test_get_action_events_by_course_after_time() {
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$course1 = $this->getDataGenerator()->create_course();
|
||
|
$course2 = $this->getDataGenerator()->create_course();
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course1->id);
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course2->id);
|
||
|
|
||
|
for ($i = 1; $i < 6; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course1->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
for ($i = 6; $i < 12; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course2->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 3);
|
||
|
$this->assertCount(3, $events);
|
||
|
$this->assertEquals('Event 3', $events[0]->get_name());
|
||
|
$this->assertEquals('Event 4', $events[1]->get_name());
|
||
|
$this->assertEquals('Event 5', $events[2]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 3, null, null, 1);
|
||
|
|
||
|
$this->assertCount(1, $events);
|
||
|
$this->assertEquals('Event 3', $events[0]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 6);
|
||
|
|
||
|
$this->assertCount(0, $events);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_course returns events before the
|
||
|
* provided timesort value.
|
||
|
*/
|
||
|
public function test_get_action_events_by_course_before_time() {
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$course1 = $this->getDataGenerator()->create_course();
|
||
|
$course2 = $this->getDataGenerator()->create_course();
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course1->id);
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course2->id);
|
||
|
|
||
|
for ($i = 1; $i < 6; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course1->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
for ($i = 6; $i < 12; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course2->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, null, 3);
|
||
|
|
||
|
$this->assertCount(3, $events);
|
||
|
$this->assertEquals('Event 1', $events[0]->get_name());
|
||
|
$this->assertEquals('Event 2', $events[1]->get_name());
|
||
|
$this->assertEquals('Event 3', $events[2]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, null, 3, null, 1);
|
||
|
|
||
|
$this->assertCount(1, $events);
|
||
|
$this->assertEquals('Event 1', $events[0]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 6);
|
||
|
|
||
|
$this->assertCount(0, $events);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_course returns events between the
|
||
|
* provided timesort values.
|
||
|
*/
|
||
|
public function test_get_action_events_by_course_between_time() {
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$course1 = $this->getDataGenerator()->create_course();
|
||
|
$course2 = $this->getDataGenerator()->create_course();
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course1->id);
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course2->id);
|
||
|
|
||
|
for ($i = 1; $i < 6; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course1->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
for ($i = 6; $i < 12; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course2->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 2, 4);
|
||
|
|
||
|
$this->assertCount(3, $events);
|
||
|
$this->assertEquals('Event 2', $events[0]->get_name());
|
||
|
$this->assertEquals('Event 3', $events[1]->get_name());
|
||
|
$this->assertEquals('Event 4', $events[2]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 2, 4, null, 1);
|
||
|
|
||
|
$this->assertCount(1, $events);
|
||
|
$this->assertEquals('Event 2', $events[0]->get_name());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_course returns events between the
|
||
|
* provided timesort values and after the last seen event when one is
|
||
|
* provided.
|
||
|
*/
|
||
|
public function test_get_action_events_by_course_between_time_after_event() {
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$course1 = $this->getDataGenerator()->create_course();
|
||
|
$course2 = $this->getDataGenerator()->create_course();
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
$records = [];
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course1->id);
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course2->id);
|
||
|
|
||
|
for ($i = 1; $i < 21; $i++) {
|
||
|
$records[] = create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course1->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
for ($i = 21; $i < 41; $i++) {
|
||
|
$records[] = create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course2->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$aftereventid = $records[6]->id;
|
||
|
$afterevent = $vault->get_event_by_id($aftereventid);
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 3, 15, $afterevent);
|
||
|
|
||
|
$this->assertCount(8, $events);
|
||
|
$this->assertEquals('Event 8', $events[0]->get_name());
|
||
|
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 3, 15, $afterevent, 3);
|
||
|
|
||
|
$this->assertCount(3, $events);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_course returns events between the
|
||
|
* provided timesort values and the last seen event can be provided to
|
||
|
* get paginated results.
|
||
|
*/
|
||
|
public function test_get_action_events_by_course_between_time_skip_even_records() {
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$course1 = $this->getDataGenerator()->create_course();
|
||
|
$course2 = $this->getDataGenerator()->create_course();
|
||
|
// The factory will return every event that is divisible by 2.
|
||
|
$factory = new action_event_test_factory(function($actionevent) {
|
||
|
static $count = 0;
|
||
|
$count++;
|
||
|
return ($count % 2) ? true : false;
|
||
|
});
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course1->id);
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course2->id);
|
||
|
|
||
|
for ($i = 1; $i < 41; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course1->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
for ($i = 41; $i < 81; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course2->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 3, 35, null, 5);
|
||
|
|
||
|
$this->assertCount(5, $events);
|
||
|
$this->assertEquals('Event 3', $events[0]->get_name());
|
||
|
$this->assertEquals('Event 5', $events[1]->get_name());
|
||
|
$this->assertEquals('Event 7', $events[2]->get_name());
|
||
|
$this->assertEquals('Event 9', $events[3]->get_name());
|
||
|
$this->assertEquals('Event 11', $events[4]->get_name());
|
||
|
|
||
|
$afterevent = $events[4];
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 3, 35, $afterevent, 5);
|
||
|
|
||
|
$this->assertCount(5, $events);
|
||
|
$this->assertEquals('Event 13', $events[0]->get_name());
|
||
|
$this->assertEquals('Event 15', $events[1]->get_name());
|
||
|
$this->assertEquals('Event 17', $events[2]->get_name());
|
||
|
$this->assertEquals('Event 19', $events[3]->get_name());
|
||
|
$this->assertEquals('Event 21', $events[4]->get_name());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_course returns events between the
|
||
|
* provided timesort values. The database will continue to be read until the
|
||
|
* number of events requested has been satisfied. In this case the first
|
||
|
* five events are rejected so it should require two database requests.
|
||
|
*/
|
||
|
public function test_get_action_events_by_course_between_time_skip_first_records() {
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$course1 = $this->getDataGenerator()->create_course();
|
||
|
$course2 = $this->getDataGenerator()->create_course();
|
||
|
$limit = 5;
|
||
|
$seen = 0;
|
||
|
// The factory will skip the first $limit events.
|
||
|
$factory = new action_event_test_factory(function($actionevent) use (&$seen, $limit) {
|
||
|
if ($seen < $limit) {
|
||
|
$seen++;
|
||
|
return false;
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
});
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course1->id);
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course2->id);
|
||
|
|
||
|
for ($i = 1; $i < 21; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course1->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
for ($i = 21; $i < 41; $i++) {
|
||
|
create_event([
|
||
|
'name' => sprintf('Event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course2->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 1, 20, null, $limit);
|
||
|
|
||
|
$this->assertCount($limit, $events);
|
||
|
$this->assertEquals(sprintf('Event %d', $limit + 1), $events[0]->get_name());
|
||
|
$this->assertEquals(sprintf('Event %d', $limit + 2), $events[1]->get_name());
|
||
|
$this->assertEquals(sprintf('Event %d', $limit + 3), $events[2]->get_name());
|
||
|
$this->assertEquals(sprintf('Event %d', $limit + 4), $events[3]->get_name());
|
||
|
$this->assertEquals(sprintf('Event %d', $limit + 5), $events[4]->get_name());
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Test that get_action_events_by_course returns events between the
|
||
|
* provided timesort values and after the last seen event when one is
|
||
|
* provided. This should work even when the event ids aren't ordered the
|
||
|
* same as the timesort order.
|
||
|
*/
|
||
|
public function test_get_action_events_by_course_non_consecutive_ids() {
|
||
|
$this->resetAfterTest(true);
|
||
|
$this->setAdminuser();
|
||
|
|
||
|
$user = $this->getDataGenerator()->create_user();
|
||
|
$course1 = $this->getDataGenerator()->create_course();
|
||
|
$course2 = $this->getDataGenerator()->create_course();
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
$this->setAdminuser();
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course1->id);
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course2->id);
|
||
|
|
||
|
/*
|
||
|
* The events should be ordered by timesort as follows:
|
||
|
*
|
||
|
* 1 event 1
|
||
|
* 2 event 1
|
||
|
* 1 event 2
|
||
|
* 2 event 2
|
||
|
* 1 event 3
|
||
|
* 2 event 3
|
||
|
* 1 event 4
|
||
|
* 2 event 4
|
||
|
* 1 event 5
|
||
|
* 2 event 5
|
||
|
* 1 event 6
|
||
|
* 2 event 6
|
||
|
* 1 event 7
|
||
|
* 2 event 7
|
||
|
* 1 event 8
|
||
|
* 2 event 8
|
||
|
* 1 event 9
|
||
|
* 2 event 9
|
||
|
* 1 event 10
|
||
|
* 2 event 10
|
||
|
*/
|
||
|
$records = [];
|
||
|
for ($i = 1; $i < 11; $i++) {
|
||
|
$records[] = create_event([
|
||
|
'name' => sprintf('1 event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course1->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
for ($i = 1; $i < 11; $i++) {
|
||
|
$records[] = create_event([
|
||
|
'name' => sprintf('2 event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course1->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
// Create events for the other course.
|
||
|
for ($i = 1; $i < 11; $i++) {
|
||
|
$records[] = create_event([
|
||
|
'name' => sprintf('3 event %d', $i),
|
||
|
'eventtype' => 'user',
|
||
|
'userid' => $user->id,
|
||
|
'timesort' => $i,
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'courseid' => $course2->id,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Expected result set:
|
||
|
*
|
||
|
* 2 event 4
|
||
|
* 1 event 5
|
||
|
* 2 event 5
|
||
|
* 1 event 6
|
||
|
* 2 event 6
|
||
|
* 1 event 7
|
||
|
* 2 event 7
|
||
|
* 1 event 8
|
||
|
* 2 event 8
|
||
|
*/
|
||
|
$aftereventid = $records[3]->id;
|
||
|
$afterevent = $vault->get_event_by_id($aftereventid);
|
||
|
// Offset results by event with name "1 event 4" which has the same timesort
|
||
|
// value as the lower boundary of this query (3). Confirm that the given
|
||
|
// $afterevent is used to ignore events with the same timesortfrom values.
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 3, 8, $afterevent);
|
||
|
|
||
|
$this->assertCount(9, $events);
|
||
|
$this->assertEquals('2 event 4', $events[0]->get_name());
|
||
|
$this->assertEquals('2 event 8', $events[8]->get_name());
|
||
|
|
||
|
/*
|
||
|
* Expected result set:
|
||
|
*
|
||
|
* 2 event 4
|
||
|
* 1 event 5
|
||
|
*/
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 3, 8, $afterevent, 2);
|
||
|
|
||
|
$this->assertCount(2, $events);
|
||
|
$this->assertEquals('2 event 4', $events[0]->get_name());
|
||
|
$this->assertEquals('1 event 5', $events[1]->get_name());
|
||
|
|
||
|
/*
|
||
|
* Expected result set:
|
||
|
*
|
||
|
* 2 event 8
|
||
|
*/
|
||
|
$aftereventid = $records[7]->id;
|
||
|
$afterevent = $vault->get_event_by_id($aftereventid);
|
||
|
// Offset results by event with name "1 event 8" which has the same timesort
|
||
|
// value as the upper boundary of this query (8). Confirm that the given
|
||
|
// $afterevent is used to ignore events with the same timesortto values.
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 3, 8, $afterevent);
|
||
|
|
||
|
$this->assertCount(1, $events);
|
||
|
$this->assertEquals('2 event 8', $events[0]->get_name());
|
||
|
|
||
|
/*
|
||
|
* Expected empty result set.
|
||
|
*/
|
||
|
$aftereventid = $records[18]->id;
|
||
|
$afterevent = $vault->get_event_by_id($aftereventid);
|
||
|
// Offset results by event with name "2 event 9" which has a timesort
|
||
|
// value larger than the upper boundary of this query (9 > 8). Confirm
|
||
|
// that the given $afterevent is used for filtering events.
|
||
|
$events = $vault->get_action_events_by_course($user, $course1, 3, 8, $afterevent);
|
||
|
|
||
|
$this->assertEmpty($events);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* There are subtle cases where the priority of an event override may be identical to another.
|
||
|
* For example, if you duplicate a group override, but make it apply to a different group. Now
|
||
|
* there are two overrides with exactly the same overridden dates. In this case the priority of
|
||
|
* both is 1.
|
||
|
*
|
||
|
* In this situation:
|
||
|
* - A user in group A should see only the A override
|
||
|
* - A user in group B should see only the B override
|
||
|
* - A user in both A and B should see both
|
||
|
*/
|
||
|
public function test_get_action_events_by_course_with_identical_group_override_priorities() {
|
||
|
$this->resetAfterTest();
|
||
|
$this->setAdminuser();
|
||
|
|
||
|
$course = $this->getDataGenerator()->create_course();
|
||
|
|
||
|
// Create an assign instance.
|
||
|
$assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
|
||
|
$assigninstance = $assigngenerator->create_instance(['course' => $course->id]);
|
||
|
|
||
|
// Create users.
|
||
|
$users = [
|
||
|
'Only in group A' => $this->getDataGenerator()->create_user(),
|
||
|
'Only in group B' => $this->getDataGenerator()->create_user(),
|
||
|
'In group A and B' => $this->getDataGenerator()->create_user(),
|
||
|
'In no groups' => $this->getDataGenerator()->create_user()
|
||
|
];
|
||
|
|
||
|
// Enrol users.
|
||
|
foreach ($users as $user) {
|
||
|
$this->getDataGenerator()->enrol_user($user->id, $course->id);
|
||
|
}
|
||
|
|
||
|
// Create groups.
|
||
|
$groupa = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
|
||
|
$groupb = $this->getDataGenerator()->create_group(['courseid' => $course->id]);
|
||
|
|
||
|
// Add members to groups.
|
||
|
// Group A.
|
||
|
$this->getDataGenerator()->create_group_member(['groupid' => $groupa->id, 'userid' => $users['Only in group A']->id]);
|
||
|
$this->getDataGenerator()->create_group_member(['groupid' => $groupa->id, 'userid' => $users['In group A and B']->id]);
|
||
|
|
||
|
// Group B.
|
||
|
$this->getDataGenerator()->create_group_member(['groupid' => $groupb->id, 'userid' => $users['Only in group B']->id]);
|
||
|
$this->getDataGenerator()->create_group_member(['groupid' => $groupb->id, 'userid' => $users['In group A and B']->id]);
|
||
|
|
||
|
// Events with the same module name, instance and event type.
|
||
|
$events = [
|
||
|
[
|
||
|
'name' => 'Assignment 1 due date - Group A override',
|
||
|
'description' => '',
|
||
|
'format' => 1,
|
||
|
'courseid' => $course->id,
|
||
|
'groupid' => $groupa->id,
|
||
|
'userid' => 2,
|
||
|
'modulename' => 'assign',
|
||
|
'instance' => $assigninstance->id,
|
||
|
'eventtype' => 'due',
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'timestart' => 1,
|
||
|
'timeduration' => 0,
|
||
|
'visible' => 1,
|
||
|
'priority' => 1
|
||
|
],
|
||
|
[
|
||
|
'name' => 'Assignment 1 due date - Group B override',
|
||
|
'description' => '',
|
||
|
'format' => 1,
|
||
|
'courseid' => $course->id,
|
||
|
'groupid' => $groupb->id,
|
||
|
'userid' => 2,
|
||
|
'modulename' => 'assign',
|
||
|
'instance' => $assigninstance->id,
|
||
|
'eventtype' => 'due',
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'timestart' => 1,
|
||
|
'timeduration' => 0,
|
||
|
'visible' => 1,
|
||
|
'priority' => 1
|
||
|
],
|
||
|
[
|
||
|
'name' => 'Assignment 1 due date',
|
||
|
'description' => '',
|
||
|
'format' => 1,
|
||
|
'courseid' => $course->id,
|
||
|
'groupid' => 0,
|
||
|
'userid' => 2,
|
||
|
'modulename' => 'assign',
|
||
|
'instance' => $assigninstance->id,
|
||
|
'eventtype' => 'due',
|
||
|
'type' => CALENDAR_EVENT_TYPE_ACTION,
|
||
|
'timestart' => 1,
|
||
|
'timeduration' => 0,
|
||
|
'visible' => 1,
|
||
|
'priority' => null,
|
||
|
]
|
||
|
];
|
||
|
|
||
|
foreach ($events as $event) {
|
||
|
calendar_event::create($event, false);
|
||
|
}
|
||
|
|
||
|
$factory = new action_event_test_factory();
|
||
|
$strategy = new raw_event_retrieval_strategy();
|
||
|
$vault = new event_vault($factory, $strategy);
|
||
|
|
||
|
$usersevents = array_reduce(array_keys($users), function($carry, $description) use ($users, $course, $vault) {
|
||
|
// NB: This is currently needed to make get_action_events_by_timesort return the right thing.
|
||
|
// It needs to be fixed, see MDL-58736.
|
||
|
$this->setUser($users[$description]);
|
||
|
return $carry + [
|
||
|
'For user ' . lcfirst($description) => $vault->get_action_events_by_course($users[$description], $course)
|
||
|
];
|
||
|
}, []);
|
||
|
|
||
|
foreach ($usersevents as $description => $userevents) {
|
||
|
if ($description == 'For user in group A and B') {
|
||
|
// User is in both A and B, so they should see the override for both
|
||
|
// given that the priority is the same.
|
||
|
$this->assertCount(2, $userevents);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Otherwise there should be only one assign event for each user.
|
||
|
$this->assertCount(1, $userevents);
|
||
|
}
|
||
|
|
||
|
// User in only group A should see the group A override.
|
||
|
$this->assertEquals('Assignment 1 due date - Group A override', $usersevents['For user only in group A'][0]->get_name());
|
||
|
|
||
|
// User in only group B should see the group B override.
|
||
|
$this->assertEquals('Assignment 1 due date - Group B override', $usersevents['For user only in group B'][0]->get_name());
|
||
|
|
||
|
// User in group A and B should see see both overrides since the priorities are the same.
|
||
|
$this->assertEquals('Assignment 1 due date - Group A override', $usersevents['For user in group A and B'][0]->get_name());
|
||
|
$this->assertEquals('Assignment 1 due date - Group B override', $usersevents['For user in group A and B'][1]->get_name());
|
||
|
|
||
|
// User in no groups should see the plain assignment event.
|
||
|
$this->assertEquals('Assignment 1 due date', $usersevents['For user in no groups'][0]->get_name());
|
||
|
}
|
||
|
}
|