Skip to content

Commit 2eebae1

Browse files
committed
fix(Cache): isolate the factories cache files used by the tests
1 parent df8b96b commit 2eebae1

7 files changed

Lines changed: 173 additions & 12 deletions

File tree

‎system/Cache/FactoriesCache/FileVarExportHandler.php‎

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,18 @@
1313

1414
namespace CodeIgniter\Cache\FactoriesCache;
1515

16-
final class FileVarExportHandler
16+
final readonly class FileVarExportHandler
1717
{
18-
private string $path = WRITEPATH . 'cache';
18+
private string $path;
19+
20+
/**
21+
* @param string|null $path The directory where the cache files are stored.
22+
* Defaults to the "writable/cache" directory.
23+
*/
24+
public function __construct(?string $path = null)
25+
{
26+
$this->path = rtrim($path ?? WRITEPATH . 'cache', '/');
27+
}
1928

2029
public function save(string $key, mixed $val): void
2130
{
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of CodeIgniter 4 framework.
7+
*
8+
* (c) CodeIgniter Foundation <admin@codeigniter.com>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace Tests\Support\Cache;
15+
16+
use CodeIgniter\Cache\FactoriesCache\FileVarExportHandler;
17+
18+
/**
19+
* Gives the test class its own directory for the files created
20+
* by the FileVarExportHandler.
21+
*
22+
* The handler stores its files in the shared "writable/cache" directory by
23+
* default. Since the random test execution runs the components in parallel,
24+
* one component may delete the cache file that another component is
25+
* asserting on. A dedicated directory per test class avoids that.
26+
*/
27+
trait IsolatedCacheTrait
28+
{
29+
/**
30+
* The directory used to store the cache files of the test class.
31+
*/
32+
private static string $isolatedCachePath;
33+
34+
public static function setUpBeforeClassIsolatedCache(): void
35+
{
36+
helper('filesystem');
37+
38+
self::$isolatedCachePath = WRITEPATH . 'cache_test_' . str_replace('\\', '_', static::class);
39+
40+
// Remove the files left over by a previous run.
41+
if (is_dir(self::$isolatedCachePath)) {
42+
delete_files(self::$isolatedCachePath, true);
43+
@rmdir(self::$isolatedCachePath);
44+
}
45+
}
46+
47+
public static function tearDownAfterClassIsolatedCache(): void
48+
{
49+
if (! isset(self::$isolatedCachePath) || ! is_dir(self::$isolatedCachePath)) {
50+
return;
51+
}
52+
53+
delete_files(self::$isolatedCachePath, true);
54+
@rmdir(self::$isolatedCachePath);
55+
}
56+
57+
/**
58+
* Returns a handler that stores its files in the isolated directory.
59+
*/
60+
protected function getIsolatedCacheHandler(): FileVarExportHandler
61+
{
62+
return new FileVarExportHandler(self::$isolatedCachePath);
63+
}
64+
65+
/**
66+
* Returns the path of the isolated cache directory.
67+
*/
68+
protected static function getIsolatedCachePath(): string
69+
{
70+
return self::$isolatedCachePath;
71+
}
72+
}

‎tests/system/Autoloader/FileLocatorCachedTest.php‎

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,37 @@
1717
use Config\Autoload;
1818
use Config\Modules;
1919
use PHPUnit\Framework\Attributes\Group;
20+
use Tests\Support\Cache\IsolatedCacheTrait;
2021

2122
/**
2223
* @internal
2324
*/
2425
#[Group('Others')]
2526
final class FileLocatorCachedTest extends FileLocatorTest
2627
{
28+
use IsolatedCacheTrait;
29+
2730
private FileVarExportHandler $handler;
2831

29-
public static function tearDownAfterClass(): void
32+
public static function setUpBeforeClass(): void
3033
{
31-
parent::tearDownAfterClass();
34+
parent::setUpBeforeClass();
3235

36+
self::setUpBeforeClassIsolatedCache();
37+
}
38+
39+
public static function tearDownAfterClass(): void
40+
{
3341
// Delete cache file.
3442
$autoloader = new Autoloader();
35-
$handler = new FileVarExportHandler();
43+
$handler = new FileVarExportHandler(self::getIsolatedCachePath());
3644
$fileLocator = new FileLocator($autoloader);
3745
$locator = new FileLocatorCached($fileLocator, $handler);
3846
$locator->deleteCache();
47+
48+
self::tearDownAfterClassIsolatedCache();
49+
50+
parent::tearDownAfterClass();
3951
}
4052

4153
protected function setUp(): void
@@ -61,7 +73,7 @@ protected function setUp(): void
6173
'Acme\Sample' => TESTPATH . '_support/does/not/exists',
6274
]);
6375

64-
$this->handler = new FileVarExportHandler();
76+
$this->handler = $this->getIsolatedCacheHandler();
6577
$fileLocator = new FileLocator($autoloader);
6678
$this->locator = new FileLocatorCached($fileLocator, $this->handler);
6779
}
@@ -70,6 +82,10 @@ protected function tearDown(): void
7082
{
7183
$this->locator->__destruct();
7284

85+
// Prevent the destructor from writing the cache file
86+
// when the test object is destroyed.
87+
$this->locator->deleteCache();
88+
7389
parent::tearDown();
7490
}
7591

