Files
mixer-tools/swupd/fullfiles_test.go
Rodrigo Chiossi e9909408a1 fullfiles: Add user configured compression list
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>
2019-11-05 15:23:22 +00:00

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)
}