mirror of
https://github.com/tailscale/tailscale.git
synced 2025-03-24 10:10:59 +00:00
cmd/testwrapper: emit logs of failed tests on timeout
It would just fail the entire pkg, but would not print any logs. It was already tracking all the logs, so have it emit them when the pkg fails/times out. Updates #9231 Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
parent
52a19b5970
commit
0f397baf77
@ -29,7 +29,8 @@ import (
|
|||||||
const maxAttempts = 3
|
const maxAttempts = 3
|
||||||
|
|
||||||
type testAttempt struct {
|
type testAttempt struct {
|
||||||
name testName
|
pkg string // "tailscale.com/types/key"
|
||||||
|
testName string // "TestFoo"
|
||||||
outcome string // "pass", "fail", "skip"
|
outcome string // "pass", "fail", "skip"
|
||||||
logs bytes.Buffer
|
logs bytes.Buffer
|
||||||
isMarkedFlaky bool // set if the test is marked as flaky
|
isMarkedFlaky bool // set if the test is marked as flaky
|
||||||
@ -37,11 +38,6 @@ type testAttempt struct {
|
|||||||
pkgFinished bool
|
pkgFinished bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type testName struct {
|
|
||||||
pkg string // "tailscale.com/types/key"
|
|
||||||
name string // "TestFoo"
|
|
||||||
}
|
|
||||||
|
|
||||||
type packageTests struct {
|
type packageTests struct {
|
||||||
// pattern is the package pattern to run.
|
// pattern is the package pattern to run.
|
||||||
// Must be a single pattern, not a list of patterns.
|
// Must be a single pattern, not a list of patterns.
|
||||||
@ -98,7 +94,7 @@ func runTests(ctx context.Context, attempt int, pt *packageTests, otherArgs []st
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
jd := json.NewDecoder(r)
|
jd := json.NewDecoder(r)
|
||||||
resultMap := make(map[testName]*testAttempt)
|
resultMap := make(map[string]map[string]*testAttempt) // pkg -> test -> testAttempt
|
||||||
for {
|
for {
|
||||||
var goOutput goTestOutput
|
var goOutput goTestOutput
|
||||||
if err := jd.Decode(&goOutput); err != nil {
|
if err := jd.Decode(&goOutput); err != nil {
|
||||||
@ -116,27 +112,34 @@ func runTests(ctx context.Context, attempt int, pt *packageTests, otherArgs []st
|
|||||||
}
|
}
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
pkg := goOutput.Package
|
||||||
|
pkgTests := resultMap[pkg]
|
||||||
if goOutput.Test == "" {
|
if goOutput.Test == "" {
|
||||||
switch goOutput.Action {
|
switch goOutput.Action {
|
||||||
case "fail", "pass", "skip":
|
case "fail", "pass", "skip":
|
||||||
|
for _, test := range pkgTests {
|
||||||
|
if test.outcome == "" {
|
||||||
|
test.outcome = "fail"
|
||||||
|
ch <- test
|
||||||
|
}
|
||||||
|
}
|
||||||
ch <- &testAttempt{
|
ch <- &testAttempt{
|
||||||
name: testName{
|
pkg: goOutput.Package,
|
||||||
pkg: goOutput.Package,
|
|
||||||
},
|
|
||||||
outcome: goOutput.Action,
|
outcome: goOutput.Action,
|
||||||
pkgFinished: true,
|
pkgFinished: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
name := testName{
|
if pkgTests == nil {
|
||||||
pkg: goOutput.Package,
|
pkgTests = make(map[string]*testAttempt)
|
||||||
name: goOutput.Test,
|
resultMap[pkg] = pkgTests
|
||||||
}
|
}
|
||||||
|
testName := goOutput.Test
|
||||||
if test, _, isSubtest := strings.Cut(goOutput.Test, "/"); isSubtest {
|
if test, _, isSubtest := strings.Cut(goOutput.Test, "/"); isSubtest {
|
||||||
name.name = test
|
testName = test
|
||||||
if goOutput.Action == "output" {
|
if goOutput.Action == "output" {
|
||||||
resultMap[name].logs.WriteString(goOutput.Output)
|
resultMap[pkg][testName].logs.WriteString(goOutput.Output)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -144,17 +147,18 @@ func runTests(ctx context.Context, attempt int, pt *packageTests, otherArgs []st
|
|||||||
case "start":
|
case "start":
|
||||||
// ignore
|
// ignore
|
||||||
case "run":
|
case "run":
|
||||||
resultMap[name] = &testAttempt{
|
pkgTests[testName] = &testAttempt{
|
||||||
name: name,
|
pkg: pkg,
|
||||||
|
testName: testName,
|
||||||
}
|
}
|
||||||
case "skip", "pass", "fail":
|
case "skip", "pass", "fail":
|
||||||
resultMap[name].outcome = goOutput.Action
|
pkgTests[testName].outcome = goOutput.Action
|
||||||
ch <- resultMap[name]
|
ch <- pkgTests[testName]
|
||||||
case "output":
|
case "output":
|
||||||
if strings.TrimSpace(goOutput.Output) == flakytest.FlakyTestLogMessage {
|
if strings.TrimSpace(goOutput.Output) == flakytest.FlakyTestLogMessage {
|
||||||
resultMap[name].isMarkedFlaky = true
|
pkgTests[testName].isMarkedFlaky = true
|
||||||
} else {
|
} else {
|
||||||
resultMap[name].logs.WriteString(goOutput.Output)
|
pkgTests[testName].logs.WriteString(goOutput.Output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,13 +251,13 @@ func main() {
|
|||||||
go runTests(ctx, thisRun.attempt, pt, otherArgs, ch)
|
go runTests(ctx, thisRun.attempt, pt, otherArgs, ch)
|
||||||
for tr := range ch {
|
for tr := range ch {
|
||||||
if tr.pkgFinished {
|
if tr.pkgFinished {
|
||||||
if tr.outcome == "fail" && len(toRetry[tr.name.pkg]) == 0 {
|
if tr.outcome == "fail" && len(toRetry[tr.pkg]) == 0 {
|
||||||
// If a package fails and we don't have any tests to
|
// If a package fails and we don't have any tests to
|
||||||
// retry, then we should fail. This typically happens
|
// retry, then we should fail. This typically happens
|
||||||
// when a package times out.
|
// when a package times out.
|
||||||
failed = true
|
failed = true
|
||||||
}
|
}
|
||||||
printPkgOutcome(tr.name.pkg, tr.outcome, thisRun.attempt)
|
printPkgOutcome(tr.pkg, tr.outcome, thisRun.attempt)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if *v || tr.outcome == "fail" {
|
if *v || tr.outcome == "fail" {
|
||||||
@ -263,7 +267,7 @@ func main() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if tr.isMarkedFlaky {
|
if tr.isMarkedFlaky {
|
||||||
toRetry[tr.name.pkg] = append(toRetry[tr.name.pkg], tr.name.name)
|
toRetry[tr.pkg] = append(toRetry[tr.pkg], tr.testName)
|
||||||
} else {
|
} else {
|
||||||
failed = true
|
failed = true
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user