|
|
@@ -83,6 +83,36 @@ async def test_stop_epoch_fences_current_owner_without_taking_process_lease(
|
|
|
await lease.release()
|
|
|
|
|
|
|
|
|
+@pytest.mark.asyncio
|
|
|
+async def test_new_owner_can_cas_stopping_build_to_stopped(
|
|
|
+ database: tuple[AsyncEngine, async_sessionmaker[AsyncSession]], tmp_path: Path
|
|
|
+) -> None:
|
|
|
+ _, sessions = database
|
|
|
+ build_id = await _bound_build(sessions)
|
|
|
+ old_lease = OwnerLease(sessions, tmp_path / "leases", owner_instance_id="old")
|
|
|
+ old_token = await old_lease.acquire(build_id)
|
|
|
+ gate = FencedCommandGate(sessions)
|
|
|
+ stop_epoch = await gate.request_stop(build_id)
|
|
|
+ assert await gate.request_stop(build_id) == stop_epoch
|
|
|
+ await old_lease.release()
|
|
|
+
|
|
|
+ takeover = OwnerLease(sessions, tmp_path / "leases", owner_instance_id="takeover")
|
|
|
+ token = await takeover.acquire(build_id)
|
|
|
+ try:
|
|
|
+ assert token.owner_epoch == old_token.owner_epoch + 1
|
|
|
+ assert token.stop_epoch == stop_epoch
|
|
|
+ await gate.verify_stop_owner(token)
|
|
|
+ await gate.complete_stop(token)
|
|
|
+ assert (
|
|
|
+ await SqlAlchemyLegacyBuildStateRepository(sessions).get_status(build_id)
|
|
|
+ is BuildStatus.STOPPED
|
|
|
+ )
|
|
|
+ with pytest.raises(MissionFencingTokenStale):
|
|
|
+ await gate.complete_stop(old_token)
|
|
|
+ finally:
|
|
|
+ await takeover.release()
|
|
|
+
|
|
|
+
|
|
|
@pytest.mark.asyncio
|
|
|
async def test_phase_three_state_and_snapshot_mutations_share_the_owner_fence(
|
|
|
database: tuple[AsyncEngine, async_sessionmaker[AsyncSession]], tmp_path: Path
|