File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -2,6 +2,7 @@ package bundle
22
33import (
44 "bufio"
5+ "context"
56 "encoding/json"
67 "fmt"
78 "io"
@@ -238,10 +239,21 @@ func memTotalKB() int64 {
238239 return 0
239240}
240241
242+ // factTimeout bounds every fact-gathering command. A probe that hangs — lsblk on
243+ // a wedged device, a binary whose `version` never returns — must not cost an
244+ // unattended campaign its start, so a fact that takes too long is treated the
245+ // same as one that cannot be gathered. A var so tests can shrink it.
246+ var factTimeout = 5 * time .Second
247+
241248// commandOutput runs a fact-gathering command and returns its trimmed stdout,
242- // or "" if it cannot be run. Every caller here is best-effort by contract.
249+ // or "" if it cannot be run or does not finish inside factTimeout. Every caller
250+ // here is best-effort by contract.
243251func commandOutput (name string , args ... string ) string {
244- out , err := exec .Command (name , args ... ).Output ()
252+ ctx , cancel := context .WithTimeout (context .Background (), factTimeout )
253+ defer cancel ()
254+ cmd := exec .CommandContext (ctx , name , args ... )
255+ cmd .WaitDelay = time .Second
256+ out , err := cmd .Output ()
245257 if err != nil {
246258 return ""
247259 }
Original file line number Diff line number Diff line change @@ -255,6 +255,19 @@ func TestCollectHardwareOffEC2(t *testing.T) {
255255 }
256256}
257257
258+ func TestCommandOutputTimesOut (t * testing.T ) {
259+ old := factTimeout
260+ factTimeout = 100 * time .Millisecond
261+ t .Cleanup (func () { factTimeout = old })
262+ start := time .Now ()
263+ if got := commandOutput ("sleep" , "30" ); got != "" {
264+ t .Errorf ("commandOutput = %q, want \" \" on timeout" , got )
265+ }
266+ if elapsed := time .Since (start ); elapsed > 5 * time .Second {
267+ t .Errorf ("commandOutput took %s, want well under the 30s sleep" , elapsed )
268+ }
269+ }
270+
258271func TestWriteMetadataUnwritableDir (t * testing.T ) {
259272 err := WriteMetadata (filepath .Join (t .TempDir (), "nope" ), goldenInput (t ))
260273 if err == nil {
Original file line number Diff line number Diff line change 11package bundle
22
33import (
4+ "context"
45 "fmt"
56 "os"
67 "os/exec"
@@ -158,9 +159,14 @@ func fsyncProbe(benchRoot string) string {
158159
159160// binaryVersion is the benchmarked binary's own version output, first 3 lines,
160161// stdout and stderr together — the binary reports its build stamp there. A
161- // binary that cannot run says so in place of its version.
162+ // binary that cannot run, or does not answer inside factTimeout, says so in
163+ // place of its version.
162164func binaryVersion (binPath string ) []string {
163- out , err := exec .Command (binPath , "version" ).CombinedOutput ()
165+ ctx , cancel := context .WithTimeout (context .Background (), factTimeout )
166+ defer cancel ()
167+ cmd := exec .CommandContext (ctx , binPath , "version" )
168+ cmd .WaitDelay = time .Second
169+ out , err := cmd .CombinedOutput ()
164170 lines := splitLines (head (strings .TrimRight (string (out ), "\n " ), 3 ))
165171 if err != nil && len (lines ) == 0 {
166172 return []string {fmt .Sprintf ("version: %v" , err )}
You can’t perform that action at this time.
0 commit comments