File: TestUserRegistry.php

package info (click to toggle)
mediawiki 1%3A1.43.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 417,464 kB
  • sloc: php: 1,062,949; javascript: 664,290; sql: 9,714; python: 5,458; xml: 3,489; sh: 1,131; makefile: 64
file content (132 lines) | stat: -rw-r--r-- 3,595 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<?php

use MediaWiki\User\User;

/**
 * @since 1.28
 */
class TestUserRegistry {

	/** @var TestUser[] (group key => TestUser) */
	private static $testUsers = [];

	/** @var int Count of users that have been generated */
	private static $counter = 0;

	/** @var int Random int, included in IDs */
	private static $randInt;

	public static function getNextId() {
		if ( !self::$randInt ) {
			self::$randInt = mt_rand( 1, 0xFFFFFF );
		}
		return sprintf( '%06x.%03x', self::$randInt, ++self::$counter );
	}

	/**
	 * Get a TestUser object that the caller may modify.
	 *
	 * @since 1.28
	 *
	 * @param string $testName Caller's __CLASS__ or arbitrary string. Used to generate the
	 *  user's username.
	 * @param string|string[] $groups Groups the test user should be added to.
	 * @param string|null $userPrefix if non-null, the user prefix will be as specified instead of "TestUser"
	 * @return TestUser
	 */
	public static function getMutableTestUser( $testName, $groups = [], $userPrefix = null ) {
		$id = self::getNextId();
		$testUserName = "$testName $id";
		$userPrefix ??= "TestUser";
		$testUser = new TestUser(
			"$userPrefix $testName $id",
			"Name $id",
			"$id@mediawiki.test",
			(array)$groups
		);
		$testUser->getUser()->clearInstanceCache();
		return $testUser;
	}

	/**
	 * Get a TestUser object that the caller may not modify.
	 *
	 * Whenever possible, unit tests should use immutable users, because
	 * immutable users can be reused in multiple tests, which helps keep
	 * the unit tests fast.
	 *
	 * @since 1.28
	 *
	 * @param string|string[] $groups Groups the test user should be added to.
	 * @return TestUser
	 */
	public static function getImmutableTestUser( $groups = [] ) {
		$groups = array_unique( (array)$groups );
		sort( $groups );
		$key = implode( ',', $groups );

		$testUser = self::$testUsers[$key] ?? false;

		if ( !$testUser || !$testUser->getUser()->isRegistered() ) {
			$id = self::getNextId();
			// Hack! If this is the primary sysop account, make the username
			// be 'UTSysop', for back-compat, and for the sake of PHPUnit data
			// provider methods, which are executed before the test database
			// is set up. See T136348.
			if ( $groups === [ 'bureaucrat', 'sysop' ] ) {
				$username = 'UTSysop';
			} else {
				$username = "TestUser $id";
			}
			self::$testUsers[$key] = $testUser = new TestUser(
				$username,
				"Name $id",
				"$id@mediawiki.test",
				$groups
			);
		}

		$testUser->getUser()->clearInstanceCache();
		return self::$testUsers[$key];
	}

	/**
	 * TestUsers created by this class will not be deleted, but any handles
	 * to existing immutable TestUsers will be deleted, ensuring these users
	 * are not reused. We don't reset the counter or random string by design.
	 *
	 * @since 1.28
	 */
	public static function clear() {
		self::$testUsers = [];
	}

	/**
	 * Call clearInstanceCache() on all User objects known to the registry.
	 * This ensures that the User objects do not retain stale references
	 * to service objects.
	 *
	 * @since 1.39
	 */
	public static function clearInstanceCaches() {
		foreach ( self::$testUsers as $user ) {
			$user->getUser()->clearInstanceCache();
		}
	}

	/**
	 * @todo It would be nice if this were a non-static method of TestUser
	 * instead, but that doesn't seem possible without friends?
	 *
	 * @param User $user
	 * @return bool True if it's safe to modify the user
	 */
	public static function isMutable( User $user ) {
		foreach ( self::$testUsers as $key => $testUser ) {
			if ( $user === $testUser->getUser() ) {
				return false;
			}
		}
		return true;
	}
}