Skip to content

Commit 8bea502

Browse files
committed
[windows][test] Ensure the ordering of stdout and stderr messages.
It is possible that the rest of the platforms are relying in some not clearly documented behaviour that the stdout is flushed before stderr can be used, or something similar. Windows didn't seem to like that, and was sometimes outputting the stderr messages interlaced with the stdout messages (specially in the Azure testing for VS2017). The initial solution was adding -DAG to some CHECK lines, but that doesn't cover all the possibilities, and wasn't enabled for all the checks. I tried to fix it in several ways, but none of them were perfect, and many of them were deadlocking. There's a fundamental difference between others and Windows and that is that for others stdout seems to have a little bit of an edge in being treated first. I tried to get the Windows code closer to that idea, but I have no luck. Some of the approaches were using the main thread to read from the threads reading stdout and stderr; using only the main thread and IOCP on the pipes reading from the child process; and flushing after every output to stdout. None of them were perfect. The final solution is a hack, but it seems to not fail when I run the test repeatedly in my machine, while other approaches were failing at least once before I discarded them. The solution is including a small sleep (1 millisecond) in the Windows code. This should yield the execution time slice to other thread/process, which seems to do the trick and keep the stdout before the stderr. Hopefully this fixes the errors in Azure, and doesn't affect the rest of the testing machines. Being a really small sleep also should not affect the duration of the test itself.
1 parent 1ff62c3 commit 8bea502

File tree

1 file changed

+31
-11
lines changed

1 file changed

+31
-11
lines changed

validation-test/StdlibUnittest/CrashingTests.swift

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,30 @@
55

66
import StdlibUnittest
77

8+
#if os(Windows)
9+
// HACK: It seems that other platforms might be lucky and the stdout and stderr
10+
// are being sent to the parent process in the order they are used. However, in
11+
// Windows the result of a print followed by a fatalError is not always ordered
12+
// the same in the parent. To avoid a random order, we add Sleep(1) before the
13+
// fatalError calls, which yields enough time to other threads so the output is
14+
// ordered like in other platforms.
15+
import WinSDK
16+
#endif
17+
818

919
_setOverrideOSVersion(.osx(major: 10, minor: 9, bugFix: 3))
1020
_setTestSuiteFailedCallback() { print("abort()") }
1121

22+
private func fatalErrorWithDelayIfNeeded(
23+
_ message: @autoclosure () -> String = String(),
24+
file: StaticString = #file, line: UInt = #line
25+
) -> Never {
26+
#if os(Windows)
27+
Sleep(1)
28+
#endif
29+
fatalError(message, file: file, line: line)
30+
}
31+
1232
//
1333
// Test that harness aborts when a test crashes during a test run.
1434
//
@@ -17,10 +37,10 @@ var TestSuiteCrashes = TestSuite("TestSuiteCrashes")
1737

1838
TestSuiteCrashes.test("crashesUnexpectedly1") {
1939
print("crashesUnexpectedly1")
20-
fatalError("This should crash")
40+
fatalErrorWithDelayIfNeeded("This should crash")
2141
}
22-
// CHECK-DAG: stdout>>> crashesUnexpectedly1
23-
// CHECK-DAG: stderr>>> Fatal error: This should crash:
42+
// CHECK: stdout>>> crashesUnexpectedly1
43+
// CHECK: stderr>>> Fatal error: This should crash:
2444
// CHECK: stderr>>> CRASHED: SIG
2545
// CHECK: [ FAIL ] TestSuiteCrashes.crashesUnexpectedly1
2646

@@ -41,7 +61,7 @@ TestSuiteCrashes.test("fails1") {
4161

4262
TestSuiteCrashes.test("crashesUnexpectedly2") {
4363
print("crashesUnexpectedly2")
44-
fatalError("This should crash")
64+
fatalErrorWithDelayIfNeeded("This should crash")
4565
}
4666
// CHECK: stdout>>> crashesUnexpectedly2
4767
// CHECK: stderr>>> Fatal error: This should crash:
@@ -66,7 +86,7 @@ TestSuiteCrashes.test("fails2") {
6686
TestSuiteCrashes.test("crashesAsExpected1") {
6787
print("crashesAsExpected1")
6888
expectCrashLater()
69-
fatalError("This should crash")
89+
fatalErrorWithDelayIfNeeded("This should crash")
7090
}
7191
// CHECK: stdout>>> crashesAsExpected1
7292
// CHECK: stderr>>> Fatal error: This should crash:
@@ -91,7 +111,7 @@ TestSuiteCrashes.test("fails3") {
91111
TestSuiteCrashes.test("crashesUnexpectedlyXfail")
92112
.xfail(.osxBugFix(10, 9, 3, reason: "")).code {
93113
print("crashesUnexpectedlyXfail")
94-
fatalError("This should crash")
114+
fatalErrorWithDelayIfNeeded("This should crash")
95115
}
96116
// CHECK: stdout>>> crashesUnexpectedlyXfail
97117
// CHECK: stderr>>> Fatal error: This should crash:
@@ -102,7 +122,7 @@ TestSuiteCrashes.test("crashesAsExpectedXfail")
102122
.xfail(.osxBugFix(10, 9, 3, reason: "")).code {
103123
print("crashesAsExpectedXfail")
104124
expectCrashLater()
105-
fatalError("This should crash")
125+
fatalErrorWithDelayIfNeeded("This should crash")
106126
}
107127
// CHECK: stdout>>> crashesAsExpectedXfail
108128
// CHECK: stderr>>> Fatal error: This should crash:
@@ -113,7 +133,7 @@ TestSuiteCrashes.test("crashesWithMessagePasses")
113133
.crashOutputMatches("This should crash").code {
114134
print("abcd")
115135
expectCrashLater()
116-
fatalError("This should crash")
136+
fatalErrorWithDelayIfNeeded("This should crash")
117137
}
118138
// CHECK: stdout>>> abcd
119139
// CHECK: stderr>>> Fatal error: This should crash:
@@ -124,7 +144,7 @@ TestSuiteCrashes.test("crashesWithMessageFails")
124144
.crashOutputMatches("This should crash").code {
125145
print("This should crash")
126146
expectCrashLater()
127-
fatalError("unexpected message")
147+
fatalErrorWithDelayIfNeeded("unexpected message")
128148
}
129149
// CHECK: stdout>>> This should crash
130150
// CHECK: stderr>>> Fatal error: unexpected message:
@@ -139,7 +159,7 @@ TestSuiteCrashes.test("crashesWithMultipleMessagesPasses")
139159
.code {
140160
print("abcd")
141161
expectCrashLater()
142-
fatalError("This should crash and your little dog too")
162+
fatalErrorWithDelayIfNeeded("This should crash and your little dog too")
143163
}
144164
// CHECK: stdout>>> abcd
145165
// CHECK: stderr>>> Fatal error: This should crash and your little dog too:
@@ -154,7 +174,7 @@ TestSuiteCrashes.test("crashesWithMultipleMessagesFails")
154174
.code {
155175
print("This should crash")
156176
expectCrashLater()
157-
fatalError("unexpected message and your little dog too")
177+
fatalErrorWithDelayIfNeeded("unexpected message and your little dog too")
158178
}
159179
// CHECK: stdout>>> This should crash
160180
// CHECK: stderr>>> Fatal error: unexpected message and your little dog too:

0 commit comments

Comments
 (0)