forked from openshift/origin
/
status.go
168 lines (153 loc) · 3.94 KB
/
status.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package ginkgo
import (
"bytes"
"context"
"fmt"
"io"
"os"
"os/exec"
"sort"
"strings"
"sync"
"syscall"
"time"
"github.com/openshift/origin/pkg/monitor"
)
type testStatus struct {
out io.Writer
timeout time.Duration
monitor monitor.Interface
env []string
includeSuccessfulOutput bool
lock sync.Mutex
failures int
index int
total int
}
func newTestStatus(out io.Writer, includeSuccessfulOutput bool, total int, timeout time.Duration, m monitor.Interface, testEnv []string) *testStatus {
return &testStatus{
out: out,
total: total,
timeout: timeout,
monitor: m,
env: testEnv,
includeSuccessfulOutput: includeSuccessfulOutput,
}
}
func (s *testStatus) Failure() {
s.lock.Lock()
defer s.lock.Unlock()
s.failures++
}
func (s *testStatus) Fprintf(format string) {
s.lock.Lock()
defer s.lock.Unlock()
if s.index < s.total {
s.index++
}
fmt.Fprintf(s.out, format, s.failures, s.index, s.total)
}
// OutputCommand prints to stdout what would have been executed.
func (s *testStatus) OutputCommand(ctx context.Context, test *testCase) {
buf := &bytes.Buffer{}
for _, env := range s.env {
parts := strings.SplitN(env, "=", 2)
fmt.Fprintf(buf, "%s=%q ", parts[0], parts[1])
}
fmt.Fprintf(buf, "%s %s %q", os.Args[0], "run-test", test.name)
fmt.Fprintln(s.out, buf.String())
}
func (s *testStatus) Run(ctx context.Context, test *testCase) {
defer func() {
switch {
case test.success:
if s.includeSuccessfulOutput {
s.out.Write(test.out)
fmt.Fprintln(s.out)
}
fmt.Fprintf(s.out, "passed: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name)
case test.skipped:
if s.includeSuccessfulOutput {
s.out.Write(test.out)
fmt.Fprintln(s.out)
} else {
message := lastLinesUntil(string(test.out), 100, "skip [")
if len(message) > 0 {
fmt.Fprintln(s.out, message)
fmt.Fprintln(s.out)
}
}
fmt.Fprintf(s.out, "skipped: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name)
case test.failed:
s.out.Write(test.out)
fmt.Fprintln(s.out)
// only write the monitor output for a test if there is more than two tests being run (otherwise it's redundant)
if s.monitor != nil && s.total > 2 {
events := s.monitor.Events(test.start, test.end)
if len(events) > 0 {
for _, event := range events {
fmt.Fprintln(s.out, event.String())
}
fmt.Fprintln(s.out)
}
}
fmt.Fprintf(s.out, "failed: (%s) %s %q\n\n", test.duration, test.end.UTC().Format("2006-01-02T15:04:05"), test.name)
s.Failure()
}
}()
test.start = time.Now()
c := exec.Command(os.Args[0], "run-test", test.name)
c.Env = append(os.Environ(), s.env...)
s.Fprintf(fmt.Sprintf("started: (%s) %q\n\n", "%d/%d/%d", test.name))
out, err := runWithTimeout(ctx, c, s.timeout)
test.end = time.Now()
duration := test.end.Sub(test.start).Round(time.Second / 10)
if duration > time.Minute {
duration = duration.Round(time.Second)
}
test.duration = duration
test.out = out
if err == nil {
test.success = true
return
}
if exitErr, ok := err.(*exec.ExitError); ok {
switch exitErr.ProcessState.Sys().(syscall.WaitStatus).ExitStatus() {
case 1:
// failed
test.failed = true
case 2:
// timeout (ABRT is an exit code 2)
test.failed = true
case 3:
// skipped
test.skipped = true
default:
test.failed = true
}
return
}
test.failed = true
}
func summarizeTests(tests []*testCase) (int, int, int, []*testCase) {
var pass, fail, skip int
var failingTests []*testCase
for _, t := range tests {
switch {
case t.success:
pass++
case t.failed:
fail++
failingTests = append(failingTests, t)
case t.skipped:
skip++
}
}
return pass, fail, skip, failingTests
}
func sortedTests(tests []*testCase) []*testCase {
copied := make([]*testCase, len(tests))
copy(copied, tests)
sort.Slice(copied, func(i, j int) bool { return copied[i].name < copied[j].name })
return copied
}