Skip to content

Commit 5d8595e

Browse files
abnegateclaude
andcommitted
test(documents): share one uncached twin across the document cache tests
DocumentCacheActivationTest, DocumentCacheEpochTest, DocumentCacheRoundTripTest and InvalidationRestoreFailureTest each built their own copy of a database over the same adapter, authorization and namespace with a None cache, used to change stored data behind the cache under test. The copies had already drifted in shape (a void updater with fixed or free arguments, a factory taking the adapter separately, an inline block), so a fix to one would not reach the others. Tests\Unit\Support\UncachedTwin::of() is now the single implementation and each test writes through it directly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 7000c40 commit 5d8595e

5 files changed

Lines changed: 35 additions & 50 deletions

File tree

‎tests/unit/Documents/DocumentCacheActivationTest.php‎

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
use PHPUnit\Framework\TestCase;
77
use Tests\Unit\Cache\LeasableHashCache;
88
use Tests\Unit\Support\CountingMemory;
9+
use Tests\Unit\Support\UncachedTwin;
910
use Utopia\Cache\Adapter as CacheAdapter;
1011
use Utopia\Cache\Adapter\Memory as MemoryCache;
11-
use Utopia\Cache\Adapter\None;
1212
use Utopia\Cache\Cache;
1313
use Utopia\Database\Attribute;
1414
use Utopia\Database\Collection;
@@ -56,7 +56,7 @@ public function testAWriterActivatingWhileAnotherIsInFlightLeavesItsBarrierInPla
5656
});
5757

5858
$this->assertSame('first', $first->getDocument(self::COLLECTION, 'hook')->getAttribute('name'));
59-
$this->changeBehindTheCache($first, 'changed');
59+
UncachedTwin::of($first)->updateDocument(self::COLLECTION, 'hook', new Document(['name' => 'changed']));
6060
$this->assertSame('changed', $first->getDocument(self::COLLECTION, 'hook')->getAttribute('name'), 'no read is cached while the second writer is in flight');
6161
});
6262

@@ -66,16 +66,6 @@ public function testAWriterActivatingWhileAnotherIsInFlightLeavesItsBarrierInPla
6666
$this->assertSame(0, $firstAdapter->documentReads, 'caching resumes once no writer is in flight');
6767
}
6868

69-
private function changeBehindTheCache(Database $database, string $name): void
70-
{
71-
$uncached = new Database($database->getAdapter(), new Cache(new None()));
72-
$uncached
73-
->setAuthorization($database->getAuthorization())
74-
->setDatabase($database->getDatabase())
75-
->setNamespace($database->getNamespace());
76-
$uncached->updateDocument(self::COLLECTION, 'hook', new Document(['name' => $name]));
77-
}
78-
7969
private function database(CountingMemory $adapter, Cache $cache, string $namespace): Database
8070
{
8171
$database = new Database($adapter, $cache);

‎tests/unit/Documents/DocumentCacheEpochTest.php‎

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
use Tests\Unit\Cache\RacedReleaseCache;
88
use Tests\Unit\Cache\RedisLeasableCache;
99
use Tests\Unit\Support\CountingMemory;
10+
use Tests\Unit\Support\UncachedTwin;
1011
use Utopia\Cache\Adapter as CacheAdapter;
1112
use Utopia\Cache\Adapter\Memory as MemoryCache;
12-
use Utopia\Cache\Adapter\None;
1313
use Utopia\Cache\Cache;
1414
use Utopia\Cache\Feature\Leasable;
1515
use Utopia\Database\Adapter\Memory as DatabaseMemory;
@@ -57,7 +57,7 @@ public function testPurgeCachedCollectionRetiresItsCachedDocuments(): void
5757
]));
5858
$this->assertSame('original', $database->getDocument('webhooks', 'hook')->getAttribute('name'));
5959

60-
$this->changeBehindTheCache($database, 'webhooks', 'hook', 'changed');
60+
UncachedTwin::of($database)->updateDocument('webhooks', 'hook', new Document(['name' => 'changed']));
6161
$this->assertSame('original', $database->getDocument('webhooks', 'hook')->getAttribute('name'), 'A document written without this cache leaves the cached copy in place');
6262

6363
$this->assertTrue($database->purgeCachedCollection('webhooks'));
@@ -105,7 +105,7 @@ public function testActivationFailureAfterCommitLeavesTheEpochBlocked(): void
105105
}
106106

107107
$this->assertSame('updated', $database->getDocument('webhooks', 'hook')->getAttribute('name'));
108-
$this->changeBehindTheCache($database, 'webhooks', 'hook', 'changed');
108+
UncachedTwin::of($database)->updateDocument('webhooks', 'hook', new Document(['name' => 'changed']));
109109
$this->assertSame('changed', $database->getDocument('webhooks', 'hook')->getAttribute('name'), 'A collection whose activation failed stays uncached');
110110
}
111111

