Monorepo for Tangled tangled.org
5

Configure Feed

Select the types of activity you want to include in your feed.

1package microvm 2 3import ( 4 "encoding/json" 5 "os" 6 "path/filepath" 7 "strings" 8 "testing" 9) 10 11func writeSpecFile(t *testing.T, path string) { 12 t.Helper() 13 data, err := json.Marshal(validImageSpec()) 14 if err != nil { 15 t.Fatal(err) 16 } 17 if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { 18 t.Fatal(err) 19 } 20 if err := os.WriteFile(path, data, 0o644); err != nil { 21 t.Fatal(err) 22 } 23} 24 25func TestResolveImageConventionalLayouts(t *testing.T) { 26 cases := []struct { 27 name string 28 layout func(t *testing.T, dir string) 29 }{ 30 { 31 name: "directory with spec.json", 32 layout: func(t *testing.T, dir string) { 33 writeSpecFile(t, filepath.Join(dir, "nixos", "spec.json")) 34 }, 35 }, 36 { 37 name: "flat <name>.json", 38 layout: func(t *testing.T, dir string) { 39 writeSpecFile(t, filepath.Join(dir, "nixos.json")) 40 }, 41 }, 42 } 43 44 for _, tc := range cases { 45 t.Run(tc.name, func(t *testing.T) { 46 dir := t.TempDir() 47 tc.layout(t, dir) 48 49 e := testEngine(t, dir) 50 spec, path, name, err := e.resolveImage("nixos") 51 if err != nil { 52 t.Fatalf("resolveImage: %v", err) 53 } 54 if name != "nixos" { 55 t.Fatalf("name = %q, want nixos", name) 56 } 57 if !strings.HasPrefix(path, dir) { 58 t.Fatalf("resolved path %q not under image dir %q", path, dir) 59 } 60 if spec.Shell == "" { 61 t.Fatal("resolved spec not loaded") 62 } 63 }) 64 } 65} 66 67func TestResolveImageDirectoryMissingSpec(t *testing.T) { 68 dir := t.TempDir() 69 if err := os.MkdirAll(filepath.Join(dir, "nixos"), 0o755); err != nil { 70 t.Fatal(err) 71 } 72 73 e := testEngine(t, dir) 74 _, _, _, err := e.resolveImage("nixos") 75 if err == nil || !strings.Contains(err.Error(), imageSpecFileName) { 76 t.Fatalf("directory without %s should error, got: %v", imageSpecFileName, err) 77 } 78} 79 80func TestResolveImageRejectsPaths(t *testing.T) { 81 e := testEngine(t, t.TempDir()) 82 for _, name := range []string{"/etc/passwd", "../evil", "sub/evil", "..", "."} { 83 if _, _, _, err := e.resolveImage(name); err == nil || !strings.Contains(err.Error(), "must be a plain name") { 84 t.Fatalf("name %q should be rejected as a path, got: %v", name, err) 85 } 86 } 87} 88 89func validImageSpec() ImageSpec { 90 return ImageSpec{ 91 Arch: "x86_64", 92 BootArgs: "console=ttyS0", 93 Initrd: "initrd", 94 Kernel: "kernel", 95 RunnerConfig: RunnerConfig{ 96 Machine: "microvm", 97 }, 98 MemoryMiB: 2048, 99 Shell: "/bin/sh", 100 StoreDisk: "store-disk", 101 VCPUs: 2, 102 } 103} 104 105func TestImageSpecValidateWithoutBaseConfigHash(t *testing.T) { 106 spec := validImageSpec() 107 if err := spec.Validate(); err != nil { 108 t.Fatalf("non-NixOS image spec should validate: %v", err) 109 } 110 if spec.SupportsConfigActivation() { 111 t.Fatal("spec without baseConfigHash should not support config activation") 112 } 113 114 spec.BaseConfigHash = "abcdef" 115 if !spec.SupportsConfigActivation() { 116 t.Fatal("spec with baseConfigHash should support config activation") 117 } 118} 119 120func TestImageSpecRequiresShell(t *testing.T) { 121 spec := validImageSpec() 122 spec.Shell = "" 123 err := spec.Validate() 124 if err == nil || !strings.Contains(err.Error(), "shell") { 125 t.Fatalf("spec without shell should fail validation, got: %v", err) 126 } 127}