@@ -560,6 +560,8 @@ func (ctxt *context) match(name string) bool {
560
560
561
561
func init () { checkShouldTest () }
562
562
563
+ var errTimeout = errors .New ("command exceeded time limit" )
564
+
563
565
// run runs a test.
564
566
func (t * test ) run () {
565
567
start := time .Now ()
@@ -611,6 +613,7 @@ func (t *test) run() {
611
613
}
612
614
613
615
var args , flags []string
616
+ var tim int
614
617
wantError := false
615
618
f , err := splitQuoted (action )
616
619
if err != nil {
@@ -644,14 +647,6 @@ func (t *test) run() {
644
647
case "errorcheck" , "errorcheckdir" , "errorcheckoutput" :
645
648
t .action = action
646
649
wantError = true
647
- for len (args ) > 0 && strings .HasPrefix (args [0 ], "-" ) {
648
- if args [0 ] == "-0" {
649
- wantError = false
650
- } else {
651
- flags = append (flags , args [0 ])
652
- }
653
- args = args [1 :]
654
- }
655
650
case "skip" :
656
651
t .action = "skip"
657
652
return
@@ -661,6 +656,38 @@ func (t *test) run() {
661
656
return
662
657
}
663
658
659
+ // collect flags
660
+ for len (args ) > 0 && strings .HasPrefix (args [0 ], "-" ) {
661
+ switch args [0 ] {
662
+ case "-1" :
663
+ wantError = true
664
+ case "-0" :
665
+ wantError = false
666
+ case "-s" :
667
+ // GOPHERJS: Doesn't use singlefilepkgs in test yet.
668
+ case "-t" : // timeout in seconds
669
+ args = args [1 :]
670
+ var err error
671
+ tim , err = strconv .Atoi (args [0 ])
672
+ if err != nil {
673
+ t .err = fmt .Errorf ("need number of seconds for -t timeout, got %s instead" , args [0 ])
674
+ }
675
+ if s := os .Getenv ("GO_TEST_TIMEOUT_SCALE" ); s != "" {
676
+ timeoutScale , err := strconv .Atoi (s )
677
+ if err != nil {
678
+ log .Fatalf ("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v" , s , err )
679
+ }
680
+ tim *= timeoutScale
681
+ }
682
+ case "-goexperiment" : // set GOEXPERIMENT environment
683
+ args = args [1 :]
684
+ // GOPHERJS: Ignore GOEXPERIMENT for now
685
+ default :
686
+ flags = append (flags , args [0 ])
687
+ }
688
+ args = args [1 :]
689
+ }
690
+
664
691
t .makeTempDir ()
665
692
defer os .RemoveAll (t .tempDir )
666
693
@@ -698,8 +725,40 @@ func (t *test) run() {
698
725
cmd .Dir = t .tempDir
699
726
cmd .Env = envForDir (cmd .Dir )
700
727
}
701
- err := cmd .Run ()
702
- if err != nil {
728
+
729
+ var err error
730
+ if tim != 0 {
731
+ err = cmd .Start ()
732
+ // This command-timeout code adapted from cmd/go/test.go
733
+ // Note: the Go command uses a more sophisticated timeout
734
+ // strategy, first sending SIGQUIT (if appropriate for the
735
+ // OS in question) to try to trigger a stack trace, then
736
+ // finally much later SIGKILL. If timeouts prove to be a
737
+ // common problem here, it would be worth porting over
738
+ // that code as well. See https://do.dev/issue/50973
739
+ // for more discussion.
740
+ if err == nil {
741
+ tick := time .NewTimer (time .Duration (tim ) * time .Second )
742
+ done := make (chan error )
743
+ go func () {
744
+ done <- cmd .Wait ()
745
+ }()
746
+ select {
747
+ case err = <- done :
748
+ // ok
749
+ case <- tick .C :
750
+ cmd .Process .Signal (os .Interrupt )
751
+ time .Sleep (1 * time .Second )
752
+ cmd .Process .Kill ()
753
+ <- done
754
+ err = errTimeout
755
+ }
756
+ tick .Stop ()
757
+ }
758
+ } else {
759
+ err = cmd .Run ()
760
+ }
761
+ if err != nil && err != errTimeout {
703
762
err = fmt .Errorf ("%s\n %s" , err , buf .Bytes ())
704
763
}
705
764
return buf .Bytes (), err
@@ -720,6 +779,10 @@ func (t *test) run() {
720
779
t .err = fmt .Errorf ("compilation succeeded unexpectedly\n %s" , out )
721
780
return
722
781
}
782
+ if err == errTimeout {
783
+ t .err = fmt .Errorf ("compilation timed out" )
784
+ return
785
+ }
723
786
} else {
724
787
if err != nil {
725
788
t .err = err
0 commit comments