Преглед изворни кода

Merge pull request #12744 from vdemeester/11603-pkg-archive-test-coverage-2

Add coverage on pkg/archive (related to #11603)
Alexander Morozov пре 10 година
родитељ
комит
272e612b65
3 измењених фајлова са 559 додато и 0 уклоњено
  1. 309 0
      pkg/archive/archive_test.go
  2. 152 0
      pkg/archive/changes_test.go
  3. 98 0
      pkg/archive/wrap_test.go

+ 309 - 0
pkg/archive/archive_test.go

@@ -207,6 +207,315 @@ func TestCmdStreamGood(t *testing.T) {
 	}
 }
 
+func TestUntarPathWithInvalidDest(t *testing.T) {
+	tempFolder, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tempFolder)
+	invalidDestFolder := path.Join(tempFolder, "invalidDest")
+	// Create a src file
+	srcFile := path.Join(tempFolder, "src")
+	_, err = os.Create(srcFile)
+	if err != nil {
+		t.Fatalf("Fail to create the source file")
+	}
+	err = UntarPath(srcFile, invalidDestFolder)
+	if err == nil {
+		t.Fatalf("UntarPath with invalid destination path should throw an error.")
+	}
+}
+
+func TestUntarPathWithInvalidSrc(t *testing.T) {
+	dest, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatalf("Fail to create the destination file")
+	}
+	defer os.RemoveAll(dest)
+	err = UntarPath("/invalid/path", dest)
+	if err == nil {
+		t.Fatalf("UntarPath with invalid src path should throw an error.")
+	}
+}
+
+func TestUntarPath(t *testing.T) {
+	tmpFolder, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpFolder)
+	srcFile := path.Join(tmpFolder, "src")
+	tarFile := path.Join(tmpFolder, "src.tar")
+	os.Create(path.Join(tmpFolder, "src"))
+	cmd := exec.Command("/bin/sh", "-c", "tar cf "+tarFile+" "+srcFile)
+	_, err = cmd.CombinedOutput()
+	if err != nil {
+		t.Fatal(err)
+	}
+	destFolder := path.Join(tmpFolder, "dest")
+	err = os.MkdirAll(destFolder, 0740)
+	if err != nil {
+		t.Fatalf("Fail to create the destination file")
+	}
+	err = UntarPath(tarFile, destFolder)
+	if err != nil {
+		t.Fatalf("UntarPath shouldn't throw an error, %s.", err)
+	}
+	expectedFile := path.Join(destFolder, srcFile)
+	_, err = os.Stat(expectedFile)
+	if err != nil {
+		t.Fatalf("Destination folder should contain the source file but did not.")
+	}
+}
+
+// Do the same test as above but with the destination as file, it should fail
+func TestUntarPathWithDestinationFile(t *testing.T) {
+	tmpFolder, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpFolder)
+	srcFile := path.Join(tmpFolder, "src")
+	tarFile := path.Join(tmpFolder, "src.tar")
+	os.Create(path.Join(tmpFolder, "src"))
+	cmd := exec.Command("/bin/sh", "-c", "tar cf "+tarFile+" "+srcFile)
+	_, err = cmd.CombinedOutput()
+	if err != nil {
+		t.Fatal(err)
+	}
+	destFile := path.Join(tmpFolder, "dest")
+	_, err = os.Create(destFile)
+	if err != nil {
+		t.Fatalf("Fail to create the destination file")
+	}
+	err = UntarPath(tarFile, destFile)
+	if err == nil {
+		t.Fatalf("UntarPath should throw an error if the destination if a file")
+	}
+}
+
+// Do the same test as above but with the destination folder already exists
+// and the destination file is a directory
+// It's working, see https://github.com/docker/docker/issues/10040
+func TestUntarPathWithDestinationSrcFileAsFolder(t *testing.T) {
+	tmpFolder, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpFolder)
+	srcFile := path.Join(tmpFolder, "src")
+	tarFile := path.Join(tmpFolder, "src.tar")
+	os.Create(srcFile)
+	cmd := exec.Command("/bin/sh", "-c", "tar cf "+tarFile+" "+srcFile)
+	_, err = cmd.CombinedOutput()
+	if err != nil {
+		t.Fatal(err)
+	}
+	destFolder := path.Join(tmpFolder, "dest")
+	err = os.MkdirAll(destFolder, 0740)
+	if err != nil {
+		t.Fatalf("Fail to create the destination folder")
+	}
+	// Let's create a folder that will has the same path as the extracted file (from tar)
+	destSrcFileAsFolder := path.Join(destFolder, srcFile)
+	err = os.MkdirAll(destSrcFileAsFolder, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = UntarPath(tarFile, destFolder)
+	if err != nil {
+		t.Fatalf("UntarPath should throw not throw an error if the extracted file already exists and is a folder")
+	}
+}
+
+func TestCopyWithTarInvalidSrc(t *testing.T) {
+	tempFolder, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatal(nil)
+	}
+	destFolder := path.Join(tempFolder, "dest")
+	invalidSrc := path.Join(tempFolder, "doesnotexists")
+	err = os.MkdirAll(destFolder, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = CopyWithTar(invalidSrc, destFolder)
+	if err == nil {
+		t.Fatalf("archiver.CopyWithTar with invalid src path should throw an error.")
+	}
+}
+
+func TestCopyWithTarInexistentDestWillCreateIt(t *testing.T) {
+	tempFolder, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatal(nil)
+	}
+	srcFolder := path.Join(tempFolder, "src")
+	inexistentDestFolder := path.Join(tempFolder, "doesnotexists")
+	err = os.MkdirAll(srcFolder, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = CopyWithTar(srcFolder, inexistentDestFolder)
+	if err != nil {
+		t.Fatalf("CopyWithTar with an inexistent folder shouldn't fail.")
+	}
+	_, err = os.Stat(inexistentDestFolder)
+	if err != nil {
+		t.Fatalf("CopyWithTar with an inexistent folder should create it.")
+	}
+}
+
+// Test CopyWithTar with a file as src
+func TestCopyWithTarSrcFile(t *testing.T) {
+	folder, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(folder)
+	dest := path.Join(folder, "dest")
+	srcFolder := path.Join(folder, "src")
+	src := path.Join(folder, path.Join("src", "src"))
+	err = os.MkdirAll(srcFolder, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = os.MkdirAll(dest, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ioutil.WriteFile(src, []byte("content"), 0777)
+	err = CopyWithTar(src, dest)
+	if err != nil {
+		t.Fatalf("archiver.CopyWithTar shouldn't throw an error, %s.", err)
+	}
+	_, err = os.Stat(dest)
+	// FIXME Check the content
+	if err != nil {
+		t.Fatalf("Destination file should be the same as the source.")
+	}
+}
+
+// Test CopyWithTar with a folder as src
+func TestCopyWithTarSrcFolder(t *testing.T) {
+	folder, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(folder)
+	dest := path.Join(folder, "dest")
+	src := path.Join(folder, path.Join("src", "folder"))
+	err = os.MkdirAll(src, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = os.MkdirAll(dest, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ioutil.WriteFile(path.Join(src, "file"), []byte("content"), 0777)
+	err = CopyWithTar(src, dest)
+	if err != nil {
+		t.Fatalf("archiver.CopyWithTar shouldn't throw an error, %s.", err)
+	}
+	_, err = os.Stat(dest)
+	// FIXME Check the content (the file inside)
+	if err != nil {
+		t.Fatalf("Destination folder should contain the source file but did not.")
+	}
+}
+
+func TestCopyFileWithTarInvalidSrc(t *testing.T) {
+	tempFolder, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tempFolder)
+	destFolder := path.Join(tempFolder, "dest")
+	err = os.MkdirAll(destFolder, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	invalidFile := path.Join(tempFolder, "doesnotexists")
+	err = CopyFileWithTar(invalidFile, destFolder)
+	if err == nil {
+		t.Fatalf("archiver.CopyWithTar with invalid src path should throw an error.")
+	}
+}
+
+func TestCopyFileWithTarInexistentDestWillCreateIt(t *testing.T) {
+	tempFolder, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatal(nil)
+	}
+	defer os.RemoveAll(tempFolder)
+	srcFile := path.Join(tempFolder, "src")
+	inexistentDestFolder := path.Join(tempFolder, "doesnotexists")
+	_, err = os.Create(srcFile)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = CopyFileWithTar(srcFile, inexistentDestFolder)
+	if err != nil {
+		t.Fatalf("CopyWithTar with an inexistent folder shouldn't fail.")
+	}
+	_, err = os.Stat(inexistentDestFolder)
+	if err != nil {
+		t.Fatalf("CopyWithTar with an inexistent folder should create it.")
+	}
+	// FIXME Test the src file and content
+}
+
+func TestCopyFileWithTarSrcFolder(t *testing.T) {
+	folder, err := ioutil.TempDir("", "docker-archive-copyfilewithtar-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(folder)
+	dest := path.Join(folder, "dest")
+	src := path.Join(folder, "srcfolder")
+	err = os.MkdirAll(src, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = os.MkdirAll(dest, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = CopyFileWithTar(src, dest)
+	if err == nil {
+		t.Fatalf("CopyFileWithTar should throw an error with a folder.")
+	}
+}
+
+func TestCopyFileWithTarSrcFile(t *testing.T) {
+	folder, err := ioutil.TempDir("", "docker-archive-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(folder)
+	dest := path.Join(folder, "dest")
+	srcFolder := path.Join(folder, "src")
+	src := path.Join(folder, path.Join("src", "src"))
+	err = os.MkdirAll(srcFolder, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	err = os.MkdirAll(dest, 0740)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ioutil.WriteFile(src, []byte("content"), 0777)
+	err = CopyWithTar(src, dest+"/")
+	if err != nil {
+		t.Fatalf("archiver.CopyFileWithTar shouldn't throw an error, %s.", err)
+	}
+	_, err = os.Stat(dest)
+	if err != nil {
+		t.Fatalf("Destination folder should contain the source file but did not.")
+	}
+}
+
 func TestTarFiles(t *testing.T) {
 	// try without hardlinks
 	if err := checkNoChanges(1000, false); err != nil {

+ 152 - 0
pkg/archive/changes_test.go

@@ -6,6 +6,7 @@ import (
 	"os/exec"
 	"path"
 	"sort"
+	"syscall"
 	"testing"
 	"time"
 )
@@ -91,17 +92,130 @@ func createSampleDir(t *testing.T, root string) {
 	}
 }
 
+func TestChangeString(t *testing.T) {
+	modifiyChange := Change{"change", ChangeModify}
+	toString := modifiyChange.String()
+	if toString != "C change" {
+		t.Fatalf("String() of a change with ChangeModifiy Kind should have been %s but was %s", "C change", toString)
+	}
+	addChange := Change{"change", ChangeAdd}
+	toString = addChange.String()
+	if toString != "A change" {
+		t.Fatalf("String() of a change with ChangeAdd Kind should have been %s but was %s", "A change", toString)
+	}
+	deleteChange := Change{"change", ChangeDelete}
+	toString = deleteChange.String()
+	if toString != "D change" {
+		t.Fatalf("String() of a change with ChangeDelete Kind should have been %s but was %s", "D change", toString)
+	}
+}
+
+func TestChangesWithNoChanges(t *testing.T) {
+	rwLayer, err := ioutil.TempDir("", "docker-changes-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(rwLayer)
+	layer, err := ioutil.TempDir("", "docker-changes-test-layer")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(layer)
+	createSampleDir(t, layer)
+	changes, err := Changes([]string{layer}, rwLayer)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(changes) != 0 {
+		t.Fatalf("Changes with no difference should have detect no changes, but detected %d", len(changes))
+	}
+}
+
+func TestChangesWithChanges(t *testing.T) {
+	rwLayer, err := ioutil.TempDir("", "docker-changes-test")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(rwLayer)
+	// Create a folder
+	dir1 := path.Join(rwLayer, "dir1")
+	os.MkdirAll(dir1, 0740)
+	deletedFile := path.Join(dir1, ".wh.file1-2")
+	ioutil.WriteFile(deletedFile, []byte{}, 0600)
+	modifiedFile := path.Join(dir1, "file1-1")
+	ioutil.WriteFile(modifiedFile, []byte{0x00}, 01444)
+	// Let's add a subfolder for a newFile
+	subfolder := path.Join(dir1, "subfolder")
+	os.MkdirAll(subfolder, 0740)
+	newFile := path.Join(subfolder, "newFile")
+	ioutil.WriteFile(newFile, []byte{}, 0740)
+	// Let's create folders that with have the role of layers with the same data
+	layer, err := ioutil.TempDir("", "docker-changes-test-layer")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(layer)
+	createSampleDir(t, layer)
+	os.MkdirAll(path.Join(layer, "dir1/subfolder"), 0740)
+
+	// Let's modify modtime for dir1 to be sure it's the same for the two layer (to not having false positive)
+	fi, err := os.Stat(dir1)
+	if err != nil {
+		return
+	}
+	mtime := fi.ModTime()
+	stat := fi.Sys().(*syscall.Stat_t)
+	atime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
+
+	layerDir1 := path.Join(layer, "dir1")
+	os.Chtimes(layerDir1, atime, mtime)
+
+	changes, err := Changes([]string{layer}, rwLayer)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	sort.Sort(changesByPath(changes))
+
+	expectedChanges := []Change{
+		{"/dir1/file1-1", ChangeModify},
+		{"/dir1/file1-2", ChangeDelete},
+		{"/dir1/subfolder", ChangeModify},
+		{"/dir1/subfolder/newFile", ChangeAdd},
+	}
+
+	for i := 0; i < max(len(changes), len(expectedChanges)); i++ {
+		if i >= len(expectedChanges) {
+			t.Fatalf("unexpected change %s\n", changes[i].String())
+		}
+		if i >= len(changes) {
+			t.Fatalf("no change for expected change %s\n", expectedChanges[i].String())
+		}
+		if changes[i].Path == expectedChanges[i].Path {
+			if changes[i] != expectedChanges[i] {
+				t.Fatalf("Wrong change for %s, expected %s, got %s\n", changes[i].Path, changes[i].String(), expectedChanges[i].String())
+			}
+		} else if changes[i].Path < expectedChanges[i].Path {
+			t.Fatalf("unexpected change %s\n", changes[i].String())
+		} else {
+			t.Fatalf("no change for expected change %s != %s\n", expectedChanges[i].String(), changes[i].String())
+		}
+	}
+}
+
 // Create an directory, copy it, make sure we report no changes between the two
 func TestChangesDirsEmpty(t *testing.T) {
 	src, err := ioutil.TempDir("", "docker-changes-test")
 	if err != nil {
 		t.Fatal(err)
 	}
+	defer os.RemoveAll(src)
 	createSampleDir(t, src)
 	dst := src + "-copy"
 	if err := copyDir(src, dst); err != nil {
 		t.Fatal(err)
 	}
+	defer os.RemoveAll(dst)
 	changes, err := ChangesDirs(dst, src)
 	if err != nil {
 		t.Fatal(err)
@@ -291,3 +405,41 @@ func TestApplyLayer(t *testing.T) {
 		t.Fatalf("Unexpected differences after reapplying mutation: %v", changes2)
 	}
 }
+
+func TestChangesSizeWithNoChanges(t *testing.T) {
+	size := ChangesSize("/tmp", nil)
+	if size != 0 {
+		t.Fatalf("ChangesSizes with no changes should be 0, was %d", size)
+	}
+}
+
+func TestChangesSizeWithOnlyDeleteChanges(t *testing.T) {
+	changes := []Change{
+		{Path: "deletedPath", Kind: ChangeDelete},
+	}
+	size := ChangesSize("/tmp", changes)
+	if size != 0 {
+		t.Fatalf("ChangesSizes with only delete changes should be 0, was %d", size)
+	}
+}
+
+func TestChangesSize(t *testing.T) {
+	parentPath, err := ioutil.TempDir("", "docker-changes-test")
+	defer os.RemoveAll(parentPath)
+	addition := path.Join(parentPath, "addition")
+	if err := ioutil.WriteFile(addition, []byte{0x01, 0x01, 0x01}, 0744); err != nil {
+		t.Fatal(err)
+	}
+	modification := path.Join(parentPath, "modification")
+	if err = ioutil.WriteFile(modification, []byte{0x01, 0x01, 0x01}, 0744); err != nil {
+		t.Fatal(err)
+	}
+	changes := []Change{
+		{Path: "addition", Kind: ChangeAdd},
+		{Path: "modification", Kind: ChangeModify},
+	}
+	size := ChangesSize(parentPath, changes)
+	if size != 6 {
+		t.Fatalf("ChangesSizes with only delete changes should be 0, was %d", size)
+	}
+}

+ 98 - 0
pkg/archive/wrap_test.go

@@ -0,0 +1,98 @@
+package archive
+
+import (
+	"archive/tar"
+	"bytes"
+	"io"
+	"testing"
+)
+
+func TestGenerateEmptyFile(t *testing.T) {
+	archive, err := Generate("emptyFile")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if archive == nil {
+		t.Fatal("The generated archive should not be nil.")
+	}
+
+	expectedFiles := [][]string{
+		{"emptyFile", ""},
+	}
+
+	tr := tar.NewReader(archive)
+	actualFiles := make([][]string, 0, 10)
+	i := 0
+	for {
+		hdr, err := tr.Next()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			t.Fatal(err)
+		}
+		buf := new(bytes.Buffer)
+		buf.ReadFrom(tr)
+		content := buf.String()
+		actualFiles = append(actualFiles, []string{hdr.Name, content})
+		i++
+	}
+	if len(actualFiles) != len(expectedFiles) {
+		t.Fatalf("Number of expected file %d, got %d.", len(expectedFiles), len(actualFiles))
+	}
+	for i := 0; i < len(expectedFiles); i++ {
+		actual := actualFiles[i]
+		expected := expectedFiles[i]
+		if actual[0] != expected[0] {
+			t.Fatalf("Expected name '%s', Actual name '%s'", expected[0], actual[0])
+		}
+		if actual[1] != expected[1] {
+			t.Fatalf("Expected content '%s', Actual content '%s'", expected[1], actual[1])
+		}
+	}
+}
+
+func TestGenerateWithContent(t *testing.T) {
+	archive, err := Generate("file", "content")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if archive == nil {
+		t.Fatal("The generated archive should not be nil.")
+	}
+
+	expectedFiles := [][]string{
+		{"file", "content"},
+	}
+
+	tr := tar.NewReader(archive)
+	actualFiles := make([][]string, 0, 10)
+	i := 0
+	for {
+		hdr, err := tr.Next()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			t.Fatal(err)
+		}
+		buf := new(bytes.Buffer)
+		buf.ReadFrom(tr)
+		content := buf.String()
+		actualFiles = append(actualFiles, []string{hdr.Name, content})
+		i++
+	}
+	if len(actualFiles) != len(expectedFiles) {
+		t.Fatalf("Number of expected file %d, got %d.", len(expectedFiles), len(actualFiles))
+	}
+	for i := 0; i < len(expectedFiles); i++ {
+		actual := actualFiles[i]
+		expected := expectedFiles[i]
+		if actual[0] != expected[0] {
+			t.Fatalf("Expected name '%s', Actual name '%s'", expected[0], actual[0])
+		}
+		if actual[1] != expected[1] {
+			t.Fatalf("Expected content '%s', Actual content '%s'", expected[1], actual[1])
+		}
+	}
+}