Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * This file contains the class that handles testing of the calendar event vault. 19 * 20 * @package core_calendar 21 * @copyright 2017 Ryan Wyllie <ryan@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 defined('MOODLE_INTERNAL') || die(); 26 27 global $CFG; 28 require_once($CFG->dirroot . '/calendar/tests/helpers.php'); 29 30 use core_calendar\local\event\data_access\event_vault; 31 use core_calendar\local\event\strategies\raw_event_retrieval_strategy; 32 33 /** 34 * This file contains the class that handles testing of the calendar event vault. 35 * 36 * @package core_calendar 37 * @copyright 2017 Ryan Wyllie <ryan@moodle.com> 38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 39 */ 40 class core_calendar_event_vault_testcase extends advanced_testcase { 41 42 /** 43 * Test that get_action_events_by_timesort returns events after the 44 * provided timesort value. 45 */ 46 public function test_get_action_events_by_timesort_after_time() { 47 $this->resetAfterTest(true); 48 49 $user = $this->getDataGenerator()->create_user(); 50 $factory = new action_event_test_factory(); 51 $strategy = new raw_event_retrieval_strategy(); 52 $vault = new event_vault($factory, $strategy); 53 54 $this->setUser($user); 55 56 for ($i = 1; $i < 6; $i++) { 57 create_event([ 58 'name' => sprintf('Event %d', $i), 59 'eventtype' => 'user', 60 'userid' => $user->id, 61 'timesort' => $i, 62 'type' => CALENDAR_EVENT_TYPE_ACTION 63 ]); 64 } 65 66 $events = $vault->get_action_events_by_timesort($user, 3); 67 68 $this->assertCount(3, $events); 69 $this->assertEquals('Event 3', $events[0]->get_name()); 70 $this->assertEquals('Event 4', $events[1]->get_name()); 71 $this->assertEquals('Event 5', $events[2]->get_name()); 72 73 $events = $vault->get_action_events_by_timesort($user, 3, null, null, 1); 74 75 $this->assertCount(1, $events); 76 $this->assertEquals('Event 3', $events[0]->get_name()); 77 78 $events = $vault->get_action_events_by_timesort($user, 6); 79 80 $this->assertCount(0, $events); 81 } 82 83 /** 84 * Test that get_action_events_by_timesort returns events before the 85 * provided timesort value. 86 */ 87 public function test_get_action_events_by_timesort_before_time() { 88 $this->resetAfterTest(true); 89 $this->setAdminuser(); 90 91 $user = $this->getDataGenerator()->create_user(); 92 $factory = new action_event_test_factory(); 93 $strategy = new raw_event_retrieval_strategy(); 94 $vault = new event_vault($factory, $strategy); 95 96 for ($i = 1; $i < 6; $i++) { 97 create_event([ 98 'name' => sprintf('Event %d', $i), 99 'eventtype' => 'user', 100 'userid' => $user->id, 101 'timesort' => $i, 102 'type' => CALENDAR_EVENT_TYPE_ACTION, 103 'courseid' => 1 104 ]); 105 } 106 107 $events = $vault->get_action_events_by_timesort($user, null, 3); 108 109 $this->assertCount(3, $events); 110 $this->assertEquals('Event 1', $events[0]->get_name()); 111 $this->assertEquals('Event 2', $events[1]->get_name()); 112 $this->assertEquals('Event 3', $events[2]->get_name()); 113 114 $events = $vault->get_action_events_by_timesort($user, null, 3, null, 1); 115 116 $this->assertCount(1, $events); 117 $this->assertEquals('Event 1', $events[0]->get_name()); 118 119 $events = $vault->get_action_events_by_timesort($user, 6); 120 121 $this->assertCount(0, $events); 122 } 123 124 /** 125 * Test that get_action_events_by_timesort returns events between the 126 * provided timesort values. 127 */ 128 public function test_get_action_events_by_timesort_between_time() { 129 $this->resetAfterTest(true); 130 $this->setAdminuser(); 131 132 $user = $this->getDataGenerator()->create_user(); 133 $factory = new action_event_test_factory(); 134 $strategy = new raw_event_retrieval_strategy(); 135 $vault = new event_vault($factory, $strategy); 136 137 for ($i = 1; $i < 6; $i++) { 138 create_event([ 139 'name' => sprintf('Event %d', $i), 140 'eventtype' => 'user', 141 'userid' => $user->id, 142 'timesort' => $i, 143 'type' => CALENDAR_EVENT_TYPE_ACTION, 144 'courseid' => 1 145 ]); 146 } 147 148 $events = $vault->get_action_events_by_timesort($user, 2, 4); 149 150 $this->assertCount(3, $events); 151 $this->assertEquals('Event 2', $events[0]->get_name()); 152 $this->assertEquals('Event 3', $events[1]->get_name()); 153 $this->assertEquals('Event 4', $events[2]->get_name()); 154 155 $events = $vault->get_action_events_by_timesort($user, 2, 4, null, 1); 156 157 $this->assertCount(1, $events); 158 $this->assertEquals('Event 2', $events[0]->get_name()); 159 } 160 161 /** 162 * Test that get_action_events_by_timesort returns events between the 163 * provided timesort values and after the last seen event when one is 164 * provided. 165 */ 166 public function test_get_action_events_by_timesort_between_time_after_event() { 167 $this->resetAfterTest(true); 168 $this->setAdminuser(); 169 170 $user = $this->getDataGenerator()->create_user(); 171 $factory = new action_event_test_factory(); 172 $strategy = new raw_event_retrieval_strategy(); 173 $vault = new event_vault($factory, $strategy); 174 175 $records = []; 176 for ($i = 1; $i < 21; $i++) { 177 $records[] = create_event([ 178 'name' => sprintf('Event %d', $i), 179 'eventtype' => 'user', 180 'userid' => $user->id, 181 'timesort' => $i, 182 'type' => CALENDAR_EVENT_TYPE_ACTION, 183 'courseid' => 1 184 ]); 185 } 186 187 $aftereventid = $records[6]->id; 188 $afterevent = $vault->get_event_by_id($aftereventid); 189 $events = $vault->get_action_events_by_timesort($user, 3, 15, $afterevent); 190 191 $this->assertCount(8, $events); 192 $this->assertEquals('Event 8', $events[0]->get_name()); 193 194 $events = $vault->get_action_events_by_timesort($user, 3, 15, $afterevent, 3); 195 196 $this->assertCount(3, $events); 197 } 198 199 /** 200 * Test that get_action_events_by_timesort returns events between the 201 * provided timesort values and the last seen event can be provided to 202 * get paginated results. 203 */ 204 public function test_get_action_events_by_timesort_between_time_skip_even_records() { 205 $this->resetAfterTest(true); 206 $this->setAdminuser(); 207 208 $user = $this->getDataGenerator()->create_user(); 209 // The factory will return every event that is divisible by 2. 210 $factory = new action_event_test_factory(function($actionevent) { 211 static $count = 0; 212 $count++; 213 return ($count % 2) ? true : false; 214 }); 215 $strategy = new raw_event_retrieval_strategy(); 216 $vault = new event_vault($factory, $strategy); 217 218 for ($i = 1; $i < 41; $i++) { 219 create_event([ 220 'name' => sprintf('Event %d', $i), 221 'eventtype' => 'user', 222 'userid' => $user->id, 223 'timesort' => $i, 224 'type' => CALENDAR_EVENT_TYPE_ACTION, 225 'courseid' => 1 226 ]); 227 } 228 229 $events = $vault->get_action_events_by_timesort($user, 3, 35, null, 5); 230 231 $this->assertCount(5, $events); 232 $this->assertEquals('Event 3', $events[0]->get_name()); 233 $this->assertEquals('Event 5', $events[1]->get_name()); 234 $this->assertEquals('Event 7', $events[2]->get_name()); 235 $this->assertEquals('Event 9', $events[3]->get_name()); 236 $this->assertEquals('Event 11', $events[4]->get_name()); 237 238 $afterevent = $events[4]; 239 $events = $vault->get_action_events_by_timesort($user, 3, 35, $afterevent, 5); 240 241 $this->assertCount(5, $events); 242 $this->assertEquals('Event 13', $events[0]->get_name()); 243 $this->assertEquals('Event 15', $events[1]->get_name()); 244 $this->assertEquals('Event 17', $events[2]->get_name()); 245 $this->assertEquals('Event 19', $events[3]->get_name()); 246 $this->assertEquals('Event 21', $events[4]->get_name()); 247 } 248 249 /** 250 * Test that get_action_events_by_timesort returns events between the 251 * provided timesort values. The database will continue to be read until the 252 * number of events requested has been satisfied. In this case the first 253 * five events are rejected so it should require two database requests. 254 */ 255 public function test_get_action_events_by_timesort_between_time_skip_first_records() { 256 $this->resetAfterTest(true); 257 $this->setAdminuser(); 258 259 $user = $this->getDataGenerator()->create_user(); 260 $limit = 5; 261 $seen = 0; 262 // The factory will skip the first $limit events. 263 $factory = new action_event_test_factory(function($actionevent) use (&$seen, $limit) { 264 if ($seen < $limit) { 265 $seen++; 266 return false; 267 } else { 268 return true; 269 } 270 }); 271 $strategy = new raw_event_retrieval_strategy(); 272 $vault = new event_vault($factory, $strategy); 273 274 for ($i = 1; $i < 21; $i++) { 275 create_event([ 276 'name' => sprintf('Event %d', $i), 277 'eventtype' => 'user', 278 'userid' => $user->id, 279 'timesort' => $i, 280 'type' => CALENDAR_EVENT_TYPE_ACTION, 281 'courseid' => 1 282 ]); 283 } 284 285 $events = $vault->get_action_events_by_timesort($user, 1, 20, null, $limit); 286 287 $this->assertCount($limit, $events); 288 $this->assertEquals(sprintf('Event %d', $limit + 1), $events[0]->get_name()); 289 $this->assertEquals(sprintf('Event %d', $limit + 2), $events[1]->get_name()); 290 $this->assertEquals(sprintf('Event %d', $limit + 3), $events[2]->get_name()); 291 $this->assertEquals(sprintf('Event %d', $limit + 4), $events[3]->get_name()); 292 $this->assertEquals(sprintf('Event %d', $limit + 5), $events[4]->get_name()); 293 } 294 295 /** 296 * Test that get_action_events_by_timesort returns events between the 297 * provided timesort values and after the last seen event when one is 298 * provided. This should work even when the event ids aren't ordered the 299 * same as the timesort order. 300 */ 301 public function test_get_action_events_by_timesort_non_consecutive_ids() { 302 $this->resetAfterTest(true); 303 $this->setAdminuser(); 304 305 $user = $this->getDataGenerator()->create_user(); 306 $factory = new action_event_test_factory(); 307 $strategy = new raw_event_retrieval_strategy(); 308 $vault = new event_vault($factory, $strategy); 309 310 /* 311 * The events should be ordered by timesort as follows: 312 * 313 * 1 event 1 314 * 2 event 1 315 * 1 event 2 316 * 2 event 2 317 * 1 event 3 318 * 2 event 3 319 * 1 event 4 320 * 2 event 4 321 * 1 event 5 322 * 2 event 5 323 * 1 event 6 324 * 2 event 6 325 * 1 event 7 326 * 2 event 7 327 * 1 event 8 328 * 2 event 8 329 * 1 event 9 330 * 2 event 9 331 * 1 event 10 332 * 2 event 10 333 */ 334 $records = []; 335 for ($i = 1; $i < 11; $i++) { 336 $records[] = create_event([ 337 'name' => sprintf('1 event %d', $i), 338 'eventtype' => 'user', 339 'userid' => $user->id, 340 'timesort' => $i, 341 'type' => CALENDAR_EVENT_TYPE_ACTION, 342 'courseid' => 1 343 ]); 344 } 345 346 for ($i = 1; $i < 11; $i++) { 347 $records[] = create_event([ 348 'name' => sprintf('2 event %d', $i), 349 'eventtype' => 'user', 350 'userid' => $user->id, 351 'timesort' => $i, 352 'type' => CALENDAR_EVENT_TYPE_ACTION, 353 'courseid' => 1 354 ]); 355 } 356 357 /* 358 * Expected result set: 359 * 360 * 2 event 4 361 * 1 event 5 362 * 2 event 5 363 * 1 event 6 364 * 2 event 6 365 * 1 event 7 366 * 2 event 7 367 * 1 event 8 368 * 2 event 8 369 */ 370 $aftereventid = $records[3]->id; 371 $afterevent = $vault->get_event_by_id($aftereventid); 372 // Offset results by event with name "1 event 4" which has the same timesort 373 // value as the lower boundary of this query (3). Confirm that the given 374 // $afterevent is used to ignore events with the same timesortfrom values. 375 $events = $vault->get_action_events_by_timesort($user, 3, 8, $afterevent); 376 377 $this->assertCount(9, $events); 378 $this->assertEquals('2 event 4', $events[0]->get_name()); 379 $this->assertEquals('2 event 8', $events[8]->get_name()); 380 381 /* 382 * Expected result set: 383 * 384 * 2 event 4 385 * 1 event 5 386 */ 387 $events = $vault->get_action_events_by_timesort($user, 3, 8, $afterevent, 2); 388 389 $this->assertCount(2, $events); 390 $this->assertEquals('2 event 4', $events[0]->get_name()); 391 $this->assertEquals('1 event 5', $events[1]->get_name()); 392 393 /* 394 * Expected result set: 395 * 396 * 2 event 8 397 */ 398 $aftereventid = $records[7]->id; 399 $afterevent = $vault->get_event_by_id($aftereventid); 400 // Offset results by event with name "1 event 8" which has the same timesort 401 // value as the upper boundary of this query (8). Confirm that the given 402 // $afterevent is used to ignore events with the same timesortto values. 403 $events = $vault->get_action_events_by_timesort($user, 3, 8, $afterevent); 404 405 $this->assertCount(1, $events); 406 $this->assertEquals('2 event 8', $events[0]->get_name()); 407 408 /* 409 * Expected empty result set. 410 */ 411 $aftereventid = $records[18]->id; 412 $afterevent = $vault->get_event_by_id($aftereventid); 413 // Offset results by event with name "2 event 9" which has a timesort 414 // value larger than the upper boundary of this query (9 > 8). Confirm 415 // that the given $afterevent is used for filtering events. 416 $events = $vault->get_action_events_by_timesort($user, 3, 8, $afterevent); 417 $this->assertEmpty($events); 418 } 419 420 /** 421 * There are subtle cases where the priority of an event override may be identical to another. 422 * For example, if you duplicate a group override, but make it apply to a different group. Now 423 * there are two overrides with exactly the same overridden dates. In this case the priority of 424 * both is 1. 425 * 426 * In this situation: 427 * - A user in group A should see only the A override 428 * - A user in group B should see only the B override 429 * - A user in both A and B should see both 430 */ 431 public function test_get_action_events_by_timesort_with_identical_group_override_priorities() { 432 $this->resetAfterTest(); 433 $this->setAdminuser(); 434 435 $course = $this->getDataGenerator()->create_course(); 436 437 // Create an assign instance. 438 $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 439 $assigninstance = $assigngenerator->create_instance(['course' => $course->id]); 440 441 // Create users. 442 $users = [ 443 'Only in group A' => $this->getDataGenerator()->create_user(), 444 'Only in group B' => $this->getDataGenerator()->create_user(), 445 'In group A and B' => $this->getDataGenerator()->create_user(), 446 'In no groups' => $this->getDataGenerator()->create_user() 447 ]; 448 449 // Enrol users. 450 foreach ($users as $user) { 451 $this->getDataGenerator()->enrol_user($user->id, $course->id); 452 } 453 454 // Create groups. 455 $groupa = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 456 $groupb = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 457 458 // Add members to groups. 459 // Group A. 460 $this->getDataGenerator()->create_group_member(['groupid' => $groupa->id, 'userid' => $users['Only in group A']->id]); 461 $this->getDataGenerator()->create_group_member(['groupid' => $groupa->id, 'userid' => $users['In group A and B']->id]); 462 463 // Group B. 464 $this->getDataGenerator()->create_group_member(['groupid' => $groupb->id, 'userid' => $users['Only in group B']->id]); 465 $this->getDataGenerator()->create_group_member(['groupid' => $groupb->id, 'userid' => $users['In group A and B']->id]); 466 467 // Events with the same module name, instance and event type. 468 $events = [ 469 [ 470 'name' => 'Assignment 1 due date - Group A override', 471 'description' => '', 472 'format' => 1, 473 'courseid' => $course->id, 474 'groupid' => $groupa->id, 475 'userid' => 2, 476 'modulename' => 'assign', 477 'instance' => $assigninstance->id, 478 'eventtype' => 'due', 479 'type' => CALENDAR_EVENT_TYPE_ACTION, 480 'timestart' => 1, 481 'timeduration' => 0, 482 'visible' => 1, 483 'priority' => 1 484 ], 485 [ 486 'name' => 'Assignment 1 due date - Group B override', 487 'description' => '', 488 'format' => 1, 489 'courseid' => $course->id, 490 'groupid' => $groupb->id, 491 'userid' => 2, 492 'modulename' => 'assign', 493 'instance' => $assigninstance->id, 494 'eventtype' => 'due', 495 'type' => CALENDAR_EVENT_TYPE_ACTION, 496 'timestart' => 1, 497 'timeduration' => 0, 498 'visible' => 1, 499 'priority' => 1 500 ], 501 [ 502 'name' => 'Assignment 1 due date', 503 'description' => '', 504 'format' => 1, 505 'courseid' => $course->id, 506 'groupid' => 0, 507 'userid' => 2, 508 'modulename' => 'assign', 509 'instance' => $assigninstance->id, 510 'eventtype' => 'due', 511 'type' => CALENDAR_EVENT_TYPE_ACTION, 512 'timestart' => 1, 513 'timeduration' => 0, 514 'visible' => 1, 515 'priority' => null, 516 ] 517 ]; 518 519 foreach ($events as $event) { 520 calendar_event::create($event, false); 521 } 522 523 $factory = new action_event_test_factory(); 524 $strategy = new raw_event_retrieval_strategy(); 525 $vault = new event_vault($factory, $strategy); 526 527 $usersevents = array_reduce(array_keys($users), function($carry, $description) use ($users, $vault) { 528 // NB: This is currently needed to make get_action_events_by_timesort return the right thing. 529 // It needs to be fixed, see MDL-58736. 530 $this->setUser($users[$description]); 531 return $carry + ['For user ' . lcfirst($description) => $vault->get_action_events_by_timesort($users[$description])]; 532 }, []); 533 534 foreach ($usersevents as $description => $userevents) { 535 if ($description == 'For user in group A and B') { 536 // User is in both A and B, so they should see the override for both 537 // given that the priority is the same. 538 $this->assertCount(2, $userevents); 539 continue; 540 } 541 542 // Otherwise there should be only one assign event for each user. 543 $this->assertCount(1, $userevents); 544 } 545 546 // User in only group A should see the group A override. 547 $this->assertEquals('Assignment 1 due date - Group A override', $usersevents['For user only in group A'][0]->get_name()); 548 549 // User in only group B should see the group B override. 550 $this->assertEquals('Assignment 1 due date - Group B override', $usersevents['For user only in group B'][0]->get_name()); 551 552 // User in group A and B should see see both overrides since the priorities are the same. 553 $this->assertEquals('Assignment 1 due date - Group A override', $usersevents['For user in group A and B'][0]->get_name()); 554 $this->assertEquals('Assignment 1 due date - Group B override', $usersevents['For user in group A and B'][1]->get_name()); 555 556 // User in no groups should see the plain assignment event. 557 $this->assertEquals('Assignment 1 due date', $usersevents['For user in no groups'][0]->get_name()); 558 } 559 560 /** 561 * Test that if a user is suspended that events related to that course are not shown. 562 * User 1 is suspended. User 2 is active. 563 */ 564 public function test_get_action_events_by_timesort_with_suspended_user() { 565 $this->resetAfterTest(); 566 $user1 = $this->getDataGenerator()->create_user(); 567 $user2 = $this->getDataGenerator()->create_user(); 568 $course = $this->getDataGenerator()->create_course(); 569 $this->setAdminuser(); 570 $lesson = $this->getDataGenerator()->create_module('lesson', [ 571 'name' => 'Lesson 1', 572 'course' => $course->id, 573 'available' => time(), 574 'deadline' => (time() + (60 * 60 * 24 * 5)) 575 ] 576 ); 577 $this->getDataGenerator()->enrol_user($user1->id, $course->id, null, 'manual', 0, 0, ENROL_USER_SUSPENDED); 578 $this->getDataGenerator()->enrol_user($user2->id, $course->id); 579 580 $factory = new action_event_test_factory(); 581 $strategy = new raw_event_retrieval_strategy(); 582 $vault = new event_vault($factory, $strategy); 583 584 $user1events = $vault->get_action_events_by_timesort($user1, null, null, null, 20, true); 585 $this->assertEmpty($user1events); 586 $user2events = $vault->get_action_events_by_timesort($user2, null, null, null, 20, true); 587 $this->assertCount(1, $user2events); 588 $this->assertEquals('Lesson 1 closes', $user2events[0]->get_name()); 589 } 590 591 /** 592 * Test that get_action_events_by_course returns events after the 593 * provided timesort value. 594 */ 595 public function test_get_action_events_by_course_after_time() { 596 $user = $this->getDataGenerator()->create_user(); 597 $course1 = $this->getDataGenerator()->create_course(); 598 $course2 = $this->getDataGenerator()->create_course(); 599 $factory = new action_event_test_factory(); 600 $strategy = new raw_event_retrieval_strategy(); 601 $vault = new event_vault($factory, $strategy); 602 603 $this->resetAfterTest(true); 604 $this->setAdminuser(); 605 $this->getDataGenerator()->enrol_user($user->id, $course1->id); 606 $this->getDataGenerator()->enrol_user($user->id, $course2->id); 607 608 for ($i = 1; $i < 6; $i++) { 609 create_event([ 610 'name' => sprintf('Event %d', $i), 611 'eventtype' => 'user', 612 'userid' => $user->id, 613 'timesort' => $i, 614 'type' => CALENDAR_EVENT_TYPE_ACTION, 615 'courseid' => $course1->id, 616 ]); 617 } 618 619 for ($i = 6; $i < 12; $i++) { 620 create_event([ 621 'name' => sprintf('Event %d', $i), 622 'eventtype' => 'user', 623 'userid' => $user->id, 624 'timesort' => $i, 625 'type' => CALENDAR_EVENT_TYPE_ACTION, 626 'courseid' => $course2->id, 627 ]); 628 } 629 630 $events = $vault->get_action_events_by_course($user, $course1, 3); 631 $this->assertCount(3, $events); 632 $this->assertEquals('Event 3', $events[0]->get_name()); 633 $this->assertEquals('Event 4', $events[1]->get_name()); 634 $this->assertEquals('Event 5', $events[2]->get_name()); 635 636 $events = $vault->get_action_events_by_course($user, $course1, 3, null, null, 1); 637 638 $this->assertCount(1, $events); 639 $this->assertEquals('Event 3', $events[0]->get_name()); 640 641 $events = $vault->get_action_events_by_course($user, $course1, 6); 642 643 $this->assertCount(0, $events); 644 } 645 646 /** 647 * Test that get_action_events_by_course returns events before the 648 * provided timesort value. 649 */ 650 public function test_get_action_events_by_course_before_time() { 651 $user = $this->getDataGenerator()->create_user(); 652 $course1 = $this->getDataGenerator()->create_course(); 653 $course2 = $this->getDataGenerator()->create_course(); 654 $factory = new action_event_test_factory(); 655 $strategy = new raw_event_retrieval_strategy(); 656 $vault = new event_vault($factory, $strategy); 657 658 $this->resetAfterTest(true); 659 $this->setAdminuser(); 660 $this->getDataGenerator()->enrol_user($user->id, $course1->id); 661 $this->getDataGenerator()->enrol_user($user->id, $course2->id); 662 663 for ($i = 1; $i < 6; $i++) { 664 create_event([ 665 'name' => sprintf('Event %d', $i), 666 'eventtype' => 'user', 667 'userid' => $user->id, 668 'timesort' => $i, 669 'type' => CALENDAR_EVENT_TYPE_ACTION, 670 'courseid' => $course1->id, 671 ]); 672 } 673 674 for ($i = 6; $i < 12; $i++) { 675 create_event([ 676 'name' => sprintf('Event %d', $i), 677 'eventtype' => 'user', 678 'userid' => $user->id, 679 'timesort' => $i, 680 'type' => CALENDAR_EVENT_TYPE_ACTION, 681 'courseid' => $course2->id, 682 ]); 683 } 684 685 $events = $vault->get_action_events_by_course($user, $course1, null, 3); 686 687 $this->assertCount(3, $events); 688 $this->assertEquals('Event 1', $events[0]->get_name()); 689 $this->assertEquals('Event 2', $events[1]->get_name()); 690 $this->assertEquals('Event 3', $events[2]->get_name()); 691 692 $events = $vault->get_action_events_by_course($user, $course1, null, 3, null, 1); 693 694 $this->assertCount(1, $events); 695 $this->assertEquals('Event 1', $events[0]->get_name()); 696 697 $events = $vault->get_action_events_by_course($user, $course1, 6); 698 699 $this->assertCount(0, $events); 700 } 701 702 /** 703 * Test that get_action_events_by_course returns events between the 704 * provided timesort values. 705 */ 706 public function test_get_action_events_by_course_between_time() { 707 $user = $this->getDataGenerator()->create_user(); 708 $course1 = $this->getDataGenerator()->create_course(); 709 $course2 = $this->getDataGenerator()->create_course(); 710 $factory = new action_event_test_factory(); 711 $strategy = new raw_event_retrieval_strategy(); 712 $vault = new event_vault($factory, $strategy); 713 714 $this->resetAfterTest(true); 715 $this->setAdminuser(); 716 $this->getDataGenerator()->enrol_user($user->id, $course1->id); 717 $this->getDataGenerator()->enrol_user($user->id, $course2->id); 718 719 for ($i = 1; $i < 6; $i++) { 720 create_event([ 721 'name' => sprintf('Event %d', $i), 722 'eventtype' => 'user', 723 'userid' => $user->id, 724 'timesort' => $i, 725 'type' => CALENDAR_EVENT_TYPE_ACTION, 726 'courseid' => $course1->id, 727 ]); 728 } 729 730 for ($i = 6; $i < 12; $i++) { 731 create_event([ 732 'name' => sprintf('Event %d', $i), 733 'eventtype' => 'user', 734 'userid' => $user->id, 735 'timesort' => $i, 736 'type' => CALENDAR_EVENT_TYPE_ACTION, 737 'courseid' => $course2->id, 738 ]); 739 } 740 741 $events = $vault->get_action_events_by_course($user, $course1, 2, 4); 742 743 $this->assertCount(3, $events); 744 $this->assertEquals('Event 2', $events[0]->get_name()); 745 $this->assertEquals('Event 3', $events[1]->get_name()); 746 $this->assertEquals('Event 4', $events[2]->get_name()); 747 748 $events = $vault->get_action_events_by_course($user, $course1, 2, 4, null, 1); 749 750 $this->assertCount(1, $events); 751 $this->assertEquals('Event 2', $events[0]->get_name()); 752 } 753 754 /** 755 * Test that get_action_events_by_course returns events between the 756 * provided timesort values and after the last seen event when one is 757 * provided. 758 */ 759 public function test_get_action_events_by_course_between_time_after_event() { 760 $user = $this->getDataGenerator()->create_user(); 761 $course1 = $this->getDataGenerator()->create_course(); 762 $course2 = $this->getDataGenerator()->create_course(); 763 $factory = new action_event_test_factory(); 764 $strategy = new raw_event_retrieval_strategy(); 765 $vault = new event_vault($factory, $strategy); 766 $records = []; 767 768 $this->resetAfterTest(true); 769 $this->setAdminuser(); 770 $this->getDataGenerator()->enrol_user($user->id, $course1->id); 771 $this->getDataGenerator()->enrol_user($user->id, $course2->id); 772 773 for ($i = 1; $i < 21; $i++) { 774 $records[] = create_event([ 775 'name' => sprintf('Event %d', $i), 776 'eventtype' => 'user', 777 'userid' => $user->id, 778 'timesort' => $i, 779 'type' => CALENDAR_EVENT_TYPE_ACTION, 780 'courseid' => $course1->id, 781 ]); 782 } 783 784 for ($i = 21; $i < 41; $i++) { 785 $records[] = create_event([ 786 'name' => sprintf('Event %d', $i), 787 'eventtype' => 'user', 788 'userid' => $user->id, 789 'timesort' => $i, 790 'type' => CALENDAR_EVENT_TYPE_ACTION, 791 'courseid' => $course2->id, 792 ]); 793 } 794 795 $aftereventid = $records[6]->id; 796 $afterevent = $vault->get_event_by_id($aftereventid); 797 $events = $vault->get_action_events_by_course($user, $course1, 3, 15, $afterevent); 798 799 $this->assertCount(8, $events); 800 $this->assertEquals('Event 8', $events[0]->get_name()); 801 802 $events = $vault->get_action_events_by_course($user, $course1, 3, 15, $afterevent, 3); 803 804 $this->assertCount(3, $events); 805 } 806 807 /** 808 * Test that get_action_events_by_course returns events between the 809 * provided timesort values and the last seen event can be provided to 810 * get paginated results. 811 */ 812 public function test_get_action_events_by_course_between_time_skip_even_records() { 813 $user = $this->getDataGenerator()->create_user(); 814 $course1 = $this->getDataGenerator()->create_course(); 815 $course2 = $this->getDataGenerator()->create_course(); 816 // The factory will return every event that is divisible by 2. 817 $factory = new action_event_test_factory(function($actionevent) { 818 static $count = 0; 819 $count++; 820 return ($count % 2) ? true : false; 821 }); 822 $strategy = new raw_event_retrieval_strategy(); 823 $vault = new event_vault($factory, $strategy); 824 825 $this->resetAfterTest(true); 826 $this->setAdminuser(); 827 $this->getDataGenerator()->enrol_user($user->id, $course1->id); 828 $this->getDataGenerator()->enrol_user($user->id, $course2->id); 829 830 for ($i = 1; $i < 41; $i++) { 831 create_event([ 832 'name' => sprintf('Event %d', $i), 833 'eventtype' => 'user', 834 'userid' => $user->id, 835 'timesort' => $i, 836 'type' => CALENDAR_EVENT_TYPE_ACTION, 837 'courseid' => $course1->id, 838 ]); 839 } 840 841 for ($i = 41; $i < 81; $i++) { 842 create_event([ 843 'name' => sprintf('Event %d', $i), 844 'eventtype' => 'user', 845 'userid' => $user->id, 846 'timesort' => $i, 847 'type' => CALENDAR_EVENT_TYPE_ACTION, 848 'courseid' => $course2->id, 849 ]); 850 } 851 852 $events = $vault->get_action_events_by_course($user, $course1, 3, 35, null, 5); 853 854 $this->assertCount(5, $events); 855 $this->assertEquals('Event 3', $events[0]->get_name()); 856 $this->assertEquals('Event 5', $events[1]->get_name()); 857 $this->assertEquals('Event 7', $events[2]->get_name()); 858 $this->assertEquals('Event 9', $events[3]->get_name()); 859 $this->assertEquals('Event 11', $events[4]->get_name()); 860 861 $afterevent = $events[4]; 862 $events = $vault->get_action_events_by_course($user, $course1, 3, 35, $afterevent, 5); 863 864 $this->assertCount(5, $events); 865 $this->assertEquals('Event 13', $events[0]->get_name()); 866 $this->assertEquals('Event 15', $events[1]->get_name()); 867 $this->assertEquals('Event 17', $events[2]->get_name()); 868 $this->assertEquals('Event 19', $events[3]->get_name()); 869 $this->assertEquals('Event 21', $events[4]->get_name()); 870 } 871 872 /** 873 * Test that get_action_events_by_course returns events between the 874 * provided timesort values. The database will continue to be read until the 875 * number of events requested has been satisfied. In this case the first 876 * five events are rejected so it should require two database requests. 877 */ 878 public function test_get_action_events_by_course_between_time_skip_first_records() { 879 $user = $this->getDataGenerator()->create_user(); 880 $course1 = $this->getDataGenerator()->create_course(); 881 $course2 = $this->getDataGenerator()->create_course(); 882 $limit = 5; 883 $seen = 0; 884 // The factory will skip the first $limit events. 885 $factory = new action_event_test_factory(function($actionevent) use (&$seen, $limit) { 886 if ($seen < $limit) { 887 $seen++; 888 return false; 889 } else { 890 return true; 891 } 892 }); 893 $strategy = new raw_event_retrieval_strategy(); 894 $vault = new event_vault($factory, $strategy); 895 896 $this->resetAfterTest(true); 897 $this->setAdminuser(); 898 $this->getDataGenerator()->enrol_user($user->id, $course1->id); 899 $this->getDataGenerator()->enrol_user($user->id, $course2->id); 900 901 for ($i = 1; $i < 21; $i++) { 902 create_event([ 903 'name' => sprintf('Event %d', $i), 904 'eventtype' => 'user', 905 'userid' => $user->id, 906 'timesort' => $i, 907 'type' => CALENDAR_EVENT_TYPE_ACTION, 908 'courseid' => $course1->id, 909 ]); 910 } 911 912 for ($i = 21; $i < 41; $i++) { 913 create_event([ 914 'name' => sprintf('Event %d', $i), 915 'eventtype' => 'user', 916 'userid' => $user->id, 917 'timesort' => $i, 918 'type' => CALENDAR_EVENT_TYPE_ACTION, 919 'courseid' => $course2->id, 920 ]); 921 } 922 923 $events = $vault->get_action_events_by_course($user, $course1, 1, 20, null, $limit); 924 925 $this->assertCount($limit, $events); 926 $this->assertEquals(sprintf('Event %d', $limit + 1), $events[0]->get_name()); 927 $this->assertEquals(sprintf('Event %d', $limit + 2), $events[1]->get_name()); 928 $this->assertEquals(sprintf('Event %d', $limit + 3), $events[2]->get_name()); 929 $this->assertEquals(sprintf('Event %d', $limit + 4), $events[3]->get_name()); 930 $this->assertEquals(sprintf('Event %d', $limit + 5), $events[4]->get_name()); 931 } 932 933 /** 934 * Test that get_action_events_by_course returns events between the 935 * provided timesort values and after the last seen event when one is 936 * provided. This should work even when the event ids aren't ordered the 937 * same as the timesort order. 938 */ 939 public function test_get_action_events_by_course_non_consecutive_ids() { 940 $this->resetAfterTest(true); 941 $this->setAdminuser(); 942 943 $user = $this->getDataGenerator()->create_user(); 944 $course1 = $this->getDataGenerator()->create_course(); 945 $course2 = $this->getDataGenerator()->create_course(); 946 $factory = new action_event_test_factory(); 947 $strategy = new raw_event_retrieval_strategy(); 948 $vault = new event_vault($factory, $strategy); 949 950 $this->setAdminuser(); 951 $this->getDataGenerator()->enrol_user($user->id, $course1->id); 952 $this->getDataGenerator()->enrol_user($user->id, $course2->id); 953 954 /* 955 * The events should be ordered by timesort as follows: 956 * 957 * 1 event 1 958 * 2 event 1 959 * 1 event 2 960 * 2 event 2 961 * 1 event 3 962 * 2 event 3 963 * 1 event 4 964 * 2 event 4 965 * 1 event 5 966 * 2 event 5 967 * 1 event 6 968 * 2 event 6 969 * 1 event 7 970 * 2 event 7 971 * 1 event 8 972 * 2 event 8 973 * 1 event 9 974 * 2 event 9 975 * 1 event 10 976 * 2 event 10 977 */ 978 $records = []; 979 for ($i = 1; $i < 11; $i++) { 980 $records[] = create_event([ 981 'name' => sprintf('1 event %d', $i), 982 'eventtype' => 'user', 983 'userid' => $user->id, 984 'timesort' => $i, 985 'type' => CALENDAR_EVENT_TYPE_ACTION, 986 'courseid' => $course1->id, 987 ]); 988 } 989 990 for ($i = 1; $i < 11; $i++) { 991 $records[] = create_event([ 992 'name' => sprintf('2 event %d', $i), 993 'eventtype' => 'user', 994 'userid' => $user->id, 995 'timesort' => $i, 996 'type' => CALENDAR_EVENT_TYPE_ACTION, 997 'courseid' => $course1->id, 998 ]); 999 } 1000 1001 // Create events for the other course. 1002 for ($i = 1; $i < 11; $i++) { 1003 $records[] = create_event([ 1004 'name' => sprintf('3 event %d', $i), 1005 'eventtype' => 'user', 1006 'userid' => $user->id, 1007 'timesort' => $i, 1008 'type' => CALENDAR_EVENT_TYPE_ACTION, 1009 'courseid' => $course2->id, 1010 ]); 1011 } 1012 1013 /* 1014 * Expected result set: 1015 * 1016 * 2 event 4 1017 * 1 event 5 1018 * 2 event 5 1019 * 1 event 6 1020 * 2 event 6 1021 * 1 event 7 1022 * 2 event 7 1023 * 1 event 8 1024 * 2 event 8 1025 */ 1026 $aftereventid = $records[3]->id; 1027 $afterevent = $vault->get_event_by_id($aftereventid); 1028 // Offset results by event with name "1 event 4" which has the same timesort 1029 // value as the lower boundary of this query (3). Confirm that the given 1030 // $afterevent is used to ignore events with the same timesortfrom values. 1031 $events = $vault->get_action_events_by_course($user, $course1, 3, 8, $afterevent); 1032 1033 $this->assertCount(9, $events); 1034 $this->assertEquals('2 event 4', $events[0]->get_name()); 1035 $this->assertEquals('2 event 8', $events[8]->get_name()); 1036 1037 /* 1038 * Expected result set: 1039 * 1040 * 2 event 4 1041 * 1 event 5 1042 */ 1043 $events = $vault->get_action_events_by_course($user, $course1, 3, 8, $afterevent, 2); 1044 1045 $this->assertCount(2, $events); 1046 $this->assertEquals('2 event 4', $events[0]->get_name()); 1047 $this->assertEquals('1 event 5', $events[1]->get_name()); 1048 1049 /* 1050 * Expected result set: 1051 * 1052 * 2 event 8 1053 */ 1054 $aftereventid = $records[7]->id; 1055 $afterevent = $vault->get_event_by_id($aftereventid); 1056 // Offset results by event with name "1 event 8" which has the same timesort 1057 // value as the upper boundary of this query (8). Confirm that the given 1058 // $afterevent is used to ignore events with the same timesortto values. 1059 $events = $vault->get_action_events_by_course($user, $course1, 3, 8, $afterevent); 1060 1061 $this->assertCount(1, $events); 1062 $this->assertEquals('2 event 8', $events[0]->get_name()); 1063 1064 /* 1065 * Expected empty result set. 1066 */ 1067 $aftereventid = $records[18]->id; 1068 $afterevent = $vault->get_event_by_id($aftereventid); 1069 // Offset results by event with name "2 event 9" which has a timesort 1070 // value larger than the upper boundary of this query (9 > 8). Confirm 1071 // that the given $afterevent is used for filtering events. 1072 $events = $vault->get_action_events_by_course($user, $course1, 3, 8, $afterevent); 1073 1074 $this->assertEmpty($events); 1075 } 1076 1077 /** 1078 * There are subtle cases where the priority of an event override may be identical to another. 1079 * For example, if you duplicate a group override, but make it apply to a different group. Now 1080 * there are two overrides with exactly the same overridden dates. In this case the priority of 1081 * both is 1. 1082 * 1083 * In this situation: 1084 * - A user in group A should see only the A override 1085 * - A user in group B should see only the B override 1086 * - A user in both A and B should see both 1087 */ 1088 public function test_get_action_events_by_course_with_identical_group_override_priorities() { 1089 $this->resetAfterTest(); 1090 $this->setAdminuser(); 1091 1092 $course = $this->getDataGenerator()->create_course(); 1093 1094 // Create an assign instance. 1095 $assigngenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign'); 1096 $assigninstance = $assigngenerator->create_instance(['course' => $course->id]); 1097 1098 // Create users. 1099 $users = [ 1100 'Only in group A' => $this->getDataGenerator()->create_user(), 1101 'Only in group B' => $this->getDataGenerator()->create_user(), 1102 'In group A and B' => $this->getDataGenerator()->create_user(), 1103 'In no groups' => $this->getDataGenerator()->create_user() 1104 ]; 1105 1106 // Enrol users. 1107 foreach ($users as $user) { 1108 $this->getDataGenerator()->enrol_user($user->id, $course->id); 1109 } 1110 1111 // Create groups. 1112 $groupa = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 1113 $groupb = $this->getDataGenerator()->create_group(['courseid' => $course->id]); 1114 1115 // Add members to groups. 1116 // Group A. 1117 $this->getDataGenerator()->create_group_member(['groupid' => $groupa->id, 'userid' => $users['Only in group A']->id]); 1118 $this->getDataGenerator()->create_group_member(['groupid' => $groupa->id, 'userid' => $users['In group A and B']->id]); 1119 1120 // Group B. 1121 $this->getDataGenerator()->create_group_member(['groupid' => $groupb->id, 'userid' => $users['Only in group B']->id]); 1122 $this->getDataGenerator()->create_group_member(['groupid' => $groupb->id, 'userid' => $users['In group A and B']->id]); 1123 1124 // Events with the same module name, instance and event type. 1125 $events = [ 1126 [ 1127 'name' => 'Assignment 1 due date - Group A override', 1128 'description' => '', 1129 'format' => 1, 1130 'courseid' => $course->id, 1131 'groupid' => $groupa->id, 1132 'userid' => 2, 1133 'modulename' => 'assign', 1134 'instance' => $assigninstance->id, 1135 'eventtype' => 'due', 1136 'type' => CALENDAR_EVENT_TYPE_ACTION, 1137 'timestart' => 1, 1138 'timeduration' => 0, 1139 'visible' => 1, 1140 'priority' => 1 1141 ], 1142 [ 1143 'name' => 'Assignment 1 due date - Group B override', 1144 'description' => '', 1145 'format' => 1, 1146 'courseid' => $course->id, 1147 'groupid' => $groupb->id, 1148 'userid' => 2, 1149 'modulename' => 'assign', 1150 'instance' => $assigninstance->id, 1151 'eventtype' => 'due', 1152 'type' => CALENDAR_EVENT_TYPE_ACTION, 1153 'timestart' => 1, 1154 'timeduration' => 0, 1155 'visible' => 1, 1156 'priority' => 1 1157 ], 1158 [ 1159 'name' => 'Assignment 1 due date', 1160 'description' => '', 1161 'format' => 1, 1162 'courseid' => $course->id, 1163 'groupid' => 0, 1164 'userid' => 2, 1165 'modulename' => 'assign', 1166 'instance' => $assigninstance->id, 1167 'eventtype' => 'due', 1168 'type' => CALENDAR_EVENT_TYPE_ACTION, 1169 'timestart' => 1, 1170 'timeduration' => 0, 1171 'visible' => 1, 1172 'priority' => null, 1173 ] 1174 ]; 1175 1176 foreach ($events as $event) { 1177 calendar_event::create($event, false); 1178 } 1179 1180 $factory = new action_event_test_factory(); 1181 $strategy = new raw_event_retrieval_strategy(); 1182 $vault = new event_vault($factory, $strategy); 1183 1184 $usersevents = array_reduce(array_keys($users), function($carry, $description) use ($users, $course, $vault) { 1185 // NB: This is currently needed to make get_action_events_by_timesort return the right thing. 1186 // It needs to be fixed, see MDL-58736. 1187 $this->setUser($users[$description]); 1188 return $carry + [ 1189 'For user ' . lcfirst($description) => $vault->get_action_events_by_course($users[$description], $course) 1190 ]; 1191 }, []); 1192 1193 foreach ($usersevents as $description => $userevents) { 1194 if ($description == 'For user in group A and B') { 1195 // User is in both A and B, so they should see the override for both 1196 // given that the priority is the same. 1197 $this->assertCount(2, $userevents); 1198 continue; 1199 } 1200 1201 // Otherwise there should be only one assign event for each user. 1202 $this->assertCount(1, $userevents); 1203 } 1204 1205 // User in only group A should see the group A override. 1206 $this->assertEquals('Assignment 1 due date - Group A override', $usersevents['For user only in group A'][0]->get_name()); 1207 1208 // User in only group B should see the group B override. 1209 $this->assertEquals('Assignment 1 due date - Group B override', $usersevents['For user only in group B'][0]->get_name()); 1210 1211 // User in group A and B should see see both overrides since the priorities are the same. 1212 $this->assertEquals('Assignment 1 due date - Group A override', $usersevents['For user in group A and B'][0]->get_name()); 1213 $this->assertEquals('Assignment 1 due date - Group B override', $usersevents['For user in group A and B'][1]->get_name()); 1214 1215 // User in no groups should see the plain assignment event. 1216 $this->assertEquals('Assignment 1 due date', $usersevents['For user in no groups'][0]->get_name()); 1217 } 1218 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body