From 9781cb8238fae1a3de43e9de46bf2e6fc228b0a9 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Fri, 4 Jul 2025 12:11:54 -0700 Subject: [PATCH] Fix flakiness in asyncReadFileDescriptor test It's not safe to "modify" a file descriptor while it's in use by DispatchIO, per the documentation, which is the likely cause of flakiness here. --- Sources/SWBUtil/FSProxy.swift | 6 +---- Tests/SWBUtilTests/FileHandleTests.swift | 28 +++++++++++++----------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/Sources/SWBUtil/FSProxy.swift b/Sources/SWBUtil/FSProxy.swift index 92a9bf56..f3d53e2c 100644 --- a/Sources/SWBUtil/FSProxy.swift +++ b/Sources/SWBUtil/FSProxy.swift @@ -529,13 +529,9 @@ class LocalFS: FSProxy, @unchecked Sendable { func write(_ path: Path, contents: (FileDescriptor) async throws -> Void) async throws { let fd = try FileDescriptor.open(FilePath(path.str), .writeOnly, options: [.create, .truncate], permissions: [.ownerReadWrite, .groupRead, .otherRead]) - do { + return try await fd.closeAfter { try await contents(fd) - } catch { - _ = try? fd.close() - throw error } - try fd.close() } func append(_ path: Path, contents: ByteString) throws { diff --git a/Tests/SWBUtilTests/FileHandleTests.swift b/Tests/SWBUtilTests/FileHandleTests.swift index 07fe017a..06423953 100644 --- a/Tests/SWBUtilTests/FileHandleTests.swift +++ b/Tests/SWBUtilTests/FileHandleTests.swift @@ -69,28 +69,30 @@ import SystemPackage // Read while triggering an I/O error do { let fd = try Path.root.str.withPlatformString { try FileDescriptor.open($0, .readOnly) } - let fh = FileHandle(fileDescriptor: fd.rawValue, closeOnDealloc: false) + try await fd.closeAfter { + let fh = FileHandle(fileDescriptor: fd.rawValue, closeOnDealloc: false) - if #available(macOS 15, iOS 18, tvOS 18, watchOS 11, visionOS 2, *) { - var it = fh.bytes().makeAsyncIterator() - try fd.close() + if #available(macOS 15, iOS 18, tvOS 18, watchOS 11, visionOS 2, *) { + var it = fh.bytes().makeAsyncIterator() - await #expect(throws: (any Error).self) { - while let _ = try await it.next() { + // Can't read a directory + await #expect(throws: (any Error).self) { + while let _ = try await it.next() { + } } - } - } else { - var it = fh._bytes().makeAsyncIterator() - try fd.close() + } else { + var it = fh._bytes().makeAsyncIterator() - await #expect(throws: (any Error).self) { - while let _ = try await it.next() { + // Can't read a directory + await #expect(throws: (any Error).self) { + while let _ = try await it.next() { + } } } } } - // Read part of a file, then close the handle + // Read part of a file, then cancel the task do { let condition = CancellableWaitCondition()