Skip to content

Commit 3decd00

Browse files
committed
Add test for callback result loss when lock release fails
- Test verifies that LockReleaseException is thrown when callback succeeds but release fails - Confirms callback result is lost in this scenario (documented limitation in ADR-003) - Uses PG_TERMINATE_BACKEND to simulate release failure - All 94 tests pass
1 parent 74f52a5 commit 3decd00

1 file changed

Lines changed: 33 additions & 0 deletions

File tree

test/Integration/Postgres/PostgresAdvisoryLockerTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,39 @@ function () use (&$callbackExecuted): void {
942942
$this->assertPgAdvisoryLockExistsInConnection($dbConnection1, $lockKey);
943943
}
944944

945+
public function testWithinSessionLevelLockLosesCallbackResultWhenReleaseFails(): void
946+
{
947+
// GIVEN: A session-level lock acquired via withinSessionLevelLock callback
948+
$locker = $this->initLocker();
949+
$dbConnection = $this->initPostgresPdoConnection();
950+
$dbConnection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
951+
$lockKey = PostgresLockKey::create('test');
952+
953+
// WHEN: Callback succeeds with a result but connection is killed before release
954+
try {
955+
$locker->withinSessionLevelLock(
956+
new PdoConnectionAdapter($dbConnection),
957+
$lockKey,
958+
function () use ($dbConnection): string {
959+
// Kill own connection's backend to make release fail
960+
$pid = $dbConnection->pgsqlGetPid();
961+
$killerConnection = $this->initPostgresPdoConnection();
962+
$killerConnection->exec("SELECT PG_TERMINATE_BACKEND($pid)");
963+
964+
return 'important-result';
965+
},
966+
TimeoutDuration::zero(),
967+
);
968+
$this->fail('Expected LockReleaseException was not thrown');
969+
} catch (\Cog\DbLocker\Exception\LockReleaseException $e) {
970+
// THEN: LockReleaseException is thrown (guaranteeing callback succeeded)
971+
$this->assertStringContainsString('Failed to release lock', $e->getMessage());
972+
// THEN: But the callback result is lost - this is a known limitation documented in ADR-003
973+
} catch (\Throwable $e) {
974+
$this->fail('Expected LockReleaseException but got: ' . get_class($e) . ' - ' . $e->getMessage());
975+
}
976+
}
977+
945978
public function testItSanitizesCommentToPreventSqlInjection(): void
946979
{
947980
// GIVEN: A lock key with newline that could break SQL comment and inject code

0 commit comments

Comments
 (0)