1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
From: =?utf-8?b?T3R0byBLZWvDpGzDpGluZW4=?= <otto@debian.org>
Date: Mon, 25 Aug 2025 18:55:34 +0000
Subject: Fix TestSpawnWithArgs race condition on fast systems (mainly s390x)
The `TestSpawnWithArgs` test was failing on the Ubuntu Launchpad `s390x`
builders with the error "Expect(a b) failed: expect: Process not
running". This indicates a race condition where the `echo` command
executed and terminated too quickly for the `Expect` function to read
its output before the process was gone.
To address this, wait with `read`, that command pauses the shell script
indefinitely until input is received, which is a more robust and
portable way to keep the process alive for the duration of the test.
After the necessary `Expect` calls, an explicit `e.Send("\n")` is added
to unblock the `read` command and allow the spawned process to exit
cleanly.
Additionally, the `t.Fatalf` message has been updated to include the
`args` slice for better debugging context if `SpawnWithArgs` fails.
---
expect_test.go | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/expect_test.go b/expect_test.go
index f306c7d..352378f 100644
--- a/expect_test.go
+++ b/expect_test.go
@@ -1093,14 +1093,14 @@ func TestSpawn(t *testing.T) {
// TestSpawnWithArgs tests that arguments with embedded spaces works.
func TestSpawnWithArgs(t *testing.T) {
- args := []string{"echo", "a b"}
+ args := []string{"sh", "-c", "echo 'a b'; read"}
e, _, err := SpawnWithArgs(args, 400*time.Millisecond)
if err != nil {
// The test environment may not have PTY support, so we log and skip.
if strings.Contains(err.Error(), "inappropriate ioctl for device") {
t.Skipf("Skipping test, PTY not available: %v", err)
}
- t.Fatalf("Spawn(echo 'a b') failed: %v", err)
+ t.Fatalf("SpawnWithArgs(%q) failed: %v", args, err)
}
defer e.Close()
@@ -1110,11 +1110,14 @@ func TestSpawnWithArgs(t *testing.T) {
t.Errorf("Expect(a b) failed: %v", err)
}
- // Expected to not match
+ // Expected to not match. This will timeout, which is expected.
_, _, err = e.Expect(regexp.MustCompile("a b"), 400*time.Millisecond)
if err == nil {
t.Error("Expect(a b) to not match")
}
+
+ // Unblock read to let process exit.
+ e.Send("\n")
}
// TestExpect tests the Expect function.
|