blob: ffb335806a475d6e1f307f472b3b1f7c0dba0a99 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package paver
import (
"bytes"
"context"
"crypto/rand"
"crypto/rsa"
"io/ioutil"
"path/filepath"
"strings"
"testing"
"golang.org/x/crypto/ssh"
)
// The easiest way to make a fake key is to just generate a real one.
func generatePublicKey(t *testing.T) ssh.PublicKey {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
t.Fatal(err)
}
pub, err := ssh.NewPublicKey(&privateKey.PublicKey)
if err != nil {
t.Fatal(err)
}
return pub
}
// createScript returns the path to a bash script that outputs its name and
// all its arguments.
func createScript(t *testing.T) string {
contents := "#!/bin/sh\necho \"$0 $@\"\n"
name := filepath.Join(t.TempDir(), "bootserver.sh")
if err := ioutil.WriteFile(name, []byte(contents), 0o700); err != nil {
t.Fatal(err)
}
return name
}
func createAndRunPaver(t *testing.T, options ...BuildPaverOption) (zedbootPaverArgs []string, paverArgs []string) {
bootserverPath := createScript(t)
var output bytes.Buffer
options = append(options, Stdout(&output))
paver, err := NewBuildPaver(bootserverPath, filepath.Dir(bootserverPath), options...)
if err != nil {
t.Fatal(err)
}
if err := paver.Pave(context.Background(), "a-fake-device-name"); err != nil {
t.Fatal(err)
}
outputs := strings.Split(output.String(), "\n")
zedbootPaverArgs = strings.Split(outputs[0], " ")
paverArgs = strings.Split(outputs[1], " ")
if zedbootPaverArgs[0] != bootserverPath || zedbootPaverArgs[4] != "pave-zedboot" {
t.Fatalf("Paver called the wrong bootserver or mode. Expected %s with mode pave-zedboot, actual %s with mode %s",
bootserverPath, zedbootPaverArgs[0], zedbootPaverArgs[4])
}
if paverArgs[0] != bootserverPath || paverArgs[4] != "pave" {
t.Fatalf("Paver called the wrong bootserver or mode. Expected %s with mode pave, actual %s with mode %s",
bootserverPath, paverArgs[0], paverArgs[4])
}
return
}
func TestDefault(t *testing.T) {
zedbootPaverArgs, paverArgs := createAndRunPaver(t)
{
var deviceName string
hasAllowVersionMismatch := false
for i, arg := range zedbootPaverArgs {
if arg == "-n" {
if i+1 < len(zedbootPaverArgs) {
deviceName = zedbootPaverArgs[i+1]
}
} else if arg == "--allow-zedboot-version-mismatch" {
hasAllowVersionMismatch = true
}
}
if deviceName != "a-fake-device-name" {
t.Fatalf("Missing device name in zedboot paver arguments.")
}
if !hasAllowVersionMismatch {
t.Fatalf("Missing allow version mismatch flag in zedboot paver arguments.")
}
}
{
var deviceName string
hasFailFastIfVersionMismatch := false
for i, arg := range paverArgs {
if arg == "-n" {
if i+1 < len(paverArgs) {
deviceName = paverArgs[i+1]
}
} else if arg == "--fail-fast-if-version-mismatch" {
hasFailFastIfVersionMismatch = true
}
}
if deviceName != "a-fake-device-name" {
t.Fatalf("Missing device name in paver arguments.")
}
if !hasFailFastIfVersionMismatch {
t.Fatalf("Missing allow version mismatch flag in paver arguments.")
}
}
}
func TestSSHKeys(t *testing.T) {
sshKey := generatePublicKey(t)
_, paverArgs := createAndRunPaver(t, SSHPublicKey(sshKey))
hasAuthorizedKeys := false
for i, arg := range paverArgs {
if arg == "--authorized-keys" {
// Check that there's at least one more argument.
if i+1 < len(paverArgs) {
hasAuthorizedKeys = true
break
}
}
}
if !hasAuthorizedKeys {
t.Fatalf("Missing authorized keys file in paver arguments.")
}
}
func TestOverrideSlotA(t *testing.T) {
name := t.TempDir()
_, paverArgs := createAndRunPaver(t, OverrideSlotA(name))
var zirconAPath string
for i, arg := range paverArgs {
if arg == "--zircona" {
if i+1 < len(paverArgs) {
zirconAPath = paverArgs[i+1]
}
}
}
if zirconAPath != name {
t.Fatalf("Missing zircon A image in paver arguments.")
}
}
func TestOverrideVBMetaA(t *testing.T) {
name := t.TempDir()
_, paverArgs := createAndRunPaver(t, OverrideVBMetaA(name))
var vbmetaAPath string
for i, arg := range paverArgs {
if arg == "--vbmetaa" {
if i+1 < len(paverArgs) {
vbmetaAPath = paverArgs[i+1]
}
}
}
if vbmetaAPath != name {
t.Fatalf("Missing vbmeta A image in paver arguments.")
}
}
func TestPaveMode(t *testing.T) {
bootserverPath := createScript(t)
var output bytes.Buffer
paver, err := NewBuildPaver(bootserverPath, filepath.Dir(bootserverPath), Stdout(&output))
if err != nil {
t.Fatal(err)
}
{
if err := paver.PaveWithOptions(context.Background(), "a-fake-device-name", Options{Mode: ZedbootOnly}); err != nil {
t.Fatal(err)
}
outputs := strings.Split(output.String(), "\n")
args := strings.Split(outputs[0], " ")
if args[4] != "pave-zedboot" {
t.Errorf("Paver called with wrong mode")
}
if len(outputs[1]) != 0 {
t.Errorf("Unexpected extra command")
}
}
{
output.Reset()
if err := paver.PaveWithOptions(context.Background(), "a-fake-device-name", Options{Mode: SkipZedboot}); err != nil {
t.Fatal(err)
}
outputs := strings.Split(output.String(), "\n")
args := strings.Split(outputs[0], " ")
if args[4] != "pave" {
t.Fatalf("Paver called with wrong mode")
}
if len(outputs[1]) != 0 {
t.Errorf("Unexpected extra command")
}
}
}