500e77bad0
Layer store manages read-only and read-write layers on a union file system. Read only layers are always referenced by content addresses. Read-write layer identifiers are handled by the caller but upon registering its difference, the committed read-only layer will be referenced by content hash. Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan) Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
217 lines
4.7 KiB
Go
217 lines
4.7 KiB
Go
package layer
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"testing"
|
|
|
|
"github.com/docker/docker/pkg/archive"
|
|
)
|
|
|
|
func TestMountInit(t *testing.T) {
|
|
ls, cleanup := newTestStore(t)
|
|
defer cleanup()
|
|
|
|
basefile := newTestFile("testfile.txt", []byte("base data!"), 0644)
|
|
initfile := newTestFile("testfile.txt", []byte("init data!"), 0777)
|
|
|
|
li := initWithFiles(basefile)
|
|
layer, err := createLayer(ls, "", li)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
mountInit := func(root string) error {
|
|
return initfile.ApplyFile(root)
|
|
}
|
|
|
|
m, err := ls.Mount("fun-mount", layer.ChainID(), "", mountInit)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
path, err := m.Path()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
f, err := os.Open(filepath.Join(path, "testfile.txt"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
fi, err := f.Stat()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
b, err := ioutil.ReadAll(f)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if expected := "init data!"; string(b) != expected {
|
|
t.Fatalf("Unexpected test file contents %q, expected %q", string(b), expected)
|
|
}
|
|
|
|
if fi.Mode().Perm() != 0777 {
|
|
t.Fatalf("Unexpected filemode %o, expecting %o", fi.Mode().Perm(), 0777)
|
|
}
|
|
}
|
|
|
|
func TestMountSize(t *testing.T) {
|
|
ls, cleanup := newTestStore(t)
|
|
defer cleanup()
|
|
|
|
content1 := []byte("Base contents")
|
|
content2 := []byte("Mutable contents")
|
|
contentInit := []byte("why am I excluded from the size ☹")
|
|
|
|
li := initWithFiles(newTestFile("file1", content1, 0644))
|
|
layer, err := createLayer(ls, "", li)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
mountInit := func(root string) error {
|
|
return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
|
|
}
|
|
|
|
m, err := ls.Mount("mount-size", layer.ChainID(), "", mountInit)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
path, err := m.Path()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(path, "file2"), content2, 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
mountSize, err := m.Size()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if expected := len(content2); int(mountSize) != expected {
|
|
t.Fatalf("Unexpected mount size %d, expected %d", int(mountSize), expected)
|
|
}
|
|
}
|
|
|
|
func TestMountChanges(t *testing.T) {
|
|
ls, cleanup := newTestStore(t)
|
|
defer cleanup()
|
|
|
|
basefiles := []FileApplier{
|
|
newTestFile("testfile1.txt", []byte("base data!"), 0644),
|
|
newTestFile("testfile2.txt", []byte("base data!"), 0644),
|
|
newTestFile("testfile3.txt", []byte("base data!"), 0644),
|
|
}
|
|
initfile := newTestFile("testfile1.txt", []byte("init data!"), 0777)
|
|
|
|
li := initWithFiles(basefiles...)
|
|
layer, err := createLayer(ls, "", li)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
mountInit := func(root string) error {
|
|
return initfile.ApplyFile(root)
|
|
}
|
|
|
|
m, err := ls.Mount("mount-changes", layer.ChainID(), "", mountInit)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
path, err := m.Path()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := os.Chmod(filepath.Join(path, "testfile1.txt"), 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(path, "testfile1.txt"), []byte("mount data!"), 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := os.Remove(filepath.Join(path, "testfile2.txt")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := os.Chmod(filepath.Join(path, "testfile3.txt"), 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := ioutil.WriteFile(filepath.Join(path, "testfile4.txt"), []byte("mount data!"), 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
changes, err := ls.Changes("mount-changes")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if expected := 4; len(changes) != expected {
|
|
t.Fatalf("Wrong number of changes %d, expected %d", len(changes), expected)
|
|
}
|
|
|
|
sortChanges(changes)
|
|
|
|
assertChange(t, changes[0], archive.Change{
|
|
Path: "/testfile1.txt",
|
|
Kind: archive.ChangeModify,
|
|
})
|
|
assertChange(t, changes[1], archive.Change{
|
|
Path: "/testfile2.txt",
|
|
Kind: archive.ChangeDelete,
|
|
})
|
|
assertChange(t, changes[2], archive.Change{
|
|
Path: "/testfile3.txt",
|
|
Kind: archive.ChangeModify,
|
|
})
|
|
assertChange(t, changes[3], archive.Change{
|
|
Path: "/testfile4.txt",
|
|
Kind: archive.ChangeAdd,
|
|
})
|
|
}
|
|
|
|
func assertChange(t *testing.T, actual, expected archive.Change) {
|
|
if actual.Path != expected.Path {
|
|
t.Fatalf("Unexpected change path %s, expected %s", actual.Path, expected.Path)
|
|
}
|
|
if actual.Kind != expected.Kind {
|
|
t.Fatalf("Unexpected change type %s, expected %s", actual.Kind, expected.Kind)
|
|
}
|
|
}
|
|
|
|
func sortChanges(changes []archive.Change) {
|
|
cs := &changeSorter{
|
|
changes: changes,
|
|
}
|
|
sort.Sort(cs)
|
|
}
|
|
|
|
type changeSorter struct {
|
|
changes []archive.Change
|
|
}
|
|
|
|
func (cs *changeSorter) Len() int {
|
|
return len(cs.changes)
|
|
}
|
|
|
|
func (cs *changeSorter) Swap(i, j int) {
|
|
cs.changes[i], cs.changes[j] = cs.changes[j], cs.changes[i]
|
|
}
|
|
|
|
func (cs *changeSorter) Less(i, j int) bool {
|
|
return cs.changes[i].Path < cs.changes[j].Path
|
|
}
|