See Release Notes
Long Term Support Release
Differences Between: [Versions 400 and 401]
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 declare(strict_types=1); 18 19 namespace core_reportbuilder\local\helpers; 20 21 use advanced_testcase; 22 use invalid_parameter_exception; 23 use core_cohort\reportbuilder\audience\cohortmember; 24 use core_reportbuilder_generator; 25 use core_reportbuilder\local\models\schedule as model; 26 use core_reportbuilder\reportbuilder\audience\manual; 27 use core_user\reportbuilder\datasource\users; 28 29 /** 30 * Unit tests for the schedule helper class 31 * 32 * @package core_reportbuilder 33 * @covers \core_reportbuilder\local\helpers\schedule 34 * @copyright 2021 Paul Holden <paulh@moodle.com> 35 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 36 */ 37 class schedule_test extends advanced_testcase { 38 39 /** 40 * Test create schedule 41 */ 42 public function test_create_schedule(): void { 43 $this->resetAfterTest(); 44 $this->setAdminUser(); 45 46 /** @var core_reportbuilder_generator $generator */ 47 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 48 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 49 50 $timescheduled = time() + DAYSECS; 51 $schedule = schedule::create_schedule((object) [ 52 'name' => 'My schedule', 53 'reportid' => $report->get('id'), 54 'format' => 'csv', 55 'subject' => 'Hello', 56 'message' => 'Hola', 57 'timescheduled' => $timescheduled, 58 ]); 59 60 $this->assertEquals('My schedule', $schedule->get('name')); 61 $this->assertEquals($report->get('id'), $schedule->get('reportid')); 62 $this->assertEquals('csv', $schedule->get('format')); 63 $this->assertEquals('Hello', $schedule->get('subject')); 64 $this->assertEquals('Hola', $schedule->get('message')); 65 $this->assertEquals($timescheduled, $schedule->get('timescheduled')); 66 $this->assertEquals($timescheduled, $schedule->get('timenextsend')); 67 } 68 69 /** 70 * Test update schedule 71 */ 72 public function test_update_schedule(): void { 73 $this->resetAfterTest(); 74 $this->setAdminUser(); 75 76 /** @var core_reportbuilder_generator $generator */ 77 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 78 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 79 $schedule = $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'My schedule']); 80 81 // Update some record properties. 82 $record = $schedule->to_record(); 83 $record->name = 'My updated schedule'; 84 $record->timescheduled = 1861340400; // 25/12/2028 07:00 UTC. 85 86 $schedule = schedule::update_schedule($record); 87 $this->assertEquals($record->name, $schedule->get('name')); 88 $this->assertEquals($record->timescheduled, $schedule->get('timescheduled')); 89 } 90 91 /** 92 * Test update invalid schedule 93 */ 94 public function test_update_schedule_invalid(): void { 95 $this->resetAfterTest(); 96 $this->setAdminUser(); 97 98 /** @var core_reportbuilder_generator $generator */ 99 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 100 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 101 102 $this->expectException(invalid_parameter_exception::class); 103 $this->expectExceptionMessage('Invalid schedule'); 104 schedule::update_schedule((object) ['id' => 42, 'reportid' => $report->get('id')]); 105 } 106 107 /** 108 * Test toggle schedule 109 */ 110 public function test_toggle_schedule(): void { 111 $this->resetAfterTest(); 112 $this->setAdminUser(); 113 114 /** @var core_reportbuilder_generator $generator */ 115 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 116 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 117 $schedule = $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'My schedule']); 118 119 // Disable the schedule. 120 schedule::toggle_schedule($report->get('id'), $schedule->get('id'), false); 121 $schedule = $schedule->read(); 122 $this->assertFalse($schedule->get('enabled')); 123 124 // Enable the schedule. 125 schedule::toggle_schedule($report->get('id'), $schedule->get('id'), true); 126 $schedule = $schedule->read(); 127 $this->assertTrue($schedule->get('enabled')); 128 } 129 130 /** 131 * Test toggle invalid schedule 132 */ 133 public function test_toggle_schedule_invalid(): void { 134 $this->resetAfterTest(); 135 $this->setAdminUser(); 136 137 /** @var core_reportbuilder_generator $generator */ 138 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 139 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 140 141 $this->expectException(invalid_parameter_exception::class); 142 $this->expectExceptionMessage('Invalid schedule'); 143 schedule::toggle_schedule($report->get('id'), 42, true); 144 } 145 146 /** 147 * Test delete schedule 148 */ 149 public function test_delete_schedule(): void { 150 $this->resetAfterTest(); 151 $this->setAdminUser(); 152 153 /** @var core_reportbuilder_generator $generator */ 154 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 155 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 156 $schedule = $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'My schedule']); 157 158 $scheduleid = $schedule->get('id'); 159 160 schedule::delete_schedule($report->get('id'), $scheduleid); 161 $this->assertFalse($schedule::record_exists($scheduleid)); 162 } 163 164 /** 165 * Test delete invalid schedule 166 */ 167 public function test_delete_schedule_invalid(): void { 168 $this->resetAfterTest(); 169 $this->setAdminUser(); 170 171 /** @var core_reportbuilder_generator $generator */ 172 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 173 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 174 175 $this->expectException(invalid_parameter_exception::class); 176 $this->expectExceptionMessage('Invalid schedule'); 177 schedule::delete_schedule($report->get('id'), 42); 178 } 179 180 /** 181 * Test getting schedule report users (those in matching audience) 182 */ 183 public function test_get_schedule_report_users(): void { 184 $this->resetAfterTest(); 185 186 /** @var core_reportbuilder_generator $generator */ 187 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 188 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 189 190 // Create cohort, with some members. 191 $cohort = $this->getDataGenerator()->create_cohort(); 192 $cohortuserone = $this->getDataGenerator()->create_user(['firstname' => 'Zoe', 'lastname' => 'Zebra']); 193 cohort_add_member($cohort->id, $cohortuserone->id); 194 $cohortusertwo = $this->getDataGenerator()->create_user(['firstname' => 'Henrietta', 'lastname' => 'Hamster']); 195 cohort_add_member($cohort->id, $cohortusertwo->id); 196 197 // Create a third user, to be added manually. 198 $manualuserone = $this->getDataGenerator()->create_user(['firstname' => 'Bob', 'lastname' => 'Badger']); 199 200 $audiencecohort = $generator->create_audience([ 201 'reportid' => $report->get('id'), 202 'classname' => cohortmember::class, 203 'configdata' => ['cohorts' => [$cohort->id]], 204 ]); 205 206 $audiencemanual = $generator->create_audience([ 207 'reportid' => $report->get('id'), 208 'classname' => manual::class, 209 'configdata' => ['users' => [$manualuserone->id]], 210 ]); 211 212 // Now create our schedule. 213 $schedule = $generator->create_schedule([ 214 'reportid' => $report->get('id'), 215 'name' => 'My schedule', 216 'audiences' => json_encode([ 217 $audiencecohort->get_persistent()->get('id'), 218 $audiencemanual->get_persistent()->get('id'), 219 ]), 220 ]); 221 222 $users = schedule::get_schedule_report_users($schedule); 223 $this->assertEquals([ 224 'Bob', 225 'Henrietta', 226 'Zoe', 227 ], array_column($users, 'firstname')); 228 229 // Now delete one of our users, ensure they are no longer returned. 230 delete_user($manualuserone); 231 232 $users = schedule::get_schedule_report_users($schedule); 233 $this->assertEquals([ 234 'Henrietta', 235 'Zoe', 236 ], array_column($users, 'firstname')); 237 } 238 239 /** 240 * Test getting schedule report row count 241 */ 242 public function test_get_schedule_report_count(): void { 243 $this->resetAfterTest(); 244 245 /** @var core_reportbuilder_generator $generator */ 246 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 247 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 248 $schedule = $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'My schedule']); 249 250 // There is only one row in the report (the only user on the site). 251 $count = schedule::get_schedule_report_count($schedule); 252 $this->assertEquals(1, $count); 253 } 254 255 /** 256 * Data provider for {@see test_get_schedule_report_file} 257 * 258 * @return string[] 259 */ 260 public function get_schedule_report_file_format(): array { 261 return [ 262 ['csv'], 263 ['excel'], 264 ['html'], 265 ['json'], 266 ['ods'], 267 ['pdf'], 268 ]; 269 } 270 271 /** 272 * Test getting schedule report exported file, in each supported format 273 * 274 * @param string $format 275 * 276 * @dataProvider get_schedule_report_file_format 277 */ 278 public function test_get_schedule_report_file(string $format): void { 279 $this->resetAfterTest(); 280 $this->setAdminUser(); 281 282 /** @var core_reportbuilder_generator $generator */ 283 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 284 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 285 $schedule = $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'My schedule', 'format' => $format]); 286 287 // There is only one row in the report (the only user on the site). 288 $file = schedule::get_schedule_report_file($schedule); 289 $this->assertGreaterThan(64, $file->get_filesize()); 290 } 291 292 /** 293 * Data provider for {@see test_should_send_schedule} 294 * 295 * @return array[] 296 */ 297 public function should_send_schedule_provider(): array { 298 $time = time(); 299 300 // We just need large offsets for dates in the past/future. 301 $yesterday = $time - DAYSECS; 302 $tomorrow = $time + DAYSECS; 303 304 return [ 305 'Disabled' => [[ 306 'enabled' => false, 307 ], false], 308 'Time scheduled in the past' => [[ 309 'recurrence' => model::RECURRENCE_NONE, 310 'timescheduled' => $yesterday, 311 ], true], 312 'Time scheduled in the past, already sent prior to schedule' => [[ 313 'recurrence' => model::RECURRENCE_NONE, 314 'timescheduled' => $yesterday, 315 'timelastsent' => $yesterday - HOURSECS, 316 ], true], 317 'Time scheduled in the past, already sent on schedule' => [[ 318 'recurrence' => model::RECURRENCE_NONE, 319 'timescheduled' => $yesterday, 320 'timelastsent' => $yesterday, 321 ], false], 322 'Time scheduled in the future' => [[ 323 'recurrence' => model::RECURRENCE_NONE, 324 'timescheduled' => $tomorrow, 325 ], false], 326 'Time scheduled in the future, already sent prior to schedule' => [[ 327 'recurrence' => model::RECURRENCE_NONE, 328 'timelastsent' => $yesterday, 329 'timescheduled' => $tomorrow, 330 ], false], 331 'Next send in the past' => [[ 332 'recurrence' => model::RECURRENCE_DAILY, 333 'timescheduled' => $yesterday, 334 'timenextsend' => $yesterday, 335 ], true], 336 'Next send in the future' => [[ 337 'recurrence' => model::RECURRENCE_DAILY, 338 'timescheduled' => $yesterday, 339 'timenextsend' => $tomorrow, 340 ], false], 341 ]; 342 } 343 344 /** 345 * Test for whether a schedule should be sent 346 * 347 * @param array $properties 348 * @param bool $expected 349 * 350 * @dataProvider should_send_schedule_provider 351 */ 352 public function test_should_send_schedule(array $properties, bool $expected): void { 353 $this->resetAfterTest(); 354 355 /** @var core_reportbuilder_generator $generator */ 356 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 357 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 358 359 $schedule = $generator->create_schedule(['reportid' => $report->get('id'), 'name' => 'My schedule'] + $properties); 360 361 // If "Time next send" is specified, then override calculated value. 362 if (array_key_exists('timenextsend', $properties)) { 363 $schedule->set('timenextsend', $properties['timenextsend']); 364 } 365 366 $this->assertEquals($expected, schedule::should_send_schedule($schedule)); 367 } 368 369 /** 370 * Data provider for {@see test_calculate_next_send_time} 371 * 372 * @return array[] 373 */ 374 public function calculate_next_send_time_provider(): array { 375 $timescheduled = 1635865200; // Tue Nov 02 2021 15:00:00 GMT+0000. 376 $timenow = 1639846800; // Sat Dec 18 2021 17:00:00 GMT+0000. 377 378 return [ 379 'No recurrence' => [model::RECURRENCE_NONE, $timescheduled, $timenow, $timescheduled], 380 'Recurrence, time scheduled in future' => [model::RECURRENCE_DAILY, $timenow + DAYSECS, $timenow, $timenow + DAYSECS], 381 // Sun Dec 19 2021 15:00:00 GMT+0000. 382 'Daily recurrence' => [model::RECURRENCE_DAILY, $timescheduled, $timenow, 1639926000], 383 // Mon Dec 20 2021 15:00:00 GMT+0000. 384 'Weekday recurrence' => [model::RECURRENCE_WEEKDAYS, $timescheduled, $timenow, 1640012400], 385 // Tue Dec 21 2021 15:00:00 GMT+0000. 386 'Weekly recurrence' => [model::RECURRENCE_WEEKLY, $timescheduled, $timenow, 1640098800], 387 // Sun Jan 02 2022 15:00:00 GMT+0000. 388 'Monthy recurrence' => [model::RECURRENCE_MONTHLY, $timescheduled, $timenow, 1641135600], 389 // Wed Nov 02 2022 15:00:00 GMT+0000. 390 'Annual recurrence' => [model::RECURRENCE_ANNUALLY, $timescheduled, $timenow, 1667401200], 391 ]; 392 } 393 394 /** 395 * Test for calculating next schedule send time 396 * 397 * @param int $recurrence 398 * @param int $timescheduled 399 * @param int $timenow 400 * @param int $expected 401 * 402 * @dataProvider calculate_next_send_time_provider 403 */ 404 public function test_calculate_next_send_time(int $recurrence, int $timescheduled, int $timenow, int $expected): void { 405 $this->resetAfterTest(); 406 407 /** @var core_reportbuilder_generator $generator */ 408 $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder'); 409 $report = $generator->create_report(['name' => 'My report', 'source' => users::class]); 410 411 $schedule = $generator->create_schedule([ 412 'reportid' => $report->get('id'), 413 'name' => 'My schedule', 414 'recurrence' => $recurrence, 415 'timescheduled' => $timescheduled, 416 'timenow' => $timenow, 417 ]); 418 419 $this->assertEquals($expected, schedule::calculate_next_send_time($schedule, $timenow)); 420 } 421 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body