Add session synchronization tests and ensure atomic session closure

This commit is contained in:
Jeppe Bundgaard
2026-06-08 16:53:24 +02:00
parent 49364864d2
commit 325b35beb7
2 changed files with 48 additions and 2 deletions
@@ -483,8 +483,8 @@ class selfserve_wash_flow implements selfserve_wash_flow_i
if (!$session->markForceStoppedIfOpen($orderId, $eventPayload)) { if (!$session->markForceStoppedIfOpen($orderId, $eventPayload)) {
$summary = $this->getSessionSummary((int)$session->id); $summary = $this->getSessionSummary((int)$session->id);
} else { } else {
$this->logSessionEvent((int)$session->id, selfserve_wash_event_type::SESSION_FORCE_STOPPED, $eventPayload); $this->logSessionEvent((int)$session->id, selfserve_wash_event_type::SESSION_FORCE_STOPPED, $eventPayload);
$summary = $this->getSessionSummary((int)$session->id); $summary = $this->getSessionSummary((int)$session->id);
} }
} }
@@ -0,0 +1,46 @@
<?php
it('serializes self-serve session synchronization before reading or creating open sessions', function (): void {
$washFlow = file_get_contents(app_path('modules/selfserve/classes/selfserve_wash_flow.php'));
expect($washFlow)->not->toBeFalse()
->and($washFlow)->toContain('withSessionMutationLock')
->and($washFlow)->toContain('sessionMutationLockKey')
->and($washFlow)->toContain('set_if_absent_with_expiration')
->and($washFlow)->toContain('GET_LOCK');
$syncOffset = strpos($washFlow, 'public function synchronizeSession');
expect($syncOffset)->not->toBeFalse();
$syncMethod = substr($washFlow, (int)$syncOffset, 9000);
$snapshotOffset = strpos($syncMethod, '$snapshot = $this->buildEligibilitySnapshot');
$lockOffset = strpos($syncMethod, '$mutationResult = $this->withSessionMutationLock');
$findOffset = strpos($syncMethod, '$session = $this->findLatestOpenSession');
$addOffset = strpos($syncMethod, '$session = (new selfserve_wash_sessions_o())->add');
$relayOffset = strpos($syncMethod, '$this->syncMachineRelayFromVisibleServices');
expect($snapshotOffset)->not->toBeFalse()
->and($lockOffset)->not->toBeFalse()
->and($findOffset)->not->toBeFalse()
->and($addOffset)->not->toBeFalse()
->and($relayOffset)->not->toBeFalse()
->and($snapshotOffset)->toBeLessThan($lockOffset)
->and($lockOffset)->toBeLessThan($findOffset)
->and($findOffset)->toBeLessThan($addOffset)
->and($addOffset)->toBeLessThan($relayOffset);
});
it('closes self-serve wash sessions with an atomic open-session guard', function (): void {
$sessionObject = file_get_contents(app_path('objects/selfserve_wash_sessions_o.php'));
$washFlow = file_get_contents(app_path('modules/selfserve/classes/selfserve_wash_flow.php'));
expect($sessionObject)->not->toBeFalse()
->and($sessionObject)->toContain('markCompletedIfOpen')
->and($sessionObject)->toContain('markForceStoppedIfOpen')
->and($sessionObject)->toContain('AND `completed_at` IS NULL')
->and($sessionObject)->toContain('AND UPPER(TRIM(`status`)) NOT IN ($terminalStatuses)');
expect($washFlow)->not->toBeFalse()
->and($washFlow)->toContain('if (!$session->markCompletedIfOpen($orderId))')
->and($washFlow)->toContain('if (!$session->markForceStoppedIfOpen($orderId, $eventPayload))');
});