695 lines
12 KiB
Go
695 lines
12 KiB
Go
package aufs
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"github.com/dotcloud/docker/archive"
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"testing"
|
|
)
|
|
|
|
var (
|
|
tmp = path.Join(os.TempDir(), "aufs-tests", "aufs")
|
|
)
|
|
|
|
func newDriver(t *testing.T) *Driver {
|
|
if err := os.MkdirAll(tmp, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
d, err := Init(tmp)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return d.(*Driver)
|
|
}
|
|
|
|
func TestNewDriver(t *testing.T) {
|
|
if err := os.MkdirAll(tmp, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
d, err := Init(tmp)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tmp)
|
|
if d == nil {
|
|
t.Fatalf("Driver should not be nil")
|
|
}
|
|
}
|
|
|
|
func TestAufsString(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if d.String() != "aufs" {
|
|
t.Fatalf("Expected aufs got %s", d.String())
|
|
}
|
|
}
|
|
|
|
func TestCreateDirStructure(t *testing.T) {
|
|
newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
paths := []string{
|
|
"mnt",
|
|
"layers",
|
|
"diff",
|
|
}
|
|
|
|
for _, p := range paths {
|
|
if _, err := os.Stat(path.Join(tmp, p)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// We should be able to create two drivers with the same dir structure
|
|
func TestNewDriverFromExistingDir(t *testing.T) {
|
|
if err := os.MkdirAll(tmp, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if _, err := Init(tmp); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := Init(tmp); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
os.RemoveAll(tmp)
|
|
}
|
|
|
|
func TestCreateNewDir(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestCreateNewDirStructure(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
paths := []string{
|
|
"mnt",
|
|
"diff",
|
|
"layers",
|
|
}
|
|
|
|
for _, p := range paths {
|
|
if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRemoveImage(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := d.Remove("1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
paths := []string{
|
|
"mnt",
|
|
"diff",
|
|
"layers",
|
|
}
|
|
|
|
for _, p := range paths {
|
|
if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil {
|
|
t.Fatalf("Error should not be nil because dirs with id 1 should be delted: %s", p)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetWithoutParent(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffPath, err := d.Get("1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
expected := path.Join(tmp, "diff", "1")
|
|
if diffPath != expected {
|
|
t.Fatalf("Expected path %s got %s", expected, diffPath)
|
|
}
|
|
}
|
|
|
|
func TestCleanupWithNoDirs(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Cleanup(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestCleanupWithDir(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := d.Cleanup(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestMountedFalseResponse(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
response, err := d.mounted("1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if response != false {
|
|
t.Fatalf("Response if dir id 1 is mounted should be false")
|
|
}
|
|
}
|
|
|
|
func TestMountedTrueReponse(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.Create("2", "1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err := d.Get("2")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
response, err := d.mounted("2")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if response != true {
|
|
t.Fatalf("Response if dir id 2 is mounted should be true")
|
|
}
|
|
}
|
|
|
|
func TestMountWithParent(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.Create("2", "1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
defer func() {
|
|
if err := d.Cleanup(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
|
|
mntPath, err := d.Get("2")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if mntPath == "" {
|
|
t.Fatal("mntPath should not be empty string")
|
|
}
|
|
|
|
expected := path.Join(tmp, "mnt", "2")
|
|
if mntPath != expected {
|
|
t.Fatalf("Expected %s got %s", expected, mntPath)
|
|
}
|
|
}
|
|
|
|
func TestRemoveMountedDir(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.Create("2", "1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
defer func() {
|
|
if err := d.Cleanup(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
|
|
mntPath, err := d.Get("2")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if mntPath == "" {
|
|
t.Fatal("mntPath should not be empty string")
|
|
}
|
|
|
|
mounted, err := d.mounted("2")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if !mounted {
|
|
t.Fatalf("Dir id 2 should be mounted")
|
|
}
|
|
|
|
if err := d.Remove("2"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestCreateWithInvalidParent(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", "docker"); err == nil {
|
|
t.Fatalf("Error should not be nil with parent does not exist")
|
|
}
|
|
}
|
|
|
|
func TestGetDiff(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffPath, err := d.Get("1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Add a file to the diff path with a fixed size
|
|
size := int64(1024)
|
|
|
|
f, err := os.Create(path.Join(diffPath, "test_file"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Truncate(size); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
f.Close()
|
|
|
|
a, err := d.Diff("1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if a == nil {
|
|
t.Fatalf("Archive should not be nil")
|
|
}
|
|
}
|
|
|
|
func TestChanges(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.Create("2", "1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
defer func() {
|
|
if err := d.Cleanup(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
|
|
mntPoint, err := d.Get("2")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Create a file to save in the mountpoint
|
|
f, err := os.Create(path.Join(mntPoint, "test.txt"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if _, err := f.WriteString("testline"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
changes, err := d.Changes("2")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(changes) != 1 {
|
|
t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
|
|
}
|
|
change := changes[0]
|
|
|
|
expectedPath := "/test.txt"
|
|
if change.Path != expectedPath {
|
|
t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
|
|
}
|
|
|
|
if change.Kind != archive.ChangeAdd {
|
|
t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
|
|
}
|
|
|
|
if err := d.Create("3", "2"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mntPoint, err = d.Get("3")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Create a file to save in the mountpoint
|
|
f, err = os.Create(path.Join(mntPoint, "test2.txt"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if _, err := f.WriteString("testline"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
changes, err = d.Changes("3")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(changes) != 1 {
|
|
t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
|
|
}
|
|
change = changes[0]
|
|
|
|
expectedPath = "/test2.txt"
|
|
if change.Path != expectedPath {
|
|
t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
|
|
}
|
|
|
|
if change.Kind != archive.ChangeAdd {
|
|
t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
|
|
}
|
|
}
|
|
|
|
func TestDiffSize(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffPath, err := d.Get("1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Add a file to the diff path with a fixed size
|
|
size := int64(1024)
|
|
|
|
f, err := os.Create(path.Join(diffPath, "test_file"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Truncate(size); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s, err := f.Stat()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
size = s.Size()
|
|
if err := f.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffSize, err := d.DiffSize("1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if diffSize != size {
|
|
t.Fatalf("Expected size to be %d got %d", size, diffSize)
|
|
}
|
|
}
|
|
|
|
func TestChildDiffSize(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffPath, err := d.Get("1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Add a file to the diff path with a fixed size
|
|
size := int64(1024)
|
|
|
|
f, err := os.Create(path.Join(diffPath, "test_file"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Truncate(size); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s, err := f.Stat()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
size = s.Size()
|
|
if err := f.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffSize, err := d.DiffSize("1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if diffSize != size {
|
|
t.Fatalf("Expected size to be %d got %d", size, diffSize)
|
|
}
|
|
|
|
if err := d.Create("2", "1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffSize, err = d.DiffSize("2")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// The diff size for the child should be zero
|
|
if diffSize != 0 {
|
|
t.Fatalf("Expected size to be %d got %d", 0, diffSize)
|
|
}
|
|
}
|
|
|
|
func TestExists(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if d.Exists("none") {
|
|
t.Fatal("id name should not exist in the driver")
|
|
}
|
|
|
|
if !d.Exists("1") {
|
|
t.Fatal("id 1 should exist in the driver")
|
|
}
|
|
}
|
|
|
|
func TestStatus(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
status := d.Status()
|
|
if status == nil || len(status) == 0 {
|
|
t.Fatal("Status should not be nil or empty")
|
|
}
|
|
rootDir := status[0]
|
|
dirs := status[1]
|
|
if rootDir[0] != "Root Dir" {
|
|
t.Fatalf("Expected Root Dir got %s", rootDir[0])
|
|
}
|
|
if rootDir[1] != d.rootPath() {
|
|
t.Fatalf("Expected %s got %s", d.rootPath(), rootDir[1])
|
|
}
|
|
if dirs[0] != "Dirs" {
|
|
t.Fatalf("Expected Dirs got %s", dirs[0])
|
|
}
|
|
if dirs[1] != "1" {
|
|
t.Fatalf("Expected 1 got %s", dirs[1])
|
|
}
|
|
}
|
|
|
|
func TestApplyDiff(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
|
|
if err := d.Create("1", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
diffPath, err := d.Get("1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Add a file to the diff path with a fixed size
|
|
size := int64(1024)
|
|
|
|
f, err := os.Create(path.Join(diffPath, "test_file"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := f.Truncate(size); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
f.Close()
|
|
|
|
diff, err := d.Diff("1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := d.Create("2", ""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := d.Create("3", "2"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := d.ApplyDiff("3", diff); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Ensure that the file is in the mount point for id 3
|
|
|
|
mountPoint, err := d.Get("3")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func hash(c string) string {
|
|
h := sha256.New()
|
|
fmt.Fprint(h, c)
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
}
|
|
|
|
func TestMountMoreThan42Layers(t *testing.T) {
|
|
d := newDriver(t)
|
|
defer os.RemoveAll(tmp)
|
|
defer d.Cleanup()
|
|
var last string
|
|
var expected int
|
|
|
|
for i := 1; i < 127; i++ {
|
|
expected++
|
|
var (
|
|
parent = fmt.Sprintf("%d", i-1)
|
|
current = fmt.Sprintf("%d", i)
|
|
)
|
|
|
|
if parent == "0" {
|
|
parent = ""
|
|
} else {
|
|
parent = hash(parent)
|
|
}
|
|
current = hash(current)
|
|
|
|
if err := d.Create(current, parent); err != nil {
|
|
t.Logf("Current layer %d", i)
|
|
t.Fatal(err)
|
|
}
|
|
point, err := d.Get(current)
|
|
if err != nil {
|
|
t.Logf("Current layer %d", i)
|
|
t.Fatal(err)
|
|
}
|
|
f, err := os.Create(path.Join(point, current))
|
|
if err != nil {
|
|
t.Logf("Current layer %d", i)
|
|
t.Fatal(err)
|
|
}
|
|
f.Close()
|
|
|
|
if i%10 == 0 {
|
|
if err := os.Remove(path.Join(point, parent)); err != nil {
|
|
t.Logf("Current layer %d", i)
|
|
t.Fatal(err)
|
|
}
|
|
expected--
|
|
}
|
|
last = current
|
|
}
|
|
|
|
// Perform the actual mount for the top most image
|
|
point, err := d.Get(last)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
files, err := ioutil.ReadDir(point)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(files) != expected {
|
|
t.Fatalf("Expected %d got %d", expected, len(files))
|
|
}
|
|
}
|