Files
swift-inotify/Tests/InotifyIntegrationTests/InotifyLimitTests.swift
T
T. R. Bernstein 3c852a565c Deliver an event enum with the queue overflow as its own case
The stream's element is now the enum InotifyEvent, and the struct that
describes a change to a watched item is FileSystemEvent. A queue
overflow was an event with descriptor -1 and an empty path that every
consumer had to know about; as a case, the compiler makes them handle
it. The enum is also where failed watches of a growing tree will be
reported, since no call site can catch them.
2026-09-19 00:10:35 +02:00

73 lines
2.4 KiB
Swift

import Testing
import Foundation
@testable import Inotify
@Suite("Inotify Limits", .serialized)
struct InotifyLimitTests {
@Test func throwsIfInotifyUpperLimitReached() async throws {
try await withTempDir { dir in
try await withInotifyWatchLimit(of: 10) {
try createSubdirectorytree(at: dir, foldersPerLevel: 4, levels: 3)
try await Task.sleep(for: .milliseconds(100))
await #expect(throws: InotifyError.self) {
let watcher = try Inotify()
try await watcher.addRecursiveWatch(forDirectory: dir, mask: .allEvents)
}
}
}
}
@Test func watchesMassivSubtreesIfAllowed() async throws {
try await withTempDir { dir in
try await withInotifyWatchLimit(of: 1000) {
try createSubdirectorytree(at: dir, foldersPerLevel: 8, levels: 3)
let subDirectory = "\(dir)/Folder 8/Folder 8/Folder 8"
let filepath = "\(subDirectory)/new-file.txt"
try await Task.sleep(for: .milliseconds(100))
let events = try await getEventsForTrigger(
in: dir,
mask: [.create],
recursive: .recursive
) { _ in
assert(FileManager.default.fileExists(atPath: subDirectory))
try createFile(at: "\(filepath)", contents: "hello")
}
let createEvent = events.first { $0.mask.contains(.create) && $0.path.string == filepath }
#expect(createEvent != nil, "Expected CREATE for '\(filepath)', got: \(events)")
}
}
}
@Test func reportsQueueOverflowInsteadOfDroppingIt() async throws {
try await withTempDir { dir in
try await withInotifyWatchLimit(of: 1, for: [.queuedEvents]) {
let watcher = try Inotify()
try await watcher.addWatch(path: dir, mask: .allEvents)
let overflowTask = Task { () -> (InotifyEvent?, Int) in
var received = 0
for await event in await watcher.events {
received += 1
if case .queueOverflow = event { return (event, received) }
}
return (nil, received)
}
let deadline = ContinuousClock.now + .seconds(5)
var index = 0
while !overflowTask.isCancelled, ContinuousClock.now < deadline {
try createFile(at: "\(dir)/burst-\(index).txt", contents: "hello")
index += 1
if index % 200 == 0 { await Task.yield() }
}
overflowTask.cancel()
let (overflow, received) = await overflowTask.value
#expect(overflow == .queueOverflow, "Expected a queue overflow event after \(index) file creations and \(received) received events")
}
}
}
}