Skip to content

Commit 39aa026

Browse files
abnegateclaude
andcommitted
(fix): drop tearDownAfterClass scrub that broke paratest functional mode
In paratest's `--functional` mode `tearDownAfterClass` runs between every test method, not just at suite end. The previous override scrubbed the adapter keyspace and nulled `self::$database`, forcing the next test to rebuild the database under a fresh `uniqid()` namespace while inherited fixture statics (`$moviesFixtureInit`, `$documentsFixtureInit`, etc.) stayed set — so cached fixture metadata pointed at collections that no longer existed. Result: 84 errors and 8 failures across `find`, unique index, and permission tests. Also align `setDatabase()` with the per-PID `$this->testDatabase` so `testCreateExistsDelete` matches the actual database name. CI Redis is ephemeral; leaking keys to process exit is safe. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 31e9fad commit 39aa026

1 file changed

Lines changed: 10 additions & 63 deletions

File tree

tests/e2e/Adapter/RedisTest.php

Lines changed: 10 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,20 @@
88
use Utopia\Database\Adapter\Redis as RedisAdapter;
99
use Utopia\Database\Database;
1010

11+
/**
12+
* Paratest's `--functional` mode invokes `setUpBeforeClass`/`tearDownAfterClass`
13+
* between every test method, not just at suite boundaries, while inherited
14+
* fixture statics (`$moviesFixtureInit`, `$documentsFixtureInit`, etc.) stay
15+
* set across methods within the same worker process. Scrubbing the namespace
16+
* or recreating the `Database` between tests would leave the cached fixture
17+
* metadata pointing at collections that no longer exist. The CI Redis
18+
* container is ephemeral, so leaking keys to process exit is safe.
19+
*/
1120
class RedisTest extends Base
1221
{
1322
public static ?Database $database = null;
1423
public static ?Redis $redisClient = null;
1524
public static string $redisNamespace = '';
16-
/** @var array<int, string> Adapter-keyspace SCAN patterns the run owns, scrubbed in tearDownAfterClass. */
17-
protected static array $keyPatterns = [];
1825

1926
public static function getAdapterName(): string
2027
{
@@ -61,18 +68,11 @@ public function getDatabase(): Database
6168
$database = new Database($adapter, $cache);
6269
$database
6370
->setAuthorization(self::$authorization)
64-
->setDatabase('utopiaTests')
71+
->setDatabase($this->testDatabase)
6572
->setNamespace(self::$redisNamespace);
6673

6774
$this->configureDatabase($database);
6875

69-
// Track every adapter-keyspace pattern this run owns so
70-
// tearDownAfterClass can scrub without a global FLUSH. The
71-
// configureDatabase() call above may have mutated the namespace
72-
// (shared-tables uses ''), so capture the post-configure namespace
73-
// too.
74-
self::$keyPatterns = self::buildKeyPatterns(self::$redisNamespace, $database->getNamespace(), $database->getDatabase());
75-
7676
if ($database->exists()) {
7777
$database->delete();
7878
}
@@ -82,27 +82,6 @@ public function getDatabase(): Database
8282
return self::$database = $database;
8383
}
8484

85-
/**
86-
* Build SCAN MATCH patterns covering the adapter keyspace for every
87-
* namespace this test class actually wrote to. The two-namespace form
88-
* (initial + post-configure) covers the shared-tables case where
89-
* setNamespace('') is applied before create().
90-
*
91-
* @return array<int, string>
92-
*/
93-
protected static function buildKeyPatterns(string $initialNamespace, string $effectiveNamespace, string $database): array
94-
{
95-
$patterns = [];
96-
$namespaces = \array_unique([$initialNamespace, $effectiveNamespace]);
97-
foreach ($namespaces as $namespace) {
98-
// Adapter writes: `KEY_PREFIX:{namespace}:{database}:*`. Empty
99-
// namespace produces a literal double-colon, which is a valid
100-
// SCAN pattern.
101-
$patterns[] = RedisAdapter::KEY_PREFIX . ':' . $namespace . ':' . $database . ':*';
102-
}
103-
return \array_values(\array_unique($patterns));
104-
}
105-
10685
protected function deleteColumn(string $collection, string $column): bool
10786
{
10887
// Redis keeps no out-of-band schema; raw column drops do not apply.
@@ -137,36 +116,4 @@ public function testUpdateAttributeSize(): void
137116
);
138117
}
139118

140-
public static function tearDownAfterClass(): void
141-
{
142-
try {
143-
if (self::$keyPatterns !== [] && self::$redisClient instanceof Redis) {
144-
self::scrubKeys(self::$redisClient, self::$keyPatterns);
145-
}
146-
} finally {
147-
self::$database = null;
148-
self::$redisClient = null;
149-
self::$redisNamespace = '';
150-
self::$keyPatterns = [];
151-
parent::tearDownAfterClass();
152-
}
153-
}
154-
155-
/**
156-
* @param array<int, string> $patterns
157-
*/
158-
private static function scrubKeys(Redis $client, array $patterns): void
159-
{
160-
foreach ($patterns as $pattern) {
161-
$iterator = null;
162-
while (($keys = $client->scan($iterator, $pattern, 500)) !== false) {
163-
if (\count($keys) > 0) {
164-
$client->del($keys);
165-
}
166-
if ($iterator === 0) {
167-
break;
168-
}
169-
}
170-
}
171-
}
172119
}

0 commit comments

Comments
 (0)