@@ -144,7 +144,7 @@ public function testActivationFailureDoesNotStrandOtherCollectionEpochs(): void
144144
}
145145

146146
$this->assertSame('updated', $database->getDocument('webhooks', 'hook')->getAttribute('name'));
147-
$this->changeBehindTheCache($database, 'webhooks', 'hook', 'changed');
147+
UncachedTwin::of($database)->updateDocument('webhooks', 'hook', new Document(['name' => 'changed']));
148148
$this->assertSame('changed', $database->getDocument('webhooks', 'hook')->getAttribute('name'), 'The collection whose activation failed stays uncached');
149149

150150
$this->assertSame('updated', $database->getDocument('logs', 'log')->getAttribute('name'));
@@ -310,7 +310,7 @@ public function testActivationRejectsACorruptedOwnerRegistration(): void
310310

311311
$cache->corruptFieldWrites(false);
312312
$this->assertSame('updated', $database->getDocument('webhooks', 'hook')->getAttribute('name'));
313-
$this->changeBehindTheCache($database, 'webhooks', 'hook', 'changed');
313+
UncachedTwin::of($database)->updateDocument('webhooks', 'hook', new Document(['name' => 'changed']));
314314
$this->assertSame('changed', $database->getDocument('webhooks', 'hook')->getAttribute('name'), 'A collection whose activation was refused stays uncached');
315315
}
316316

@@ -332,7 +332,7 @@ public function testActivationPropagatesAnOwnerReleaseFailure(): void
332332
}
333333

334334
$this->assertSame('updated', $database->getDocument('webhooks', 'hook')->getAttribute('name'));
335-
$this->changeBehindTheCache($database, 'webhooks', 'hook', 'changed');
335+
UncachedTwin::of($database)->updateDocument('webhooks', 'hook', new Document(['name' => 'changed']));
336336
$this->assertSame('changed', $database->getDocument('webhooks', 'hook')->getAttribute('name'), 'A collection whose owner release failed stays uncached');
337337
}
338338

@@ -341,16 +341,6 @@ private function renameDocument(Database $database, string $collection, string $
341341
return $database->updateDocuments($collection, new Document(['name' => $name]), [Query::equal('$id', [$id])]);
342342
}
343343

344-
private function changeBehindTheCache(Database $database, string $collection, string $id, string $name): void
345-
{
346-
$uncached = new Database($database->getAdapter(), new Cache(new None()));
347-
$uncached
348-
->setAuthorization($database->getAuthorization())
349-
->setDatabase($database->getDatabase())
350-
->setNamespace($database->getNamespace());
351-
$uncached->updateDocument($collection, $id, new Document(['name' => $name]));
352-
}
353-
354344
private function createDatabaseWithCache(CacheAdapter $cache, ?string $namespace = null, DatabaseMemory $adapter = new DatabaseMemory()): Database
355345
{
356346
$database = new Database($adapter, new Cache($cache));
@@ -439,7 +429,7 @@ public function testALostActivationDoesNotKeepTheCollectionUncached(): void
439429
}
440430

441431
$this->assertSame('updated', $database->getDocument('webhooks', 'hook')->getAttribute('name'));
442-
$this->changeBehindTheCache($database, 'webhooks', 'hook', 'changed');
432+
UncachedTwin::of($database)->updateDocument('webhooks', 'hook', new Document(['name' => 'changed']));
443433
$this->assertSame('changed', $database->getDocument('webhooks', 'hook')->getAttribute('name'), 'A collection whose write has not activated stays uncached while the write is younger than the writer timeout');
444434

445435
$database->setCacheWriterTimeout(0);
@@ -467,7 +457,7 @@ public function testAWriteAfterAnAbandonedWriteReenablesTheCollection(): void
467457

468458
$this->renameDocument($database, 'webhooks', 'hook', 'second');
469459
$this->assertSame('second', $database->getDocument('webhooks', 'hook')->getAttribute('name'));
470-
$this->changeBehindTheCache($database, 'webhooks', 'hook', 'changed');
460+
UncachedTwin::of($database)->updateDocument('webhooks', 'hook', new Document(['name' => 'changed']));
471461
$this->assertSame('changed', $database->getDocument('webhooks', 'hook')->getAttribute('name'), 'A write younger than the writer timeout counts as in flight, so the next write leaves the collection uncached');
472462

473463
$database->setCacheWriterTimeout(0);

