Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

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