1 package main
2
3 import (
4 "bytes"
5 "fmt"
6 "golang.conradwood.net/go-easyops/cmdline"
7 "golang.conradwood.net/go-easyops/errors"
8 "golang.conradwood.net/go-easyops/utils"
9 "html/template"
10 "io"
11 "os"
12 "sort"
13 "strings"
14 "sync"
15 )
16
17 var (
18 old_stdout *os.File
19 testctr = 0
20 tests []*test
21 newidlock sync.Mutex
22 )
23
24 type test struct {
25 err error
26 id int
27 prefix string
28 dc_start bool
29 dc_error bool
30 builder_start int
31 builder_error int
32 stdout_writer io.Writer
33 stdout_buf *bytes.Buffer
34 }
35
36 func NewTest(format string, args ...interface{}) *test {
37 t := &test{
38 id: newid(),
39 prefix: fmt.Sprintf(format, args...),
40 dc_start: cmdline.Datacenter(),
41 builder_start: cmdline.GetContextBuilderVersion(),
42 stdout_buf: &bytes.Buffer{},
43 }
44 t.builder_error = t.builder_start
45 t.dc_error = t.dc_start
46 if old_stdout == nil {
47 old_stdout = os.Stdout
48 }
49 r, w, err := os.Pipe()
50 utils.Bail("failed to open pipe for stdout", err)
51 wrprefix := fmt.Sprintf("TEST %s ", t.Prefix())
52 t.stdout_writer = NewTee(t.stdout_buf, old_stdout, wrprefix)
53 os.Stdout = w
54 go t.pipe_reader(r)
55 fmt.Printf("%s -------- STARTING\n", t.Prefix())
56 tests = append(tests, t)
57 return t
58 }
59 func newid() int {
60 newidlock.Lock()
61 testctr++
62 newid := testctr
63 newidlock.Unlock()
64 return newid
65 }
66 func (t *test) Prefix() string {
67 v := fmt.Sprintf("%v", t.builder_start)
68 d := fmt.Sprintf("%v", t.dc_start)
69 return fmt.Sprintf("[#%02d dc=%5s %s (builder=%5s)]", t.id, d, t.prefix, v)
70 }
71
72 func (t *test) Printf(format string, args ...interface{}) {
73 fmt.Printf(t.Prefix()+" "+format, args...)
74 }
75 func (t *test) Error(err error) {
76 if err == nil {
77 return
78 }
79 if t.err != nil {
80 return
81 }
82 t.dc_error = cmdline.Datacenter()
83 t.builder_error = cmdline.GetContextBuilderVersion()
84
85 t.err = err
86 fmt.Printf("%s Failed (%s)\n", t.Prefix(), err)
87 }
88 func (t *test) Getstdout() string {
89 return t.stdout_buf.String()
90 }
91 func (t *test) Done() {
92 if t.err != nil {
93 fmt.Printf("%s -------- FAILURE\n", t.Prefix())
94 return
95 }
96 fmt.Printf("%s -------- SUCCESS\n", t.Prefix())
97 }
98
99 func PrintResult() {
100 os.Stdout = old_stdout
101 failed := 0
102 succeeded := 0
103 sort.Slice(tests, func(i, j int) bool {
104 if tests[i].prefix != tests[j].prefix {
105 return tests[i].prefix < tests[j].prefix
106 }
107 if tests[i].builder_start != tests[j].builder_start {
108 return tests[i].builder_start < tests[j].builder_start
109 }
110 if tests[i].builder_error != tests[j].builder_error {
111 return tests[i].builder_error < tests[j].builder_error
112 }
113 return tests[i].id < tests[j].id
114 })
115 var failed_tests []*test
116 for _, t := range tests {
117 if t.err != nil {
118 failed++
119 failed_tests = append(failed_tests, t)
120 } else {
121 succeeded++
122 }
123 }
124 if failed > 0 {
125 fmt.Printf("List of failed tests:\n")
126 for _, t := range failed_tests {
127 fmt.Println(t.Getstdout())
128 }
129 ta := utils.Table{}
130
131 ta.AddHeaders("name", "dc (start)", "dc (error)", "builder (start)", "builder (error)", "error", "long")
132 for _, t := range failed_tests {
133 s := utils.ErrorString(t.err) + "\n" + t.Getstdout()
134 ge := errors.UnmarshalError(t.err)
135 se := ge.MultilineError()
136 ta.AddString(t.prefix)
137 ta.AddBool(t.dc_start)
138 ta.AddBool(t.dc_error)
139 ta.AddInt(t.builder_start)
140 ta.AddInt(t.builder_error)
141 ta.AddString(se)
142 ta.AddString(s)
143 ta.NewRow()
144 }
145 fmt.Println(ta.ToPrettyString())
146 }
147 fmt.Printf("Overall Result: %d tests suceeded, %d tests failed\n", succeeded, failed)
148
149 if failed > 0 {
150 fmt.Printf("TESTS FAILED\n")
151 }
152
153 b, err := render_tests_to_html(tests)
154 if err != nil {
155 fmt.Printf("failed to render to html: %s", err)
156 } else {
157 fname := "/tmp/tests.html"
158 err = utils.WriteFile(fname, b)
159 utils.Bail("failed to write file", err)
160 fmt.Printf("HTML written to %s\n", fname)
161 }
162 }
163
164 func (t *test) pipe_reader(r *os.File) {
165 io.Copy(t.stdout_writer, r)
166
167 }
168 func (t *test) BuilderStart() int {
169 return t.builder_start
170 }
171 func (t *test) BuilderError() int {
172 return t.builder_error
173 }
174 func (t *test) GetError() error {
175 return t.err
176 }
177 func (t *test) ID() int {
178 return t.id
179 }
180 func (t *test) Name() string {
181 return t.prefix
182 }
183 func (t *test) HtmlErrorDetails() template.HTML {
184 lines := strings.Split(t.Getstdout(), "\n")
185 res := ""
186 for _, l := range lines {
187 res = res + l + "<br/>"
188 }
189 return template.HTML(res)
190 }
191 func (t *test) DCStart() bool {
192 return t.dc_start
193 }
194 func (t *test) DCError() bool {
195 return t.dc_error
196 }
197
View as plain text