‎tests/system/Cache/FactoriesCacheFileVarExportHandlerTest.php‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,52 @@
1515

1616
use CodeIgniter\Cache\FactoriesCache\FileVarExportHandler;
1717
use PHPUnit\Framework\Attributes\Group;
18+
use Tests\Support\Cache\IsolatedCacheTrait;
1819

1920
/**
2021
* @internal
2122
*/
2223
#[Group('Others')]
2324
final class FactoriesCacheFileVarExportHandlerTest extends AbstractFactoriesCacheHandlerTestCase
2425
{
26+
use IsolatedCacheTrait;
27+
2528
public static function setUpBeforeClass(): void
2629
{
2730
parent::setUpBeforeClass();
2831

32+
self::setUpBeforeClassIsolatedCache();
33+
2934
helper('filesystem');
3035
}
3136

37+
public static function tearDownAfterClass(): void
38+
{
39+
self::tearDownAfterClassIsolatedCache();
40+
41+
parent::tearDownAfterClass();
42+
}
43+
3244
protected function createFactoriesCache(): void
3345
{
34-
$this->handler = new FileVarExportHandler();
46+
$this->handler = $this->getIsolatedCacheHandler();
3547
$this->cache = new FactoriesCache($this->handler);
3648
}
3749

50+
public function testUsesTheWritableCacheDirectoryByDefault(): void
51+
{
52+
$handler = new FileVarExportHandler();
53+
54+
$this->assertSame(WRITEPATH . 'cache', $this->getPrivateProperty($handler, 'path'));
55+
}
56+
3857
public function testSaveCreatesDirectoryAndFileWithCorrectPermissions(): void
3958
{
4059
$dir = WRITEPATH . 'cache_test_dir_' . uniqid('', true);
4160
$oldUmask = umask(0000);
4261

4362
try {
44-
$handler = new FileVarExportHandler();
45-
$this->setPrivateProperty($handler, 'path', $dir);
63+
$handler = new FileVarExportHandler($dir);
4664

4765
$handler->save('test_key', ['data']);
4866

‎tests/system/Commands/Cache/ClearCacheTest.php‎

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
use CodeIgniter\Autoloader\FileLocator;
1717
use CodeIgniter\Autoloader\FileLocatorCached;
1818
use CodeIgniter\Cache\CacheFactory;
19-
use CodeIgniter\Cache\FactoriesCache\FileVarExportHandler;
2019
use CodeIgniter\Cache\Handlers\FileHandler;
2120
use CodeIgniter\CLI\CLI;
2221
use CodeIgniter\Config\Factories;
@@ -25,17 +24,33 @@
2524
use Config\Cache;
2625
use Config\Services;
2726
use PHPUnit\Framework\Attributes\Group;
27+
use Tests\Support\Cache\IsolatedCacheTrait;
2828

2929
/**
3030
* @internal
3131
*/
3232
#[Group('Others')]
3333
final class ClearCacheTest extends CIUnitTestCase
3434
{
35+
use IsolatedCacheTrait;
3536
use StreamFilterTrait;
3637

3738
private Cache $config;
3839

40+
public static function setUpBeforeClass(): void
41+
{
42+
parent::setUpBeforeClass();
43+
44+
self::setUpBeforeClassIsolatedCache();
45+
}
46+
47+
public static function tearDownAfterClass(): void
48+
{
49+
self::tearDownAfterClassIsolatedCache();
50+
51+
parent::tearDownAfterClass();
52+
}
53+
3954
protected function setUp(): void
4055
{
4156
parent::setUp();
@@ -98,7 +113,7 @@ public function testClearCacheWorks(): void
98113

99114
public function testClearCacheDiscardsSharedLocatorCache(): void
100115
{
101-
$handler = new FileVarExportHandler();
116+
$handler = $this->getIsolatedCacheHandler();
102117
$handler->delete('FileLocatorCache');
103118

104119
$locator = new FileLocatorCached(new FileLocator(service('autoloader')), $handler);
@@ -117,6 +132,10 @@ public function testClearCacheDiscardsSharedLocatorCache(): void
117132
$this->assertArrayHasKey('Config/Cache', $cached['search']);
118133

119134
$handler->delete('FileLocatorCache');
135+
136+
// Prevent the destructor from writing the cache file
137+
// when the locator is destroyed.
138+
$locator->deleteCache();
120139
}
121140

122141
public function testClearCacheFails(): void

‎tests/system/Commands/Utilities/OptimizeTest.php‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,39 @@
2222
use CodeIgniter\Test\StreamFilterTrait;
2323
use Config\Services;
2424
use PHPUnit\Framework\Attributes\Group;
25+
use Tests\Support\Cache\IsolatedCacheTrait;
2526

2627
/**
2728
* @internal
2829
*/
2930
#[Group('Others')]
3031
final class OptimizeTest extends CIUnitTestCase
3132
{
33+
use IsolatedCacheTrait;
3234
use ReflectionHelper;
3335
use StreamFilterTrait;
3436

3537
private FileVarExportHandler $handler;
3638

39+
public static function setUpBeforeClass(): void
40+
{
41+
parent::setUpBeforeClass();
42+
43+
self::setUpBeforeClassIsolatedCache();
44+
}
45+
46+
public static function tearDownAfterClass(): void
47+
{
48+
self::tearDownAfterClassIsolatedCache();
49+
50+
parent::tearDownAfterClass();
51+
}
52+
3753
protected function setUp(): void
3854
{
3955
parent::setUp();
4056

41-
$this->handler = new FileVarExportHandler();
57+
$this->handler = $this->getIsolatedCacheHandler();
4258
$this->handler->delete('FileLocatorCache');
4359
}
4460

@@ -74,12 +90,19 @@ public function testClearCacheDiscardsSharedLocatorCache(): void
7490
$this->assertArrayNotHasKey('Config/App', $cached['search']);
7591
$this->assertArrayHasKey('Config/Cache', $cached['search']);
7692
$this->assertStringContainsString('Removed FileLocatorCache.', $this->getStreamFilterBuffer());
93+
94+
// Prevent the destructor from writing the cache file
95+
// when the locator is destroyed.
96+
$locator->deleteCache();
7797
}
7898

7999
public function testClearCacheDeletesTheFileWithoutSharedLocatorCache(): void
80100
{
81101
$this->handler->save('FileLocatorCache', ['search' => []]);
82102

103+
$locator = new FileLocatorCached(new FileLocator(service('autoloader')), $this->handler);
104+
Services::injectMock('locator', $locator);
105+
83106
($this->getClearCache())();
84107

85108
$this->assertFalse($this->handler->get('FileLocatorCache'));

‎user_guide_src/source/changelogs/v4.7.6.rst‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ Message Changes
2424
Changes
2525
*******
2626

27+
- **Cache:** Added an optional ``$path`` parameter to
28+
``FileVarExportHandler::__construct()`` so the cache files can be stored in
29+
a custom directory.
30+
2731
************
2832
Deprecations
2933
************

0 commit comments

Comments
 (0)