mirror of
https://github.com/clearlinux/mixer-tools.git
synced 2026-10-03 15:29:44 +00:00
This patch allows users to configure the compression methods that will be used for fullfiles creation. The compression method can be set in the Swupd.COMPRESSION property in builder.conf. Instead of enabling all methods as previosly, xz is the only method that comes enabled by default. Note: internal gzip is still used for Link and Directory fullfile creation. Signed-off-by: Rodrigo Chiossi <rodrigo.chiossi@intel.com>
272 lines
6.4 KiB
Go
272 lines
6.4 KiB
Go
package swupd
|
|
|
|
import (
|
|
"archive/tar"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
"testing"
|
|
)
|
|
|
|
func TestCreateFullfiles(t *testing.T) {
|
|
dir, err := ioutil.TempDir("", "fullfiles-test-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer removeAllIgnoreErr(dir)
|
|
|
|
chrootDir := filepath.Join(dir, "chroot")
|
|
mustMkdir(t, chrootDir)
|
|
|
|
outputDir := filepath.Join(dir, "output")
|
|
mustMkdir(t, outputDir)
|
|
|
|
files := map[string]*struct {
|
|
Contents string
|
|
Version uint32
|
|
Mode os.FileMode
|
|
IsDir bool
|
|
Linkname string
|
|
|
|
ExpectedHash string
|
|
}{
|
|
"A": {Contents: `file1`, Version: 20, Mode: 0755},
|
|
"B": {Contents: `file2`, Version: 20, Mode: 0644},
|
|
"C": {Contents: `file3`, Version: 20, Mode: 0644},
|
|
|
|
// File from previous version will not have a fullfile.
|
|
"D": {Contents: `DDD`, Version: 10, Mode: 0755},
|
|
|
|
// File with same content and mode (and hash).
|
|
"E": {Contents: `file1`, Version: 20, Mode: 0755},
|
|
|
|
// File with same content but different mode.
|
|
"F": {Contents: `file1`, Version: 20, Mode: 0644},
|
|
|
|
// Directories.
|
|
"G": {IsDir: true, Version: 20},
|
|
"H": {IsDir: true, Version: 10},
|
|
|
|
// Links.
|
|
"I": {Linkname: "A", Version: 20},
|
|
"J": {Linkname: "A", Version: 10},
|
|
}
|
|
|
|
m := &Manifest{}
|
|
m.Header.Version = 20
|
|
|
|
unique := make(map[Hashval]bool)
|
|
for name, desc := range files {
|
|
var typeFlag TypeFlag
|
|
path := filepath.Join(chrootDir, name)
|
|
switch {
|
|
case desc.IsDir:
|
|
typeFlag = TypeDirectory
|
|
if desc.Mode == 0 {
|
|
desc.Mode = 0755
|
|
}
|
|
err = os.Mkdir(path, desc.Mode)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.Chmod(path, desc.Mode)
|
|
case desc.Linkname != "":
|
|
typeFlag = TypeLink
|
|
err = os.Symlink(desc.Linkname, path)
|
|
default:
|
|
typeFlag = TypeFile
|
|
if desc.Mode == 0 {
|
|
desc.Mode = 0644
|
|
}
|
|
err = ioutil.WriteFile(path, []byte(desc.Contents), desc.Mode)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
err = os.Chmod(path, desc.Mode)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
desc.ExpectedHash, err = GetHashForFile(path)
|
|
if err != nil {
|
|
t.Fatalf("couldn't get hashes for the test file %s: %s", path, err)
|
|
}
|
|
|
|
f := &File{
|
|
Name: name,
|
|
Hash: internHash(desc.ExpectedHash),
|
|
Type: typeFlag,
|
|
Version: desc.Version,
|
|
}
|
|
if m.Header.Version == f.Version {
|
|
unique[f.Hash] = true
|
|
}
|
|
m.Files = append(m.Files, f)
|
|
}
|
|
|
|
_, err = CreateFullfiles(m, chrootDir, outputDir, 0, []string{"external-xz"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// All correct files were created.
|
|
for _, desc := range files {
|
|
if desc.Version != m.Header.Version {
|
|
continue
|
|
}
|
|
tarName := filepath.Join(outputDir, desc.ExpectedHash+".tar")
|
|
mustExist(t, tarName)
|
|
mustHaveMatchingHash(t, tarName)
|
|
}
|
|
|
|
// No extra files were created.
|
|
fis, err := ioutil.ReadDir(outputDir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(fis) != len(unique) {
|
|
t.Fatalf("generated %d fullfiles, but want %d", len(fis), len(unique))
|
|
}
|
|
}
|
|
|
|
func TestCreateFullfilesErrorPaths(t *testing.T) {
|
|
if _, err := CreateFullfiles(nil, "/tmp/bogusdir", "/tmp/bogusdir", 1, []string{"external-xz"}); err == nil {
|
|
t.Error("CreateFullfiles did not return error on bogus chroot directory")
|
|
}
|
|
}
|
|
|
|
func TestCreateDirectoryFullfileErrorPaths(t *testing.T) {
|
|
if err := createDirectoryFullfile("bogusfile", "bogus", "bogus", nil); err == nil {
|
|
t.Error("createDirectoryFullfile did not return error on bogus file")
|
|
}
|
|
|
|
f, err := ioutil.TempFile("", "")
|
|
if err != nil {
|
|
t.Fatal("couldn't create test file")
|
|
}
|
|
defer func() {
|
|
_ = os.Remove(f.Name())
|
|
}()
|
|
|
|
if err := createDirectoryFullfile(f.Name(), f.Name(), "bogus", nil); err == nil {
|
|
t.Error("createDirectoryFullfile did not return error on regular file")
|
|
}
|
|
}
|
|
|
|
func TestCreateLinkFullfileErrorPaths(t *testing.T) {
|
|
if err := createLinkFullfile("bogusfile", "bogus", "bogus", nil); err == nil {
|
|
t.Error("createLinkFullfile did not return error on bogus file")
|
|
}
|
|
|
|
f, err := ioutil.TempFile("", "")
|
|
if err != nil {
|
|
t.Fatal("couldn't create test file")
|
|
}
|
|
defer func() {
|
|
_ = os.Remove(f.Name())
|
|
}()
|
|
|
|
if err := createLinkFullfile(f.Name(), f.Name(), "bogus", nil); err == nil {
|
|
t.Error("createLinkFullfile did not return error on regular file")
|
|
}
|
|
}
|
|
|
|
func TestCreateRegularFullfileErrorPaths(t *testing.T) {
|
|
debugFullfiles = true
|
|
if err := createRegularFullfile("bogusfile", "bogus", "bogus", nil, []string{"external-xz"}); err == nil {
|
|
t.Error("createRegularFullfile did not return error on bogus file")
|
|
}
|
|
|
|
d, err := ioutil.TempDir("", "")
|
|
if err != nil {
|
|
t.Fatal("couldn't create test directory")
|
|
}
|
|
defer func() {
|
|
_ = os.RemoveAll(d)
|
|
}()
|
|
|
|
if err := createRegularFullfile(d, "bogus", "bogus", nil, []string{"external-xz"}); err == nil {
|
|
t.Error("createRegularFullfile did not return error on directory")
|
|
}
|
|
}
|
|
|
|
func TestTarRegularFullfileErrorPaths(t *testing.T) {
|
|
f, err := ioutil.TempFile("", "")
|
|
if err != nil {
|
|
t.Fatal("couldn't create test file")
|
|
}
|
|
defer func() {
|
|
_ = os.Remove(f.Name())
|
|
}()
|
|
|
|
var fi os.FileInfo
|
|
if err = tarRegularFullfile(f, "test", "test", fi); err == nil {
|
|
t.Error("tarRegularFullfile did not return error on invalid fileinfo")
|
|
}
|
|
}
|
|
|
|
func mustHaveMatchingHash(t *testing.T, path string) {
|
|
t.Helper()
|
|
expectedHash := filepath.Base(path)
|
|
// Take the ".tar" extension off.
|
|
expectedHash = expectedHash[:len(expectedHash)-4]
|
|
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
t.Fatalf("couldn't open %s to check contents hash: %s", path, err)
|
|
}
|
|
defer func() {
|
|
_ = f.Close()
|
|
}()
|
|
|
|
tr, err := NewCompressedTarReader(f)
|
|
if err != nil {
|
|
t.Fatalf("couldn't uncompress %s to check contents hash: %s", path, err)
|
|
}
|
|
defer func() {
|
|
_ = tr.Close()
|
|
}()
|
|
|
|
hdr, err := tr.Next()
|
|
if err != nil {
|
|
t.Fatalf("couldn't read archive in %s: %s", path, err)
|
|
}
|
|
|
|
h, err := newHashFromTarHeader(hdr)
|
|
if err != nil {
|
|
t.Fatalf("couldn't create hash struct from %s: %s", path, err)
|
|
}
|
|
|
|
_, err = io.Copy(h, tr)
|
|
if err != nil {
|
|
t.Fatalf("couldn't read archive %s contents: %s", path, err)
|
|
}
|
|
|
|
hash := h.Sum()
|
|
if hash != expectedHash {
|
|
t.Fatalf("unexpected hash %s for contents of %s", hash, path)
|
|
}
|
|
}
|
|
|
|
func newHashFromTarHeader(hdr *tar.Header) (*Hash, error) {
|
|
info := &HashFileInfo{
|
|
Mode: uint32(hdr.Mode),
|
|
UID: uint32(hdr.Uid),
|
|
GID: uint32(hdr.Gid),
|
|
Size: hdr.Size,
|
|
Linkname: hdr.Linkname,
|
|
}
|
|
switch hdr.Typeflag {
|
|
case tar.TypeReg, tar.TypeRegA:
|
|
info.Mode |= syscall.S_IFREG
|
|
case tar.TypeDir:
|
|
info.Mode |= syscall.S_IFDIR
|
|
case tar.TypeSymlink:
|
|
info.Mode |= syscall.S_IFLNK
|
|
}
|
|
return NewHash(info)
|
|
}
|