pkg/chrootarchive/archive_test.go
Yestin Sun 6ae14a2625 Improve test accuracy for pkg/chrootarchive (part 2)
Check test correctness of untar by comparing destination with
source. For part 2, it checkes hashes of source and destination
files or the target files of symbolic links.

This is a supplement to the #11601 fix.

Signed-off-by: Yestin Sun <sunyi0804@gmail.com>
2015-04-13 21:46:14 -07:00

381 lines
9.5 KiB
Go

package chrootarchive
import (
"bytes"
"fmt"
"hash/crc32"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"testing"
"time"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/reexec"
)
func init() {
reexec.Init()
}
func TestChrootTarUntar(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-TestChrootTarUntar")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "src")
if err := os.MkdirAll(src, 0700); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(src, "toto"), []byte("hello toto"), 0644); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(src, "lolo"), []byte("hello lolo"), 0644); err != nil {
t.Fatal(err)
}
stream, err := archive.Tar(src, archive.Uncompressed)
if err != nil {
t.Fatal(err)
}
dest := filepath.Join(tmpdir, "src")
if err := os.MkdirAll(dest, 0700); err != nil {
t.Fatal(err)
}
if err := Untar(stream, dest, &archive.TarOptions{ExcludePatterns: []string{"lolo"}}); err != nil {
t.Fatal(err)
}
}
// gh#10426: Verify the fix for having a huge excludes list (like on `docker load` with large # of
// local images)
func TestChrootUntarWithHugeExcludesList(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarHugeExcludes")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "src")
if err := os.MkdirAll(src, 0700); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(src, "toto"), []byte("hello toto"), 0644); err != nil {
t.Fatal(err)
}
stream, err := archive.Tar(src, archive.Uncompressed)
if err != nil {
t.Fatal(err)
}
dest := filepath.Join(tmpdir, "dest")
if err := os.MkdirAll(dest, 0700); err != nil {
t.Fatal(err)
}
options := &archive.TarOptions{}
//65534 entries of 64-byte strings ~= 4MB of environment space which should overflow
//on most systems when passed via environment or command line arguments
excludes := make([]string, 65534, 65534)
for i := 0; i < 65534; i++ {
excludes[i] = strings.Repeat(string(i), 64)
}
options.ExcludePatterns = excludes
if err := Untar(stream, dest, options); err != nil {
t.Fatal(err)
}
}
func TestChrootUntarEmptyArchive(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarEmptyArchive")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
if err := Untar(nil, tmpdir, nil); err == nil {
t.Fatal("expected error on empty archive")
}
}
func prepareSourceDirectory(numberOfFiles int, targetPath string, makeSymLinks bool) (int, error) {
fileData := []byte("fooo")
for n := 0; n < numberOfFiles; n++ {
fileName := fmt.Sprintf("file-%d", n)
if err := ioutil.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil {
return 0, err
}
if makeSymLinks {
if err := os.Symlink(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil {
return 0, err
}
}
}
totalSize := numberOfFiles * len(fileData)
return totalSize, nil
}
func getHash(filename string) (uint32, error) {
stream, err := ioutil.ReadFile(filename)
if err != nil {
return 0, err
}
hash := crc32.NewIEEE()
hash.Write(stream)
return hash.Sum32(), nil
}
func compareDirectories(src string, dest string) error {
changes, err := archive.ChangesDirs(dest, src)
if err != nil {
return err
}
if len(changes) > 0 {
return fmt.Errorf("Unexpected differences after untar: %v", changes)
}
return nil
}
func compareFiles(src string, dest string) error {
srcHash, err := getHash(src)
if err != nil {
return err
}
destHash, err := getHash(dest)
if err != nil {
return err
}
if srcHash != destHash {
return fmt.Errorf("%s is different from %s", src, dest)
}
return nil
}
func TestChrootTarUntarWithSymlink(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-TestChrootTarUntarWithSymlink")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "src")
if err := os.MkdirAll(src, 0700); err != nil {
t.Fatal(err)
}
if _, err := prepareSourceDirectory(10, src, true); err != nil {
t.Fatal(err)
}
dest := filepath.Join(tmpdir, "dest")
if err := TarUntar(src, dest); err != nil {
t.Fatal(err)
}
if err := compareDirectories(src, dest); err != nil {
t.Fatal(err)
}
}
func TestChrootCopyWithTar(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-TestChrootCopyWithTar")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "src")
if err := os.MkdirAll(src, 0700); err != nil {
t.Fatal(err)
}
if _, err := prepareSourceDirectory(10, src, true); err != nil {
t.Fatal(err)
}
// Copy directory
dest := filepath.Join(tmpdir, "dest")
if err := CopyWithTar(src, dest); err != nil {
t.Fatal(err)
}
if err := compareDirectories(src, dest); err != nil {
t.Fatal(err)
}
// Copy file
srcfile := filepath.Join(src, "file-1")
dest = filepath.Join(tmpdir, "destFile")
destfile := filepath.Join(dest, "file-1")
if err := CopyWithTar(srcfile, destfile); err != nil {
t.Fatal(err)
}
if err := compareFiles(srcfile, destfile); err != nil {
t.Fatal(err)
}
// Copy symbolic link
srcLinkfile := filepath.Join(src, "file-1-link")
dest = filepath.Join(tmpdir, "destSymlink")
destLinkfile := filepath.Join(dest, "file-1-link")
if err := CopyWithTar(srcLinkfile, destLinkfile); err != nil {
t.Fatal(err)
}
if err := compareFiles(srcLinkfile, destLinkfile); err != nil {
t.Fatal(err)
}
}
func TestChrootCopyFileWithTar(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-TestChrootCopyFileWithTar")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "src")
if err := os.MkdirAll(src, 0700); err != nil {
t.Fatal(err)
}
if _, err := prepareSourceDirectory(10, src, true); err != nil {
t.Fatal(err)
}
// Copy directory
dest := filepath.Join(tmpdir, "dest")
if err := CopyFileWithTar(src, dest); err == nil {
t.Fatal("Expected error on copying directory")
}
// Copy file
srcfile := filepath.Join(src, "file-1")
dest = filepath.Join(tmpdir, "destFile")
destfile := filepath.Join(dest, "file-1")
if err := CopyFileWithTar(srcfile, destfile); err != nil {
t.Fatal(err)
}
if err := compareFiles(srcfile, destfile); err != nil {
t.Fatal(err)
}
// Copy symbolic link
srcLinkfile := filepath.Join(src, "file-1-link")
dest = filepath.Join(tmpdir, "destSymlink")
destLinkfile := filepath.Join(dest, "file-1-link")
if err := CopyFileWithTar(srcLinkfile, destLinkfile); err != nil {
t.Fatal(err)
}
if err := compareFiles(srcLinkfile, destLinkfile); err != nil {
t.Fatal(err)
}
}
func TestChrootUntarPath(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarPath")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "src")
if err := os.MkdirAll(src, 0700); err != nil {
t.Fatal(err)
}
if _, err := prepareSourceDirectory(10, src, true); err != nil {
t.Fatal(err)
}
dest := filepath.Join(tmpdir, "dest")
// Untar a directory
if err := UntarPath(src, dest); err == nil {
t.Fatal("Expected error on untaring a directory")
}
// Untar a tar file
stream, err := archive.Tar(src, archive.Uncompressed)
if err != nil {
t.Fatal(err)
}
buf := new(bytes.Buffer)
buf.ReadFrom(stream)
tarfile := filepath.Join(tmpdir, "src.tar")
if err := ioutil.WriteFile(tarfile, buf.Bytes(), 0644); err != nil {
t.Fatal(err)
}
if err := UntarPath(tarfile, dest); err != nil {
t.Fatal(err)
}
if err := compareDirectories(src, dest); err != nil {
t.Fatal(err)
}
}
type slowEmptyTarReader struct {
size int
offset int
chunkSize int
}
// Read is a slow reader of an empty tar (like the output of "tar c --files-from /dev/null")
func (s *slowEmptyTarReader) Read(p []byte) (int, error) {
time.Sleep(100 * time.Millisecond)
count := s.chunkSize
if len(p) < s.chunkSize {
count = len(p)
}
for i := 0; i < count; i++ {
p[i] = 0
}
s.offset += count
if s.offset > s.size {
return count, io.EOF
}
return count, nil
}
func TestChrootUntarEmptyArchiveFromSlowReader(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarEmptyArchiveFromSlowReader")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
dest := filepath.Join(tmpdir, "dest")
if err := os.MkdirAll(dest, 0700); err != nil {
t.Fatal(err)
}
stream := &slowEmptyTarReader{size: 10240, chunkSize: 1024}
if err := Untar(stream, dest, nil); err != nil {
t.Fatal(err)
}
}
func TestChrootApplyEmptyArchiveFromSlowReader(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-TestChrootApplyEmptyArchiveFromSlowReader")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
dest := filepath.Join(tmpdir, "dest")
if err := os.MkdirAll(dest, 0700); err != nil {
t.Fatal(err)
}
stream := &slowEmptyTarReader{size: 10240, chunkSize: 1024}
if _, err := ApplyLayer(dest, stream); err != nil {
t.Fatal(err)
}
}
func TestChrootApplyDotDotFile(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "docker-TestChrootApplyDotDotFile")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "src")
if err := os.MkdirAll(src, 0700); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(src, "..gitme"), []byte(""), 0644); err != nil {
t.Fatal(err)
}
stream, err := archive.Tar(src, archive.Uncompressed)
if err != nil {
t.Fatal(err)
}
dest := filepath.Join(tmpdir, "dest")
if err := os.MkdirAll(dest, 0700); err != nil {
t.Fatal(err)
}
if _, err := ApplyLayer(dest, stream); err != nil {
t.Fatal(err)
}
}