Refuse to park a track whose pre-park snapshot is gone, rather than re-snapshotting the already-parked chain as the user's state

This commit is contained in:
2026-08-03 18:30:40 -04:00
parent 2f96dd3da5
commit 203961f41c
6 changed files with 189 additions and 22 deletions
+71 -1
View File
@@ -4,7 +4,8 @@
// The properties under test: a mode switch leaves its per-FX offline work here,
// so a second switch arriving before the first drained must leave every track in
// the state the SECOND switch specifies — never the first's, never both replayed;
// and a cancel must not strand the pre-park FX state it was the last record of.
// a cancel must not strand the pre-park FX state it was the last record of; and
// a pre-park snapshot is never taken from a chain a park has already touched.
#include "../src/shell/view/view_fx_park.h"
@@ -233,6 +234,67 @@ static void testRestorePlanOpsRebuildTheSlotKeyedSnapshotVerbatim() {
CHECK(rebuilt.states == snap.fxOffline);
}
// -- may this chain be snapshotted? -------------------------------------------
//
// The pre-park snapshot is restore's only source of truth, so one taken from an
// already-parked chain makes every later restore write hidden/out-of-mix/
// FX-disabled back, permanently. The park site cannot infer a clean chain from
// an absent snapshot — discardDeferredFxParks drops intents whose flag writes
// already landed — so the chain itself has to be asked.
static void testAChainSittingAtEveryValueTheParkWouldWriteReadsAsParked() {
// The four zeros are what a parked track's driven flags actually read; if
// makeParkPlan ever writes something else, this is the test that says so.
const TrackPlan park = makeParkPlan("{A}", /*fxCount=*/0);
CHECK(park.flags.size() == 4);
CHECK(parkFlagsAlreadyApplied(park.flags, {0, 0, 0, 0}));
}
static void testOneFlagStillAtTheUsersValueMeansNoParkReachedTheChain() {
const TrackPlan park = makeParkPlan("{A}", /*fxCount=*/0);
// Flag order is ShowInTcp, ShowInMixer, MainSend, FxEnable — each alone is
// enough to prove the chain was never parked.
CHECK(!parkFlagsAlreadyApplied(park.flags, {1, 0, 0, 0}));
CHECK(!parkFlagsAlreadyApplied(park.flags, {0, 1, 0, 0}));
CHECK(!parkFlagsAlreadyApplied(park.flags, {0, 0, 1, 0}));
CHECK(!parkFlagsAlreadyApplied(park.flags, {0, 0, 0, 1}));
}
static void testAnEmptyOrMismatchedPlanProvesNothing() {
const TrackPlan park = makeParkPlan("{A}", /*fxCount=*/0);
CHECK(!parkFlagsAlreadyApplied({}, {}));
CHECK(!parkFlagsAlreadyApplied(park.flags, {0, 0, 0}));
}
static void testACleanChainIsSnapshottedThenParked() {
CHECK(decidePark(/*haveSnapshot=*/false, /*chainReadsParked=*/false) ==
ParkAction::SnapshotThenPark);
}
static void testAHeldSnapshotIsNeverOverwrittenWhateverTheChainReads() {
// The held snapshot IS the pre-park truth, so the chain is not consulted —
// which is what lets the shell skip the live flag reads on this path.
CHECK(decidePark(/*haveSnapshot=*/true, /*chainReadsParked=*/false) == ParkAction::ParkOnly);
CHECK(decidePark(/*haveSnapshot=*/true, /*chainReadsParked=*/true) == ParkAction::ParkOnly);
}
static void testAParkedChainWithNoSnapshotIsRefusedRatherThanResnapshotted() {
// The defect this whole section exists for: the truth is gone, so the only
// non-destructive act is to leave the track alone. Snapshotting here commits
// park state as the user's state and no later restore can undo it.
CHECK(decidePark(/*haveSnapshot=*/false, /*chainReadsParked=*/true) == ParkAction::Refuse);
}
static void testRefusalIsReportedWithItsTrackCountAndSaysNothingWhenNoneWereRefused() {
CHECK(describeRefusedParks(0).empty());
CHECK(describeRefusedParks(-1).empty());
CHECK(describeRefusedParks(1).find("1 track ") != std::string::npos);
CHECK(describeRefusedParks(3).find("3 tracks ") != std::string::npos);
}
// -- re-entrancy -------------------------------------------------------------
static void testTakeDetachesEverythingAndLeavesTheQueueEmpty() {
@@ -297,6 +359,14 @@ int main() {
testSlotKeyedRestoreDoesNotBecomeIdentityKeyedWithNoIdentities();
testRestorePlanOpsRebuildTheIdentityKeyedSnapshotVerbatim();
testRestorePlanOpsRebuildTheSlotKeyedSnapshotVerbatim();
testAChainSittingAtEveryValueTheParkWouldWriteReadsAsParked();
testOneFlagStillAtTheUsersValueMeansNoParkReachedTheChain();
testAnEmptyOrMismatchedPlanProvesNothing();
testACleanChainIsSnapshottedThenParked();
testAHeldSnapshotIsNeverOverwrittenWhateverTheChainReads();
testAParkedChainWithNoSnapshotIsRefusedRatherThanResnapshotted();
testRefusalIsReportedWithItsTrackCountAndSaysNothingWhenNoneWereRefused();
testTakeDetachesEverythingAndLeavesTheQueueEmpty();
testIntentsArrivingDuringADrainSurviveIt();
testAReEntrantParkCancelsOnlyWhatIsStillPending();