github.com/kubri/kubri@v0.5.1-0.20240317001612-bda2aaef967e/integrations/apt/build_test.go (about) 1 package apt_test 2 3 import ( 4 "context" 5 "io" 6 "io/fs" 7 "maps" 8 "os" 9 "path" 10 "path/filepath" 11 "strings" 12 "testing" 13 "testing/fstest" 14 "time" 15 16 "github.com/google/go-cmp/cmp" 17 18 "github.com/kubri/kubri/integrations/apt" 19 "github.com/kubri/kubri/internal/test" 20 "github.com/kubri/kubri/pkg/crypto/pgp" 21 source "github.com/kubri/kubri/source/file" 22 "github.com/kubri/kubri/target" 23 ftarget "github.com/kubri/kubri/target/file" 24 ) 25 26 func TestBuild(t *testing.T) { 27 want := readTestData(t, ".gz", ".xz") 28 now := time.Date(2023, 11, 19, 23, 37, 12, 0, time.UTC) 29 30 dir := t.TempDir() + "/apt" 31 src, _ := source.New(source.Config{Path: "../../testdata"}) 32 tgt, _ := ftarget.New(ftarget.Config{Path: dir}) 33 34 test.Golden(t, "testdata", dir, test.Ignore("*.deb", "*.gz", "*.xz")) 35 36 t.Run("New", func(t *testing.T) { 37 c := &apt.Config{Source: src, Target: tgt} 38 testBuild(t, c, want, now) 39 }) 40 41 // Should be no-op as nothing changed so timestamp should still be valid. 42 t.Run("NoChange", func(t *testing.T) { 43 c := &apt.Config{Source: src, Target: tgt} 44 testBuild(t, c, want, now.Add(time.Hour)) 45 }) 46 47 t.Run("PGP", func(t *testing.T) { 48 dir := t.TempDir() 49 pgpKey, _ := pgp.NewPrivateKey("test", "test@example.com") 50 tgt, _ := ftarget.New(ftarget.Config{Path: dir}) 51 52 c := &apt.Config{ 53 Source: src, 54 Target: tgt, 55 PGPKey: pgpKey, 56 } 57 58 // Remove InRelease and test that separately below. 59 wantPGP := maps.Clone(want) 60 delete(wantPGP, "dists/stable/InRelease") 61 62 testBuild(t, c, wantPGP, now) 63 64 data, _ := os.ReadFile(filepath.Join(dir, "dists", "stable", "Release")) 65 sig, _ := os.ReadFile(filepath.Join(dir, "dists", "stable", "Release.gpg")) 66 if !pgp.Verify(pgp.Public(pgpKey), data, sig) { 67 t.Error("should pass pgp verification") 68 } 69 70 in, _ := os.ReadFile(filepath.Join(dir, "dists", "stable", "InRelease")) 71 data, sig, err := pgp.Split(in) 72 if err != nil { 73 t.Fatal(err) 74 } 75 if !pgp.Verify(pgp.Public(c.PGPKey), data, sig) { 76 t.Error("failed to verify InRelease signature") 77 } 78 if diff := cmp.Diff(want["dists/stable/Release"], string(data)); diff != "" { 79 t.Error("dists/stable/InRelease", diff) 80 } 81 }) 82 83 t.Run("CustomCompress", func(t *testing.T) { 84 dir := t.TempDir() 85 tgt, _ := ftarget.New(ftarget.Config{Path: dir}) 86 87 c := &apt.Config{ 88 Source: src, 89 Target: tgt, 90 Compress: apt.BZIP2 | apt.ZSTD, 91 } 92 93 err := apt.Build(context.Background(), c) 94 if err != nil { 95 t.Fatal(err) 96 } 97 98 err = fstest.TestFS(os.DirFS(dir), 99 "dists/stable/main/binary-amd64/Packages", 100 "dists/stable/main/binary-amd64/Packages.bz2", 101 "dists/stable/main/binary-amd64/Packages.zst", 102 "dists/stable/main/binary-i386/Packages", 103 "dists/stable/main/binary-i386/Packages.bz2", 104 "dists/stable/main/binary-i386/Packages.zst", 105 ) 106 if err != nil { 107 t.Error(err) 108 } 109 110 err = fstest.TestFS(os.DirFS(dir), 111 "dists/stable/main/binary-amd64/Packages.gz", 112 "dists/stable/main/binary-i386/Packages.gz", 113 ) 114 if err == nil { 115 t.Error("should not have gzip files") 116 } 117 }) 118 } 119 120 func readTestData(t *testing.T, compress ...string) map[string]string { 121 t.Helper() 122 123 want := make(map[string]string) 124 125 err := fs.WalkDir(os.DirFS("testdata"), ".", func(path string, d fs.DirEntry, err error) error { 126 if err != nil || d.IsDir() { 127 return err 128 } 129 b, err := fs.ReadFile(os.DirFS("testdata"), path) 130 if err != nil { 131 return err 132 } 133 want[path] = string(b) 134 if d.Name() == "Packages" { 135 for _, ext := range compress { 136 want[path+ext] = string(b) 137 } 138 } 139 return nil 140 }) 141 if err != nil { 142 t.Fatal(err) 143 } 144 145 return want 146 } 147 148 func testBuild(t *testing.T, c *apt.Config, want map[string]string, now time.Time) { //nolint:thelper 149 apt.SetTime(now) 150 151 err := apt.Build(context.Background(), c) 152 if err != nil { 153 t.Fatal(err) 154 } 155 156 for name, data := range want { 157 got := readFile(t, c.Target, name) 158 159 ext := path.Ext(name) 160 base := strings.TrimSuffix(path.Base(name), ext) 161 if base == "Packages" { 162 data = want[strings.TrimSuffix(name, ext)] 163 } 164 165 if diff := cmp.Diff(data, string(got)); diff != "" { 166 t.Error(name, diff) 167 } 168 } 169 } 170 171 func readFile(t *testing.T, tgt target.Target, name string) []byte { 172 t.Helper() 173 174 r, err := tgt.NewReader(context.Background(), name) 175 if err != nil { 176 t.Fatal(name, err) 177 } 178 defer r.Close() 179 180 r, err = apt.Decompress(path.Ext(name))(r) 181 if err != nil { 182 t.Fatal(name, err) 183 } 184 defer r.Close() 185 186 b, err := io.ReadAll(r) 187 if err != nil { 188 t.Fatal(name, err) 189 } 190 191 return b 192 }