blob: 88160b4a3cbedc958929062b4340462b3675ffd9 [file] [log] [blame]
David Brown8e0016e2018-01-29 12:15:37 -07001// +build ignore
2//
3// Build multiple configurations of MCUboot for Zephyr, making sure
4// that they run properly.
5//
6// Run as:
7//
8// go run run-tests.go [flags]
9//
10// Add -help as a flag to get help. See comment below for logIn on
11// how to configure terminal output to a file so this program can see
12// the output of the Zephyr device.
13
14package main
15
16import (
17 "bufio"
18 "flag"
19 "fmt"
20 "io"
21 "log"
22 "os"
23 "os/exec"
24 "strings"
25 "time"
26)
27
28// logIn gives the pathname of the log output from the Zephyr device.
29// In order to see the serial output, but still be useful for human
30// debugging, the output of the terminal emulator should be teed to a
31// file that this program will read from. This can be done with
32// something like:
33//
34// picocom -b 115200 /dev/ttyACM0 | tee /tmp/zephyr.out
35//
36// Other terminal programs should also have logging options.
37var logIn = flag.String("login", "/tmp/zephyr.out", "File name of terminal log from Zephyr device")
38
39// Output from this test run is written to the given log file.
40var logOut = flag.String("logout", "tests.log", "Log file to write to")
41
42// The main driver of this consists of a series of tests. Each test
43// then contains a series of commands and expect results.
44var tests = []struct {
45 name string
46 tests []oneTest
47}{
48 {
49 name: "Good RSA",
50 tests: []oneTest{
51 {
52 commands: [][]string{
53 {"make", "test-good-rsa"},
David Brown8e0016e2018-01-29 12:15:37 -070054 {"make", "flash_boot"},
55 },
56 expect: "Unable to find bootable image",
57 },
58 {
59 commands: [][]string{
60 {"make", "flash_hello1"},
61 },
62 expect: "Hello World from hello1",
63 },
64 {
65 commands: [][]string{
66 {"make", "flash_hello2"},
67 },
68 expect: "Hello World from hello2",
69 },
70 {
71 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -060072 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -070073 },
74 expect: "Hello World from hello1",
75 },
76 },
77 },
78 {
79 name: "Good ECDSA",
80 tests: []oneTest{
81 {
82 commands: [][]string{
83 {"make", "test-good-ecdsa"},
David Brown8e0016e2018-01-29 12:15:37 -070084 {"make", "flash_boot"},
85 },
86 expect: "Unable to find bootable image",
87 },
88 {
89 commands: [][]string{
90 {"make", "flash_hello1"},
91 },
92 expect: "Hello World from hello1",
93 },
94 {
95 commands: [][]string{
96 {"make", "flash_hello2"},
97 },
98 expect: "Hello World from hello2",
99 },
100 {
101 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600102 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700103 },
104 expect: "Hello World from hello1",
105 },
106 },
107 },
108 {
109 name: "Overwrite",
110 tests: []oneTest{
111 {
112 commands: [][]string{
113 {"make", "test-overwrite"},
David Brown8e0016e2018-01-29 12:15:37 -0700114 {"make", "flash_boot"},
115 },
116 expect: "Unable to find bootable image",
117 },
118 {
119 commands: [][]string{
120 {"make", "flash_hello1"},
121 },
122 expect: "Hello World from hello1",
123 },
124 {
125 commands: [][]string{
126 {"make", "flash_hello2"},
127 },
128 expect: "Hello World from hello2",
129 },
130 {
131 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600132 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700133 },
134 expect: "Hello World from hello2",
135 },
136 },
137 },
138 {
139 name: "Bad RSA",
140 tests: []oneTest{
141 {
142 commands: [][]string{
143 {"make", "test-bad-rsa-upgrade"},
David Brown8e0016e2018-01-29 12:15:37 -0700144 {"make", "flash_boot"},
145 },
146 expect: "Unable to find bootable image",
147 },
148 {
149 commands: [][]string{
150 {"make", "flash_hello1"},
151 },
152 expect: "Hello World from hello1",
153 },
154 {
155 commands: [][]string{
156 {"make", "flash_hello2"},
157 },
158 expect: "Hello World from hello1",
159 },
160 {
161 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600162 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700163 },
164 expect: "Hello World from hello1",
165 },
166 },
167 },
168 {
169 name: "Bad RSA",
170 tests: []oneTest{
171 {
172 commands: [][]string{
173 {"make", "test-bad-ecdsa-upgrade"},
David Brown8e0016e2018-01-29 12:15:37 -0700174 {"make", "flash_boot"},
175 },
176 expect: "Unable to find bootable image",
177 },
178 {
179 commands: [][]string{
180 {"make", "flash_hello1"},
181 },
182 expect: "Hello World from hello1",
183 },
184 {
185 commands: [][]string{
186 {"make", "flash_hello2"},
187 },
188 expect: "Hello World from hello1",
189 },
190 {
191 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600192 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700193 },
194 expect: "Hello World from hello1",
195 },
196 },
197 },
198 {
199 name: "No bootcheck",
200 tests: []oneTest{
201 {
202 commands: [][]string{
203 {"make", "test-no-bootcheck"},
David Brown8e0016e2018-01-29 12:15:37 -0700204 {"make", "flash_boot"},
205 },
206 expect: "Unable to find bootable image",
207 },
208 {
209 commands: [][]string{
210 {"make", "flash_hello1"},
211 },
212 expect: "Hello World from hello1",
213 },
214 {
215 commands: [][]string{
216 {"make", "flash_hello2"},
217 },
218 expect: "Hello World from hello1",
219 },
220 {
221 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600222 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700223 },
224 expect: "Hello World from hello1",
225 },
226 },
227 },
228 {
229 name: "Wrong RSA",
230 tests: []oneTest{
231 {
232 commands: [][]string{
233 {"make", "test-wrong-rsa"},
David Brown8e0016e2018-01-29 12:15:37 -0700234 {"make", "flash_boot"},
235 },
236 expect: "Unable to find bootable image",
237 },
238 {
239 commands: [][]string{
240 {"make", "flash_hello1"},
241 },
242 expect: "Hello World from hello1",
243 },
244 {
245 commands: [][]string{
246 {"make", "flash_hello2"},
247 },
248 expect: "Hello World from hello1",
249 },
250 {
251 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600252 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700253 },
254 expect: "Hello World from hello1",
255 },
256 },
257 },
258 {
259 name: "Wrong ECDSA",
260 tests: []oneTest{
261 {
262 commands: [][]string{
263 {"make", "test-wrong-ecdsa"},
David Brown8e0016e2018-01-29 12:15:37 -0700264 {"make", "flash_boot"},
265 },
266 expect: "Unable to find bootable image",
267 },
268 {
269 commands: [][]string{
270 {"make", "flash_hello1"},
271 },
272 expect: "Hello World from hello1",
273 },
274 {
275 commands: [][]string{
276 {"make", "flash_hello2"},
277 },
278 expect: "Hello World from hello1",
279 },
280 {
281 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600282 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700283 },
284 expect: "Hello World from hello1",
285 },
286 },
287 },
288}
289
290type oneTest struct {
291 commands [][]string
292 expect string
293}
294
295func main() {
296 err := run()
297 if err != nil {
298 log.Fatal(err)
299 }
300}
301
302func run() error {
303 flag.Parse()
304
305 lines := make(chan string, 30)
306 go readLog(lines)
307
308 // Write output to a log file
309 logFile, err := os.Create(*logOut)
310 if err != nil {
311 return err
312 }
313 defer logFile.Close()
314 lg := bufio.NewWriter(logFile)
315 defer lg.Flush()
316
317 for _, group := range tests {
318 fmt.Printf("Running %q\n", group.name)
319 fmt.Fprintf(lg, "-------------------------------------\n")
320 fmt.Fprintf(lg, "---- Running %q\n", group.name)
321
322 for _, test := range group.tests {
323 for _, cmd := range test.commands {
324 fmt.Printf(" %s\n", cmd)
325 fmt.Fprintf(lg, "---- Run: %s\n", cmd)
326 err = runCommand(cmd, lg)
327 if err != nil {
328 return err
329 }
330 }
331
332 err = expect(lg, lines, test.expect)
333 if err != nil {
334 return err
335 }
336
337 fmt.Fprintf(lg, "---- Passed\n")
338 }
339 fmt.Printf(" Passed!\n")
340 }
341
342 return nil
343}
344
345// Run a single command.
346func runCommand(cmd []string, lg io.Writer) error {
347 c := exec.Command(cmd[0], cmd[1:]...)
348 c.Stdout = lg
349 c.Stderr = lg
350 return c.Run()
351}
352
353// Expect the given string.
354func expect(lg io.Writer, lines <-chan string, exp string) error {
355 // Read lines, and if we hit a timeout before seeing our
356 // expected line, then consider that an error.
357 fmt.Fprintf(lg, "---- expect: %q\n", exp)
358
359 stopper := time.NewTimer(10 * time.Second)
360 defer stopper.Stop()
361outer:
362 for {
363 select {
364 case line := <-lines:
365 fmt.Fprintf(lg, "---- target: %q\n", line)
366 if strings.Contains(line, exp) {
367 break outer
368 }
369 case <-stopper.C:
370 fmt.Fprintf(lg, "timeout, didn't receive output\n")
371 return fmt.Errorf("timeout, didn't receive expected string: %q", exp)
372 }
373 }
374
375 return nil
376}
377
378// Read things from the log file, discarding everything already there.
379func readLog(sink chan<- string) {
380 file, err := os.Open(*logIn)
381 if err != nil {
382 log.Fatal(err)
383 }
384
385 _, err = file.Seek(0, 2)
386 if err != nil {
387 log.Fatal(err)
388 }
389
390 prefix := ""
391 for {
392 // Read lines until EOF, then delay a bit, and do it
393 // all again.
394 rd := bufio.NewReader(file)
395
396 for {
397 line, err := rd.ReadString('\n')
398 if err == io.EOF {
399 // A partial line can happen because
400 // we are racing with the writer.
401 if line != "" {
402 prefix = line
403 }
404 break
405 }
406 if err != nil {
407 log.Fatal(err)
408 }
409
410 line = prefix + line
411 prefix = ""
412 sink <- line
413 // fmt.Printf("line: %q\n", line)
414 }
415
416 // Pause a little
417 time.Sleep(250 * time.Millisecond)
418 }
419}