MDL-67271 core: Add test to find missing SVG icons
[moodle.git] / lib / tests / db / upgradelib_test.php
blobf989d285ec809266572e72111f1079312f77b770
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.
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/>.
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;
21 /**
22 * Unit tests for the lib/db/upgradelib.php library.
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
29 class upgradelib_test extends \advanced_testcase {
31 /**
32 * Shared setup for the testcase.
34 public function setUp(): void {
35 global $CFG;
37 require_once("{$CFG->libdir}/db/upgradelib.php");
38 require_once("{$CFG->dirroot}/my/lib.php");
41 /**
42 * Ensure that the upgrade_block_set_defaultregion function performs as expected.
44 * Only targetted blocks and pages should be affected.
46 * @covers ::upgrade_block_set_defaultregion
48 public function test_upgrade_block_set_defaultregion(): void {
49 global $DB;
51 $this->resetAfterTest();
53 // Ensure that only the targetted blocks are affected.
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 ]);
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 ]);
67 $unchanged = [];
68 $changed = [];
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 ]);
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 ]);
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 ]);
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',
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',
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');
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);
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);
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);
139 * Ensure that the upgrade_block_set_defaultregion function performs as expected.
141 * Missing block entries will be created.
143 * @covers ::upgrade_block_set_defaultregion
145 public function test_upgrade_block_set_defaultregion_create_missing(): void {
146 global $DB;
148 $this->resetAfterTest();
150 // Ensure that only the targetted blocks are affected.
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,
163 $mycourses[] = $DB->insert_record('my_pages', (object) [
164 'userid' => $user->id,
165 'name' => '__courses',
166 'private' => MY_PAGE_PRIVATE,
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 ]));
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');
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,
190 $this->assertCount(1, $blocks);
192 $theblock = reset($blocks);
193 $this->assertEquals('calendar_month', $theblock->blockname);
194 $this->assertEquals('content', $theblock->defaultregion);
195 $this->assertEquals('my-index', $theblock->pagetypepattern);
197 // Fetch the user details.
198 $dashboard = $DB->get_record('my_pages', ['id' => $dashboardid]);
199 $usercontext = \context_user::instance($dashboard->userid);
201 $this->assertEquals($usercontext->id, $theblock->parentcontextid);
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 ]));
213 * Ensure that the upgrade_block_delete_instances function performs as expected.
215 * Missing block entries will be created.
217 * @covers ::upgrade_block_delete_instances
219 public function test_upgrade_block_delete_instances(): void {
220 global $DB;
222 $this->resetAfterTest();
224 $DB->delete_records('block_instances');
226 // Ensure that only the targetted blocks are affected.
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;
235 // Get the page for the my-courses page.
236 $mycoursesid = $DB->get_record('my_pages', [
237 'name' => MY_PAGE_COURSES,
238 ], 'id')->id;
240 $dashboards = [];
241 $unchanged = [];
242 $unchangedcontexts = [];
243 $unchangedpreferences = [];
244 $deleted = [];
245 $deletedcontexts = [];
246 $deletedpreferences = [];
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',
253 $unchanged[] = $this->getDataGenerator()->create_block('myoverview', [
254 'defaultregion' => 'left-side',
256 $unchanged[] = $this->getDataGenerator()->create_block('calendar_month', [
257 'defaultregion' => 'left-side',
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',
266 $unchanged[] = $this->getDataGenerator()->create_block('myoverview', [
267 'pagetypepattern' => 'my-index',
268 'subpagepattern' => $dashboardid,
269 'defaultregion' => 'left-side',
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',
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',
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',
293 // Create blocks for users with preferences now.
294 while (count($dashboards) < 10) {
295 $userunchangedblocks = [];
296 $userdeletedblocks = [];
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,
304 $dashboards[] = $userdashboardid;
306 $usermycoursesid = $DB->insert_record('my_pages', (object) [
307 'userid' => $user->id,
308 'name' => '__courses',
309 'private' => MY_PAGE_PRIVATE,
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',
318 $userunchangedblocks[] = $this->getDataGenerator()->create_block('myoverview', [
319 'pagetypepattern' => 'my-index',
320 'subpagepattern' => $userdashboardid,
321 'defaultregion' => 'left-side',
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',
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',
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',
345 $unchanged += $userunchangedblocks;
346 $deleted += $userdeletedblocks;
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;
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;
363 // Create missing contexts.
364 \context_helper::create_instances(CONTEXT_BLOCK);
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);
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,
383 foreach ($deleted as $block) {
384 // Get contexts.
385 $deletedcontexts[] = \context_block::instance($block->id);
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,
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');
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);
408 // Ensure that the block positions remain.
409 $this->assertEquals(1, $DB->count_records('block_positions', ['blockinstanceid' => $original->id]));
412 foreach ($unchangedcontexts as $context) {
413 // Ensure that the context still exists.
414 $this->assertEquals(1, $DB->count_records('context', ['id' => $context->id]));
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 ]));
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]));
429 // Ensure that the block positions was removed.
430 $this->assertEquals(0, $DB->count_records('block_positions', ['blockinstanceid' => $original->id]));
433 foreach ($deletedcontexts as $context) {
434 // Ensure that the context still exists.
435 $this->assertEquals(0, $DB->count_records('context', ['id' => $context->id]));
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 ]));
448 * Ensrue that the upgrade_block_set_my_user_parent_context function performs as expected.
450 * @covers ::upgrade_block_set_my_user_parent_context
452 public function test_upgrade_block_set_my_user_parent_context(): void {
453 global $DB;
455 $this->resetAfterTest();
456 $this->preventResetByRollback();
458 $systemcontext = \context_system::instance();
460 $dashboards = [];
461 $otherblocknames = [
462 'online_users',
463 'myoverview',
464 'calendar_month',
466 $affectedblockname = 'timeline';
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,
476 $dashboards[] = $dashboard;
478 $mycourse = $DB->insert_record('my_pages', (object) [
479 'userid' => $user->id,
480 'name' => '__courses',
481 'private' => MY_PAGE_PRIVATE,
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,
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,
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,
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,
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');
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);
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);
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);
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);