github.com/linuxboot/fiano@v1.2.0/integration/utk_test.go (about) 1 // Copyright 2018 the LinuxBoot Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package utk_test 6 7 import ( 8 "bytes" 9 "fmt" 10 "os" 11 "os/exec" 12 "path/filepath" 13 "strings" 14 "testing" 15 16 "github.com/linuxboot/fiano/pkg/uefi" 17 "github.com/linuxboot/fiano/pkg/utk" 18 "github.com/linuxboot/fiano/pkg/visitors" 19 ) 20 21 // Returns all the ROM names (files which end in .rom) inside the roms folder. 22 func romList(t *testing.T) []string { 23 roms, err := filepath.Glob("roms/*.rom") 24 if err != nil { 25 t.Fatalf("could not glob roms/*.rom, %v", err) 26 } 27 if len(roms) == 0 { 28 t.Fatal("no ROMs found with roms/*.rom") 29 } 30 return roms 31 } 32 33 // Create a temporary directory. 34 func createTempDir(t *testing.T) string { 35 // Create temporary directory for test files. 36 tmpDir, err := os.MkdirTemp("", "utk-test") 37 if err != nil { 38 t.Fatalf("could not create temp dir: %v", err) 39 } 40 return tmpDir 41 } 42 43 // TestExtractAssembleExtract tests the extract and assemble subcommand of UTK. 44 // The subcommands are run in this order: 45 // 46 // 1. utk extract tt.rom dir1 47 // 2. utk assemble dir1 tmp.rom 48 // 3. utk extract tmp.rom dir2 49 // 50 // The test passes iff the contents or dir1 and dir2 recursively equal. This 51 // roundabout method is used because UTK can re-assemble a ROM image which is 52 // logically equal to the original, but not bitwise equal (due to a different 53 // compression algorithm being used). To compare the ROMs logically, step 3 is 54 // required to decompresses it. 55 func TestExtractAssembleExtract(t *testing.T) { 56 // Create a temporary directory. 57 tmpDir := createTempDir(t) 58 // For debugging, uncomment the next line and comment out os.RemoveAll 59 // t.Logf("temp %v", tmpDir) 60 defer os.RemoveAll(tmpDir) 61 62 for _, tt := range romList(t) { 63 t.Run(tt, func(t *testing.T) { 64 tmpDirT := filepath.Join(tmpDir, filepath.Base(tt)) 65 if err := os.Mkdir(tmpDirT, 0777); err != nil { 66 t.Fatal(err) 67 } 68 69 // Test paths 70 var ( 71 dir1 = filepath.Join(tmpDirT, "dir1") 72 tmpRom = filepath.Join(tmpDirT, "tmp.rom") 73 dir2 = filepath.Join(tmpDirT, "dir2") 74 summary1Json = filepath.Join(dir1, "summary.json") 75 summary2Json = filepath.Join(dir2, "summary.json") 76 ) 77 78 // Extract 79 if err := utk.Run(tt, "extract", dir1); err != nil { 80 t.Fatal(err) 81 } 82 // Assemble 83 if err := utk.Run(dir1, "save", tmpRom); err != nil { 84 t.Fatal(err) 85 } 86 // Extract 87 if err := utk.Run(tmpRom, "extract", dir2); err != nil { 88 t.Fatal(err) 89 } 90 91 // Output directories must not be empty. 92 for _, d := range []string{dir1, dir2} { 93 files, err := os.ReadDir(d) 94 if err != nil { 95 t.Fatalf("cannot read directory %q: %v", d, err) 96 } 97 if len(files) == 0 { 98 t.Errorf("no files in directory %q", d) 99 } 100 } 101 102 sedRemove := func(path string) { 103 sedCmd := exec.Command("sed", "-i", "/\"Size\": [0-9]*.*/d", path) 104 sedCmd.Stderr = os.Stderr 105 sedCmd.Stdout = os.Stdout 106 if err := sedCmd.Run(); err != nil { 107 t.Error(fmt.Sprintf("Sed failed for %s, error: %s", path, err.Error())) 108 } 109 } 110 // Remove all occurences of Size from JSON file 111 // compressed sizes are different 112 // diff will always fail if this is not done. 113 sedRemove(summary1Json) 114 sedRemove(summary2Json) 115 116 // Recursively test for equality. 117 cmd := exec.Command("diff", "-r", dir1, dir2) 118 cmd.Stderr = os.Stderr 119 cmd.Stdout = os.Stdout 120 if err := cmd.Run(); err != nil { 121 t.Error("directories did not recursively compare equal") 122 } 123 }) 124 } 125 } 126 127 // TestRegressionJson tests for regression in the JSON. After making a change 128 // which affects the tree, you must commit changes to the golden JSON files 129 // with: 130 // 131 // utk integration/roms/OVMF.rom json > integration/roms/OVMF.json 132 // 133 // Otherwise, this test will fail. This gives you a chance to review how your 134 // code affects the tree and identify any mistakes. 135 func TestRegressionJson(t *testing.T) { 136 // Create a temporary directory. 137 tmpDir := createTempDir(t) 138 defer os.RemoveAll(tmpDir) 139 140 for _, tt := range romList(t) { 141 t.Run(tt, func(t *testing.T) { 142 goldenJSONFile := strings.TrimSuffix(tt, ".rom") + ".json" 143 newJSONFile := filepath.Join(tmpDir, filepath.Base(goldenJSONFile)) 144 if _, err := os.Stat(goldenJSONFile); os.IsNotExist(err) { 145 t.Skip("skipping test because no golden JSON file exists") 146 } 147 148 // Read and parse the image. 149 image, err := os.ReadFile(tt) 150 if err != nil { 151 t.Fatal(err) 152 } 153 parsedRoot, err := uefi.Parse(image) 154 if err != nil { 155 t.Fatal(err) 156 } 157 158 buf := &bytes.Buffer{} 159 json := &visitors.JSON{W: buf} 160 if err := json.Run(parsedRoot); err != nil { 161 t.Fatal(err) 162 } 163 if buf.String() == "" || buf.String() == "null" { 164 t.Fatal("no json") 165 } 166 if err := os.WriteFile(newJSONFile, buf.Bytes(), 0666); err != nil { 167 t.Fatal(err) 168 } 169 170 // Print diff. 171 cmd := exec.Command("diff", goldenJSONFile, newJSONFile) 172 cmd.Stdout = os.Stdout 173 if err := cmd.Run(); err != nil { 174 t.Error("json files did not compare equal") 175 } 176 }) 177 } 178 }