3 use MediaWiki\MainConfigNames
;
4 use Wikimedia\ObjectCache\EmptyBagOStuff
;
5 use Wikimedia\ObjectCache\HashBagOStuff
;
6 use Wikimedia\Rdbms\DatabaseDomain
;
7 use Wikimedia\TestingAccessWrapper
;
10 * @covers \ObjectCacheFactory
14 class ObjectCacheFactoryIntegrationTest
extends MediaWikiIntegrationTestCase
{
16 protected function setUp(): void
{
17 $this->setCacheConfig();
18 $this->setMainCache( CACHE_NONE
);
19 $this->overrideConfigValues( [
20 MainConfigNames
::MessageCacheType
=> CACHE_NONE
,
21 MainConfigNames
::ParserCacheType
=> CACHE_NONE
,
24 // Mock ACCEL with 'hash' as being installed.
25 // This makes tests deterministic regardless of whether APCu is installed.
26 ObjectCacheFactory
::$localServerCacheClass = 'HashBagOStuff';
29 protected function tearDown(): void
{
30 ObjectCacheFactory
::$localServerCacheClass = null;
33 private function setCacheConfig( $arr = [] ) {
35 CACHE_NONE
=> [ 'class' => EmptyBagOStuff
::class ],
36 CACHE_DB
=> [ 'class' => SqlBagOStuff
::class ],
37 'hash' => [ 'class' => HashBagOStuff
::class ],
38 CACHE_ANYTHING
=> [ 'class' => HashBagOStuff
::class ],
40 $this->overrideConfigValue( MainConfigNames
::ObjectCaches
, $arr +
$defaults );
43 public function testNewAnythingNothing() {
44 $ocf = $this->getServiceContainer()->getObjectCacheFactory();
45 $this->assertInstanceOf(
47 $ocf->getInstance( $ocf->getAnythingId() ),
48 'No available types. Fallback to DB'
52 public function testNewAnythingHash() {
53 $this->setMainCache( CACHE_HASH
);
55 $ocf = $this->getServiceContainer()->getObjectCacheFactory();
56 $this->assertInstanceOf(
58 $ocf->getInstance( $ocf->getAnythingId() ),
59 'Use an available type (hash)'
63 public function testNewAnythingAccel() {
64 $this->setMainCache( CACHE_ACCEL
);
66 $ocf = $this->getServiceContainer()->getObjectCacheFactory();
67 $this->assertInstanceOf(
69 $ocf->getInstance( $ocf->getAnythingId() ),
70 'Use an available type (CACHE_ACCEL)'
74 public function testNewAnythingNoAccel() {
75 // Mock APC not being installed (T160519, T147161)
76 ObjectCacheFactory
::$localServerCacheClass = EmptyBagOStuff
::class;
77 $this->setMainCache( CACHE_ACCEL
);
79 $ocf = $this->getServiceContainer()->getObjectCacheFactory();
80 $this->assertInstanceOf(
82 $ocf->getInstance( $ocf->getAnythingId() ),
83 'Fallback to DB if available types fall back to Empty'
87 public function testNewAnythingNoAccelNoDb() {
88 $this->setCacheConfig( [
89 // Mock APCu not being installed (T160519, T147161)
90 CACHE_ACCEL
=> [ 'class' => EmptyBagOStuff
::class ]
92 $this->setMainCache( CACHE_ACCEL
);
94 $this->getServiceContainer()->disableStorage();
96 $ocf = $this->getServiceContainer()->getObjectCacheFactory();
97 $this->assertInstanceOf(
98 EmptyBagOStuff
::class,
99 $ocf->getInstance( $ocf->getAnythingId() ),
100 'Fallback to none if available types and DB are unavailable'
104 public function testNewAnythingNothingNoDb() {
105 $this->getServiceContainer()->disableStorage();
107 $ocf = $this->getServiceContainer()->getObjectCacheFactory();
108 $this->assertInstanceOf(
109 EmptyBagOStuff
::class,
110 $ocf->getInstance( $ocf->getAnythingId() ),
111 'No available types or DB. Fallback to none.'
115 public function testNewFromIdWincacheAccel() {
116 $ocf = $this->getServiceContainer()->getObjectCacheFactory();
117 $className = get_class( $ocf );
119 $this->expectDeprecationAndContinue( "/^Use of $className::newFromId with cache ID \"wincache\"\s/" );
121 $this->assertInstanceOf(
122 HashBagOStuff
::class,
123 $ocf->getInstance( 'wincache' ),
124 'Fallback to APCu for deprecated wincache'
128 public function testNewFromIdWincacheNoAccel() {
129 // Mock APC not being installed (T160519, T147161)
130 ObjectCacheFactory
::$localServerCacheClass = EmptyBagOStuff
::class;
132 $ocf = $this->getServiceContainer()->getObjectCacheFactory();
133 $className = get_class( $ocf );
135 $this->expectDeprecationAndContinue( "/^Use of $className::newFromId with cache ID \"wincache\"\s/" );
137 $this->assertInstanceOf(
138 EmptyBagOStuff
::class,
139 $ocf->getInstance( 'wincache' ),
140 'No caching if APCu is not available'
144 public function provideLocalServerKeyspace() {
145 $dbDomain = static function ( $dbName, $dbPrefix ) {
146 global $wgDBmwschema;
147 return ( new DatabaseDomain( $dbName, $wgDBmwschema, $dbPrefix ) )->getId();
150 'default' => [ false, 'my_wiki', '', $dbDomain( 'my_wiki', '' ) ],
151 'custom' => [ 'custom', 'my_wiki', '', 'custom' ],
152 'prefix' => [ false, 'my_wiki', 'nl_', $dbDomain( 'my_wiki', 'nl_' ) ],
153 'empty string' => [ '', 'my_wiki', 'nl_', $dbDomain( 'my_wiki', 'nl_' ) ],
158 * @dataProvider provideLocalServerKeyspace
160 public function testLocalServerKeyspace( $cachePrefix, $dbName, $dbPrefix, $expect ) {
161 $this->overrideConfigValues( [
162 MainConfigNames
::CachePrefix
=> $cachePrefix,
163 MainConfigNames
::DBname
=> $dbName,
164 MainConfigNames
::DBprefix
=> $dbPrefix,
166 // Regression against T247562, T361177.
167 $cache = $this->getServiceContainer()->getObjectCacheFactory()->getInstance( CACHE_ACCEL
);
168 $cache = TestingAccessWrapper
::newFromObject( $cache );
169 $this->assertSame( $expect, $cache->keyspace
);
172 public function testNewMultiWrite() {
173 $this->overrideConfigValues( [
174 MainConfigNames
::CachePrefix
=> 'moon-river',
176 $this->setCacheConfig( [
178 'class' => 'MultiWriteBagOStuff',
181 'class' => 'HashBagOStuff',
184 'class' => 'HashBagOStuff',
190 $ocf = $this->getServiceContainer()->getObjectCacheFactory();
191 $multi = $ocf->getInstance( 'multi-example' );
192 $caches = TestingAccessWrapper
::newFromObject( $multi )->caches
;
194 $this->assertSame( 'moon-river:x', $multi->makeKey( 'x' ), 'MultiWrite key' );
196 // Confirm that dependency injection is also applied to the objects constructed
197 // for the child caches (T318272).
198 $this->assertSame( 'moon-river:x', $caches[0]->makeKey( 'x' ), 'inject cache 0 keyspace' );
199 $this->assertSame( 'moon-river:x', $caches[1]->makeKey( 'x' ), 'inject cache 1 keyspace' );
202 public static function provideIsDatabaseId() {
204 [ CACHE_DB
, CACHE_NONE
, true ],
205 [ CACHE_ANYTHING
, CACHE_DB
, true ],
206 [ CACHE_ANYTHING
, 'hash', false ],
207 [ CACHE_ANYTHING
, CACHE_ANYTHING
, true ]
212 * @dataProvider provideIsDatabaseId
213 * @param string|int $id
214 * @param string|int $mainCacheType
215 * @param bool $expected
217 public function testIsDatabaseId( $id, $mainCacheType, $expected ) {
218 $this->overrideConfigValues( [
219 MainConfigNames
::MainCacheType
=> $mainCacheType
221 $ocf = $this->getServiceContainer()->getObjectCacheFactory();
222 $this->assertSame( $expected, $ocf->isDatabaseId( $id ) );