420 lines
8.1 KiB
Go
420 lines
8.1 KiB
Go
// +build ignore
|
|
//
|
|
// Build multiple configurations of MCUboot for Zephyr, making sure
|
|
// that they run properly.
|
|
//
|
|
// Run as:
|
|
//
|
|
// go run run-tests.go [flags]
|
|
//
|
|
// Add -help as a flag to get help. See comment below for logIn on
|
|
// how to configure terminal output to a file so this program can see
|
|
// the output of the Zephyr device.
|
|
|
|
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// logIn gives the pathname of the log output from the Zephyr device.
|
|
// In order to see the serial output, but still be useful for human
|
|
// debugging, the output of the terminal emulator should be teed to a
|
|
// file that this program will read from. This can be done with
|
|
// something like:
|
|
//
|
|
// picocom -b 115200 /dev/ttyACM0 | tee /tmp/zephyr.out
|
|
//
|
|
// Other terminal programs should also have logging options.
|
|
var logIn = flag.String("login", "/tmp/zephyr.out", "File name of terminal log from Zephyr device")
|
|
|
|
// Output from this test run is written to the given log file.
|
|
var logOut = flag.String("logout", "tests.log", "Log file to write to")
|
|
|
|
// The main driver of this consists of a series of tests. Each test
|
|
// then contains a series of commands and expect results.
|
|
var tests = []struct {
|
|
name string
|
|
tests []oneTest
|
|
}{
|
|
{
|
|
name: "Good RSA",
|
|
tests: []oneTest{
|
|
{
|
|
commands: [][]string{
|
|
{"make", "test-good-rsa"},
|
|
{"make", "flash_boot"},
|
|
},
|
|
expect: "Unable to find bootable image",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello1"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello2"},
|
|
},
|
|
expect: "Hello World from hello2",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"pyocd", "commander", "-c", "reset"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Good ECDSA",
|
|
tests: []oneTest{
|
|
{
|
|
commands: [][]string{
|
|
{"make", "test-good-ecdsa"},
|
|
{"make", "flash_boot"},
|
|
},
|
|
expect: "Unable to find bootable image",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello1"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello2"},
|
|
},
|
|
expect: "Hello World from hello2",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"pyocd", "commander", "-c", "reset"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Overwrite",
|
|
tests: []oneTest{
|
|
{
|
|
commands: [][]string{
|
|
{"make", "test-overwrite"},
|
|
{"make", "flash_boot"},
|
|
},
|
|
expect: "Unable to find bootable image",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello1"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello2"},
|
|
},
|
|
expect: "Hello World from hello2",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"pyocd", "commander", "-c", "reset"},
|
|
},
|
|
expect: "Hello World from hello2",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Bad RSA",
|
|
tests: []oneTest{
|
|
{
|
|
commands: [][]string{
|
|
{"make", "test-bad-rsa-upgrade"},
|
|
{"make", "flash_boot"},
|
|
},
|
|
expect: "Unable to find bootable image",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello1"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello2"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"pyocd", "commander", "-c", "reset"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Bad RSA",
|
|
tests: []oneTest{
|
|
{
|
|
commands: [][]string{
|
|
{"make", "test-bad-ecdsa-upgrade"},
|
|
{"make", "flash_boot"},
|
|
},
|
|
expect: "Unable to find bootable image",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello1"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello2"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"pyocd", "commander", "-c", "reset"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "No bootcheck",
|
|
tests: []oneTest{
|
|
{
|
|
commands: [][]string{
|
|
{"make", "test-no-bootcheck"},
|
|
{"make", "flash_boot"},
|
|
},
|
|
expect: "Unable to find bootable image",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello1"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello2"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"pyocd", "commander", "-c", "reset"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Wrong RSA",
|
|
tests: []oneTest{
|
|
{
|
|
commands: [][]string{
|
|
{"make", "test-wrong-rsa"},
|
|
{"make", "flash_boot"},
|
|
},
|
|
expect: "Unable to find bootable image",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello1"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello2"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"pyocd", "commander", "-c", "reset"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Wrong ECDSA",
|
|
tests: []oneTest{
|
|
{
|
|
commands: [][]string{
|
|
{"make", "test-wrong-ecdsa"},
|
|
{"make", "flash_boot"},
|
|
},
|
|
expect: "Unable to find bootable image",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello1"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"make", "flash_hello2"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
{
|
|
commands: [][]string{
|
|
{"pyocd", "commander", "-c", "reset"},
|
|
},
|
|
expect: "Hello World from hello1",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
type oneTest struct {
|
|
commands [][]string
|
|
expect string
|
|
}
|
|
|
|
func main() {
|
|
err := run()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func run() error {
|
|
flag.Parse()
|
|
|
|
lines := make(chan string, 30)
|
|
go readLog(lines)
|
|
|
|
// Write output to a log file
|
|
logFile, err := os.Create(*logOut)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer logFile.Close()
|
|
lg := bufio.NewWriter(logFile)
|
|
defer lg.Flush()
|
|
|
|
for _, group := range tests {
|
|
fmt.Printf("Running %q\n", group.name)
|
|
fmt.Fprintf(lg, "-------------------------------------\n")
|
|
fmt.Fprintf(lg, "---- Running %q\n", group.name)
|
|
|
|
for _, test := range group.tests {
|
|
for _, cmd := range test.commands {
|
|
fmt.Printf(" %s\n", cmd)
|
|
fmt.Fprintf(lg, "---- Run: %s\n", cmd)
|
|
err = runCommand(cmd, lg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
err = expect(lg, lines, test.expect)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Fprintf(lg, "---- Passed\n")
|
|
}
|
|
fmt.Printf(" Passed!\n")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Run a single command.
|
|
func runCommand(cmd []string, lg io.Writer) error {
|
|
c := exec.Command(cmd[0], cmd[1:]...)
|
|
c.Stdout = lg
|
|
c.Stderr = lg
|
|
return c.Run()
|
|
}
|
|
|
|
// Expect the given string.
|
|
func expect(lg io.Writer, lines <-chan string, exp string) error {
|
|
// Read lines, and if we hit a timeout before seeing our
|
|
// expected line, then consider that an error.
|
|
fmt.Fprintf(lg, "---- expect: %q\n", exp)
|
|
|
|
stopper := time.NewTimer(10 * time.Second)
|
|
defer stopper.Stop()
|
|
outer:
|
|
for {
|
|
select {
|
|
case line := <-lines:
|
|
fmt.Fprintf(lg, "---- target: %q\n", line)
|
|
if strings.Contains(line, exp) {
|
|
break outer
|
|
}
|
|
case <-stopper.C:
|
|
fmt.Fprintf(lg, "timeout, didn't receive output\n")
|
|
return fmt.Errorf("timeout, didn't receive expected string: %q", exp)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Read things from the log file, discarding everything already there.
|
|
func readLog(sink chan<- string) {
|
|
file, err := os.Open(*logIn)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
_, err = file.Seek(0, 2)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
prefix := ""
|
|
for {
|
|
// Read lines until EOF, then delay a bit, and do it
|
|
// all again.
|
|
rd := bufio.NewReader(file)
|
|
|
|
for {
|
|
line, err := rd.ReadString('\n')
|
|
if err == io.EOF {
|
|
// A partial line can happen because
|
|
// we are racing with the writer.
|
|
if line != "" {
|
|
prefix = line
|
|
}
|
|
break
|
|
}
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
line = prefix + line
|
|
prefix = ""
|
|
sink <- line
|
|
// fmt.Printf("line: %q\n", line)
|
|
}
|
|
|
|
// Pause a little
|
|
time.Sleep(250 * time.Millisecond)
|
|
}
|
|
}
|