Skip to content

Commit 9898ed1

Browse files
committed
Add tests
1 parent 20dd6e4 commit 9898ed1

1 file changed

Lines changed: 104 additions & 0 deletions

File tree

tests/e2e/Adapter/Scopes/DocumentTests.php

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,6 +1572,110 @@ public function testCreateDocumentDefaults(): void
15721572
$database->deleteCollection('defaults');
15731573
}
15741574

1575+
/**
1576+
* When a document's UID changes on update, its permission rows in the
1577+
* collection's _perms table must follow the new UID. Otherwise the old
1578+
* rows are orphaned and the renamed document is left with no permissions,
1579+
* even when the permission set itself was not changed.
1580+
*/
1581+
public function testUpdateDocumentChangeIdMigratesPermissions(): void
1582+
{
1583+
/** @var Database $database */
1584+
$database = $this->getDatabase();
1585+
1586+
$auth = $database->getAuthorization();
1587+
1588+
$collection = 'update_change_id_perms';
1589+
1590+
// documentSecurity with no collection-level permissions: reads are
1591+
// governed purely by the document's rows in the _perms table.
1592+
$database->createCollection($collection, permissions: [], documentSecurity: true);
1593+
$this->assertEquals(true, $database->createAttribute($collection, 'name', Database::VAR_STRING, 128, false));
1594+
1595+
// Create a document whose read permission is scoped to a single role,
1596+
// so that find() must consult the _perms table to return it.
1597+
$document = $auth->skip(fn () => $database->createDocument($collection, new Document([
1598+
'$id' => 'old_id',
1599+
'name' => 'test',
1600+
'$permissions' => [
1601+
Permission::read(Role::user('alice')),
1602+
Permission::update(Role::user('alice')),
1603+
Permission::delete(Role::user('alice')),
1604+
],
1605+
])));
1606+
$this->assertEquals('old_id', $document->getId());
1607+
1608+
// Sanity: as alice the document is visible via the _perms table.
1609+
$auth->addRole(Role::user('alice')->toString());
1610+
$this->assertCount(1, $database->find($collection));
1611+
1612+
// Rename the document WITHOUT changing its permission set.
1613+
$renamed = $auth->skip(fn () => $database->updateDocument($collection, 'old_id', new Document(\array_merge(
1614+
$document->getArrayCopy(),
1615+
['$id' => 'new_id'],
1616+
))));
1617+
$this->assertEquals('new_id', $renamed->getId());
1618+
1619+
// The old UID must no longer resolve to a document.
1620+
$this->assertTrue($auth->skip(fn () => $database->getDocument($collection, 'old_id'))->isEmpty());
1621+
1622+
// The new UID must exist and keep its permissions on the main row.
1623+
$newDoc = $auth->skip(fn () => $database->getDocument($collection, 'new_id'));
1624+
$this->assertFalse($newDoc->isEmpty());
1625+
$this->assertContains(Permission::read(Role::user('alice')), $newDoc->getPermissions());
1626+
1627+
// The crucial check: the permission rows must have migrated to the new
1628+
// UID in the _perms table. As alice, find() (which joins _perms) must
1629+
// still return exactly the renamed document. With orphaned rows under
1630+
// the old UID this returns 0.
1631+
$found = $database->find($collection);
1632+
$this->assertCount(1, $found);
1633+
$this->assertEquals('new_id', $found[0]->getId());
1634+
1635+
/**
1636+
* Second scenario: change the UID AND the permission set in the same
1637+
* update. Drop alice's access and grant bob instead. The removed rows
1638+
* must be gone, the added rows must land under the new UID, and nothing
1639+
* may be left orphaned under the old UID.
1640+
*/
1641+
$rekeyed = $auth->skip(fn () => $database->updateDocument($collection, 'new_id', new Document(\array_merge(
1642+
$newDoc->getArrayCopy(),
1643+
[
1644+
'$id' => 'final_id',
1645+
'$permissions' => [
1646+
Permission::read(Role::user('bob')),
1647+
Permission::update(Role::user('bob')),
1648+
Permission::delete(Role::user('bob')),
1649+
],
1650+
],
1651+
))));
1652+
$this->assertEquals('final_id', $rekeyed->getId());
1653+
1654+
// The old UID must no longer resolve to a document.
1655+
$this->assertTrue($auth->skip(fn () => $database->getDocument($collection, 'new_id'))->isEmpty());
1656+
1657+
// The main row must reflect the new permission set.
1658+
$finalDoc = $auth->skip(fn () => $database->getDocument($collection, 'final_id'));
1659+
$this->assertFalse($finalDoc->isEmpty());
1660+
$this->assertContains(Permission::read(Role::user('bob')), $finalDoc->getPermissions());
1661+
$this->assertNotContains(Permission::read(Role::user('alice')), $finalDoc->getPermissions());
1662+
1663+
// alice's permission rows were removed: as alice nothing is returned.
1664+
$this->assertCount(0, $database->find($collection));
1665+
1666+
// bob's permission rows landed under the new UID: as bob the renamed
1667+
// document is returned via the _perms join.
1668+
$auth->addRole(Role::user('bob')->toString());
1669+
$foundAsBob = $database->find($collection);
1670+
$this->assertCount(1, $foundAsBob);
1671+
$this->assertEquals('final_id', $foundAsBob[0]->getId());
1672+
1673+
$auth->removeRole(Role::user('alice')->toString());
1674+
$auth->removeRole(Role::user('bob')->toString());
1675+
1676+
$auth->skip(fn () => $database->deleteCollection($collection));
1677+
}
1678+
15751679
public function testIncreaseDecrease(): Document
15761680
{
15771681
/** @var Database $database */

0 commit comments

Comments
 (0)