‎tests/unit/Documents/DocumentCacheRoundTripTest.php‎

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use Tests\Unit\Cache\CountingCache;
99
use Tests\Unit\Cache\RedisLeasableCache;
1010
use Tests\Unit\Support\CountingMemory;
11-
use Utopia\Cache\Adapter\None;
11+
use Tests\Unit\Support\UncachedTwin;
1212
use Utopia\Cache\Cache;
1313
use Utopia\Database\Attribute;
1414
use Utopia\Database\Collection;
@@ -255,12 +255,12 @@ public function testATenantNeverServesUnderAnotherTenantsEpochOfAGlobalDefinitio
255255

256256
public function testPurgingTheMetadataCollectionRetiresEveryCachedDefinition(): void
257257
{
258-
[$database, $adapter] = $this->createDatabase();
258+
[$database] = $this->createDatabase();
259259
$database->createCollection(new Collection(id: 'logs', permissions: [Permission::read(Role::any())]));
260260
$this->assertTrue($database->getCollection('webhooks')->getAttribute('documentSecurity'));
261261
$this->assertTrue($database->getCollection('logs')->getAttribute('documentSecurity'));
262262

263-
$uncached = $this->createUncachedTwin($database, $adapter);
263+
$uncached = UncachedTwin::of($database);
264264
$uncached->updateCollection('webhooks', [Permission::read(Role::any())], false);
265265
$uncached->updateCollection('logs', [Permission::read(Role::any())], false);
266266
$this->assertTrue($database->getCollection('webhooks')->getAttribute('documentSecurity'), 'A definition written without this cache leaves the cached definition in place');
@@ -273,10 +273,10 @@ public function testPurgingTheMetadataCollectionRetiresEveryCachedDefinition():
273273

274274
public function testPurgingTheMetadataCollectionRetiresACachedMissingCollection(): void
275275
{
276-
[$database, $adapter] = $this->createDatabase();
276+
[$database] = $this->createDatabase();
277277
$this->assertTrue($database->getCollection('logs')->isEmpty());
278278

279-
$uncached = $this->createUncachedTwin($database, $adapter);
279+
$uncached = UncachedTwin::of($database);
280280
$uncached->createCollection(new Collection(id: 'logs', permissions: [Permission::read(Role::any())]));
281281
$this->assertTrue($database->getCollection('logs')->isEmpty(), 'A definition written without this cache leaves the cached miss in place');
282282

@@ -307,14 +307,6 @@ private function createDatabase(): array
307307
return [$database, $adapter, $cache];
308308
}
309309

310-
private function createUncachedTwin(Database $database, CountingMemory $adapter): Database
311-
{
312-
return (new Database($adapter, new Cache(new None())))
313-
->setAuthorization($database->getAuthorization())
314-
->setDatabase($database->getDatabase())
315-
->setNamespace($database->getNamespace());
316-
}
317-
318310
private function hook(string $id): Document
319311
{
320312
return new Document([

‎tests/unit/Documents/InvalidationRestoreFailureTest.php‎

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
use DomainException;
66
use PHPUnit\Framework\TestCase;
77
use RuntimeException;
8+
use Tests\Unit\Support\UncachedTwin;
89
use Utopia\Cache\Adapter\Memory as MemoryCache;
9-
use Utopia\Cache\Adapter\None;
1010
use Utopia\Cache\Cache;
1111
use Utopia\Database\Adapter\Memory;
1212
use Utopia\Database\Attribute;
@@ -57,12 +57,7 @@ public function testAFailedWriteKeepsItsErrorWhenRestoringTheCacheEpochsFails():
5757

5858
$this->assertSame('kept', $database->getDocument(self::COLLECTION, 'kept')->getAttribute('entry'));
5959

60-
$uncached = new Database($database->getAdapter(), new Cache(new None()));
61-
$uncached
62-
->setAuthorization($database->getAuthorization())
63-
->setDatabase($database->getDatabase())
64-
->setNamespace($database->getNamespace());
65-
$uncached->updateDocument(self::COLLECTION, 'kept', new Document(['entry' => 'changed']));
60+
UncachedTwin::of($database)->updateDocument(self::COLLECTION, 'kept', new Document(['entry' => 'changed']));
6661
$this->assertSame('changed', $database->getDocument(self::COLLECTION, 'kept')->getAttribute('entry'), 'a restore that failed leaves the document cache fail-closed');
6762
}
6863

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Tests\Unit\Support;
4+
5+
use Utopia\Cache\Adapter\None;
6+
use Utopia\Cache\Cache;
7+
use Utopia\Database\Database;
8+
9+
final class UncachedTwin
10+
{
11+
public static function of(Database $database): Database
12+
{
13+
return (new Database($database->getAdapter(), new Cache(new None())))
14+
->setAuthorization($database->getAuthorization())
15+
->setDatabase($database->getDatabase())
16+
->setNamespace($database->getNamespace());
17+
}
18+
}

0 commit comments

Comments
 (0)