package buildstep import ( "bytes" "compress/gzip" "crypto/sha256" "encoding/hex" "io" "os" "path/filepath" "testing" "time" ) // fixture writes three files in two directories (modes 0644 and 0755). func fixture(t *testing.T) string { t.Helper() root := t.TempDir() for _, f := range []struct { p string mode os.FileMode body string }{{"a/x.txt", 0o644, "x\n"}, {"a/run.sh", 0o755, "#!/bin/sh\necho hi\n"}, {"b/c/y.txt", 0o644, "why\n"}} { path := filepath.Join(root, f.p) if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(path, []byte(f.body), f.mode); err != nil { t.Fatal(err) } if err := os.Chmod(path, f.mode); err != nil { t.Fatal(err) } } return root } // 1479/AC1: the tar stream inside the archive equals the bytes mesh-controller's pack makes for this tree. // testdata/pack-golden.tar is the uncompressed stream, made once by running mesh-controller // internal/builder/builder.go pack (origin/main 073ccc29, :1351-1425) on this fixture (above, modes set by chmod) // and gunzipping its archive. The gzip layer is not compared byte for byte, since compress/gzip's output differs // between Go versions; its header is checked to carry no name, no comment and no time. func TestPackEqualsTheBuildAgentsArchive(t *testing.T) { golden, err := os.ReadFile("testdata/pack-golden.tar") if err != nil { t.Fatal(err) } archive, digest, err := Pack(fixture(t)) if err != nil { t.Fatal(err) } zr, err := gzip.NewReader(bytes.NewReader(archive)) if err != nil { t.Fatal(err) } if zr.Name != "" || zr.Comment != "" || !zr.ModTime.IsZero() { t.Errorf("gzip header = name %q, comment %q, time %v; want none", zr.Name, zr.Comment, zr.ModTime) } tarBytes, err := io.ReadAll(zr) if err != nil { t.Fatal(err) } if !bytes.Equal(tarBytes, golden) { t.Errorf("the tar stream is %d bytes, the build agent's %d, and they differ", len(tarBytes), len(golden)) } sum := sha256.Sum256(archive) if digest != "sha256:"+hex.EncodeToString(sum[:]) { t.Errorf("digest = %s, not the sha256 of the archive", digest) } } // 1479/AC2: touching every file's time changes nothing. func TestPackDigestIgnoresFileTimes(t *testing.T) { root := fixture(t) _, first, err := Pack(root) if err != nil { t.Fatal(err) } later := time.Now().Add(48 * time.Hour) filepath.Walk(root, func(p string, _ os.FileInfo, _ error) error { return os.Chtimes(p, later, later) }) if _, second, err := Pack(root); err != nil || second != first { t.Errorf("digests %s and %s (%v)", first, second, err) } }