From e6493f16743c5965610e7f7fba316693bd403f42 Mon Sep 17 00:00:00 2001 From: Jeremy Massel <1123407+jkmassel@users.noreply.github.com> Date: Tue, 8 Sep 2026 14:00:21 -0600 Subject: [PATCH] test(ios): reuse ResizingProcessor instead of a second transcoding mock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `TranscodingProcessor` duplicated `ResizingProcessor` — same `.processed(_, mimeType: "video/mp4", filename: "clip.mp4")` result, one call site — and was the weaker of the two. It wrote to a fixed `$TMPDIR/clip.mp4` instead of a per-call UUID path inside the managed upload directory, and swallowed the write with `try?`, so a failed write still returned `.processed(, …)` and the test passed green against a file that never existed. `ResizingProcessor` uses `try` and a unique path. Also drops `@unchecked Sendable` from `ThrowingUploader` and `DecliningProcessor`, which are stateless. The escape hatch is only needed by the mocks holding `NSLock`-guarded state; carrying it on stateless ones normalizes it as boilerplate, which is how a real race gets hidden later. `ContentTypeDeleteClient` keeps it — it subclasses an `@unchecked Sendable` class and must restate the conformance. --- .../Media/MediaUploadServerTests.swift | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/ios/Tests/GutenbergKitTests/Media/MediaUploadServerTests.swift b/ios/Tests/GutenbergKitTests/Media/MediaUploadServerTests.swift index 4befc9a1e..7b03a10bf 100644 --- a/ios/Tests/GutenbergKitTests/Media/MediaUploadServerTests.swift +++ b/ios/Tests/GutenbergKitTests/Media/MediaUploadServerTests.swift @@ -671,7 +671,7 @@ struct MediaUploadServerTests { // those reads: a file admitted for processing was forwarded unprocessed. The // host dropping it before the request is the same condition, deterministically. let mockUploader = MockInternalMediaClient() - var delegate: TranscodingProcessor? = TranscodingProcessor() + var delegate: ResizingProcessor? = ResizingProcessor() weak let weakDelegate = delegate let server = try await MediaUploadServer.start(processor: delegate, internalClient: mockUploader) defer { server.stop() } @@ -1106,7 +1106,7 @@ private final class RecordingUploader: MediaUploader, @unchecked Sendable { /// An uploader whose delivery fails terminally, as one would after exhausting its own /// post-process recovery and force-deleting the orphan. -private final class ThrowingUploader: MediaUploader, @unchecked Sendable { +private final class ThrowingUploader: MediaUploader { struct Failure: Error {} func upload(_ upload: MediaUpload) async throws -> Data { @@ -1114,17 +1114,27 @@ private final class ThrowingUploader: MediaUploader, @unchecked Sendable { } } -/// A delegate that transcodes, used to check the server holds it across the whole -/// request rather than re-reading a reference the host may have dropped. -private final class TranscodingProcessor: MediaProcessor, @unchecked Sendable { +/// A processor that declines every file by metadata. +private final class DecliningProcessor: MediaProcessor { func handlesFile(ofType mimeType: String, named filename: String) -> Bool { - true + false } +} + +private final class MockProcessor: MediaProcessor, @unchecked Sendable { + private let lock = NSLock() + private var _processFileCalled = false + private var _lastMimeType: String? + + var processFileCalled: Bool { lock.withLock { _processFileCalled } } + var lastMimeType: String? { lock.withLock { _lastMimeType } } func processFile(at url: URL, mimeType: String, filename: String) async throws -> ProcessedProxyFile { - let processed = FileManager.default.temporaryDirectory.appendingPathComponent("clip.mp4") - try? Data("transcoded".utf8).write(to: processed) - return .processed(processed, mimeType: "video/mp4", filename: "clip.mp4") + lock.withLock { + _processFileCalled = true + _lastMimeType = mimeType + } + return .original } }