MDL-67499 restore: add 100% cov. to restore_dbops::precheck_user()
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Sat, 28 Mar 2020 18:53:36 +0000 (19:53 +0100)
committerPaul Holden <paulh@moodle.com>
Mon, 6 Apr 2020 10:48:27 +0000 (11:48 +0100)
Supports multiple mails to be tested.

So we can perform changes to it and also some related stuff,
like delete_user() with confidence.

backup/util/dbops/tests/restore_dbops_test.php

index d0fd2cc..9459580 100644 (file)
@@ -119,4 +119,237 @@ class restore_dbops_testcase extends advanced_testcase {
             $this->assertSame('Table "backup_ids_temp" does not exist', $e->getMessage());
         }
     }
+
+    /**
+     * Data provider for {@link test_precheck_user()}
+     */
+    public function precheck_user_provider() {
+
+        $emailmultiplier = [
+            'shortmail' => 'normalusername@example.com',
+            //'longmail' => str_repeat('a', 100)  // It's not validated, hence any string is ok.
+        ];
+
+        $providercases = [];
+
+        foreach ($emailmultiplier as $emailk => $email) {
+            // Get the related cases.
+            $cases = $this->precheck_user_cases($email);
+            // Rename them (keys).
+            foreach ($cases as $key => $case) {
+                $providercases[$key . ' - ' . $emailk] = $case;
+            }
+        }
+
+        return $providercases;
+    }
+
+    /**
+     * Get all the cases implemented in {@link restore_dbops::precheck_users()}
+     */
+    private function precheck_user_cases($email) {
+        global $CFG;
+
+        $baseuserarr = [
+            'username' => 'normalusername',
+            'email'    => $email,
+            'mnethostid' => $CFG->mnet_localhost_id,
+            'firstaccess'=> 123456789,
+            'deleted'    => 0,
+            'forceemailcleanup' => false, // Hack to force the DB record to have empty mail.
+            'forceduplicateadminallowed' => false]; // Hack to enable import_general_duplicate_admin_allowed.
+
+        return [
+            // Cases with samesite = true.
+            'samesite match existing (1A)' => [
+                'dbuser' => $baseuserarr,
+                'backupuser' => $baseuserarr,
+                'samesite' => true,
+                'outcome' => 'match'
+            ],
+            'samesite match existing anon (1B)' => [
+                'dbuser' => array_merge($baseuserarr, [
+                    'username' => 'anon01']),
+                'backupuser' => array_merge($baseuserarr, [
+                    'id' => -1, 'username' => 'anon01', 'firstname' => 'anonfirstname01',
+                    'lastname' => 'anonlastname01', 'email' => 'anon01@doesntexist.invalid']),
+                'samesite' => true,
+                'outcome' => 'match'
+            ],
+            'samesite match existing deleted in db, alive in backup, by db username (1C)' => [
+                'dbuser' => array_merge($baseuserarr, [
+                    'deleted' => 1]),
+                'backupuser' => array_merge($baseuserarr, [
+                    'username' => 'this_wont_match']),
+                'samesite' => true,
+                'outcome' => 'match'
+            ],
+            'samesite match existing deleted in db, alive in backup, by db email (1C)' => [
+                'dbuser' => array_merge($baseuserarr, [
+                    'deleted' => 1]),
+                'backupuser' => array_merge($baseuserarr, [
+                    'email' => 'this_wont_match']),
+                'samesite' => true,
+                'outcome' => 'match'
+            ],
+            'samesite match existing alive in db, deleted in backup (1D)' => [
+                'dbuser' => $baseuserarr,
+                'backupuser' => array_merge($baseuserarr, [
+                    'deleted' => 1]),
+                'samesite' => true,
+                'outcome' => 'match'
+            ],
+            'samesite conflict (1E)' => [
+                'dbuser' => $baseuserarr,
+                'backupuser' => array_merge($baseuserarr, ['id' => -1]),
+                'samesite' => true,
+                'outcome' => false
+            ],
+            'samesite create user (1F)' => [
+                'dbuser' => $baseuserarr,
+                'backupuser' => array_merge($baseuserarr,[
+                    'username' => 'newusername']),
+                'samesite' => false,
+                'outcome' => true
+            ],
+
+            // Cases with samesite = false.
+            'no samesite match existing, by db email (2A1)' => [
+                'dbuser' => $baseuserarr,
+                'backupuser' => array_merge($baseuserarr,[
+                    'firstaccess' => 0]),
+                'samesite' => false,
+                'outcome' => 'match'
+            ],
+            'no samesite match existing, by db firstaccess (2A1)' => [
+                'dbuser' => $baseuserarr,
+                'backupuser' => array_merge($baseuserarr,[
+                    'email' => 'this_wont_match@example.con']),
+                'samesite' => false,
+                'outcome' => 'match'
+            ],
+            'no samesite match existing anon (2A1 too)' => [
+                'dbuser' => array_merge($baseuserarr, [
+                    'username' => 'anon01']),
+                'backupuser' => array_merge($baseuserarr, [
+                    'id' => -1, 'username' => 'anon01', 'firstname' => 'anonfirstname01',
+                    'lastname' => 'anonlastname01', 'email' => 'anon01@doesntexist.invalid']),
+                'samesite' => false,
+                'outcome' => 'match'
+            ],
+            'no samesite match dupe admin (2A2)' => [
+                'dbuser' => array_merge($baseuserarr, [
+                    'username' => 'admin_old_site_id',
+                    'forceduplicateadminallowed' => true]),
+                'backupuser' => array_merge($baseuserarr, [
+                    'username' => 'admin']),
+                'samesite' => false,
+                'outcome' => 'match'
+            ],
+            'no samesite match existing deleted in db, alive in backup, by db username (2B1)' => [
+                'dbuser' => array_merge($baseuserarr, [
+                    'deleted' => 1]),
+                'backupuser' => array_merge($baseuserarr, [
+                    'firstaccess' => 0]),
+                'samesite' => false,
+                'outcome' => 'match'
+            ],
+            'no samesite match existing deleted in db, alive in backup, by db firstaccess (2B1)' => [
+                'dbuser' => array_merge($baseuserarr, [
+                    'deleted' => 1]),
+                'backupuser' => array_merge($baseuserarr, [
+                    'mail' => 'this_wont_match']),
+                'samesite' => false,
+                'outcome' => 'match'
+            ],
+            'no samesite match existing deleted in db, alive in backup (2B2)' => [
+                'dbuser' => array_merge($baseuserarr, [
+                    'deleted' => 1,
+                    'forceemailcleanup' => true]),
+                'backupuser' => $baseuserarr,
+                'samesite' => false,
+                'outcome' => 'match'
+            ],
+            'no samesite match existing alive in db, deleted in backup (2C)' => [
+                'dbuser' => $baseuserarr,
+                'backupuser' => array_merge($baseuserarr, [
+                    'deleted' => 1]),
+                'samesite' => false,
+                'outcome' => 'match'
+            ],
+            'no samesite conflict (2D)' => [
+                'dbuser' => $baseuserarr,
+                'backupuser' => array_merge($baseuserarr,[
+                    'email' => 'anotheruser@example.com', 'firstaccess' => 0]),
+                'samesite' => false,
+                'outcome' => false
+            ],
+            'no samesite create user (2E)' => [
+                'dbuser' => $baseuserarr,
+                'backupuser' => array_merge($baseuserarr,[
+                    'username' => 'newusername']),
+                'samesite' => false,
+                'outcome' => true
+            ],
+
+        ];
+    }
+
+    /**
+     * @dataProvider precheck_user_provider
+     * @covers restore_dbops::precheck_user()
+     * */
+    public function test_precheck_user($dbuser, $backupuser, $samesite, $outcome) {
+        global $DB;
+
+        $this->resetAfterTest();
+
+        $dbuser = (object)$dbuser;
+        $backupuser = (object)$backupuser;
+
+        $siteid = null;
+
+        // If the backup user must be deleted, simulate it (by temp inserting to DB, deleting and fetching it back).
+        if ($backupuser->deleted) {
+            $backupuser->id = $DB->insert_record('user', array_merge((array)$backupuser, ['deleted' => 0]));
+            delete_user($backupuser);
+            $backupuser = $DB->get_record('user', ['id' => $backupuser->id]);
+            $DB->delete_records('user', ['id' => $backupuser->id]);
+            unset($backupuser->id);
+        }
+
+        // Create the db user, normally.
+        $dbuser->id = $DB->insert_record('user', array_merge((array)$dbuser, ['deleted' => 0]));
+        $backupuser->id = $backupuser->id ?? $dbuser->id;
+
+        // We may want to enable the import_general_duplicate_admin_allowed setting and look for old admin records.
+        if ($dbuser->forceduplicateadminallowed) {
+            set_config('import_general_duplicate_admin_allowed', true, 'backup');
+            $siteid = 'old_site_id';
+        }
+
+        // If the DB user must be deleted, do it and fetch it back.
+        if ($dbuser->deleted) {
+            delete_user($dbuser);
+            // We may want to clean the mail field (old behavior, not containing the current md5(username)
+            if ($dbuser->forceemailcleanup) {
+                $DB->set_field('user', 'email', '', ['id' => $dbuser->id]);
+            }
+        }
+
+        // Get the dbuser  record, because we may have changed it above.
+        $dbuser = $DB->get_record('user', ['id' => $dbuser->id]);
+
+        $method = (new ReflectionClass('restore_dbops'))->getMethod('precheck_user');
+        $method->setAccessible(true);
+        $result = $method->invoke(null, $backupuser, $samesite, $siteid);
+
+        if (is_bool($result)) {
+            $this->assertSame($outcome, $result);
+        } else {
+            $outcome = $dbuser; // Outcome is not bool, matching found, so it must be the dbuser,
+            // Just check ids, it means the expected match has been found in database.
+            $this->assertSame($outcome->id, $result->id);
+        }
+    }
 }