Add offline resilience coverage

This commit is contained in:
diyaa
2026-06-19 04:08:36 +02:00
parent 6f35912a38
commit ef6f11c7b1
5 changed files with 1007 additions and 2 deletions
@@ -290,6 +290,86 @@ final class RemoteLibrarySyncServiceTests: XCTestCase {
XCTAssertEqual(storedCursor, SyncCursor(value: "7"))
}
func testPersistedCursorSurvivesRelaunchFailureAndLaterRecovery() async throws {
let fileManager = FileManager.default
let tempDirectory = fileManager.temporaryDirectory.appendingPathComponent(
UUID().uuidString,
isDirectory: true
)
let remoteLibraryFileURL = tempDirectory.appendingPathComponent("remote-library.json")
let syncCursorFileURL = tempDirectory.appendingPathComponent("remote-library-sync-cursor.json")
let bootstrapTrack = makeRemoteTrack(trackId: "track-cursor-persist")
let updatedTrack = makeRemoteTrack(
trackId: bootstrapTrack.trackId,
title: "Track Cursor Updated"
)
defer {
try? fileManager.removeItem(at: tempDirectory)
}
let firstService = makeSyncService(
apiClient: MockVelodyAPIClient(
bootstrapResponse: SyncBootstrapResponse(
nextCursor: SyncCursor(value: "1"),
tracks: [bootstrapTrack],
serverTime: "2026-06-15T12:00:00.000Z"
)
),
store: try FileRemoteLibraryStore(fileURL: remoteLibraryFileURL),
cursorStore: try FileRemoteLibrarySyncCursorStore(fileURL: syncCursorFileURL)
)
_ = try await firstService.syncRemoteLibrary(deviceId: "device-123")
let offlineService = makeSyncService(
apiClient: MockVelodyAPIClient(
changeError: VelodyAPIError.requestFailed("Offline")
),
store: try FileRemoteLibraryStore(fileURL: remoteLibraryFileURL),
cursorStore: try FileRemoteLibrarySyncCursorStore(fileURL: syncCursorFileURL)
)
await XCTAssertThrowsErrorAsync {
_ = try await offlineService.syncRemoteLibrary(deviceId: "device-123")
}
let recoveryClient = MockVelodyAPIClient(
changeResponses: [
SyncChangesResponse(
nextCursor: SyncCursor(value: "2"),
hasMore: false,
requiresBootstrap: false,
events: [
SyncEvent(
cursor: SyncCursor(value: "2"),
entityType: "TRACK",
entityId: updatedTrack.trackId,
action: "UPDATED",
track: updatedTrack,
createdAt: "2026-06-15T12:05:00.000Z"
),
],
serverTime: "2026-06-15T12:05:00.000Z"
),
]
)
let recoveredService = makeSyncService(
apiClient: recoveryClient,
store: try FileRemoteLibraryStore(fileURL: remoteLibraryFileURL),
cursorStore: try FileRemoteLibrarySyncCursorStore(fileURL: syncCursorFileURL)
)
let recoveredTracks = try await recoveredService.syncRemoteLibrary(deviceId: "device-123")
let recoveredCursor = try await FileRemoteLibrarySyncCursorStore(fileURL: syncCursorFileURL)
.loadCursor()
XCTAssertEqual(recoveredTracks, [updatedTrack])
XCTAssertEqual(recoveredCursor, SyncCursor(value: "2"))
let recordedChangeCursors = await recoveryClient.recordedChangeCursors()
XCTAssertEqual(recordedChangeCursors, ["1"])
}
func testSyncFailurePreservesDownloadedStateAndLocalFile() async throws {
let track = makeRemoteTrack(trackId: "track-offline", assetId: "asset-offline")
let localFilePath = "/in-memory/\(track.assetId).mp3"