2018-02-05 16:05:59 -05:00
|
|
|
package layer // import "github.com/docker/docker/layer"
|
2015-11-18 17:15:00 -05:00
|
|
|
|
|
|
|
import (
|
2021-08-24 06:10:50 -04:00
|
|
|
"io"
|
2022-09-22 20:59:58 -04:00
|
|
|
"os"
|
2022-09-22 20:49:47 -04:00
|
|
|
"path/filepath"
|
2016-02-28 23:16:10 -05:00
|
|
|
"runtime"
|
2015-11-18 17:15:00 -05:00
|
|
|
"sort"
|
|
|
|
"testing"
|
|
|
|
|
2017-08-03 20:22:00 -04:00
|
|
|
"github.com/containerd/continuity/driver"
|
2015-11-18 17:15:00 -05:00
|
|
|
"github.com/docker/docker/pkg/archive"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestMountInit(t *testing.T) {
|
2016-02-28 23:16:10 -05:00
|
|
|
// TODO Windows: Figure out why this is failing
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
t.Skip("Failing on Windows")
|
|
|
|
}
|
2016-02-09 14:38:37 -05:00
|
|
|
ls, _, cleanup := newTestStore(t)
|
2015-11-18 17:15:00 -05:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:21:31 -04:00
|
|
|
mountInit := func(root string) error {
|
2015-11-18 17:15:00 -05:00
|
|
|
return initfile.ApplyFile(root)
|
|
|
|
}
|
|
|
|
|
2016-11-16 16:31:23 -05:00
|
|
|
rwLayerOpts := &CreateRWLayerOpts{
|
|
|
|
InitFunc: mountInit,
|
|
|
|
}
|
|
|
|
m, err := ls.CreateRWLayer("fun-mount", layer.ChainID(), rwLayerOpts)
|
2015-11-18 17:15:00 -05:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-08-03 20:22:00 -04:00
|
|
|
pathFS, err := m.Mount("")
|
2015-11-18 17:15:00 -05:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:09:51 -04:00
|
|
|
fi, err := os.Stat(filepath.Join(pathFS, "testfile.txt"))
|
2015-11-18 17:15:00 -05:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:09:51 -04:00
|
|
|
f, err := os.Open(filepath.Join(pathFS, "testfile.txt"))
|
2015-11-18 17:15:00 -05:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-08-03 20:22:00 -04:00
|
|
|
defer f.Close()
|
2015-11-18 17:15:00 -05:00
|
|
|
|
2021-08-24 06:10:50 -04:00
|
|
|
b, err := io.ReadAll(f)
|
2015-11-18 17:15:00 -05:00
|
|
|
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) {
|
2016-02-28 23:16:10 -05:00
|
|
|
// TODO Windows: Figure out why this is failing
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
t.Skip("Failing on Windows")
|
|
|
|
}
|
2016-02-09 14:38:37 -05:00
|
|
|
ls, _, cleanup := newTestStore(t)
|
2015-11-18 17:15:00 -05:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:21:31 -04:00
|
|
|
mountInit := func(root string) error {
|
2015-11-18 17:15:00 -05:00
|
|
|
return newTestFile("file-init", contentInit, 0777).ApplyFile(root)
|
|
|
|
}
|
2016-11-16 16:31:23 -05:00
|
|
|
rwLayerOpts := &CreateRWLayerOpts{
|
|
|
|
InitFunc: mountInit,
|
|
|
|
}
|
2015-11-18 17:15:00 -05:00
|
|
|
|
2016-11-16 16:31:23 -05:00
|
|
|
m, err := ls.CreateRWLayer("mount-size", layer.ChainID(), rwLayerOpts)
|
2015-11-18 17:15:00 -05:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-08-03 20:22:00 -04:00
|
|
|
pathFS, err := m.Mount("")
|
2015-11-18 17:15:00 -05:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:09:51 -04:00
|
|
|
if err := os.WriteFile(filepath.Join(pathFS, "file2"), content2, 0755); err != nil {
|
2015-11-18 17:15:00 -05:00
|
|
|
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) {
|
2016-02-28 23:16:10 -05:00
|
|
|
// TODO Windows: Figure out why this is failing
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
t.Skip("Failing on Windows")
|
|
|
|
}
|
2016-02-09 14:38:37 -05:00
|
|
|
ls, _, cleanup := newTestStore(t)
|
2015-11-18 17:15:00 -05:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:21:31 -04:00
|
|
|
mountInit := func(root string) error {
|
2015-11-18 17:15:00 -05:00
|
|
|
return initfile.ApplyFile(root)
|
|
|
|
}
|
2016-11-16 16:31:23 -05:00
|
|
|
rwLayerOpts := &CreateRWLayerOpts{
|
|
|
|
InitFunc: mountInit,
|
|
|
|
}
|
2015-11-18 17:15:00 -05:00
|
|
|
|
2016-11-16 16:31:23 -05:00
|
|
|
m, err := ls.CreateRWLayer("mount-changes", layer.ChainID(), rwLayerOpts)
|
2015-11-18 17:15:00 -05:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2017-08-03 20:22:00 -04:00
|
|
|
pathFS, err := m.Mount("")
|
2015-11-18 17:15:00 -05:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:09:51 -04:00
|
|
|
if err := driver.LocalDriver.Lchmod(filepath.Join(pathFS, "testfile1.txt"), 0755); err != nil {
|
2015-11-18 17:15:00 -05:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:09:51 -04:00
|
|
|
if err := os.WriteFile(filepath.Join(pathFS, "testfile1.txt"), []byte("mount data!"), 0755); err != nil {
|
2015-11-18 17:15:00 -05:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:09:51 -04:00
|
|
|
if err := os.Remove(filepath.Join(pathFS, "testfile2.txt")); err != nil {
|
2015-11-18 17:15:00 -05:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:09:51 -04:00
|
|
|
if err := driver.LocalDriver.Lchmod(filepath.Join(pathFS, "testfile3.txt"), 0755); err != nil {
|
2015-11-18 17:15:00 -05:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:09:51 -04:00
|
|
|
if err := os.WriteFile(filepath.Join(pathFS, "testfile4.txt"), []byte("mount data!"), 0644); err != nil {
|
2015-11-18 17:15:00 -05:00
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2015-12-16 17:13:50 -05:00
|
|
|
changes, err := m.Changes()
|
2015-11-18 17:15:00 -05:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-04-25 10:23:48 -04:00
|
|
|
func TestMountApply(t *testing.T) {
|
|
|
|
// TODO Windows: Figure out why this is failing
|
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
t.Skip("Failing on Windows")
|
|
|
|
}
|
|
|
|
ls, _, cleanup := newTestStore(t)
|
|
|
|
defer cleanup()
|
|
|
|
|
|
|
|
basefile := newTestFile("testfile.txt", []byte("base data!"), 0644)
|
|
|
|
newfile := newTestFile("newfile.txt", []byte("new data!"), 0755)
|
|
|
|
|
|
|
|
li := initWithFiles(basefile)
|
|
|
|
layer, err := createLayer(ls, "", li)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
di := initWithFiles(newfile)
|
|
|
|
diffLayer, err := createLayer(ls, "", di)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
m, err := ls.CreateRWLayer("fun-mount", layer.ChainID(), nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
r, err := diffLayer.TarStream()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := m.ApplyDiff(r); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
pathFS, err := m.Mount("")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2022-09-23 14:09:51 -04:00
|
|
|
f, err := os.Open(filepath.Join(pathFS, "newfile.txt"))
|
2019-04-25 10:23:48 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
|
2021-08-24 06:10:50 -04:00
|
|
|
b, err := io.ReadAll(f)
|
2019-04-25 10:23:48 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if expected := "new data!"; string(b) != expected {
|
|
|
|
t.Fatalf("Unexpected test file contents %q, expected %q", string(b), expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-18 17:15:00 -05:00
|
|
|
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
|
|
|
|
}
|