TeraAddMediaHarness.swift (3263B)
1 import Foundation 2 @testable import TeraApp 3 4 actor AddMediaHarness: TeraAddMediaHandling { 5 /// Metadata-only fake backend tests; real file durability has separate fixtures. 6 func confirmDurableComposerMedia(_: [TeraComposerMedia]) {} 7 8 private let delayFirstUpload: Bool 9 private let delaySettlement: Bool 10 private let openPause: ResourceTestPause? 11 private let failOpen: Bool 12 private let foreground: Bool 13 private var uploadAttempts = 0 14 private var settlementStarted = false 15 private var settlements: [Bool] = [] 16 private var reconciliations = 0 17 private(set) var openCount = 0 18 private(set) var submissionReconciliations = 0 19 private let item = TeraPreparedMedia( 20 opaqueReference: "media:\(String(repeating: "0", count: 64))", 21 remoteURL: nil, 22 sha256: String(repeating: "0", count: 64), 23 mediaType: "image/png", 24 byteSize: 4, 25 width: 2, 26 height: 2, 27 alt: "Carrots", 28 preparedAtUnixSeconds: 1_800_000_000 29 ) 30 31 init(delayFirstUpload: Bool = false, delaySettlement: Bool = false, 32 openPause: ResourceTestPause? = nil, failOpen: Bool = false, foreground: Bool = false) 33 { 34 self.delayFirstUpload = delayFirstUpload 35 self.delaySettlement = delaySettlement 36 self.openPause = openPause 37 self.failOpen = failOpen 38 self.foreground = foreground 39 } 40 41 func prefersSharedForegroundUpload(ownerID _: String) -> Bool { 42 foreground 43 } 44 45 func support() -> TeraAddMediaSupport { 46 .init(library: true, camera: true) 47 } 48 49 func importImages(limit _: Int) -> [TeraPreparedMedia] { 50 [item] 51 } 52 53 func captureImage() -> TeraPreparedMedia { 54 item 55 } 56 57 func open(_ media: [TeraPreparedMedia]) async throws -> TeraOpenedMedia { 58 openCount += 1 59 await openPause?.wait() 60 if failOpen { 61 throw TeraComposerAcknowledgment.unconfirmed 62 } 63 return try TeraMediaFileFixture.open(media, bytes: Data(repeating: 0, count: 4)) 64 } 65 66 func uploadInBackground( 67 transfer job: TeraNativeTransferJob, 68 media _: TeraPreparedMedia 69 ) async throws -> TeraAddBackgroundUploadReceipt { 70 uploadAttempts += 1 71 if delayFirstUpload, uploadAttempts == 1 { 72 try await Task.sleep(nanoseconds: 50_000_000) 73 } 74 return TeraAddBackgroundUploadReceipt( 75 identifier: "radroots.add.\(job.ownerID).\(job.expectedRevision).\(job.operationID)", 76 draftID: job.ownerID, 77 expectedRevision: job.expectedRevision, 78 statusCode: 200, 79 mediaType: "application/json", 80 contentEncoding: nil, 81 body: Data("{}".utf8) 82 ) 83 } 84 85 func settleBackgroundUpload(identifier _: String, accepted: Bool) async throws { 86 settlementStarted = true 87 if delaySettlement { 88 try await Task.sleep(nanoseconds: 50_000_000) 89 } 90 settlements.append(accepted) 91 } 92 93 func recoverNativeUploads(client _: TeraRuntimeClient) -> TeraNativeRecoveryProgress { 94 reconciliations += 1 95 return .init(visited: 0, remaining: 0, needsAttention: false) 96 } 97 98 func reconcileBackgroundSubmissions(_: [TeraSubmissionStatus], client _: TeraRuntimeClient) { 99 submissionReconciliations += 1 100 } 101 102 func didBeginSettlement() -> Bool { 103 settlementStarted 104 } 105 106 func settlementValues() -> [Bool] { 107 settlements 108 } 109 110 func reconciliationCount() -> Int { 111 reconciliations 112 } 113 }