blob: 1b1fd769c93039c325e94adfb5a9bc1e8a9e314e [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 },
296}
297
298type oneTest struct {
299 commands [][]string
300 expect string
301}
302
303func main() {
304 err := run()
305 if err != nil {
306 log.Fatal(err)
307 }
308}
309
310func run() error {
311 flag.Parse()
312
313 lines := make(chan string, 30)
314 go readLog(lines)
315
316 // Write output to a log file
317 logFile, err := os.Create(*logOut)
318 if err != nil {
319 return err
320 }
321 defer logFile.Close()
322 lg := bufio.NewWriter(logFile)
323 defer lg.Flush()
324
325 for _, group := range tests {
326 fmt.Printf("Running %q\n", group.name)
327 fmt.Fprintf(lg, "-------------------------------------\n")
328 fmt.Fprintf(lg, "---- Running %q\n", group.name)
329
330 for _, test := range group.tests {
331 for _, cmd := range test.commands {
332 fmt.Printf(" %s\n", cmd)
333 fmt.Fprintf(lg, "---- Run: %s\n", cmd)
334 err = runCommand(cmd, lg)
335 if err != nil {
336 return err
337 }
338 }
339
340 err = expect(lg, lines, test.expect)
341 if err != nil {
342 return err
343 }
344
345 fmt.Fprintf(lg, "---- Passed\n")
346 }
347 fmt.Printf(" Passed!\n")
348 }
349
350 return nil
351}
352
353// Run a single command.
354func runCommand(cmd []string, lg io.Writer) error {
355 c := exec.Command(cmd[0], cmd[1:]...)
356 c.Stdout = lg
357 c.Stderr = lg
358 return c.Run()
359}
360
361// Expect the given string.
362func expect(lg io.Writer, lines <-chan string, exp string) error {
363 // Read lines, and if we hit a timeout before seeing our
364 // expected line, then consider that an error.
365 fmt.Fprintf(lg, "---- expect: %q\n", exp)
366
367 stopper := time.NewTimer(10 * time.Second)
368 defer stopper.Stop()
369outer:
370 for {
371 select {
372 case line := <-lines:
373 fmt.Fprintf(lg, "---- target: %q\n", line)
374 if strings.Contains(line, exp) {
375 break outer
376 }
377 case <-stopper.C:
378 fmt.Fprintf(lg, "timeout, didn't receive output\n")
379 return fmt.Errorf("timeout, didn't receive expected string: %q", exp)
380 }
381 }
382
383 return nil
384}
385
386// Read things from the log file, discarding everything already there.
387func readLog(sink chan<- string) {
388 file, err := os.Open(*logIn)
389 if err != nil {
390 log.Fatal(err)
391 }
392
393 _, err = file.Seek(0, 2)
394 if err != nil {
395 log.Fatal(err)
396 }
397
398 prefix := ""
399 for {
400 // Read lines until EOF, then delay a bit, and do it
401 // all again.
402 rd := bufio.NewReader(file)
403
404 for {
405 line, err := rd.ReadString('\n')
406 if err == io.EOF {
407 // A partial line can happen because
408 // we are racing with the writer.
409 if line != "" {
410 prefix = line
411 }
412 break
413 }
414 if err != nil {
415 log.Fatal(err)
416 }
417
418 line = prefix + line
419 prefix = ""
420 sink <- line
421 // fmt.Printf("line: %q\n", line)
422 }
423
424 // Pause a little
425 time.Sleep(250 * time.Millisecond)
426 }
427}