blob: dab894f81bc3dd9a4ed82cbc9c2e4a85ffcd94ff [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"},
Maureen Helm0e0c4882019-02-18 17:20:00 -060054 {"pyocd", "erase", "--chip"},
David Brown8e0016e2018-01-29 12:15:37 -070055 {"make", "flash_boot"},
56 },
57 expect: "Unable to find bootable image",
58 },
59 {
60 commands: [][]string{
61 {"make", "flash_hello1"},
62 },
63 expect: "Hello World from hello1",
64 },
65 {
66 commands: [][]string{
67 {"make", "flash_hello2"},
68 },
69 expect: "Hello World from hello2",
70 },
71 {
72 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -060073 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -070074 },
75 expect: "Hello World from hello1",
76 },
77 },
78 },
79 {
80 name: "Good ECDSA",
81 tests: []oneTest{
82 {
83 commands: [][]string{
84 {"make", "test-good-ecdsa"},
Maureen Helm0e0c4882019-02-18 17:20:00 -060085 {"pyocd", "erase", "--chip"},
David Brown8e0016e2018-01-29 12:15:37 -070086 {"make", "flash_boot"},
87 },
88 expect: "Unable to find bootable image",
89 },
90 {
91 commands: [][]string{
92 {"make", "flash_hello1"},
93 },
94 expect: "Hello World from hello1",
95 },
96 {
97 commands: [][]string{
98 {"make", "flash_hello2"},
99 },
100 expect: "Hello World from hello2",
101 },
102 {
103 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600104 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700105 },
106 expect: "Hello World from hello1",
107 },
108 },
109 },
110 {
111 name: "Overwrite",
112 tests: []oneTest{
113 {
114 commands: [][]string{
115 {"make", "test-overwrite"},
Maureen Helm0e0c4882019-02-18 17:20:00 -0600116 {"pyocd", "erase", "--chip"},
David Brown8e0016e2018-01-29 12:15:37 -0700117 {"make", "flash_boot"},
118 },
119 expect: "Unable to find bootable image",
120 },
121 {
122 commands: [][]string{
123 {"make", "flash_hello1"},
124 },
125 expect: "Hello World from hello1",
126 },
127 {
128 commands: [][]string{
129 {"make", "flash_hello2"},
130 },
131 expect: "Hello World from hello2",
132 },
133 {
134 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600135 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700136 },
137 expect: "Hello World from hello2",
138 },
139 },
140 },
141 {
142 name: "Bad RSA",
143 tests: []oneTest{
144 {
145 commands: [][]string{
146 {"make", "test-bad-rsa-upgrade"},
Maureen Helm0e0c4882019-02-18 17:20:00 -0600147 {"pyocd", "erase", "--chip"},
David Brown8e0016e2018-01-29 12:15:37 -0700148 {"make", "flash_boot"},
149 },
150 expect: "Unable to find bootable image",
151 },
152 {
153 commands: [][]string{
154 {"make", "flash_hello1"},
155 },
156 expect: "Hello World from hello1",
157 },
158 {
159 commands: [][]string{
160 {"make", "flash_hello2"},
161 },
162 expect: "Hello World from hello1",
163 },
164 {
165 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600166 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700167 },
168 expect: "Hello World from hello1",
169 },
170 },
171 },
172 {
173 name: "Bad RSA",
174 tests: []oneTest{
175 {
176 commands: [][]string{
177 {"make", "test-bad-ecdsa-upgrade"},
Maureen Helm0e0c4882019-02-18 17:20:00 -0600178 {"pyocd", "erase", "--chip"},
David Brown8e0016e2018-01-29 12:15:37 -0700179 {"make", "flash_boot"},
180 },
181 expect: "Unable to find bootable image",
182 },
183 {
184 commands: [][]string{
185 {"make", "flash_hello1"},
186 },
187 expect: "Hello World from hello1",
188 },
189 {
190 commands: [][]string{
191 {"make", "flash_hello2"},
192 },
193 expect: "Hello World from hello1",
194 },
195 {
196 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600197 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700198 },
199 expect: "Hello World from hello1",
200 },
201 },
202 },
203 {
204 name: "No bootcheck",
205 tests: []oneTest{
206 {
207 commands: [][]string{
208 {"make", "test-no-bootcheck"},
Maureen Helm0e0c4882019-02-18 17:20:00 -0600209 {"pyocd", "erase", "--chip"},
David Brown8e0016e2018-01-29 12:15:37 -0700210 {"make", "flash_boot"},
211 },
212 expect: "Unable to find bootable image",
213 },
214 {
215 commands: [][]string{
216 {"make", "flash_hello1"},
217 },
218 expect: "Hello World from hello1",
219 },
220 {
221 commands: [][]string{
222 {"make", "flash_hello2"},
223 },
224 expect: "Hello World from hello1",
225 },
226 {
227 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600228 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700229 },
230 expect: "Hello World from hello1",
231 },
232 },
233 },
234 {
235 name: "Wrong RSA",
236 tests: []oneTest{
237 {
238 commands: [][]string{
239 {"make", "test-wrong-rsa"},
Maureen Helm0e0c4882019-02-18 17:20:00 -0600240 {"pyocd", "erase", "--chip"},
David Brown8e0016e2018-01-29 12:15:37 -0700241 {"make", "flash_boot"},
242 },
243 expect: "Unable to find bootable image",
244 },
245 {
246 commands: [][]string{
247 {"make", "flash_hello1"},
248 },
249 expect: "Hello World from hello1",
250 },
251 {
252 commands: [][]string{
253 {"make", "flash_hello2"},
254 },
255 expect: "Hello World from hello1",
256 },
257 {
258 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600259 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700260 },
261 expect: "Hello World from hello1",
262 },
263 },
264 },
265 {
266 name: "Wrong ECDSA",
267 tests: []oneTest{
268 {
269 commands: [][]string{
270 {"make", "test-wrong-ecdsa"},
Maureen Helm0e0c4882019-02-18 17:20:00 -0600271 {"pyocd", "erase", "--chip"},
David Brown8e0016e2018-01-29 12:15:37 -0700272 {"make", "flash_boot"},
273 },
274 expect: "Unable to find bootable image",
275 },
276 {
277 commands: [][]string{
278 {"make", "flash_hello1"},
279 },
280 expect: "Hello World from hello1",
281 },
282 {
283 commands: [][]string{
284 {"make", "flash_hello2"},
285 },
286 expect: "Hello World from hello1",
287 },
288 {
289 commands: [][]string{
Maureen Helm0e0c4882019-02-18 17:20:00 -0600290 {"pyocd", "commander", "-c", "reset"},
David Brown8e0016e2018-01-29 12:15:37 -0700291 },
292 expect: "Hello World from hello1",
293 },
294 },
295 },
David Brownde8e72d2019-01-29 15:18:26 -0700296 {
297 name: "Good SUIT RSA",
298 tests: []oneTest{
299 {
300 commands: [][]string{
301 {"make", "test-good-suit-rsa"},
302 {"pyocd-flashtool", "-ce"},
303 {"make", "flash_boot"},
304 },
305 expect: "Unable to find bootable image",
306 },
307 {
308 commands: [][]string{
309 {"make", "flash_hello1"},
310 },
311 expect: "Hello World from hello1",
312 },
313 {
314 commands: [][]string{
315 {"make", "flash_hello2"},
316 },
317 expect: "Hello World from hello2",
318 },
319 {
320 commands: [][]string{
321 {"pyocd-tool", "reset"},
322 },
323 expect: "Hello World from hello1",
324 },
325 },
326 },
327 {
328 name: "Wrong SUIT RSA",
329 tests: []oneTest{
330 {
331 commands: [][]string{
332 {"make", "test-wrong-suit-rsa"},
333 {"pyocd-flashtool", "-ce"},
334 {"make", "flash_boot"},
335 },
336 expect: "Unable to find bootable image",
337 },
338 {
339 commands: [][]string{
340 {"make", "flash_hello1"},
341 },
342 expect: "Hello World from hello1",
343 },
344 {
345 commands: [][]string{
346 {"make", "flash_hello2"},
347 },
348 expect: "Hello World from hello1",
349 },
350 {
351 commands: [][]string{
352 {"pyocd-tool", "reset"},
353 },
354 expect: "Hello World from hello1",
355 },
356 },
357 },
David Brown8e0016e2018-01-29 12:15:37 -0700358}
359
360type oneTest struct {
361 commands [][]string
362 expect string
363}
364
365func main() {
366 err := run()
367 if err != nil {
368 log.Fatal(err)
369 }
370}
371
372func run() error {
373 flag.Parse()
374
375 lines := make(chan string, 30)
376 go readLog(lines)
377
378 // Write output to a log file
379 logFile, err := os.Create(*logOut)
380 if err != nil {
381 return err
382 }
383 defer logFile.Close()
384 lg := bufio.NewWriter(logFile)
385 defer lg.Flush()
386
387 for _, group := range tests {
388 fmt.Printf("Running %q\n", group.name)
389 fmt.Fprintf(lg, "-------------------------------------\n")
390 fmt.Fprintf(lg, "---- Running %q\n", group.name)
391
392 for _, test := range group.tests {
393 for _, cmd := range test.commands {
394 fmt.Printf(" %s\n", cmd)
395 fmt.Fprintf(lg, "---- Run: %s\n", cmd)
396 err = runCommand(cmd, lg)
397 if err != nil {
398 return err
399 }
400 }
401
402 err = expect(lg, lines, test.expect)
403 if err != nil {
404 return err
405 }
406
407 fmt.Fprintf(lg, "---- Passed\n")
408 }
409 fmt.Printf(" Passed!\n")
410 }
411
412 return nil
413}
414
415// Run a single command.
416func runCommand(cmd []string, lg io.Writer) error {
417 c := exec.Command(cmd[0], cmd[1:]...)
418 c.Stdout = lg
419 c.Stderr = lg
420 return c.Run()
421}
422
423// Expect the given string.
424func expect(lg io.Writer, lines <-chan string, exp string) error {
425 // Read lines, and if we hit a timeout before seeing our
426 // expected line, then consider that an error.
427 fmt.Fprintf(lg, "---- expect: %q\n", exp)
428
429 stopper := time.NewTimer(10 * time.Second)
430 defer stopper.Stop()
431outer:
432 for {
433 select {
434 case line := <-lines:
435 fmt.Fprintf(lg, "---- target: %q\n", line)
436 if strings.Contains(line, exp) {
437 break outer
438 }
439 case <-stopper.C:
440 fmt.Fprintf(lg, "timeout, didn't receive output\n")
441 return fmt.Errorf("timeout, didn't receive expected string: %q", exp)
442 }
443 }
444
445 return nil
446}
447
448// Read things from the log file, discarding everything already there.
449func readLog(sink chan<- string) {
450 file, err := os.Open(*logIn)
451 if err != nil {
452 log.Fatal(err)
453 }
454
455 _, err = file.Seek(0, 2)
456 if err != nil {
457 log.Fatal(err)
458 }
459
460 prefix := ""
461 for {
462 // Read lines until EOF, then delay a bit, and do it
463 // all again.
464 rd := bufio.NewReader(file)
465
466 for {
467 line, err := rd.ReadString('\n')
468 if err == io.EOF {
469 // A partial line can happen because
470 // we are racing with the writer.
471 if line != "" {
472 prefix = line
473 }
474 break
475 }
476 if err != nil {
477 log.Fatal(err)
478 }
479
480 line = prefix + line
481 prefix = ""
482 sink <- line
483 // fmt.Printf("line: %q\n", line)
484 }
485
486 // Pause a little
487 time.Sleep(250 * time.Millisecond)
488 }
489}