1c4b7073de0e8f459ee832b82791cc42e84e2c33
[moodle.git] / lib / tests / upgradelib_test.php
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/>.
17 /**
18  * Unit tests for the lib/upgradelib.php library.
19  *
20  * @package   core
21  * @category  phpunit
22  * @copyright 2013 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
23  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->libdir.'/upgradelib.php');
32 /**
33  * Tests various classes and functions in upgradelib.php library.
34  */
35 class core_upgradelib_testcase extends advanced_testcase {
37     /**
38      * Test the {@link upgrade_stale_php_files_present() function
39      */
40     public function test_upgrade_stale_php_files_present() {
41         // Just call the function, must return bool false always
42         // if there aren't any old files in the codebase.
43         $this->assertFalse(upgrade_stale_php_files_present());
44     }
46     /**
47      * Populate some fake grade items into the database with specified
48      * sortorder and course id.
49      *
50      * NOTE: This function doesn't make much attempt to respect the
51      * gradebook internals, its simply used to fake some data for
52      * testing the upgradelib function. Please don't use it for other
53      * purposes.
54      *
55      * @param int $courseid id of course
56      * @param int $sortorder numeric sorting order of item
57      * @return stdClass grade item object from the database.
58      */
59     private function insert_fake_grade_item_sortorder($courseid, $sortorder) {
60         global $DB, $CFG;
61         require_once($CFG->libdir.'/gradelib.php');
63         $item = new stdClass();
64         $item->courseid = $courseid;
65         $item->sortorder = $sortorder;
66         $item->gradetype = GRADE_TYPE_VALUE;
67         $item->grademin = 30;
68         $item->grademax = 110;
69         $item->itemnumber = 1;
70         $item->iteminfo = '';
71         $item->timecreated = time();
72         $item->timemodified = time();
74         $item->id = $DB->insert_record('grade_items', $item);
76         return $DB->get_record('grade_items', array('id' => $item->id));
77     }
79     public function test_upgrade_fix_missing_root_folders_draft() {
80         global $DB, $SITE;
82         $this->resetAfterTest(true);
84         $user = $this->getDataGenerator()->create_user();
85         $usercontext = context_user::instance($user->id);
86         $this->setUser($user);
87         $resource1 = $this->getDataGenerator()->get_plugin_generator('mod_resource')
88             ->create_instance(array('course' => $SITE->id));
89         $context = context_module::instance($resource1->cmid);
90         $draftitemid = 0;
91         file_prepare_draft_area($draftitemid, $context->id, 'mod_resource', 'content', 0);
93         $queryparams = array(
94             'component' => 'user',
95             'contextid' => $usercontext->id,
96             'filearea' => 'draft',
97             'itemid' => $draftitemid,
98         );
100         // Make sure there are two records in files for the draft file area and one of them has filename '.'.
101         $records = $DB->get_records_menu('files', $queryparams, '', 'id, filename');
102         $this->assertEquals(2, count($records));
103         $this->assertTrue(in_array('.', $records));
104         $originalhash = $DB->get_field('files', 'pathnamehash', $queryparams + array('filename' => '.'));
106         // Delete record with filename '.' and make sure it does not exist any more.
107         $DB->delete_records('files', $queryparams + array('filename' => '.'));
109         $records = $DB->get_records_menu('files', $queryparams, '', 'id, filename');
110         $this->assertEquals(1, count($records));
111         $this->assertFalse(in_array('.', $records));
113         // Run upgrade script and make sure the record is restored.
114         upgrade_fix_missing_root_folders_draft();
116         $records = $DB->get_records_menu('files', $queryparams, '', 'id, filename');
117         $this->assertEquals(2, count($records));
118         $this->assertTrue(in_array('.', $records));
119         $newhash = $DB->get_field('files', 'pathnamehash', $queryparams + array('filename' => '.'));
120         $this->assertEquals($originalhash, $newhash);
121     }
123     /**
124      * Test upgrade minmaxgrade step.
125      */
126     public function test_upgrade_minmaxgrade() {
127         global $CFG, $DB;
128         require_once($CFG->libdir . '/gradelib.php');
129         $initialminmax = $CFG->grade_minmaxtouse;
130         $this->resetAfterTest();
132         $c1 = $this->getDataGenerator()->create_course();
133         $c2 = $this->getDataGenerator()->create_course();
134         $c3 = $this->getDataGenerator()->create_course();
135         $u1 = $this->getDataGenerator()->create_user();
136         $a1 = $this->getDataGenerator()->create_module('assign', array('course' => $c1, 'grade' => 100));
137         $a2 = $this->getDataGenerator()->create_module('assign', array('course' => $c2, 'grade' => 100));
138         $a3 = $this->getDataGenerator()->create_module('assign', array('course' => $c3, 'grade' => 100));
140         $cm1 = get_coursemodule_from_instance('assign', $a1->id);
141         $ctx1 = context_module::instance($cm1->id);
142         $assign1 = new assign($ctx1, $cm1, $c1);
144         $cm2 = get_coursemodule_from_instance('assign', $a2->id);
145         $ctx2 = context_module::instance($cm2->id);
146         $assign2 = new assign($ctx2, $cm2, $c2);
148         $cm3 = get_coursemodule_from_instance('assign', $a3->id);
149         $ctx3 = context_module::instance($cm3->id);
150         $assign3 = new assign($ctx3, $cm3, $c3);
152         // Give a grade to the student.
153         $ug = $assign1->get_user_grade($u1->id, true);
154         $ug->grade = 10;
155         $assign1->update_grade($ug);
157         $ug = $assign2->get_user_grade($u1->id, true);
158         $ug->grade = 20;
159         $assign2->update_grade($ug);
161         $ug = $assign3->get_user_grade($u1->id, true);
162         $ug->grade = 30;
163         $assign3->update_grade($ug);
166         // Run the upgrade.
167         upgrade_minmaxgrade();
169         // Nothing has happened.
170         $this->assertFalse($DB->record_exists('config', array('name' => 'show_min_max_grades_changed_' . $c1->id)));
171         $this->assertSame(false, grade_get_setting($c1->id, 'minmaxtouse', false, true));
172         $this->assertFalse($DB->record_exists('grade_items', array('needsupdate' => 1, 'courseid' => $c1->id)));
173         $this->assertFalse($DB->record_exists('config', array('name' => 'show_min_max_grades_changed_' . $c2->id)));
174         $this->assertSame(false, grade_get_setting($c2->id, 'minmaxtouse', false, true));
175         $this->assertFalse($DB->record_exists('grade_items', array('needsupdate' => 1, 'courseid' => $c2->id)));
176         $this->assertFalse($DB->record_exists('config', array('name' => 'show_min_max_grades_changed_' . $c3->id)));
177         $this->assertSame(false, grade_get_setting($c3->id, 'minmaxtouse', false, true));
178         $this->assertFalse($DB->record_exists('grade_items', array('needsupdate' => 1, 'courseid' => $c3->id)));
180         // Create inconsistency in c1 and c2.
181         $giparams = array('itemtype' => 'mod', 'itemmodule' => 'assign', 'iteminstance' => $a1->id,
182                 'courseid' => $c1->id, 'itemnumber' => 0);
183         $gi = grade_item::fetch($giparams);
184         $gi->grademin = 5;
185         $gi->update();
187         $giparams = array('itemtype' => 'mod', 'itemmodule' => 'assign', 'iteminstance' => $a2->id,
188                 'courseid' => $c2->id, 'itemnumber' => 0);
189         $gi = grade_item::fetch($giparams);
190         $gi->grademax = 50;
191         $gi->update();
194         // C1 and C2 should be updated, but the course setting should not be set.
195         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_GRADE;
197         // Run the upgrade.
198         upgrade_minmaxgrade();
200         // C1 and C2 were partially updated.
201         $this->assertTrue($DB->record_exists('config', array('name' => 'show_min_max_grades_changed_' . $c1->id)));
202         $this->assertSame(false, grade_get_setting($c1->id, 'minmaxtouse', false, true));
203         $this->assertTrue($DB->record_exists('grade_items', array('needsupdate' => 1, 'courseid' => $c1->id)));
204         $this->assertTrue($DB->record_exists('config', array('name' => 'show_min_max_grades_changed_' . $c2->id)));
205         $this->assertSame(false, grade_get_setting($c2->id, 'minmaxtouse', false, true));
206         $this->assertTrue($DB->record_exists('grade_items', array('needsupdate' => 1, 'courseid' => $c2->id)));
208         // Nothing has happened for C3.
209         $this->assertFalse($DB->record_exists('config', array('name' => 'show_min_max_grades_changed_' . $c3->id)));
210         $this->assertSame(false, grade_get_setting($c3->id, 'minmaxtouse', false, true));
211         $this->assertFalse($DB->record_exists('grade_items', array('needsupdate' => 1, 'courseid' => $c3->id)));
214         // Course setting should not be set on a course that has the setting already.
215         $CFG->grade_minmaxtouse = GRADE_MIN_MAX_FROM_GRADE_ITEM;
216         grade_set_setting($c1->id, 'minmaxtouse', -1); // Sets different value than constant to check that it remained the same.
218         // Run the upgrade.
219         upgrade_minmaxgrade();
221         // C2 was updated.
222         $this->assertSame((string) GRADE_MIN_MAX_FROM_GRADE_GRADE, grade_get_setting($c2->id, 'minmaxtouse', false, true));
224         // Nothing has happened for C1.
225         $this->assertSame('-1', grade_get_setting($c1->id, 'minmaxtouse', false, true));
227         // Nothing has happened for C3.
228         $this->assertFalse($DB->record_exists('config', array('name' => 'show_min_max_grades_changed_' . $c3->id)));
229         $this->assertSame(false, grade_get_setting($c3->id, 'minmaxtouse', false, true));
230         $this->assertFalse($DB->record_exists('grade_items', array('needsupdate' => 1, 'courseid' => $c3->id)));
233         // Final check, this time we'll unset the default config.
234         unset($CFG->grade_minmaxtouse);
235         grade_set_setting($c1->id, 'minmaxtouse', null);
237         // Run the upgrade.
238         upgrade_minmaxgrade();
240         // C1 was updated.
241         $this->assertSame((string) GRADE_MIN_MAX_FROM_GRADE_GRADE, grade_get_setting($c1->id, 'minmaxtouse', false, true));
243         // Nothing has happened for C3.
244         $this->assertFalse($DB->record_exists('config', array('name' => 'show_min_max_grades_changed_' . $c3->id)));
245         $this->assertSame(false, grade_get_setting($c3->id, 'minmaxtouse', false, true));
246         $this->assertFalse($DB->record_exists('grade_items', array('needsupdate' => 1, 'courseid' => $c3->id)));
248         // Restore value.
249         $CFG->grade_minmaxtouse = $initialminmax;
250     }
252     public function test_upgrade_extra_credit_weightoverride() {
253         global $DB, $CFG;
255         $this->resetAfterTest(true);
257         require_once($CFG->libdir . '/db/upgradelib.php');
259         $c = array();
260         $a = array();
261         $gi = array();
262         for ($i=0; $i<5; $i++) {
263             $c[$i] = $this->getDataGenerator()->create_course();
264             $a[$i] = array();
265             $gi[$i] = array();
266             for ($j=0;$j<3;$j++) {
267                 $a[$i][$j] = $this->getDataGenerator()->create_module('assign', array('course' => $c[$i], 'grade' => 100));
268                 $giparams = array('itemtype' => 'mod', 'itemmodule' => 'assign', 'iteminstance' => $a[$i][$j]->id,
269                     'courseid' => $c[$i]->id, 'itemnumber' => 0);
270                 $gi[$i][$j] = grade_item::fetch($giparams);
271             }
272         }
274         // Case 1: Course $c[0] has aggregation method different from natural.
275         $coursecategory = grade_category::fetch_course_category($c[0]->id);
276         $coursecategory->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN;
277         $coursecategory->update();
278         $gi[0][1]->aggregationcoef = 1;
279         $gi[0][1]->update();
280         $gi[0][2]->weightoverride = 1;
281         $gi[0][2]->update();
283         // Case 2: Course $c[1] has neither extra credits nor overrides
285         // Case 3: Course $c[2] has extra credits but no overrides
286         $gi[2][1]->aggregationcoef = 1;
287         $gi[2][1]->update();
289         // Case 4: Course $c[3] has no extra credits and has overrides
290         $gi[3][2]->weightoverride = 1;
291         $gi[3][2]->update();
293         // Case 5: Course $c[4] has both extra credits and overrides
294         $gi[4][1]->aggregationcoef = 1;
295         $gi[4][1]->update();
296         $gi[4][2]->weightoverride = 1;
297         $gi[4][2]->update();
299         // Run the upgrade script and make sure only course $c[4] was marked as needed to be fixed.
300         upgrade_extra_credit_weightoverride();
302         $this->assertTrue(empty($CFG->{'gradebook_calculations_freeze_' . $c[0]->id}));
303         $this->assertTrue(empty($CFG->{'gradebook_calculations_freeze_' . $c[1]->id}));
304         $this->assertTrue(empty($CFG->{'gradebook_calculations_freeze_' . $c[2]->id}));
305         $this->assertTrue(empty($CFG->{'gradebook_calculations_freeze_' . $c[3]->id}));
306         $this->assertEquals(20150619, $CFG->{'gradebook_calculations_freeze_' . $c[4]->id});
308         set_config('gradebook_calculations_freeze_' . $c[4]->id, null);
310         // Run the upgrade script for a single course only.
311         upgrade_extra_credit_weightoverride($c[0]->id);
312         $this->assertTrue(empty($CFG->{'gradebook_calculations_freeze_' . $c[0]->id}));
313         upgrade_extra_credit_weightoverride($c[4]->id);
314         $this->assertEquals(20150619, $CFG->{'gradebook_calculations_freeze_' . $c[4]->id});
315     }
317     /**
318      * Test the upgrade function for flagging courses with calculated grade item problems.
319      */
320     public function test_upgrade_calculated_grade_items_freeze() {
321         global $DB, $CFG;
323         $this->resetAfterTest();
325         require_once($CFG->libdir . '/db/upgradelib.php');
327         // Create a user.
328         $user = $this->getDataGenerator()->create_user();
330         // Create a couple of courses.
331         $course1 = $this->getDataGenerator()->create_course();
332         $course2 = $this->getDataGenerator()->create_course();
333         $course3 = $this->getDataGenerator()->create_course();
335         // Enrol the user in the courses.
336         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
337         $maninstance1 = $DB->get_record('enrol', array('courseid' => $course1->id, 'enrol' => 'manual'), '*', MUST_EXIST);
338         $maninstance2 = $DB->get_record('enrol', array('courseid' => $course2->id, 'enrol' => 'manual'), '*', MUST_EXIST);
339         $maninstance3 = $DB->get_record('enrol', array('courseid' => $course3->id, 'enrol' => 'manual'), '*', MUST_EXIST);
340         $manual = enrol_get_plugin('manual');
341         $manual->enrol_user($maninstance1, $user->id, $studentrole->id);
342         $manual->enrol_user($maninstance2, $user->id, $studentrole->id);
343         $manual->enrol_user($maninstance3, $user->id, $studentrole->id);
345         // To create the data we need we freeze the grade book to use the old behaviour.
346         set_config('gradebook_calculations_freeze_' . $course1->id, 20150627);
347         set_config('gradebook_calculations_freeze_' . $course2->id, 20150627);
348         set_config('gradebook_calculations_freeze_' . $course3->id, 20150627);
349         $CFG->grade_minmaxtouse = 2;
351         // Creating a category for a grade item.
352         $gradecategory = new grade_category();
353         $gradecategory->fullname = 'calculated grade category';
354         $gradecategory->courseid = $course1->id;
355         $gradecategory->insert();
356         $gradecategoryid = $gradecategory->id;
358         // This is a manual grade item.
359         $gradeitem = new grade_item();
360         $gradeitem->itemname = 'grade item one';
361         $gradeitem->itemtype = 'manual';
362         $gradeitem->categoryid = $gradecategoryid;
363         $gradeitem->courseid = $course1->id;
364         $gradeitem->idnumber = 'gi1';
365         $gradeitem->insert();
367         // Changing the category into a calculated grade category.
368         $gradecategoryitem = grade_item::fetch(array('iteminstance' => $gradecategory->id));
369         $gradecategoryitem->calculation = '=##gi' . $gradeitem->id . '##/2';
370         $gradecategoryitem->update();
372         // Setting a grade for the student.
373         $grade = $gradeitem->get_grade($user->id, true);
374         $grade->finalgrade = 50;
375         $grade->update();
376         // Creating all the grade_grade items.
377         grade_regrade_final_grades($course1->id);
378         // Updating the grade category to a new grade max and min.
379         $gradecategoryitem->grademax = 50;
380         $gradecategoryitem->grademin = 5;
381         $gradecategoryitem->update();
383         // Different manual grade item for course 2. We are creating a course with a calculated grade item that has a grade max of
384         // 50. The grade_grade will have a rawgrademax of 100 regardless.
385         $gradeitem = new grade_item();
386         $gradeitem->itemname = 'grade item one';
387         $gradeitem->itemtype = 'manual';
388         $gradeitem->courseid = $course2->id;
389         $gradeitem->idnumber = 'gi1';
390         $gradeitem->grademax = 25;
391         $gradeitem->insert();
393         // Calculated grade item for course 2.
394         $calculatedgradeitem = new grade_item();
395         $calculatedgradeitem->itemname = 'calculated grade';
396         $calculatedgradeitem->itemtype = 'manual';
397         $calculatedgradeitem->courseid = $course2->id;
398         $calculatedgradeitem->calculation = '=##gi' . $gradeitem->id . '##*2';
399         $calculatedgradeitem->grademax = 50;
400         $calculatedgradeitem->insert();
402         // Assigning a grade for the user.
403         $grade = $gradeitem->get_grade($user->id, true);
404         $grade->finalgrade = 10;
405         $grade->update();
407         // Setting all of the grade_grade items.
408         grade_regrade_final_grades($course2->id);
410         // Different manual grade item for course 3. We are creating a course with a calculated grade item that has a grade max of
411         // 50. The grade_grade will have a rawgrademax of 100 regardless.
412         $gradeitem = new grade_item();
413         $gradeitem->itemname = 'grade item one';
414         $gradeitem->itemtype = 'manual';
415         $gradeitem->courseid = $course3->id;
416         $gradeitem->idnumber = 'gi1';
417         $gradeitem->grademax = 25;
418         $gradeitem->insert();
420         // Calculated grade item for course 2.
421         $calculatedgradeitem = new grade_item();
422         $calculatedgradeitem->itemname = 'calculated grade';
423         $calculatedgradeitem->itemtype = 'manual';
424         $calculatedgradeitem->courseid = $course3->id;
425         $calculatedgradeitem->calculation = '=##gi' . $gradeitem->id . '##*2';
426         $calculatedgradeitem->grademax = 50;
427         $calculatedgradeitem->insert();
429         // Assigning a grade for the user.
430         $grade = $gradeitem->get_grade($user->id, true);
431         $grade->finalgrade = 10;
432         $grade->update();
434         // Setting all of the grade_grade items.
435         grade_regrade_final_grades($course3->id);
436         // Need to do this first before changing the other courses, otherwise they will be flagged too early.
437         set_config('gradebook_calculations_freeze_' . $course3->id, null);
438         upgrade_calculated_grade_items($course3->id);
439         $this->assertEquals(20150627, $CFG->{'gradebook_calculations_freeze_' . $course3->id});
441         // Change the setting back to null.
442         set_config('gradebook_calculations_freeze_' . $course1->id, null);
443         set_config('gradebook_calculations_freeze_' . $course2->id, null);
444         // Run the upgrade.
445         upgrade_calculated_grade_items();
446         // The setting should be set again after the upgrade.
447         $this->assertEquals(20150627, $CFG->{'gradebook_calculations_freeze_' . $course1->id});
448         $this->assertEquals(20150627, $CFG->{'gradebook_calculations_freeze_' . $course2->id});
449     }
451     function test_upgrade_calculated_grade_items_regrade() {
452         global $DB, $CFG;
454         $this->resetAfterTest();
456         require_once($CFG->libdir . '/db/upgradelib.php');
458         // Create a user.
459         $user = $this->getDataGenerator()->create_user();
461         // Create a course.
462         $course = $this->getDataGenerator()->create_course();
464         // Enrol the user in the course.
465         $studentrole = $DB->get_record('role', array('shortname' => 'student'));
466         $maninstance1 = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'manual'), '*', MUST_EXIST);
467         $manual = enrol_get_plugin('manual');
468         $manual->enrol_user($maninstance1, $user->id, $studentrole->id);
470         set_config('upgrade_calculatedgradeitemsonlyregrade', 1);
472         // Creating a category for a grade item.
473         $gradecategory = new grade_category();
474         $gradecategory->fullname = 'calculated grade category';
475         $gradecategory->courseid = $course->id;
476         $gradecategory->insert();
477         $gradecategoryid = $gradecategory->id;
479         // This is a manual grade item.
480         $gradeitem = new grade_item();
481         $gradeitem->itemname = 'grade item one';
482         $gradeitem->itemtype = 'manual';
483         $gradeitem->categoryid = $gradecategoryid;
484         $gradeitem->courseid = $course->id;
485         $gradeitem->idnumber = 'gi1';
486         $gradeitem->insert();
488         // Changing the category into a calculated grade category.
489         $gradecategoryitem = grade_item::fetch(array('iteminstance' => $gradecategory->id));
490         $gradecategoryitem->calculation = '=##gi' . $gradeitem->id . '##/2';
491         $gradecategoryitem->grademax = 50;
492         $gradecategoryitem->grademin = 15;
493         $gradecategoryitem->update();
495         // Setting a grade for the student.
496         $grade = $gradeitem->get_grade($user->id, true);
497         $grade->finalgrade = 50;
498         $grade->update();
500         grade_regrade_final_grades($course->id);
501         $grade = grade_grade::fetch(array('itemid' => $gradecategoryitem->id, 'userid' => $user->id));
502         $grade->rawgrademax = 100;
503         $grade->rawgrademin = 0;
504         $grade->update();
505         $this->assertNotEquals($gradecategoryitem->grademax, $grade->rawgrademax);
506         $this->assertNotEquals($gradecategoryitem->grademin, $grade->rawgrademin);
508         // This is the function that we are testing. If we comment out this line, then the test fails because the grade items
509         // are not flagged for regrading.
510         upgrade_calculated_grade_items();
511         grade_regrade_final_grades($course->id);
513         $grade = grade_grade::fetch(array('itemid' => $gradecategoryitem->id, 'userid' => $user->id));
515         $this->assertEquals($gradecategoryitem->grademax, $grade->rawgrademax);
516         $this->assertEquals($gradecategoryitem->grademin, $grade->rawgrademin);
517     }
519     public function test_upgrade_course_tags() {
520         global $DB, $CFG;
522         $this->resetAfterTest();
524         require_once($CFG->libdir . '/db/upgradelib.php');
526         // Running upgrade script when there are no tags.
527         upgrade_course_tags();
528         $this->assertFalse($DB->record_exists('tag_instance', array()));
530         // No course entries.
531         $DB->insert_record('tag_instance', array('itemid' => 123, 'tagid' => 101, 'tiuserid' => 0,
532             'itemtype' => 'post', 'component' => 'core', 'contextid' => 1));
533         $DB->insert_record('tag_instance', array('itemid' => 333, 'tagid' => 103, 'tiuserid' => 1002,
534             'itemtype' => 'post', 'component' => 'core', 'contextid' => 1));
536         upgrade_course_tags();
537         $records = array_values($DB->get_records('tag_instance', array(), 'id', '*'));
538         $this->assertEquals(2, count($records));
539         $this->assertEquals(123, $records[0]->itemid);
540         $this->assertEquals(333, $records[1]->itemid);
542         // Imagine we have tags 101, 102, 103, ... and courses 1, 2, 3, ... and users 1001, 1002, ... .
543         $keys = array('itemid', 'tagid', 'tiuserid');
544         $valuesets = array(
545             array(1, 101, 0),
546             array(1, 102, 0),
548             array(2, 102, 0),
549             array(2, 103, 1001),
551             array(3, 103, 0),
552             array(3, 103, 1001),
554             array(3, 104, 1006),
555             array(3, 104, 1001),
556             array(3, 104, 1002),
557         );
559         foreach ($valuesets as $values) {
560             $DB->insert_record('tag_instance', array_combine($keys, $values) +
561                     array('itemtype' => 'course', 'component' => 'core', 'contextid' => 1));
562         }
564         upgrade_course_tags();
565         // There are 8 records in 'tag_instance' table and 7 of them do not have tiuserid (except for one 'post').
566         $records = array_values($DB->get_records('tag_instance', array(), 'id', '*'));
567         $this->assertEquals(8, count($records));
568         $this->assertEquals(7, $DB->count_records('tag_instance', array('tiuserid' => 0)));
569         // Course 1 is mapped to tags 101 and 102.
570         $this->assertEquals(array(101, 102), array_values($DB->get_fieldset_select('tag_instance', 'tagid',
571                 'itemtype = ? AND itemid = ? ORDER BY tagid', array('course', 1))));
572         // Course 2 is mapped to tags 102 and 103.
573         $this->assertEquals(array(102, 103), array_values($DB->get_fieldset_select('tag_instance', 'tagid',
574                 'itemtype = ? AND itemid = ? ORDER BY tagid', array('course', 2))));
575         // Course 1 is mapped to tags 101 and 102.
576         $this->assertEquals(array(103, 104), array_values($DB->get_fieldset_select('tag_instance', 'tagid',
577                 'itemtype = ? AND itemid = ? ORDER BY tagid', array('course', 3))));
578     }