blob: 9b57664d0f4719c707007508c9cb854a78b0d644 [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"
David Brown5e8dbb92020-09-09 13:17:38 -060026
27 "github.com/JuulLabs-OSS/mcuboot/samples/zephyr/mcutests"
David Brown8e0016e2018-01-29 12:15:37 -070028)
29
30// logIn gives the pathname of the log output from the Zephyr device.
31// In order to see the serial output, but still be useful for human
32// debugging, the output of the terminal emulator should be teed to a
33// file that this program will read from. This can be done with
34// something like:
35//
36// picocom -b 115200 /dev/ttyACM0 | tee /tmp/zephyr.out
37//
38// Other terminal programs should also have logging options.
39var logIn = flag.String("login", "/tmp/zephyr.out", "File name of terminal log from Zephyr device")
40
41// Output from this test run is written to the given log file.
42var logOut = flag.String("logout", "tests.log", "Log file to write to")
43
David Brown8e0016e2018-01-29 12:15:37 -070044func main() {
45 err := run()
46 if err != nil {
47 log.Fatal(err)
48 }
49}
50
51func run() error {
52 flag.Parse()
53
54 lines := make(chan string, 30)
55 go readLog(lines)
56
57 // Write output to a log file
58 logFile, err := os.Create(*logOut)
59 if err != nil {
60 return err
61 }
62 defer logFile.Close()
63 lg := bufio.NewWriter(logFile)
64 defer lg.Flush()
65
David Brown5e8dbb92020-09-09 13:17:38 -060066 for _, group := range mcutests.Tests {
67 fmt.Printf("Running %q\n", group.Name)
David Brown8e0016e2018-01-29 12:15:37 -070068 fmt.Fprintf(lg, "-------------------------------------\n")
David Brown5e8dbb92020-09-09 13:17:38 -060069 fmt.Fprintf(lg, "---- Running %q\n", group.Name)
David Brown8e0016e2018-01-29 12:15:37 -070070
David Brown5e8dbb92020-09-09 13:17:38 -060071 for _, test := range group.Tests {
72 for _, cmd := range test.Commands {
David Brown8e0016e2018-01-29 12:15:37 -070073 fmt.Printf(" %s\n", cmd)
74 fmt.Fprintf(lg, "---- Run: %s\n", cmd)
75 err = runCommand(cmd, lg)
76 if err != nil {
77 return err
78 }
79 }
80
David Brown5e8dbb92020-09-09 13:17:38 -060081 err = expect(lg, lines, test.Expect)
David Brown8e0016e2018-01-29 12:15:37 -070082 if err != nil {
83 return err
84 }
85
86 fmt.Fprintf(lg, "---- Passed\n")
87 }
88 fmt.Printf(" Passed!\n")
89 }
90
91 return nil
92}
93
94// Run a single command.
95func runCommand(cmd []string, lg io.Writer) error {
96 c := exec.Command(cmd[0], cmd[1:]...)
97 c.Stdout = lg
98 c.Stderr = lg
99 return c.Run()
100}
101
102// Expect the given string.
103func expect(lg io.Writer, lines <-chan string, exp string) error {
104 // Read lines, and if we hit a timeout before seeing our
105 // expected line, then consider that an error.
106 fmt.Fprintf(lg, "---- expect: %q\n", exp)
107
108 stopper := time.NewTimer(10 * time.Second)
109 defer stopper.Stop()
110outer:
111 for {
112 select {
113 case line := <-lines:
114 fmt.Fprintf(lg, "---- target: %q\n", line)
115 if strings.Contains(line, exp) {
116 break outer
117 }
118 case <-stopper.C:
119 fmt.Fprintf(lg, "timeout, didn't receive output\n")
120 return fmt.Errorf("timeout, didn't receive expected string: %q", exp)
121 }
122 }
123
124 return nil
125}
126
127// Read things from the log file, discarding everything already there.
128func readLog(sink chan<- string) {
129 file, err := os.Open(*logIn)
130 if err != nil {
131 log.Fatal(err)
132 }
133
134 _, err = file.Seek(0, 2)
135 if err != nil {
136 log.Fatal(err)
137 }
138
139 prefix := ""
140 for {
141 // Read lines until EOF, then delay a bit, and do it
142 // all again.
143 rd := bufio.NewReader(file)
144
145 for {
146 line, err := rd.ReadString('\n')
147 if err == io.EOF {
148 // A partial line can happen because
149 // we are racing with the writer.
150 if line != "" {
151 prefix = line
152 }
153 break
154 }
155 if err != nil {
156 log.Fatal(err)
157 }
158
159 line = prefix + line
160 prefix = ""
161 sink <- line
162 // fmt.Printf("line: %q\n", line)
163 }
164
165 // Pause a little
166 time.Sleep(250 * time.Millisecond)
167 }
168}