@@ -568,6 +568,8 @@ func (ctxt *context) match(name string) bool {
568
568
569
569
func init () { checkShouldTest () }
570
570
571
+ var errTimeout = errors .New ("command exceeded time limit" )
572
+
571
573
// run runs a test.
572
574
func (t * test ) run () {
573
575
start := time .Now ()
@@ -619,6 +621,7 @@ func (t *test) run() {
619
621
}
620
622
621
623
var args , flags []string
624
+ var tim int
622
625
wantError := false
623
626
f , err := splitQuoted (action )
624
627
if err != nil {
@@ -652,14 +655,6 @@ func (t *test) run() {
652
655
case "errorcheck" , "errorcheckdir" , "errorcheckoutput" :
653
656
t .action = action
654
657
wantError = true
655
- for len (args ) > 0 && strings .HasPrefix (args [0 ], "-" ) {
656
- if args [0 ] == "-0" {
657
- wantError = false
658
- } else {
659
- flags = append (flags , args [0 ])
660
- }
661
- args = args [1 :]
662
- }
663
658
case "skip" :
664
659
t .action = "skip"
665
660
return
@@ -669,6 +664,38 @@ func (t *test) run() {
669
664
return
670
665
}
671
666
667
+ // collect flags
668
+ for len (args ) > 0 && strings .HasPrefix (args [0 ], "-" ) {
669
+ switch args [0 ] {
670
+ case "-1" :
671
+ wantError = true
672
+ case "-0" :
673
+ wantError = false
674
+ case "-s" :
675
+ // GOPHERJS: Doesn't use singlefilepkgs in test yet.
676
+ case "-t" : // timeout in seconds
677
+ args = args [1 :]
678
+ var err error
679
+ tim , err = strconv .Atoi (args [0 ])
680
+ if err != nil {
681
+ t .err = fmt .Errorf ("need number of seconds for -t timeout, got %s instead" , args [0 ])
682
+ }
683
+ if s := os .Getenv ("GO_TEST_TIMEOUT_SCALE" ); s != "" {
684
+ timeoutScale , err := strconv .Atoi (s )
685
+ if err != nil {
686
+ log .Fatalf ("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v" , s , err )
687
+ }
688
+ tim *= timeoutScale
689
+ }
690
+ case "-goexperiment" : // set GOEXPERIMENT environment
691
+ args = args [1 :]
692
+ // GOPHERJS: Ignore GOEXPERIMENT for now
693
+ default :
694
+ flags = append (flags , args [0 ])
695
+ }
696
+ args = args [1 :]
697
+ }
698
+
672
699
t .makeTempDir ()
673
700
defer os .RemoveAll (t .tempDir )
674
701
@@ -706,8 +733,40 @@ func (t *test) run() {
706
733
cmd .Dir = t .tempDir
707
734
cmd .Env = envForDir (cmd .Dir )
708
735
}
709
- err := cmd .Run ()
710
- if err != nil {
736
+
737
+ var err error
738
+ if tim != 0 {
739
+ err = cmd .Start ()
740
+ // This command-timeout code adapted from cmd/go/test.go
741
+ // Note: the Go command uses a more sophisticated timeout
742
+ // strategy, first sending SIGQUIT (if appropriate for the
743
+ // OS in question) to try to trigger a stack trace, then
744
+ // finally much later SIGKILL. If timeouts prove to be a
745
+ // common problem here, it would be worth porting over
746
+ // that code as well. See https://do.dev/issue/50973
747
+ // for more discussion.
748
+ if err == nil {
749
+ tick := time .NewTimer (time .Duration (tim ) * time .Second )
750
+ done := make (chan error )
751
+ go func () {
752
+ done <- cmd .Wait ()
753
+ }()
754
+ select {
755
+ case err = <- done :
756
+ // ok
757
+ case <- tick .C :
758
+ cmd .Process .Signal (os .Interrupt )
759
+ time .Sleep (1 * time .Second )
760
+ cmd .Process .Kill ()
761
+ <- done
762
+ err = errTimeout
763
+ }
764
+ tick .Stop ()
765
+ }
766
+ } else {
767
+ err = cmd .Run ()
768
+ }
769
+ if err != nil && err != errTimeout {
711
770
err = fmt .Errorf ("%s\n %s" , err , buf .Bytes ())
712
771
}
713
772
return buf .Bytes (), err
@@ -728,6 +787,10 @@ func (t *test) run() {
728
787
t .err = fmt .Errorf ("compilation succeeded unexpectedly\n %s" , out )
729
788
return
730
789
}
790
+ if err == errTimeout {
791
+ t .err = fmt .Errorf ("compilation timed out" )
792
+ return
793
+ }
731
794
} else {
732
795
if err != nil {
733
796
t .err = err
0 commit comments