blob: c1f4d38812b207512a50c815be6efab83331d325 [file]
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cosboot
import (
"os"
"os/exec"
"path/filepath"
"testing"
"cos.googlesource.com/cos/tools.git/src/pkg/tools/partutil"
"cos.googlesource.com/cos/tools.git/src/pkg/utils"
)
func TestDiskBootPath(t *testing.T) {
tests := []struct {
name string
input string
want BootPath
}{
{
name: "GRUB",
input: "testdata/shimefi.img",
want: GRUBBoot,
},
{
name: "Kernel",
input: "testdata/kernelefi.img",
want: UKI,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
got, err := DiskBootPath(test.input)
if err != nil {
t.Fatalf("DiskBootPath(%q) = %v; want nil", test.input, err)
}
if got != test.want {
t.Errorf("DiskBootPath(%q) = %v; want %v", test.input, got, test.want)
}
})
}
}
func TestBootEFIPath(t *testing.T) {
// 1. Test standard x86_64 bootloader paths on existing test data
tests := []struct {
name string
input string
want string
}{
{
name: "GRUB x86_64",
input: "testdata/shimefi.img",
want: "/efi/boot/bootx64.efi",
},
{
name: "Kernel UKI x86_64",
input: "testdata/kernelefi.img",
want: "/efi/boot/bootx64.efi",
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
got, err := BootEFIPath(test.input)
if err != nil {
t.Fatalf("BootEFIPath(%q) = %v; want nil", test.input, err)
}
if got != test.want {
t.Errorf("BootEFIPath(%q) = %q; want %q", test.input, got, test.want)
}
})
}
// 2. Test ARM64 bootloader fallback using partition extraction and patching
t.Run("ARM64 Fallback", func(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "cos-bootefipathtest-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
copiedImage := filepath.Join(tmpDir, "test_arm64.img")
if err := utils.CopyFile("testdata/shimefi.img", copiedImage); err != nil {
t.Fatal(err)
}
// Find and extract the EFI partition
sfdiskTable, err := partutil.ReadPartitionTableJSON(copiedImage)
if err != nil {
t.Fatal(err)
}
partTable := sfdiskTable.PartitionTable
var partIndex int
var found bool
for i := range partTable.Partitions {
if partTable.Partitions[i].Name == "EFI-SYSTEM" {
partIndex = i
found = true
break
}
}
if !found {
t.Fatal("failed to find EFI partition")
}
efiPartNum := partIndex + 1
efiData, err := partutil.ReadPartitionData(copiedImage, efiPartNum)
if err != nil {
t.Fatal(err)
}
efiBin := filepath.Join(tmpDir, "efi.bin")
if err := os.WriteFile(efiBin, efiData, 0644); err != nil {
t.Fatal(err)
}
// Delete the x86_64 EFI loader from efi.bin
cmdDel := exec.Command("mdel", "-i", efiBin, "::/efi/boot/bootx64.efi")
if err := cmdDel.Run(); err != nil {
t.Fatalf("failed to delete bootx64.efi: %v", err)
}
// Write modified partition back to disk image
updatedData, err := os.ReadFile(efiBin)
if err != nil {
t.Fatal(err)
}
if err := partutil.WritePartitionData(copiedImage, efiPartNum, updatedData); err != nil {
t.Fatal(err)
}
// Verify it now fails since no EFI loaders are present
_, err = BootEFIPath(copiedImage)
if err == nil {
t.Error("BootEFIPath(copiedImage) succeeded; want error (no bootloader present)")
}
// Write dummy ARM64 loader file to efi.bin
dummyLoader := filepath.Join(tmpDir, "dummy")
if err := os.WriteFile(dummyLoader, []byte("dummy-arm64-loader"), 0644); err != nil {
t.Fatal(err)
}
cmdCopy := exec.Command("mcopy", "-i", efiBin, dummyLoader, "::/efi/boot/bootaa64.efi")
if err := cmdCopy.Run(); err != nil {
t.Fatalf("failed to write bootaa64.efi: %v", err)
}
// Write modified partition back to disk image
updatedData2, err := os.ReadFile(efiBin)
if err != nil {
t.Fatal(err)
}
if err := partutil.WritePartitionData(copiedImage, efiPartNum, updatedData2); err != nil {
t.Fatal(err)
}
// Verify dynamic resolution successfully falls back to bootaa64.efi
got, err := BootEFIPath(copiedImage)
if err != nil {
t.Fatalf("BootEFIPath(copiedImage) = %v; want nil", err)
}
if got != "/efi/boot/bootaa64.efi" {
t.Errorf("BootEFIPath(copiedImage) = %q; want /efi/boot/bootaa64.efi", got)
}
})
}