forked from jen20/teamcity-go-test
-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.go
137 lines (114 loc) · 2.8 KB
/
main.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
package main
import (
"bufio"
"bytes"
"flag"
"fmt"
"io"
"os"
"os/exec"
"strings"
"time"
)
const (
// PackageSummary is the format string for the result summary of packages.
// [ok|FAIL] github.com/metacpp/parallel-go-test 100.00s
PackageSummary = "%s %s %.3fs\n"
)
func usage() string {
return `Usage:
parallel-go-test -f <binary> [-p n] [-t timeout]
Test names must be listed one per line on stdin.
Timeout is measured in seconds.
`
}
func main() {
binaryPath := flag.String("f", "", "file path of test package")
parallelism := flag.Int("p", 1, "number of tests to execute in parallel")
timeout := flag.String("t", "3600s", "Panit test binary after specific duration(seconds).")
flag.Parse()
if binaryPath == nil || *binaryPath == "" {
fmt.Fprint(os.Stderr, usage())
os.Exit(1)
}
if _, err := os.Stat(*binaryPath); err != nil {
fmt.Fprintf(os.Stderr, "Not valid file path: %s\n", *binaryPath)
os.Exit(1)
}
testNames := make([]string, 0, 0)
stdInReader := bufio.NewReader(os.Stdin)
for {
line, err := stdInReader.ReadString('\n')
if err != nil {
if err == io.EOF {
if strings.TrimSpace(line) != "" {
testNames = append(testNames, line)
}
break
}
fmt.Fprintf(os.Stderr, "error reading stdin: %s", err)
os.Exit(1)
}
if strings.TrimSpace(line) != "" {
testNames = append(testNames, line)
}
}
testQueue := make(chan string)
messages := make(chan string)
completed := make(chan struct{})
startTime := time.Now()
for i := 0; i < *parallelism; i++ {
go runWorker(testQueue, messages, completed, *binaryPath, *timeout)
}
go func() {
for _, testName := range testNames {
testQueue <- strings.TrimSpace(testName)
}
}()
failsCount := 0
resultsCount := 0
for {
select {
case message := <-messages:
if strings.Contains(message, "--- FAIL") {
failsCount++
}
fmt.Printf("%s", message)
case <-completed:
resultsCount++
}
if resultsCount == len(testNames) {
break
}
}
endTime := time.Now()
elapsed := endTime.Sub(startTime)
status := "ok"
if failsCount > 0 {
status = "FAIL"
}
fmt.Printf(PackageSummary, status, *binaryPath, elapsed.Seconds())
}
func runWorker(inputQueue <-chan string, messages chan<- string,
done chan<- struct{}, binaryName string, timeout string) {
for {
select {
case testName := <-inputQueue:
messages <- runTest(testName, binaryName, timeout)
done <- struct{}{}
}
}
}
func runTest(testName string, binaryPath string, timeout string) string {
var stdResult bytes.Buffer
cmd := exec.Command(binaryPath,
"-test.v",
"-test.timeout", timeout,
"-test.run", fmt.Sprintf("^%s$", testName))
cmd.Stdout = &stdResult
cmd.Stderr = &stdResult
if err := cmd.Run(); err != nil {
stdResult.WriteString(fmt.Sprintf("%s\n", err.Error()))
}
return stdResult.String()
}