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 // Note: This namespace is not technically correct, but we have to make it different to the tests for lib/upgradelib.php 18 // and this is more correct than alternatives. 19 namespace core\db; 20 21 /** 22 * Unit tests for the lib/db/upgradelib.php library. 23 * 24 * @package core 25 * @category phpunit 26 * @copyright 2022 Andrew Lyons <andrew@thelyons.family> 27 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 28 */ 29 class upgradelib_test extends \advanced_testcase { 30 31 /** 32 * Shared setup for the testcase. 33 */ 34 public function setUp(): void { 35 global $CFG; 36 37 require_once("{$CFG->libdir}/db/upgradelib.php"); 38 require_once("{$CFG->dirroot}/my/lib.php"); 39 } 40 41 /** 42 * Ensure that the upgrade_block_set_defaultregion function performs as expected. 43 * 44 * Only targetted blocks and pages should be affected. 45 * 46 * @covers ::upgrade_block_set_defaultregion 47 */ 48 public function test_upgrade_block_set_defaultregion(): void { 49 global $DB; 50 51 $this->resetAfterTest(); 52 53 // Ensure that only the targetted blocks are affected. 54 55 // Create a my-index entry for the Dashboard. 56 $dashboardid = $DB->insert_record('my_pages', (object) [ 57 'name' => '__default', 58 'private' => MY_PAGE_PRIVATE, 59 ]); 60 61 // Create a page for the my-courses page. 62 $mycoursesid = $DB->insert_record('my_pages', (object) [ 63 'name' => '__courses', 64 'private' => MY_PAGE_PRIVATE, 65 ]); 66 67 $unchanged = []; 68 $changed = []; 69 70 // Create several blocks of different types. 71 // These are not linked to the my-index page above, so should not be modified. 72 $unchanged[] = $this->getDataGenerator()->create_block('online_users', [ 73 'defaultregion' => 'left-side', 74 ]); 75 $unchanged[] = $this->getDataGenerator()->create_block('myoverview', [ 76 'defaultregion' => 'left-side', 77 ]); 78 $unchanged[] = $this->getDataGenerator()->create_block('calendar_month', [ 79 'defaultregion' => 'left-side', 80 ]); 81 82 // These are on the my-index above, but are not the block being updated. 83 $unchanged[] = $this->getDataGenerator()->create_block('online_users', [ 84 'pagetypepattern' => 'my-index', 85 'subpagepattern' => $dashboardid, 86 'defaultregion' => 'left-side', 87 ]); 88 $unchanged[] = $this->getDataGenerator()->create_block('myoverview', [ 89 'pagetypepattern' => 'my-index', 90 'subpagepattern' => $dashboardid, 91 'defaultregion' => 'left-side', 92 ]); 93 94 // This is on a my-index page, and is the affected block, but is on the mycourses page, not the dashboard. 95 $unchanged[] = $this->getDataGenerator()->create_block('calendar_month', [ 96 'pagetypepattern' => 'my-index', 97 'subpagepattern' => $mycoursesid, 98 'defaultregion' => 'left-side', 99 ]); 100 101 // This is on the default dashboard, and is the affected block, but not a my-index page. 102 $unchanged[] = $this->getDataGenerator()->create_block('calendar_month', [ 103 'pagetypepattern' => 'not-my-index', 104 'subpagepattern' => $dashboardid, 105 'defaultregion' => 'left-side', 106 ]); 107 108 // This is the match which should be changed. 109 $changed[] = $this->getDataGenerator()->create_block('calendar_month', [ 110 'pagetypepattern' => 'my-index', 111 'subpagepattern' => $dashboardid, 112 'defaultregion' => 'left-side', 113 ]); 114 115 // Perform the operation. 116 // Target all calendar_month blocks matching 'my-index' and update them to the 'content' region where they 117 // belong to the user dashboard ('pagename' == '__default'). 118 upgrade_block_set_defaultregion('calendar_month', '__default', 'my-index', 'content'); 119 120 // Ensure that the relevant blocks remain unchanged. 121 foreach ($unchanged as $original) { 122 $block = $DB->get_record('block_instances', ['id' => $original->id]); 123 $this->assertEquals($original, $block); 124 } 125 126 // Ensure that only the expected blocks were changed. 127 foreach ($changed as $original) { 128 $block = $DB->get_record('block_instances', ['id' => $original->id]); 129 $this->assertNotEquals($original, $block); 130 131 // Only the defaultregion should be updated to content. No other changes are expected. 132 $expected = (object) $original; 133 $expected->defaultregion = 'content'; 134 $this->assertEquals($expected, $block); 135 } 136 } 137 138 /** 139 * Ensure that the upgrade_block_set_defaultregion function performs as expected. 140 * 141 * Missing block entries will be created. 142 * 143 * @covers ::upgrade_block_set_defaultregion 144 */ 145 public function test_upgrade_block_set_defaultregion_create_missing(): void { 146 global $DB; 147 148 $this->resetAfterTest(); 149 150 // Ensure that only the targetted blocks are affected. 151 152 $dashboards = []; 153 $mycourses = []; 154 // Create dashboard pages for a number of users. 155 while (count($dashboards) < 10) { 156 $user = $this->getDataGenerator()->create_user(); 157 $dashboards[] = $DB->insert_record('my_pages', (object) [ 158 'userid' => $user->id, 159 'name' => '__default', 160 'private' => MY_PAGE_PRIVATE, 161 ]); 162 163 $mycourses[] = $DB->insert_record('my_pages', (object) [ 164 'userid' => $user->id, 165 'name' => '__courses', 166 'private' => MY_PAGE_PRIVATE, 167 ]); 168 } 169 170 // Enusre that there are no blocks initially. 171 foreach ($dashboards as $dashboardid) { 172 $this->assertEquals(0, $DB->count_records('block_instances', [ 173 'subpagepattern' => $dashboardid, 174 ])); 175 } 176 177 // Perform the operation. 178 // Target all calendar_month blocks matching 'my-index' and update them to the 'content' region where they 179 // belong to the user dashboard ('pagename' == '__default'). 180 // Any dashboards which are missing the block will have it created by the operation. 181 upgrade_block_set_defaultregion('calendar_month', '__default', 'my-index', 'content'); 182 183 // Each of the dashboards should now have a block instance of the calendar_month block in the 'content' region 184 // on 'my-index' only. 185 foreach ($dashboards as $dashboardid) { 186 // Only one block should have been created. 187 $blocks = $DB->get_records('block_instances', [ 188 'subpagepattern' => $dashboardid, 189 ]); 190 $this->assertCount(1, $blocks); 191 192 $theblock = reset($blocks); 193 $this->assertEquals('calendar_month', $theblock->blockname); 194 $this->assertEquals('content', $theblock->defaultregion); 195 $this->assertEquals('my-index', $theblock->pagetypepattern); 196 197 // Fetch the user details. 198 $dashboard = $DB->get_record('my_pages', ['id' => $dashboardid]); 199 $usercontext = \context_user::instance($dashboard->userid); 200 201 $this->assertEquals($usercontext->id, $theblock->parentcontextid); 202 } 203 204 // Enusre that there are no blocks on the mycourses page. 205 foreach ($mycourses as $pageid) { 206 $this->assertEquals(0, $DB->count_records('block_instances', [ 207 'subpagepattern' => $pageid, 208 ])); 209 } 210 } 211 212 /** 213 * Ensure that the upgrade_block_delete_instances function performs as expected. 214 * 215 * Missing block entries will be created. 216 * 217 * @covers ::upgrade_block_delete_instances 218 */ 219 public function test_upgrade_block_delete_instances(): void { 220 global $DB; 221 222 $this->resetAfterTest(); 223 224 $DB->delete_records('block_instances'); 225 226 // Ensure that only the targetted blocks are affected. 227 228 // Get the my-index entry for the Dashboard. 229 $dashboardid = $DB->get_record('my_pages', [ 230 'userid' => null, 231 'name' => '__default', 232 'private' => MY_PAGE_PRIVATE, 233 ], 'id')->id; 234 235 // Get the page for the my-courses page. 236 $mycoursesid = $DB->get_record('my_pages', [ 237 'name' => MY_PAGE_COURSES, 238 ], 'id')->id; 239 240 $dashboards = []; 241 $unchanged = []; 242 $unchangedcontexts = []; 243 $unchangedpreferences = []; 244 $deleted = []; 245 $deletedcontexts = []; 246 $deletedpreferences = []; 247 248 // Create several blocks of different types. 249 // These are not linked to the my page above, so should not be modified. 250 $unchanged[] = $this->getDataGenerator()->create_block('online_users', [ 251 'defaultregion' => 'left-side', 252 ]); 253 $unchanged[] = $this->getDataGenerator()->create_block('myoverview', [ 254 'defaultregion' => 'left-side', 255 ]); 256 $unchanged[] = $this->getDataGenerator()->create_block('calendar_month', [ 257 'defaultregion' => 'left-side', 258 ]); 259 260 // These are on the my-index above, but are not the block being updated. 261 $unchanged[] = $this->getDataGenerator()->create_block('online_users', [ 262 'pagetypepattern' => 'my-index', 263 'subpagepattern' => $dashboardid, 264 'defaultregion' => 'left-side', 265 ]); 266 $unchanged[] = $this->getDataGenerator()->create_block('myoverview', [ 267 'pagetypepattern' => 'my-index', 268 'subpagepattern' => $dashboardid, 269 'defaultregion' => 'left-side', 270 ]); 271 272 // This is on a my-index page, and is the affected block, but is on the mycourses page, not the dashboard. 273 $unchanged[] = $this->getDataGenerator()->create_block('calendar_month', [ 274 'pagetypepattern' => 'my-index', 275 'subpagepattern' => $mycoursesid, 276 'defaultregion' => 'left-side', 277 ]); 278 279 // This is on the default dashboard, and is the affected block, but not a my-index page. 280 $unchanged[] = $this->getDataGenerator()->create_block('calendar_month', [ 281 'pagetypepattern' => 'not-my-index', 282 'subpagepattern' => $dashboardid, 283 'defaultregion' => 'left-side', 284 ]); 285 286 // This is the match which should be changed. 287 $deleted[] = $this->getDataGenerator()->create_block('calendar_month', [ 288 'pagetypepattern' => 'my-index', 289 'subpagepattern' => $dashboardid, 290 'defaultregion' => 'left-side', 291 ]); 292 293 // Create blocks for users with preferences now. 294 while (count($dashboards) < 10) { 295 $userunchangedblocks = []; 296 $userdeletedblocks = []; 297 298 $user = $this->getDataGenerator()->create_user(); 299 $userdashboardid = $DB->insert_record('my_pages', (object) [ 300 'userid' => $user->id, 301 'name' => '__default', 302 'private' => MY_PAGE_PRIVATE, 303 ]); 304 $dashboards[] = $userdashboardid; 305 306 $usermycoursesid = $DB->insert_record('my_pages', (object) [ 307 'userid' => $user->id, 308 'name' => '__courses', 309 'private' => MY_PAGE_PRIVATE, 310 ]); 311 312 // These are on the my-index above, but are not the block being updated. 313 $userunchangedblocks[] = $this->getDataGenerator()->create_block('online_users', [ 314 'pagetypepattern' => 'my-index', 315 'subpagepattern' => $userdashboardid, 316 'defaultregion' => 'left-side', 317 ]); 318 $userunchangedblocks[] = $this->getDataGenerator()->create_block('myoverview', [ 319 'pagetypepattern' => 'my-index', 320 'subpagepattern' => $userdashboardid, 321 'defaultregion' => 'left-side', 322 ]); 323 324 // This is on a my-index page, and is the affected block, but is on the mycourses page, not the dashboard. 325 $userunchangedblocks[] = $this->getDataGenerator()->create_block('calendar_month', [ 326 'pagetypepattern' => 'my-index', 327 'subpagepattern' => $usermycoursesid, 328 'defaultregion' => 'left-side', 329 ]); 330 331 // This is on the default dashboard, and is the affected block, but not a my-index page. 332 $userunchangedblocks[] = $this->getDataGenerator()->create_block('calendar_month', [ 333 'pagetypepattern' => 'not-my-index', 334 'subpagepattern' => $userdashboardid, 335 'defaultregion' => 'left-side', 336 ]); 337 338 // This is the match which should be changed. 339 $userdeletedblocks[] = $this->getDataGenerator()->create_block('calendar_month', [ 340 'pagetypepattern' => 'my-index', 341 'subpagepattern' => $userdashboardid, 342 'defaultregion' => 'left-side', 343 ]); 344 345 $unchanged += $userunchangedblocks; 346 $deleted += $userdeletedblocks; 347 348 foreach ($userunchangedblocks as $block) { 349 // Create user preferences for these blocks. 350 set_user_preference("block{$block->id}hidden", 1, $user); 351 set_user_preference("docked_block_instance_{$block->id}", 1, $user); 352 $unchangedpreferences[] = $block->id; 353 } 354 355 foreach ($userdeletedblocks as $block) { 356 // Create user preferences for these blocks. 357 set_user_preference("block{$block->id}hidden", 1, $user); 358 set_user_preference("docked_block_instance_{$block->id}", 1, $user); 359 $deletedpreferences[] = $block->id; 360 } 361 } 362 363 // Create missing contexts. 364 \context_helper::create_instances(CONTEXT_BLOCK); 365 366 // Ensure that other related test data is present. 367 $systemcontext = \context_system::instance(); 368 foreach ($unchanged as $block) { 369 // Get contexts. 370 $unchangedcontexts[] = \context_block::instance($block->id); 371 372 // Create a block position. 373 $DB->insert_record('block_positions', [ 374 'blockinstanceid' => $block->id, 375 'contextid' => $systemcontext->id, 376 'pagetype' => 'course-view-topics', 377 'region' => 'site-post', 378 'weight' => 1, 379 'visible' => 1, 380 ]); 381 } 382 383 foreach ($deleted as $block) { 384 // Get contexts. 385 $deletedcontexts[] = \context_block::instance($block->id); 386 387 // Create a block position. 388 $DB->insert_record('block_positions', [ 389 'blockinstanceid' => $block->id, 390 'contextid' => $systemcontext->id, 391 'pagetype' => 'course-view-topics', 392 'region' => 'site-post', 393 'weight' => 1, 394 'visible' => 1, 395 ]); 396 } 397 398 // Perform the operation. 399 // Target all calendar_month blocks matching 'my-index' and update them to the 'content' region where they 400 // belong to the user dashboard ('pagename' == '__default'). 401 upgrade_block_delete_instances('calendar_month', '__default', 'my-index'); 402 403 // Ensure that the relevant blocks remain unchanged. 404 foreach ($unchanged as $original) { 405 $block = $DB->get_record('block_instances', ['id' => $original->id]); 406 $this->assertEquals($original, $block); 407 408 // Ensure that the block positions remain. 409 $this->assertEquals(1, $DB->count_records('block_positions', ['blockinstanceid' => $original->id])); 410 } 411 412 foreach ($unchangedcontexts as $context) { 413 // Ensure that the context still exists. 414 $this->assertEquals(1, $DB->count_records('context', ['id' => $context->id])); 415 } 416 417 foreach ($unchangedpreferences as $blockid) { 418 // Ensure that the context still exists. 419 $this->assertEquals(1, $DB->count_records('user_preferences', ['name' => "block{$blockid}hidden"])); 420 $this->assertEquals(1, $DB->count_records('user_preferences', [ 421 'name' => "docked_block_instance_{$blockid}", 422 ])); 423 } 424 425 // Ensure that only the expected blocks were changed. 426 foreach ($deleted as $original) { 427 $this->assertCount(0, $DB->get_records('block_instances', ['id' => $original->id])); 428 429 // Ensure that the block positions was removed. 430 $this->assertEquals(0, $DB->count_records('block_positions', ['blockinstanceid' => $original->id])); 431 } 432 433 foreach ($deletedcontexts as $context) { 434 // Ensure that the context still exists. 435 $this->assertEquals(0, $DB->count_records('context', ['id' => $context->id])); 436 } 437 438 foreach ($deletedpreferences as $blockid) { 439 // Ensure that the context still exists. 440 $this->assertEquals(0, $DB->count_records('user_preferences', ['name' => "block{$blockid}hidden"])); 441 $this->assertEquals(0, $DB->count_records('user_preferences', [ 442 'name' => "docked_block_instance_{$blockid}", 443 ])); 444 } 445 } 446 447 /** 448 * Ensrue that the upgrade_block_set_my_user_parent_context function performs as expected. 449 * 450 * @covers ::upgrade_block_set_my_user_parent_context 451 */ 452 public function test_upgrade_block_set_my_user_parent_context(): void { 453 global $DB; 454 455 $this->resetAfterTest(); 456 $this->preventResetByRollback(); 457 458 $systemcontext = \context_system::instance(); 459 460 $dashboards = []; 461 $otherblocknames = [ 462 'online_users', 463 'myoverview', 464 'calendar_month', 465 ]; 466 $affectedblockname = 'timeline'; 467 468 // Create dashboard pages for a number of users. 469 while (count($dashboards) < 10) { 470 $user = $this->getDataGenerator()->create_user(); 471 $dashboard = $DB->insert_record('my_pages', (object) [ 472 'userid' => $user->id, 473 'name' => '__default', 474 'private' => MY_PAGE_PRIVATE, 475 ]); 476 $dashboards[] = $dashboard; 477 478 $mycourse = $DB->insert_record('my_pages', (object) [ 479 'userid' => $user->id, 480 'name' => '__courses', 481 'private' => MY_PAGE_PRIVATE, 482 ]); 483 484 // These are on the my-index above, but are not the block being updated. 485 foreach ($otherblocknames as $blockname) { 486 $unchanged[] = $this->getDataGenerator()->create_block($blockname, [ 487 'parentcontextid' => $systemcontext->id, 488 'pagetypepattern' => 'my-index', 489 'subpagepattern' => $dashboard, 490 ]); 491 } 492 493 // This is on a my-index page, and is the affected block, but is on the mycourses page, not the dashboard. 494 $unchanged[] = $this->getDataGenerator()->create_block($affectedblockname, [ 495 'parentcontextid' => $systemcontext->id, 496 'pagetypepattern' => 'my-index', 497 'subpagepattern' => $mycourse, 498 ]); 499 500 // This is on the default dashboard, and is the affected block, but not a my-index page. 501 $unchanged[] = $this->getDataGenerator()->create_block($affectedblockname, [ 502 'parentcontextid' => $systemcontext->id, 503 'pagetypepattern' => 'not-my-index', 504 'subpagepattern' => $dashboard, 505 ]); 506 507 // This is the match which should be changed. 508 $changed[] = $this->getDataGenerator()->create_block($affectedblockname, [ 509 'parentcontextid' => $systemcontext->id, 510 'pagetypepattern' => 'my-index', 511 'subpagepattern' => $dashboard, 512 ]); 513 } 514 515 // Perform the operation. 516 // Target all affected blocks matching 'my-index' and correct the context to the relevant user's contexct. 517 // Only the '__default' dashboard on the 'my-index' my_page should be affected. 518 upgrade_block_set_my_user_parent_context($affectedblockname, '__default', 'my-index'); 519 520 // Ensure that the relevant blocks remain unchanged. 521 foreach ($unchanged as $original) { 522 $block = $DB->get_record('block_instances', ['id' => $original->id]); 523 $this->assertEquals($original, $block); 524 } 525 526 // Ensure that only the expected blocks were changed. 527 foreach ($changed as $original) { 528 $block = $DB->get_record('block_instances', ['id' => $original->id]); 529 $this->assertNotEquals($original, $block); 530 531 // Fetch the my page and user details. 532 $dashboard = $DB->get_record('my_pages', ['id' => $original->subpagepattern]); 533 $usercontext = \context_user::instance($dashboard->userid); 534 535 // Only the contextid should be updated to the relevant user's context. 536 // No other changes are expected. 537 $expected = (object) $original; 538 $expected->parentcontextid = $usercontext->id; 539 $this->assertEquals($expected, $block); 540 } 541 } 542 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body