test(selftest): ONEDRIVE-SELFTEST sub-step 1c — toggle immediately followed by Send
Adds a third rapid-toggle assertion alongside the existing folder-reconcile check: chooseTransport(.airDrop) immediately followed by chooseTransport(.oneDrive), with NO sleep, then an immediate send(anchor: nil) — proving send() correctly awaits the pending reconcile Task (SendController.swift/AppModel.swift in this series) rather than racing ahead with a stale recordUncommented flag. Asserts the freshly-sent, still-unmarked PDF is never itself reported as an already-returned document. Also updates composePDFForSend's call site for its new transport: parameter. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ZiTXPbPCSjzPVsfoweAbp
This commit is contained in:
@@ -223,7 +223,7 @@ enum PickerSelfTest {
|
|||||||
sendTruthFail("seeded session was empty")
|
sendTruthFail("seeded session was empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
let pending = try await model.composePDFForSend(outbox: model.outboxURL)
|
let pending = try await model.composePDFForSend(outbox: model.outboxURL, transport: .airDrop)
|
||||||
guard fm.fileExists(atPath: pending.fileURL.path) else {
|
guard fm.fileExists(atPath: pending.fileURL.path) else {
|
||||||
sendTruthFail("PDF was not written")
|
sendTruthFail("PDF was not written")
|
||||||
}
|
}
|
||||||
@@ -543,6 +543,13 @@ enum PickerSelfTest {
|
|||||||
/// does let the last choice win instead of an earlier, superseded call applying its
|
/// does let the last choice win instead of an earlier, superseded call applying its
|
||||||
/// stale folder after a later one already won.
|
/// stale folder after a later one already won.
|
||||||
///
|
///
|
||||||
|
/// Sub-step 1c: the OTHER race — a toggle immediately followed by Send, with no
|
||||||
|
/// sleep at all before send() runs. Proves send() awaits `pendingReconcileTask`
|
||||||
|
/// before snapshotting transport/folder: a freshly-sent, still-unmarked PDF must
|
||||||
|
/// never be reported as an already-returned document (which is exactly what would
|
||||||
|
/// happen if send() raced ahead while recordUncommented was still `true`, stale
|
||||||
|
/// from the .airDrop leg of the toggle).
|
||||||
|
///
|
||||||
/// Sub-step 2: relaunch simulation — the exact BLOCKER scenario this phase exists to
|
/// Sub-step 2: relaunch simulation — the exact BLOCKER scenario this phase exists to
|
||||||
/// catch. OneDrive is still persisted in defaults from sub-step 1; builds a FRESH
|
/// catch. OneDrive is still persisted in defaults from sub-step 1; builds a FRESH
|
||||||
/// model the same way the real app launches (`AppDelegate.makeLaunchModel()` itself,
|
/// model the same way the real app launches (`AppDelegate.makeLaunchModel()` itself,
|
||||||
@@ -673,6 +680,52 @@ enum PickerSelfTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sub-step 1c: toggle-then-immediate-send race — see the doc comment above
|
||||||
|
// this function. No sleep here: this IS the exact race window finding #3
|
||||||
|
// exists to close, so send() itself must wait out the pending reconcile.
|
||||||
|
let racePNG = try makeTinyPNGData()
|
||||||
|
_ = try await model.spool.append(
|
||||||
|
pngData: racePNG, pixelWidth: 64, pixelHeight: 48, scale: 1, capturedAt: Date()
|
||||||
|
)
|
||||||
|
model.replaceSession(try await model.spool.currentSession())
|
||||||
|
guard !model.session.isEmpty else {
|
||||||
|
throw OneDriveSelfTestError.detail("toggle-then-send: re-seeded session was empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
let knownBeforeToggleSend = Set(
|
||||||
|
((try? fm.contentsOfDirectory(at: selftestFolder, includingPropertiesForKeys: nil)) ?? [])
|
||||||
|
.map(\.lastPathComponent)
|
||||||
|
)
|
||||||
|
model.chooseTransport(.airDrop)
|
||||||
|
model.chooseTransport(.oneDrive) // immediately superseding, no sleep before send()
|
||||||
|
await model.send(anchor: nil)
|
||||||
|
|
||||||
|
guard let toggleSendStatus = model.statusLine, toggleSendStatus.hasPrefix("Saved to OneDrive") else {
|
||||||
|
throw OneDriveSelfTestError.detail(
|
||||||
|
"toggle-then-send: status was \(model.statusLine ?? "nil"), expected 'Saved to OneDrive'"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
guard model.session.isEmpty else {
|
||||||
|
throw OneDriveSelfTestError.detail("toggle-then-send: session was not archived")
|
||||||
|
}
|
||||||
|
let filesAfterToggleSend = (try? fm.contentsOfDirectory(
|
||||||
|
at: selftestFolder, includingPropertiesForKeys: nil
|
||||||
|
)) ?? []
|
||||||
|
guard let toggleSendPDFURL = filesAfterToggleSend.first(where: {
|
||||||
|
$0.pathExtension.lowercased() == "pdf" && !knownBeforeToggleSend.contains($0.lastPathComponent)
|
||||||
|
}) else {
|
||||||
|
throw OneDriveSelfTestError.detail("toggle-then-send: no new PDF found in \(selftestFolder.path)")
|
||||||
|
}
|
||||||
|
// The freshly-sent PDF is UNMARKED. If send() had raced ahead of the pending
|
||||||
|
// reconcile, recordUncommented could still have been (stale) true, and this
|
||||||
|
// scan would wrongly report it as already returned.
|
||||||
|
let scanAfterToggleSend = try await model.watcher.scanNow()
|
||||||
|
guard !scanAfterToggleSend.contains(where: { $0.fileURL == toggleSendPDFURL }) else {
|
||||||
|
throw OneDriveSelfTestError.detail(
|
||||||
|
"toggle-then-send: freshly-sent unmarked PDF at \(toggleSendPDFURL.path) was reported as returned — send() raced ahead of the pending reconcile"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Sub-step 2: relaunch simulation — see the doc comment above this function.
|
// Sub-step 2: relaunch simulation — see the doc comment above this function.
|
||||||
let relaunchAppSupportRoot = fm.temporaryDirectory
|
let relaunchAppSupportRoot = fm.temporaryDirectory
|
||||||
.appendingPathComponent("shotdeck-onedrive-relaunch-\(UUID().uuidString)", isDirectory: true)
|
.appendingPathComponent("shotdeck-onedrive-relaunch-\(UUID().uuidString)", isDirectory: true)
|
||||||
|
|||||||
Reference in New Issue
Block a user