Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import AVFoundation
import HardwareControllerAudioBoundary
import Testing

@Suite(.serialized)
struct AudioEngineExceptionBoundaryTest {
/// Converts a duplicate-tap exception into a recoverable error.
@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,13 @@ struct ControllerRuntimeTest {
)
}

@Test
@Test(
.enabled(
if: ProcessInfo.processInfo.environment[
"HC_RUN_HID_PERFORMANCE"
] == "1"
)
)
func tenThousandTransitionSoakMeetsDispatchBudget() {
let executor = RecordingExecutor()
let snapshots = SnapshotRecorder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1228,7 +1228,7 @@ private actor RemoteCapableRefinerProbe: TranscriptRefining {
}

private func localAIWaitUntil(
timeout: Duration = .seconds(1),
timeout: Duration = .seconds(5),
_ condition: @escaping @Sendable () async -> Bool
) async throws {
let clock = ContinuousClock()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,7 @@ private final class SnapshotRecorder: @unchecked Sendable {
}

private func waitUntil(
timeout: Duration = .seconds(1),
timeout: Duration = .seconds(5),
_ condition: @escaping @Sendable () async -> Bool
) async throws {
let clock = ContinuousClock()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,18 +66,12 @@ struct VoiceHistoryReconcilerTest {
let root = temporaryRoot("expiration_restore")
defer { try? FileManager.default.removeItem(at: root) }
let sessionID = UUID()
var history: SQLiteVoiceSessionHistory? = try SQLiteVoiceSessionHistory(
rootDirectory: root
)
let document = historyDocument(sessionID: sessionID)
try await record(document, in: try #require(history))
let finalURL = root.appending(path: "audio/\(sessionID).caf")
let finalURL = try await insertFixture(document, root: root)
let quarantineFilename =
".expiring_\(sessionID.uuidString)_\(UUID().uuidString).caf"
let quarantineURL = root.appending(path: "audio/\(quarantineFilename)")
try FileManager.default.moveItem(at: finalURL, to: quarantineURL)
history = nil

let reopened = try SQLiteVoiceSessionHistory(rootDirectory: root)
let item = try #require(try await reopened.session(id: sessionID))

Expand Down Expand Up @@ -155,18 +149,14 @@ struct VoiceHistoryReconcilerTest {
defer { try? FileManager.default.removeItem(at: root) }
let validID = UUID()
let corruptID = UUID()
var history: SQLiteVoiceSessionHistory? = try SQLiteVoiceSessionHistory(
rootDirectory: root
)
try await record(
_ = try await insertFixture(
historyDocument(sessionID: validID),
in: try #require(history)
root: root
)
try await record(
_ = try await insertFixture(
historyDocument(sessionID: corruptID),
in: try #require(history)
root: root
)
history = nil
try executeSQL(
"UPDATE voice_sessions SET delivery_outcome = 'invalid', ended_at = 2000 "
+ "WHERE id = '\(corruptID.uuidString)';",
Expand All @@ -189,16 +179,14 @@ struct VoiceHistoryReconcilerTest {
let root = temporaryRoot("expiration_discard")
defer { try? FileManager.default.removeItem(at: root) }
let sessionID = UUID()
var history: SQLiteVoiceSessionHistory? = try SQLiteVoiceSessionHistory(
rootDirectory: root
let finalURL = try await insertFixture(
historyDocument(sessionID: sessionID),
root: root
)
try await record(historyDocument(sessionID: sessionID), in: try #require(history))
let finalURL = root.appending(path: "audio/\(sessionID).caf")
let quarantineFilename =
".expiring_\(sessionID.uuidString)_\(UUID().uuidString).caf"
let quarantineURL = root.appending(path: "audio/\(quarantineFilename)")
try FileManager.default.moveItem(at: finalURL, to: quarantineURL)
history = nil
try executeSQL(
"""
UPDATE voice_sessions
Expand Down Expand Up @@ -260,14 +248,10 @@ struct VoiceHistoryReconcilerTest {
defer { try? FileManager.default.removeItem(at: root) }
let retainedID = UUID()
let partialID = UUID()
var history: SQLiteVoiceSessionHistory? = try SQLiteVoiceSessionHistory(
rootDirectory: root
)
try await record(
let retainedURL = try await insertFixture(
historyDocument(sessionID: retainedID),
in: try #require(history)
root: root
)
let retainedURL = root.appending(path: "audio/\(retainedID).caf")
let quarantineFilename =
".expiring_\(retainedID.uuidString)_\(UUID().uuidString).caf"
try FileManager.default.copyItem(
Expand All @@ -284,8 +268,6 @@ struct VoiceHistoryReconcilerTest {
"partial"
)
)
history = nil

let reopened = try SQLiteVoiceSessionHistory(rootDirectory: root)
let sessions = try await reopened.recentSessions(limit: 10)

Expand Down Expand Up @@ -424,13 +406,26 @@ struct VoiceHistoryReconcilerTest {
)
}

private func record(
/// Inserts crash-test evidence without starting live maintenance tasks.
private func insertFixture(
_ document: VoiceSessionDocument,
in history: SQLiteVoiceSessionHistory
) async throws {
history.begin(sessionID: document.id, startedAt: document.startedAt)
history.append(try makeVoiceAudioFixture())
try await history.complete(document)
root: URL
) async throws -> URL {
let audioDirectory = root.appending(path: "audio")
try FileManager.default.createDirectory(
at: audioDirectory,
withIntermediateDirectories: true
)
let audioURL = try await recordFixture(
sessionID: document.id,
audioDirectory: audioDirectory
)
let store = try SQLiteVoiceSessionStore(
databaseURL: root.appending(path: "history.sqlite3"),
audioDirectory: audioDirectory
)
try await store.insert(document, audioURL: audioURL)
return audioURL
}

private func recordFixture(
Expand Down
2 changes: 2 additions & 0 deletions docs/contributor_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
Demo mode uses deterministic process data and does not request Accessibility,
Microphone, Speech Recognition, or hardware access. Tests replace process
boundaries and skip opt-in system checks unless their environment flag is set.
`scripts/check.sh` runs the required HID latency soak in its own test process so
unrelated parallel suites cannot create scheduler outliers.

## Source map

Expand Down
2 changes: 2 additions & 0 deletions scripts/build_release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ main() {
Sources/HardwareControllerAudioBoundary/audio_engine_exception_boundary.m \
Sources/HardwareControllerAudioBoundary/include/audio_engine_exception_boundary.h
swift test
HC_RUN_HID_PERFORMANCE=1 swift test \
--filter tenThousandTransitionSoakMeetsDispatchBudget
zsh -n scripts/*.sh
plutil -lint packaging/*.plist >/dev/null

Expand Down
2 changes: 2 additions & 0 deletions scripts/check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ xcrun clang-format --dry-run --Werror \
Sources/HardwareControllerAudioBoundary/include/audio_engine_exception_boundary.h
zsh -n scripts/*.sh
swift test
HC_RUN_HID_PERFORMANCE=1 swift test \
--filter tenThousandTransitionSoakMeetsDispatchBudget
swift build -c release --product HardwareController
scripts/build_release_test.sh
scripts/notarize_release_test.sh