Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compileopts/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"regexp"
"strconv"
"strings"
"time"

"github.com/google/shlex"
"github.com/tinygo-org/tinygo/goenv"
Expand Down Expand Up @@ -659,4 +660,5 @@ type TestConfig struct {
BenchTime string
BenchMem bool
Shuffle string
Timeout time.Duration
}
6 changes: 5 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,9 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
if testConfig.Shuffle != "" {
flags = append(flags, "-test.shuffle="+testConfig.Shuffle)
}
if t := testConfig.Timeout; t != 0 {
flags = append(flags, "-test.timeout="+t.String())
}

logToStdout := testConfig.Verbose || testConfig.BenchRegexp != ""

Expand Down Expand Up @@ -1628,7 +1631,7 @@ func main() {
ocdCommandsString := flag.String("ocd-commands", "", "OpenOCD commands, overriding target spec (can specify multiple separated by commas)")
ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug")
port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)")
timeout := flag.Duration("timeout", 20*time.Second, "the length of time to retry locating the MSD volume to be used for flashing")
timeout := flag.Duration("volume-timeout", 20*time.Second, "the length of time to retry locating the MSD volume to be used for flashing")
programmer := flag.String("programmer", "", "which hardware programmer to use")
ldflags := flag.String("ldflags", "", "Go link tool compatible ldflags")
llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable")
Expand Down Expand Up @@ -1675,6 +1678,7 @@ func main() {
flag.StringVar(&testConfig.BenchTime, "benchtime", "", "run each benchmark for duration `d`")
flag.BoolVar(&testConfig.BenchMem, "benchmem", false, "show memory stats for benchmarks")
flag.StringVar(&testConfig.Shuffle, "shuffle", "", "shuffle the order the tests and benchmarks run")
flag.DurationVar(&testConfig.Timeout, "timeout", 10*time.Minute, "panic test binary after duration `d`")
}

// Early command processing, before commands are interpreted by the Go flag
Expand Down
36 changes: 30 additions & 6 deletions src/testing/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var (
flagSkipRegexp string
flagShuffle string
flagCount int
flagTimeout time.Duration
)

var initRan bool
Expand All @@ -52,6 +53,7 @@ func Init() {
flag.StringVar(&flagShuffle, "test.shuffle", "off", "shuffle: off, on, <numeric-seed>")

flag.IntVar(&flagCount, "test.count", 1, "run each test or benchmark `count` times")
flag.DurationVar(&flagTimeout, "test.timeout", 0, "panic test binary after duration d (default 0, timeout disabled)")

initBenchmarkFlags()
}
Expand Down Expand Up @@ -513,8 +515,6 @@ func (t *T) Run(name string, f func(t *T)) bool {
//
// The ok result is false if the -timeout flag indicates “no timeout” (0).
// For now tinygo always return 0, false.
//
// Not Implemented.
func (t *T) Deadline() (deadline time.Time, ok bool) {
deadline = t.context.deadline
return deadline, !deadline.IsZero()
Expand All @@ -527,7 +527,7 @@ type testContext struct {
deadline time.Time
}

func newTestContext(m *matcher) *testContext {
func newTestContext(deadline time.Time, m *matcher) *testContext {
return &testContext{
match: m,
}
Expand All @@ -544,6 +544,8 @@ type M struct {
// value to pass to os.Exit, the outer test func main
// harness calls os.Exit with this code. See #34129.
exitCode int

timer *time.Timer
}

type testDeps interface {
Expand Down Expand Up @@ -588,7 +590,8 @@ func (m *M) Run() (code int) {
}
}

testRan, testOk := runTests(m.deps.MatchString, m.Tests)
deadline := m.startAlarm()
testRan, testOk := runTests(deadline, m.deps.MatchString, m.Tests)
if !testRan && *matchBenchmarks == "" {
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
}
Expand All @@ -599,13 +602,34 @@ func (m *M) Run() (code int) {
fmt.Println("PASS")
m.exitCode = 0
}
m.stopAlarm()
return
}

func runTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ran, ok bool) {
// startAlarm starts an alarm if requested.
func (m *M) startAlarm() time.Time {
if flagTimeout <= 0 {
return time.Time{}
}

deadline := time.Now().Add(flagTimeout)
m.timer = time.AfterFunc(flagTimeout, func() {
panic(fmt.Sprintf("test timed out after %v", flagTimeout))
})
return deadline
}

// stopAlarm turns off the alarm.
func (m *M) stopAlarm() {
if flagTimeout > 0 {
m.timer.Stop()
}
}

func runTests(deadline time.Time, matchString func(pat, str string) (bool, error), tests []InternalTest) (ran, ok bool) {
ok = true

ctx := newTestContext(newMatcher(matchString, flagRunRegexp, "-test.run", flagSkipRegexp))
ctx := newTestContext(deadline, newMatcher(matchString, flagRunRegexp, "-test.run", flagSkipRegexp))
t := &T{
common: common{
output: &logger{logToStdout: flagVerbose},
Expand Down
Loading