internal/agent/bootstrap/bootstrap_test.go
Ref: Size: 7.2 KiB History
package bootstrap
import (
"bytes"
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"log/slog"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/a73x/eitri/internal/relmanifest"
)
var platform = runtime.GOOS + "/" + runtime.GOARCH
// fixture describes a manifest server's content: which artifact keys are
// present for the test's platform, their bodies, and (optionally) a SHA256
// override to force a mismatch.
type fixture struct {
chBody, fwBody []byte
chSHA, fwSHA string // "" ⇒ compute the correct sha of the body
includeCH, includeFW bool
}
// newServer stands up an httptest server exposing /manifest.json, /ch, and
// /fw, and returns the manifest URL. Also returns the running request
// counter so callers can assert on how many requests were made.
func newServer(t *testing.T, f fixture) (manifestURL string, requests *int) {
t.Helper()
mux := http.NewServeMux()
srv := httptest.NewServer(mux)
t.Cleanup(srv.Close)
count := 0
requests = &count
mux.HandleFunc("/ch", func(w http.ResponseWriter, r *http.Request) {
*requests++
w.Write(f.chBody)
})
mux.HandleFunc("/fw", func(w http.ResponseWriter, r *http.Request) {
*requests++
w.Write(f.fwBody)
})
artifacts := map[string]map[string]relmanifest.Artifact{}
if f.includeCH {
sha := f.chSHA
if sha == "" {
sum := sha256.Sum256(f.chBody)
sha = hex.EncodeToString(sum[:])
}
artifacts["cloud-hypervisor"] = map[string]relmanifest.Artifact{platform: {URL: srv.URL + "/ch", SHA256: sha}}
}
if f.includeFW {
sha := f.fwSHA
if sha == "" {
sum := sha256.Sum256(f.fwBody)
sha = hex.EncodeToString(sum[:])
}
artifacts["firmware"] = map[string]relmanifest.Artifact{platform: {URL: srv.URL + "/fw", SHA256: sha}}
}
manifest := relmanifest.Manifest{Version: "v1", Artifacts: artifacts}
mux.HandleFunc("/manifest.json", func(w http.ResponseWriter, r *http.Request) {
*requests++
_ = json.NewEncoder(w).Encode(manifest)
})
return srv.URL + "/manifest.json", requests
}
func TestEnsureNoopWhenBothFilesExist(t *testing.T) {
dir := t.TempDir()
chPath := filepath.Join(dir, "cloud-hypervisor")
fwPath := filepath.Join(dir, "CLOUDHV.fd")
if err := os.WriteFile(chPath, []byte("ch"), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(fwPath, []byte("fw"), 0o644); err != nil {
t.Fatal(err)
}
requests := 0
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requests++
w.WriteHeader(http.StatusInternalServerError)
}))
t.Cleanup(srv.Close)
b := &Bootstrapper{CHPath: chPath, FirmwarePath: fwPath, ManifestURL: srv.URL}
if err := b.Ensure(context.Background()); err != nil {
t.Fatalf("Ensure: %v", err)
}
if requests != 0 {
t.Fatalf("want zero HTTP requests when both files exist, got %d", requests)
}
}
func TestEnsureInstallsBothWhenMissing(t *testing.T) {
dir := t.TempDir()
// Nested, not-yet-created parent dirs: Ensure must MkdirAll them.
chPath := filepath.Join(dir, "bin", "cloud-hypervisor")
fwPath := filepath.Join(dir, "share", "CLOUDHV.fd")
chBody := []byte("ch-binary-contents")
fwBody := []byte("firmware-contents")
manifestURL, requests := newServer(t, fixture{chBody: chBody, fwBody: fwBody, includeCH: true, includeFW: true})
b := &Bootstrapper{CHPath: chPath, FirmwarePath: fwPath, ManifestURL: manifestURL}
if err := b.Ensure(context.Background()); err != nil {
t.Fatalf("Ensure: %v", err)
}
if *requests == 0 {
t.Fatal("want at least one HTTP request")
}
gotCH, err := os.ReadFile(chPath)
if err != nil || string(gotCH) != string(chBody) {
t.Fatalf("cloud-hypervisor contents = %q, %v; want %q", gotCH, err, chBody)
}
if fi, _ := os.Stat(chPath); fi.Mode().Perm() != 0o755 {
t.Fatalf("cloud-hypervisor mode = %v, want 0755", fi.Mode().Perm())
}
gotFW, err := os.ReadFile(fwPath)
if err != nil || string(gotFW) != string(fwBody) {
t.Fatalf("firmware contents = %q, %v; want %q", gotFW, err, fwBody)
}
if fi, _ := os.Stat(fwPath); fi.Mode().Perm() != 0o644 {
t.Fatalf("firmware mode = %v, want 0644", fi.Mode().Perm())
}
}
func TestEnsureShaMismatchOnCloudHypervisor(t *testing.T) {
dir := t.TempDir()
chPath := filepath.Join(dir, "cloud-hypervisor")
fwPath := filepath.Join(dir, "CLOUDHV.fd")
// Firmware already present so only the cloud-hypervisor path is exercised.
if err := os.WriteFile(fwPath, []byte("fw"), 0o644); err != nil {
t.Fatal(err)
}
manifestURL, _ := newServer(t, fixture{chBody: []byte("ch-binary"), chSHA: "deadbeef", includeCH: true})
b := &Bootstrapper{CHPath: chPath, FirmwarePath: fwPath, ManifestURL: manifestURL}
err := b.Ensure(context.Background())
if err == nil {
t.Fatal("want sha mismatch error")
}
if _, statErr := os.Stat(chPath); !os.IsNotExist(statErr) {
t.Fatal("cloud-hypervisor destination must be absent after sha mismatch")
}
entries, _ := os.ReadDir(dir)
for _, e := range entries {
if e.Name() != "CLOUDHV.fd" {
t.Fatalf("temp file leaked in %s: %v", dir, e.Name())
}
}
}
func TestEnsureSkipsWhenManifestURLEmpty(t *testing.T) {
dir := t.TempDir()
chPath := filepath.Join(dir, "cloud-hypervisor")
fwPath := filepath.Join(dir, "CLOUDHV.fd")
b := &Bootstrapper{CHPath: chPath, FirmwarePath: fwPath, ManifestURL: ""}
if err := b.Ensure(context.Background()); err != nil {
t.Fatalf("Ensure: %v", err)
}
if _, err := os.Stat(chPath); !os.IsNotExist(err) {
t.Fatal("cloud-hypervisor must not be installed when ManifestURL is empty")
}
if _, err := os.Stat(fwPath); !os.IsNotExist(err) {
t.Fatal("firmware must not be installed when ManifestURL is empty")
}
}
func TestEnsureWarnsWhenFirmwareEntryAbsent(t *testing.T) {
dir := t.TempDir()
chPath := filepath.Join(dir, "cloud-hypervisor")
fwPath := filepath.Join(dir, "CLOUDHV.fd") // missing; manifest has no entry (arm64-style)
chBody := []byte("ch-binary")
manifestURL, _ := newServer(t, fixture{chBody: chBody, includeCH: true, includeFW: false})
var logs bytes.Buffer
logger := slog.New(slog.NewTextHandler(&logs, nil))
b := &Bootstrapper{CHPath: chPath, FirmwarePath: fwPath, ManifestURL: manifestURL, Log: logger}
if err := b.Ensure(context.Background()); err != nil {
t.Fatalf("Ensure: %v", err)
}
if _, err := os.Stat(chPath); err != nil {
t.Fatalf("cloud-hypervisor must be installed: %v", err)
}
if _, err := os.Stat(fwPath); !os.IsNotExist(err) {
t.Fatal("firmware must remain absent when the manifest has no entry for this platform")
}
if !strings.Contains(logs.String(), "level=WARN") {
t.Fatalf("want a warning logged for the missing firmware entry, got: %s", logs.String())
}
}
func TestEnsureErrorsWhenCloudHypervisorEntryAbsent(t *testing.T) {
dir := t.TempDir()
chPath := filepath.Join(dir, "cloud-hypervisor") // missing; manifest has no entry
fwPath := filepath.Join(dir, "CLOUDHV.fd")
if err := os.WriteFile(fwPath, []byte("fw"), 0o644); err != nil {
t.Fatal(err)
}
manifestURL, _ := newServer(t, fixture{includeCH: false, includeFW: false})
b := &Bootstrapper{CHPath: chPath, FirmwarePath: fwPath, ManifestURL: manifestURL}
err := b.Ensure(context.Background())
if err == nil {
t.Fatal("want an error when cloud-hypervisor is missing and has no manifest entry")
}
if !strings.Contains(err.Error(), "cloud-hypervisor") {
t.Fatalf("error should name cloud-hypervisor, got: %v", err)
}
}