| // Copyright 2019 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 main | |
| import ( | |
| "context" | |
| "io" | |
| "io/ioutil" | |
| "os" | |
| "path/filepath" | |
| "testing" | |
| "go.fuchsia.dev/fuchsia/tools/bootserver" | |
| ) | |
| type mockReadAtCloser struct { | |
| contents string | |
| isClosed bool | |
| } | |
| func newMockReadAtCloser(contents string) *mockReadAtCloser { | |
| return &mockReadAtCloser{ | |
| contents: contents, | |
| isClosed: false, | |
| } | |
| } | |
| func (m *mockReadAtCloser) ReadAt(_ []byte, _ int64) (int, error) { | |
| return len(m.contents), nil | |
| } | |
| func (m *mockReadAtCloser) Close() error { | |
| m.isClosed = true | |
| return nil | |
| } | |
| func TestOverrideImage(t *testing.T) { | |
| imgMap := map[string]bootserver.Image{} | |
| reader := newMockReadAtCloser("contents") | |
| bootloaderImg := bootserver.Image{ | |
| Name: "bootloader", | |
| Reader: reader, | |
| } | |
| imgMap = overrideImage(context.Background(), imgMap, bootloaderImg) | |
| if img := imgMap["bootloader"]; img.Reader != bootloaderImg.Reader { | |
| t.Errorf("expected %v, got %v", bootloaderImg, img) | |
| } | |
| if reader.isClosed { | |
| t.Errorf("reader was closed") | |
| } | |
| reader2 := newMockReadAtCloser("some other contents") | |
| bootloaderOverrideImg := bootserver.Image{ | |
| Name: "bootloader", | |
| Reader: reader2, | |
| } | |
| imgMap = overrideImage(context.Background(), imgMap, bootloaderOverrideImg) | |
| if img := imgMap["bootloader"]; img.Reader != bootloaderOverrideImg.Reader { | |
| t.Errorf("expected %v, got %v", bootloaderOverrideImg, img) | |
| } | |
| if !reader.isClosed { | |
| t.Errorf("failed to close old image reader") | |
| } | |
| if reader2.isClosed { | |
| t.Errorf("new image reader is closed") | |
| } | |
| } | |
| func TestPopulateReaders(t *testing.T) { | |
| bootloaderImage := bootserver.Image{ | |
| Name: "bootloader", | |
| Args: []string{"--bootloader"}, | |
| } | |
| firmwareImage := bootserver.Image{ | |
| Name: "firmware", | |
| Args: []string{"--firmware"}, | |
| } | |
| firmware2Image := bootserver.Image{ | |
| Name: "firmware_2", | |
| Args: []string{"--firmware-2"}, | |
| } | |
| vbmetaRImage := bootserver.Image{ | |
| Name: "zedboot.vbmeta", | |
| Args: []string{"--vbmetar"}, | |
| } | |
| zedbootImage := bootserver.Image{ | |
| Name: "zedboot", | |
| Args: []string{"--zirconr"}, | |
| } | |
| allImgs := []bootserver.Image{bootloaderImage, firmwareImage, firmware2Image, vbmetaRImage, zedbootImage} | |
| tests := []struct { | |
| name string | |
| existingImageIndexes []int | |
| expectErr bool | |
| }{ | |
| {"PopulateAllReaders", []int{0, 1, 2, 3, 4}, false}, | |
| {"FileNotFound", []int{0}, true}, | |
| } | |
| for _, test := range tests { | |
| testImgs := make([]bootserver.Image, len(allImgs)) | |
| copy(testImgs, allImgs) | |
| tmpDir, err := ioutil.TempDir("", "test-data") | |
| if err != nil { | |
| t.Fatalf("failed to create temp dir: %v", err) | |
| } | |
| defer os.RemoveAll(tmpDir) | |
| for i := range testImgs { | |
| imgPath := filepath.Join(tmpDir, testImgs[i].Name) | |
| testImgs[i].Path = imgPath | |
| } | |
| for _, i := range test.existingImageIndexes { | |
| err := ioutil.WriteFile(testImgs[i].Path, []byte("data"), 0755) | |
| if err != nil { | |
| t.Fatalf("Failed to create tmp file: %s", err) | |
| } | |
| } | |
| closeFunc, err := populateReaders(testImgs) | |
| if test.expectErr && err == nil { | |
| t.Errorf("Test%v: Expected errors; no errors found", test.name) | |
| } | |
| if !test.expectErr && err != nil { | |
| t.Errorf("Test%v: Expected no errors; found error - %v", test.name, err) | |
| } | |
| if test.expectErr && err != nil { | |
| continue | |
| } | |
| for _, img := range testImgs { | |
| if img.Reader == nil { | |
| t.Errorf("Test%v: missing reader for %s", test.name, img.Name) | |
| } | |
| // The contents of each image is `data` so the size should be 4. | |
| if img.Size != int64(4) { | |
| t.Errorf("Test%v: incorrect size for %s; actual: %d, expected: 4", test.name, img.Name, img.Size) | |
| } | |
| buf := make([]byte, 1) | |
| if _, err := img.Reader.ReadAt(buf, 0); err != nil { | |
| t.Errorf("Test%v: failed to read %s: %v", test.name, img.Name, err) | |
| } | |
| } | |
| closeFunc() | |
| for _, img := range testImgs { | |
| buf := make([]byte, 1) | |
| if _, err := img.Reader.ReadAt(buf, 0); err == nil || err == io.EOF { | |
| t.Fatalf("Test%v: reader is not closed for %s", test.name, img.Name) | |
| } | |
| } | |
| } | |
| } | |
| // Checks that getFirmwareArgs(args) returns the expected arg names and types. | |
| // To simplify usage, does not check for help text equality. | |
| func expectGetFirmwareArgs(t *testing.T, args []string, expected []firmwareArg) { | |
| actual := getFirmwareArgs(args) | |
| if len(actual) != len(expected) { | |
| t.Errorf("Firmware length mismatch: expected %+v but got %+v", expected, actual) | |
| } | |
| for i := 0; i < len(actual); i++ { | |
| if actual[i].name != expected[i].name || actual[i].fwType != expected[i].fwType { | |
| t.Errorf("Firmware arg mismatch: expected %+v but got %+v", expected, actual) | |
| break | |
| } | |
| } | |
| } | |
| func TestGetFirmwareArgsNil(t *testing.T) { | |
| // Args always include the default "--firmware". | |
| expectGetFirmwareArgs(t, | |
| nil, | |
| []firmwareArg{{name: "firmware", fwType: ""}}) | |
| } | |
| func TestGetFirmwareArgsNoFirmware(t *testing.T) { | |
| expectGetFirmwareArgs(t, | |
| []string{"--foo", "bar"}, | |
| []firmwareArg{{name: "firmware", fwType: ""}}) | |
| } | |
| func TestGetFirmwareArgsUntypedFirmware(t *testing.T) { | |
| expectGetFirmwareArgs(t, | |
| []string{"--firmware"}, | |
| []firmwareArg{{name: "firmware", fwType: ""}}) | |
| } | |
| func TestGetFirmwareArgsTypedFirmware(t *testing.T) { | |
| expectGetFirmwareArgs(t, | |
| []string{"--firmware-foo"}, | |
| []firmwareArg{ | |
| {name: "firmware", fwType: ""}, | |
| {name: "firmware-foo", fwType: "foo"}, | |
| }) | |
| } | |
| func TestGetFirmwareArgsSingleDash(t *testing.T) { | |
| expectGetFirmwareArgs(t, | |
| []string{"-firmware-foo"}, | |
| []firmwareArg{ | |
| {name: "firmware", fwType: ""}, | |
| {name: "firmware-foo", fwType: "foo"}, | |
| }) | |
| } | |
| func TestGetFirmwareArgsWithEquals(t *testing.T) { | |
| expectGetFirmwareArgs(t, | |
| []string{"--firmware-foo=bar"}, | |
| []firmwareArg{ | |
| {name: "firmware", fwType: ""}, | |
| {name: "firmware-foo", fwType: "foo"}, | |
| }) | |
| } | |
| func TestGetFirmwareArgsMultiple(t *testing.T) { | |
| expectGetFirmwareArgs(t, | |
| []string{"abc", "--firmware", "fw1", "--firmware-2", "fw2", "skip_me", "-firmware-3=fw3"}, | |
| []firmwareArg{ | |
| {name: "firmware", fwType: ""}, | |
| {name: "firmware-2", fwType: "2"}, | |
| {name: "firmware-3", fwType: "3"}, | |
| }) | |
| } |