Skip to content

Commit 8e3c239

Browse files
committed
[testing] Generalize interruptable behavior to support non-erroring syscalls
1 parent 090d109 commit 8e3c239

File tree

2 files changed

+41
-15
lines changed

2 files changed

+41
-15
lines changed

Tests/SystemTests/FileOperationsTest.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,55 +29,55 @@ final class FileOperationsTest: XCTestCase {
2929
let writeBufAddr = writeBuf.baseAddress
3030

3131
let syscallTestCases: Array<MockTestCase> = [
32-
MockTestCase(name: "open", "a path", O_RDWR | O_APPEND, interruptable: true) {
32+
MockTestCase(name: "open", .interruptable, "a path", O_RDWR | O_APPEND) {
3333
retryOnInterrupt in
3434
_ = try FileDescriptor.open(
3535
"a path", .readWrite, options: [.append], retryOnInterrupt: retryOnInterrupt)
3636
},
3737

38-
MockTestCase(name: "open", "a path", O_WRONLY | O_CREAT | O_APPEND, 0o777, interruptable: true) {
38+
MockTestCase(name: "open", .interruptable, "a path", O_WRONLY | O_CREAT | O_APPEND, 0o777) {
3939
retryOnInterrupt in
4040
_ = try FileDescriptor.open(
4141
"a path", .writeOnly, options: [.create, .append],
4242
permissions: [.groupReadWriteExecute, .ownerReadWriteExecute, .otherReadWriteExecute],
4343
retryOnInterrupt: retryOnInterrupt)
4444
},
4545

46-
MockTestCase(name: "read", rawFD, bufAddr, bufCount, interruptable: true) {
46+
MockTestCase(name: "read", .interruptable, rawFD, bufAddr, bufCount) {
4747
retryOnInterrupt in
4848
_ = try fd.read(into: rawBuf, retryOnInterrupt: retryOnInterrupt)
4949
},
5050

51-
MockTestCase(name: "pread", rawFD, bufAddr, bufCount, 5, interruptable: true) {
51+
MockTestCase(name: "pread", .interruptable, rawFD, bufAddr, bufCount, 5) {
5252
retryOnInterrupt in
5353
_ = try fd.read(fromAbsoluteOffset: 5, into: rawBuf, retryOnInterrupt: retryOnInterrupt)
5454
},
5555

56-
MockTestCase(name: "lseek", rawFD, -2, SEEK_END, interruptable: false) {
56+
MockTestCase(name: "lseek", .noInterrupt, rawFD, -2, SEEK_END) {
5757
_ in
5858
_ = try fd.seek(offset: -2, from: .end)
5959
},
6060

61-
MockTestCase(name: "write", rawFD, writeBufAddr, bufCount, interruptable: true) {
61+
MockTestCase(name: "write", .interruptable, rawFD, writeBufAddr, bufCount) {
6262
retryOnInterrupt in
6363
_ = try fd.write(writeBuf, retryOnInterrupt: retryOnInterrupt)
6464
},
6565

66-
MockTestCase(name: "pwrite", rawFD, writeBufAddr, bufCount, 7, interruptable: true) {
66+
MockTestCase(name: "pwrite", .interruptable, rawFD, writeBufAddr, bufCount, 7) {
6767
retryOnInterrupt in
6868
_ = try fd.write(toAbsoluteOffset: 7, writeBuf, retryOnInterrupt: retryOnInterrupt)
6969
},
7070

71-
MockTestCase(name: "close", rawFD, interruptable: false) {
71+
MockTestCase(name: "close", .noInterrupt, rawFD) {
7272
_ in
7373
_ = try fd.close()
7474
},
7575

76-
MockTestCase(name: "dup", rawFD, interruptable: true) { retryOnInterrupt in
76+
MockTestCase(name: "dup", .interruptable, rawFD) { retryOnInterrupt in
7777
_ = try fd.duplicate(retryOnInterrupt: retryOnInterrupt)
7878
},
7979

80-
MockTestCase(name: "dup2", rawFD, 42, interruptable: true) { retryOnInterrupt in
80+
MockTestCase(name: "dup2", .interruptable, rawFD, 42) { retryOnInterrupt in
8181
_ = try fd.duplicate(as: FileDescriptor(rawValue: 42),
8282
retryOnInterrupt: retryOnInterrupt)
8383
},
@@ -128,7 +128,7 @@ final class FileOperationsTest: XCTestCase {
128128
func testGithubIssues() {
129129
// https://github.com/apple/swift-system/issues/26
130130
let issue26 = MockTestCase(
131-
name: "open", "a path", O_WRONLY | O_CREAT, 0o020, interruptable: true
131+
name: "open", .interruptable, "a path", O_WRONLY | O_CREAT, 0o020
132132
) {
133133
retryOnInterrupt in
134134
_ = try FileDescriptor.open(

Tests/SystemTests/TestingInfrastructure.swift

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,22 +107,35 @@ internal struct MockTestCase: TestCase {
107107
var line: UInt
108108

109109
var expected: Trace.Entry
110-
var interruptable: Bool
110+
var interruptBehavior: InterruptBehavior
111+
112+
var interruptable: Bool { return interruptBehavior == .interruptable }
113+
114+
internal enum InterruptBehavior {
115+
// Retry the syscall on EINTR
116+
case interruptable
117+
118+
// Cannot return EINTR
119+
case noInterrupt
120+
121+
// Cannot error at all
122+
case noError
123+
}
111124

112125
var body: (_ retryOnInterrupt: Bool) throws -> ()
113126

114127
init(
115128
_ file: StaticString = #file,
116129
_ line: UInt = #line,
117130
name: String,
131+
_ interruptable: InterruptBehavior,
118132
_ args: AnyHashable...,
119-
interruptable: Bool,
120-
_ body: @escaping (_ retryOnInterrupt: Bool) throws -> ()
133+
body: @escaping (_ retryOnInterrupt: Bool) throws -> ()
121134
) {
122135
self.file = file
123136
self.line = line
124137
self.expected = Trace.Entry(name: name, args)
125-
self.interruptable = interruptable
138+
self.interruptBehavior = interruptable
126139
self.body = body
127140
}
128141

@@ -141,6 +154,19 @@ internal struct MockTestCase: TestCase {
141154
self.fail()
142155
}
143156

157+
// Non-error-ing syscalls shouldn't ever throw
158+
guard interruptBehavior != .noError else {
159+
do {
160+
try body(interruptable)
161+
self.expectEqual(self.expected, mocking.trace.dequeue())
162+
try body(!interruptable)
163+
self.expectEqual(self.expected, mocking.trace.dequeue())
164+
} catch {
165+
self.fail()
166+
}
167+
return
168+
}
169+
144170
// Test interupt behavior. Interruptable calls will be told not to
145171
// retry to catch the EINTR. Non-interruptable calls will be told to
146172
// retry, to make sure they don't spin (e.g. if API changes to include

0 commit comments

Comments
 (0)