Switch to github.com/golang/dep for vendoring
Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
This commit is contained in:
parent
d6ab91be27
commit
8e5b17cf13
15431 changed files with 3971413 additions and 8881 deletions
2
vendor/github.com/containers/storage/pkg/archive/archive.go
generated
vendored
2
vendor/github.com/containers/storage/pkg/archive/archive.go
generated
vendored
|
@ -220,7 +220,7 @@ func CompressStream(dest io.Writer, compression Compression) (io.WriteCloser, er
|
|||
return writeBufWrapper, nil
|
||||
case Bzip2, Xz:
|
||||
// archive/bzip2 does not support writing, and there is no xz support at all
|
||||
// However, this is not a problem as docker only currently generates gzipped tars
|
||||
// However, this is not a problem as we only currently generates gzipped tars
|
||||
return nil, fmt.Errorf("Unsupported compression format %s", (&compression).Extension())
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported compression format %s", (&compression).Extension())
|
||||
|
|
1148
vendor/github.com/containers/storage/pkg/archive/archive_test.go
generated
vendored
Normal file
1148
vendor/github.com/containers/storage/pkg/archive/archive_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
245
vendor/github.com/containers/storage/pkg/archive/archive_unix_test.go
generated
vendored
Normal file
245
vendor/github.com/containers/storage/pkg/archive/archive_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,245 @@
|
|||
// +build !windows
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/storage/pkg/system"
|
||||
)
|
||||
|
||||
func TestCanonicalTarNameForPath(t *testing.T) {
|
||||
cases := []struct{ in, expected string }{
|
||||
{"foo", "foo"},
|
||||
{"foo/bar", "foo/bar"},
|
||||
{"foo/dir/", "foo/dir/"},
|
||||
}
|
||||
for _, v := range cases {
|
||||
if out, err := CanonicalTarNameForPath(v.in); err != nil {
|
||||
t.Fatalf("cannot get canonical name for path: %s: %v", v.in, err)
|
||||
} else if out != v.expected {
|
||||
t.Fatalf("wrong canonical tar name. expected:%s got:%s", v.expected, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalTarName(t *testing.T) {
|
||||
cases := []struct {
|
||||
in string
|
||||
isDir bool
|
||||
expected string
|
||||
}{
|
||||
{"foo", false, "foo"},
|
||||
{"foo", true, "foo/"},
|
||||
{"foo/bar", false, "foo/bar"},
|
||||
{"foo/bar", true, "foo/bar/"},
|
||||
}
|
||||
for _, v := range cases {
|
||||
if out, err := canonicalTarName(v.in, v.isDir); err != nil {
|
||||
t.Fatalf("cannot get canonical name for path: %s: %v", v.in, err)
|
||||
} else if out != v.expected {
|
||||
t.Fatalf("wrong canonical tar name. expected:%s got:%s", v.expected, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestChmodTarEntry(t *testing.T) {
|
||||
cases := []struct {
|
||||
in, expected os.FileMode
|
||||
}{
|
||||
{0000, 0000},
|
||||
{0777, 0777},
|
||||
{0644, 0644},
|
||||
{0755, 0755},
|
||||
{0444, 0444},
|
||||
}
|
||||
for _, v := range cases {
|
||||
if out := chmodTarEntry(v.in); out != v.expected {
|
||||
t.Fatalf("wrong chmod. expected:%v got:%v", v.expected, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTarWithHardLink(t *testing.T) {
|
||||
origin, err := ioutil.TempDir("", "docker-test-tar-hardlink")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(origin)
|
||||
if err := ioutil.WriteFile(filepath.Join(origin, "1"), []byte("hello world"), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Link(filepath.Join(origin, "1"), filepath.Join(origin, "2")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var i1, i2 uint64
|
||||
if i1, err = getNlink(filepath.Join(origin, "1")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// sanity check that we can hardlink
|
||||
if i1 != 2 {
|
||||
t.Skipf("skipping since hardlinks don't work here; expected 2 links, got %d", i1)
|
||||
}
|
||||
|
||||
dest, err := ioutil.TempDir("", "docker-test-tar-hardlink-dest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dest)
|
||||
|
||||
// we'll do this in two steps to separate failure
|
||||
fh, err := Tar(origin, Uncompressed)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// ensure we can read the whole thing with no error, before writing back out
|
||||
buf, err := ioutil.ReadAll(fh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bRdr := bytes.NewReader(buf)
|
||||
err = Untar(bRdr, dest, &TarOptions{Compression: Uncompressed})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if i1, err = getInode(filepath.Join(dest, "1")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if i2, err = getInode(filepath.Join(dest, "2")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if i1 != i2 {
|
||||
t.Errorf("expected matching inodes, but got %d and %d", i1, i2)
|
||||
}
|
||||
}
|
||||
|
||||
func getNlink(path string) (uint64, error) {
|
||||
stat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
statT, ok := stat.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("expected type *syscall.Stat_t, got %t", stat.Sys())
|
||||
}
|
||||
// We need this conversion on ARM64
|
||||
return uint64(statT.Nlink), nil
|
||||
}
|
||||
|
||||
func getInode(path string) (uint64, error) {
|
||||
stat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
statT, ok := stat.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("expected type *syscall.Stat_t, got %t", stat.Sys())
|
||||
}
|
||||
return statT.Ino, nil
|
||||
}
|
||||
|
||||
func TestTarWithBlockCharFifo(t *testing.T) {
|
||||
origin, err := ioutil.TempDir("", "docker-test-tar-hardlink")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(origin)
|
||||
if err := ioutil.WriteFile(filepath.Join(origin, "1"), []byte("hello world"), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := system.Mknod(filepath.Join(origin, "2"), syscall.S_IFBLK, int(system.Mkdev(int64(12), int64(5)))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := system.Mknod(filepath.Join(origin, "3"), syscall.S_IFCHR, int(system.Mkdev(int64(12), int64(5)))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := system.Mknod(filepath.Join(origin, "4"), syscall.S_IFIFO, int(system.Mkdev(int64(12), int64(5)))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dest, err := ioutil.TempDir("", "docker-test-tar-hardlink-dest")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dest)
|
||||
|
||||
// we'll do this in two steps to separate failure
|
||||
fh, err := Tar(origin, Uncompressed)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// ensure we can read the whole thing with no error, before writing back out
|
||||
buf, err := ioutil.ReadAll(fh)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
bRdr := bytes.NewReader(buf)
|
||||
err = Untar(bRdr, dest, &TarOptions{Compression: Uncompressed})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
changes, err := ChangesDirs(origin, dest)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(changes) > 0 {
|
||||
t.Fatalf("Tar with special device (block, char, fifo) should keep them (recreate them when untar) : %v", changes)
|
||||
}
|
||||
}
|
||||
|
||||
// TestTarUntarWithXattr is Unix as Lsetxattr is not supported on Windows
|
||||
func TestTarUntarWithXattr(t *testing.T) {
|
||||
origin, err := ioutil.TempDir("", "docker-test-untar-origin")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(origin)
|
||||
if err := ioutil.WriteFile(filepath.Join(origin, "1"), []byte("hello world"), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(origin, "2"), []byte("welcome!"), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(origin, "3"), []byte("will be ignored"), 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := system.Lsetxattr(filepath.Join(origin, "2"), "security.capability", []byte{0x00}, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, c := range []Compression{
|
||||
Uncompressed,
|
||||
Gzip,
|
||||
} {
|
||||
changes, err := tarUntar(t, origin, &TarOptions{
|
||||
Compression: c,
|
||||
ExcludePatterns: []string{"3"},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Error tar/untar for compression %s: %s", c.Extension(), err)
|
||||
}
|
||||
|
||||
if len(changes) != 1 || changes[0].Path != "/3" {
|
||||
t.Fatalf("Unexpected differences after tarUntar: %v", changes)
|
||||
}
|
||||
capability, _ := system.Lgetxattr(filepath.Join(origin, "2"), "security.capability")
|
||||
if capability == nil && capability[0] != 0x00 {
|
||||
t.Fatalf("Untar should have kept the 'security.capability' xattr.")
|
||||
}
|
||||
}
|
||||
}
|
91
vendor/github.com/containers/storage/pkg/archive/archive_windows_test.go
generated
vendored
Normal file
91
vendor/github.com/containers/storage/pkg/archive/archive_windows_test.go
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
// +build windows
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCopyFileWithInvalidDest(t *testing.T) {
|
||||
// TODO Windows: This is currently failing. Not sure what has
|
||||
// recently changed in CopyWithTar as used to pass. Further investigation
|
||||
// is required.
|
||||
t.Skip("Currently fails")
|
||||
folder, err := ioutil.TempDir("", "docker-archive-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(folder)
|
||||
dest := "c:dest"
|
||||
srcFolder := filepath.Join(folder, "src")
|
||||
src := filepath.Join(folder, "src", "src")
|
||||
err = os.MkdirAll(srcFolder, 0740)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ioutil.WriteFile(src, []byte("content"), 0777)
|
||||
err = CopyWithTar(src, dest)
|
||||
if err == nil {
|
||||
t.Fatalf("archiver.CopyWithTar should throw an error on invalid dest.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalTarNameForPath(t *testing.T) {
|
||||
cases := []struct {
|
||||
in, expected string
|
||||
shouldFail bool
|
||||
}{
|
||||
{"foo", "foo", false},
|
||||
{"foo/bar", "___", true}, // unix-styled windows path must fail
|
||||
{`foo\bar`, "foo/bar", false},
|
||||
}
|
||||
for _, v := range cases {
|
||||
if out, err := CanonicalTarNameForPath(v.in); err != nil && !v.shouldFail {
|
||||
t.Fatalf("cannot get canonical name for path: %s: %v", v.in, err)
|
||||
} else if v.shouldFail && err == nil {
|
||||
t.Fatalf("canonical path call should have failed with error. in=%s out=%s", v.in, out)
|
||||
} else if !v.shouldFail && out != v.expected {
|
||||
t.Fatalf("wrong canonical tar name. expected:%s got:%s", v.expected, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCanonicalTarName(t *testing.T) {
|
||||
cases := []struct {
|
||||
in string
|
||||
isDir bool
|
||||
expected string
|
||||
}{
|
||||
{"foo", false, "foo"},
|
||||
{"foo", true, "foo/"},
|
||||
{`foo\bar`, false, "foo/bar"},
|
||||
{`foo\bar`, true, "foo/bar/"},
|
||||
}
|
||||
for _, v := range cases {
|
||||
if out, err := canonicalTarName(v.in, v.isDir); err != nil {
|
||||
t.Fatalf("cannot get canonical name for path: %s: %v", v.in, err)
|
||||
} else if out != v.expected {
|
||||
t.Fatalf("wrong canonical tar name. expected:%s got:%s", v.expected, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestChmodTarEntry(t *testing.T) {
|
||||
cases := []struct {
|
||||
in, expected os.FileMode
|
||||
}{
|
||||
{0000, 0111},
|
||||
{0777, 0755},
|
||||
{0644, 0755},
|
||||
{0755, 0755},
|
||||
{0444, 0555},
|
||||
}
|
||||
for _, v := range cases {
|
||||
if out := chmodTarEntry(v.in); out != v.expected {
|
||||
t.Fatalf("wrong chmod. expected:%v got:%v", v.expected, out)
|
||||
}
|
||||
}
|
||||
}
|
127
vendor/github.com/containers/storage/pkg/archive/changes_posix_test.go
generated
vendored
Normal file
127
vendor/github.com/containers/storage/pkg/archive/changes_posix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,127 @@
|
|||
package archive
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHardLinkOrder(t *testing.T) {
|
||||
names := []string{"file1.txt", "file2.txt", "file3.txt"}
|
||||
msg := []byte("Hey y'all")
|
||||
|
||||
// Create dir
|
||||
src, err := ioutil.TempDir("", "docker-hardlink-test-src-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
//defer os.RemoveAll(src)
|
||||
for _, name := range names {
|
||||
func() {
|
||||
fh, err := os.Create(path.Join(src, name))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer fh.Close()
|
||||
if _, err = fh.Write(msg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
// Create dest, with changes that includes hardlinks
|
||||
dest, err := ioutil.TempDir("", "docker-hardlink-test-dest-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
os.RemoveAll(dest) // we just want the name, at first
|
||||
if err := copyDir(src, dest); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(dest)
|
||||
for _, name := range names {
|
||||
for i := 0; i < 5; i++ {
|
||||
if err := os.Link(path.Join(dest, name), path.Join(dest, fmt.Sprintf("%s.link%d", name, i))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get changes
|
||||
changes, err := ChangesDirs(dest, src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// sort
|
||||
sort.Sort(changesByPath(changes))
|
||||
|
||||
// ExportChanges
|
||||
ar, err := ExportChanges(dest, changes, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hdrs, err := walkHeaders(ar)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// reverse sort
|
||||
sort.Sort(sort.Reverse(changesByPath(changes)))
|
||||
// ExportChanges
|
||||
arRev, err := ExportChanges(dest, changes, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hdrsRev, err := walkHeaders(arRev)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// line up the two sets
|
||||
sort.Sort(tarHeaders(hdrs))
|
||||
sort.Sort(tarHeaders(hdrsRev))
|
||||
|
||||
// compare Size and LinkName
|
||||
for i := range hdrs {
|
||||
if hdrs[i].Name != hdrsRev[i].Name {
|
||||
t.Errorf("headers - expected name %q; but got %q", hdrs[i].Name, hdrsRev[i].Name)
|
||||
}
|
||||
if hdrs[i].Size != hdrsRev[i].Size {
|
||||
t.Errorf("headers - %q expected size %d; but got %d", hdrs[i].Name, hdrs[i].Size, hdrsRev[i].Size)
|
||||
}
|
||||
if hdrs[i].Typeflag != hdrsRev[i].Typeflag {
|
||||
t.Errorf("headers - %q expected type %d; but got %d", hdrs[i].Name, hdrs[i].Typeflag, hdrsRev[i].Typeflag)
|
||||
}
|
||||
if hdrs[i].Linkname != hdrsRev[i].Linkname {
|
||||
t.Errorf("headers - %q expected linkname %q; but got %q", hdrs[i].Name, hdrs[i].Linkname, hdrsRev[i].Linkname)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type tarHeaders []tar.Header
|
||||
|
||||
func (th tarHeaders) Len() int { return len(th) }
|
||||
func (th tarHeaders) Swap(i, j int) { th[j], th[i] = th[i], th[j] }
|
||||
func (th tarHeaders) Less(i, j int) bool { return th[i].Name < th[j].Name }
|
||||
|
||||
func walkHeaders(r io.Reader) ([]tar.Header, error) {
|
||||
t := tar.NewReader(r)
|
||||
headers := []tar.Header{}
|
||||
for {
|
||||
hdr, err := t.Next()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return headers, err
|
||||
}
|
||||
headers = append(headers, *hdr)
|
||||
}
|
||||
return headers, nil
|
||||
}
|
565
vendor/github.com/containers/storage/pkg/archive/changes_test.go
generated
vendored
Normal file
565
vendor/github.com/containers/storage/pkg/archive/changes_test.go
generated
vendored
Normal file
|
@ -0,0 +1,565 @@
|
|||
package archive
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"runtime"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containers/storage/pkg/system"
|
||||
)
|
||||
|
||||
func max(x, y int) int {
|
||||
if x >= y {
|
||||
return x
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
func copyDir(src, dst string) error {
|
||||
cmd := exec.Command("cp", "-a", src, dst)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type FileType uint32
|
||||
|
||||
const (
|
||||
Regular FileType = iota
|
||||
Dir
|
||||
Symlink
|
||||
)
|
||||
|
||||
type FileData struct {
|
||||
filetype FileType
|
||||
path string
|
||||
contents string
|
||||
permissions os.FileMode
|
||||
}
|
||||
|
||||
func createSampleDir(t *testing.T, root string) {
|
||||
files := []FileData{
|
||||
{Regular, "file1", "file1\n", 0600},
|
||||
{Regular, "file2", "file2\n", 0666},
|
||||
{Regular, "file3", "file3\n", 0404},
|
||||
{Regular, "file4", "file4\n", 0600},
|
||||
{Regular, "file5", "file5\n", 0600},
|
||||
{Regular, "file6", "file6\n", 0600},
|
||||
{Regular, "file7", "file7\n", 0600},
|
||||
{Dir, "dir1", "", 0740},
|
||||
{Regular, "dir1/file1-1", "file1-1\n", 01444},
|
||||
{Regular, "dir1/file1-2", "file1-2\n", 0666},
|
||||
{Dir, "dir2", "", 0700},
|
||||
{Regular, "dir2/file2-1", "file2-1\n", 0666},
|
||||
{Regular, "dir2/file2-2", "file2-2\n", 0666},
|
||||
{Dir, "dir3", "", 0700},
|
||||
{Regular, "dir3/file3-1", "file3-1\n", 0666},
|
||||
{Regular, "dir3/file3-2", "file3-2\n", 0666},
|
||||
{Dir, "dir4", "", 0700},
|
||||
{Regular, "dir4/file3-1", "file4-1\n", 0666},
|
||||
{Regular, "dir4/file3-2", "file4-2\n", 0666},
|
||||
{Symlink, "symlink1", "target1", 0666},
|
||||
{Symlink, "symlink2", "target2", 0666},
|
||||
{Symlink, "symlink3", root + "/file1", 0666},
|
||||
{Symlink, "symlink4", root + "/symlink3", 0666},
|
||||
{Symlink, "dirSymlink", root + "/dir1", 0740},
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
for _, info := range files {
|
||||
p := path.Join(root, info.path)
|
||||
if info.filetype == Dir {
|
||||
if err := os.MkdirAll(p, info.permissions); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else if info.filetype == Regular {
|
||||
if err := ioutil.WriteFile(p, []byte(info.contents), info.permissions); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else if info.filetype == Symlink {
|
||||
if err := os.Symlink(info.contents, p); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if info.filetype != Symlink {
|
||||
// Set a consistent ctime, atime for all files and dirs
|
||||
if err := system.Chtimes(p, now, now); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
// TODO Windows. There may be a way of running this, but turning off for now
|
||||
// as createSampleDir uses symlinks.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("symlinks on Windows")
|
||||
}
|
||||
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) {
|
||||
// TODO Windows. There may be a way of running this, but turning off for now
|
||||
// as createSampleDir uses symlinks.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("symlinks on Windows")
|
||||
}
|
||||
// Mock the readonly layer
|
||||
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)
|
||||
|
||||
// Mock the RW layer
|
||||
rwLayer, err := ioutil.TempDir("", "docker-changes-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(rwLayer)
|
||||
|
||||
// Create a folder in RW layer
|
||||
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)
|
||||
|
||||
changes, err := Changes([]string{layer}, rwLayer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedChanges := []Change{
|
||||
{"/dir1", ChangeModify},
|
||||
{"/dir1/file1-1", ChangeModify},
|
||||
{"/dir1/file1-2", ChangeDelete},
|
||||
{"/dir1/subfolder", ChangeModify},
|
||||
{"/dir1/subfolder/newFile", ChangeAdd},
|
||||
}
|
||||
checkChanges(expectedChanges, changes, t)
|
||||
}
|
||||
|
||||
// See https://github.com/docker/docker/pull/13590
|
||||
func TestChangesWithChangesGH13590(t *testing.T) {
|
||||
// TODO Windows. There may be a way of running this, but turning off for now
|
||||
// as createSampleDir uses symlinks.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("symlinks on Windows")
|
||||
}
|
||||
baseLayer, err := ioutil.TempDir("", "docker-changes-test.")
|
||||
defer os.RemoveAll(baseLayer)
|
||||
|
||||
dir3 := path.Join(baseLayer, "dir1/dir2/dir3")
|
||||
os.MkdirAll(dir3, 07400)
|
||||
|
||||
file := path.Join(dir3, "file.txt")
|
||||
ioutil.WriteFile(file, []byte("hello"), 0666)
|
||||
|
||||
layer, err := ioutil.TempDir("", "docker-changes-test2.")
|
||||
defer os.RemoveAll(layer)
|
||||
|
||||
// Test creating a new file
|
||||
if err := copyDir(baseLayer+"/dir1", layer+"/"); err != nil {
|
||||
t.Fatalf("Cmd failed: %q", err)
|
||||
}
|
||||
|
||||
os.Remove(path.Join(layer, "dir1/dir2/dir3/file.txt"))
|
||||
file = path.Join(layer, "dir1/dir2/dir3/file1.txt")
|
||||
ioutil.WriteFile(file, []byte("bye"), 0666)
|
||||
|
||||
changes, err := Changes([]string{baseLayer}, layer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedChanges := []Change{
|
||||
{"/dir1/dir2/dir3", ChangeModify},
|
||||
{"/dir1/dir2/dir3/file1.txt", ChangeAdd},
|
||||
}
|
||||
checkChanges(expectedChanges, changes, t)
|
||||
|
||||
// Now test changing a file
|
||||
layer, err = ioutil.TempDir("", "docker-changes-test3.")
|
||||
defer os.RemoveAll(layer)
|
||||
|
||||
if err := copyDir(baseLayer+"/dir1", layer+"/"); err != nil {
|
||||
t.Fatalf("Cmd failed: %q", err)
|
||||
}
|
||||
|
||||
file = path.Join(layer, "dir1/dir2/dir3/file.txt")
|
||||
ioutil.WriteFile(file, []byte("bye"), 0666)
|
||||
|
||||
changes, err = Changes([]string{baseLayer}, layer)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedChanges = []Change{
|
||||
{"/dir1/dir2/dir3/file.txt", ChangeModify},
|
||||
}
|
||||
checkChanges(expectedChanges, changes, t)
|
||||
}
|
||||
|
||||
// Create a directory, copy it, make sure we report no changes between the two
|
||||
func TestChangesDirsEmpty(t *testing.T) {
|
||||
// TODO Windows. There may be a way of running this, but turning off for now
|
||||
// as createSampleDir uses symlinks.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("symlinks on Windows")
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
if len(changes) != 0 {
|
||||
t.Fatalf("Reported changes for identical dirs: %v", changes)
|
||||
}
|
||||
os.RemoveAll(src)
|
||||
os.RemoveAll(dst)
|
||||
}
|
||||
|
||||
func mutateSampleDir(t *testing.T, root string) {
|
||||
// Remove a regular file
|
||||
if err := os.RemoveAll(path.Join(root, "file1")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Remove a directory
|
||||
if err := os.RemoveAll(path.Join(root, "dir1")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Remove a symlink
|
||||
if err := os.RemoveAll(path.Join(root, "symlink1")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Rewrite a file
|
||||
if err := ioutil.WriteFile(path.Join(root, "file2"), []byte("fileNN\n"), 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Replace a file
|
||||
if err := os.RemoveAll(path.Join(root, "file3")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(path.Join(root, "file3"), []byte("fileMM\n"), 0404); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Touch file
|
||||
if err := system.Chtimes(path.Join(root, "file4"), time.Now().Add(time.Second), time.Now().Add(time.Second)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Replace file with dir
|
||||
if err := os.RemoveAll(path.Join(root, "file5")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.MkdirAll(path.Join(root, "file5"), 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create new file
|
||||
if err := ioutil.WriteFile(path.Join(root, "filenew"), []byte("filenew\n"), 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create new dir
|
||||
if err := os.MkdirAll(path.Join(root, "dirnew"), 0766); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Create a new symlink
|
||||
if err := os.Symlink("targetnew", path.Join(root, "symlinknew")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Change a symlink
|
||||
if err := os.RemoveAll(path.Join(root, "symlink2")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink("target2change", path.Join(root, "symlink2")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Replace dir with file
|
||||
if err := os.RemoveAll(path.Join(root, "dir2")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(path.Join(root, "dir2"), []byte("dir2\n"), 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Touch dir
|
||||
if err := system.Chtimes(path.Join(root, "dir3"), time.Now().Add(time.Second), time.Now().Add(time.Second)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangesDirsMutated(t *testing.T) {
|
||||
// TODO Windows. There may be a way of running this, but turning off for now
|
||||
// as createSampleDir uses symlinks.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("symlinks on Windows")
|
||||
}
|
||||
src, err := ioutil.TempDir("", "docker-changes-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
createSampleDir(t, src)
|
||||
dst := src + "-copy"
|
||||
if err := copyDir(src, dst); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(src)
|
||||
defer os.RemoveAll(dst)
|
||||
|
||||
mutateSampleDir(t, dst)
|
||||
|
||||
changes, err := ChangesDirs(dst, src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
sort.Sort(changesByPath(changes))
|
||||
|
||||
expectedChanges := []Change{
|
||||
{"/dir1", ChangeDelete},
|
||||
{"/dir2", ChangeModify},
|
||||
{"/dirnew", ChangeAdd},
|
||||
{"/file1", ChangeDelete},
|
||||
{"/file2", ChangeModify},
|
||||
{"/file3", ChangeModify},
|
||||
{"/file4", ChangeModify},
|
||||
{"/file5", ChangeModify},
|
||||
{"/filenew", ChangeAdd},
|
||||
{"/symlink1", ChangeDelete},
|
||||
{"/symlink2", ChangeModify},
|
||||
{"/symlinknew", 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyLayer(t *testing.T) {
|
||||
// TODO Windows. There may be a way of running this, but turning off for now
|
||||
// as createSampleDir uses symlinks.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("symlinks on Windows")
|
||||
}
|
||||
src, err := ioutil.TempDir("", "docker-changes-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
createSampleDir(t, src)
|
||||
defer os.RemoveAll(src)
|
||||
dst := src + "-copy"
|
||||
if err := copyDir(src, dst); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mutateSampleDir(t, dst)
|
||||
defer os.RemoveAll(dst)
|
||||
|
||||
changes, err := ChangesDirs(dst, src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
layer, err := ExportChanges(dst, changes, nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
layerCopy, err := NewTempArchive(layer, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := ApplyLayer(src, layerCopy); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
changes2, err := ChangesDirs(src, dst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(changes2) != 0 {
|
||||
t.Fatalf("Unexpected differences after reapplying mutation: %v", changes2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangesSizeWithHardlinks(t *testing.T) {
|
||||
// TODO Windows. There may be a way of running this, but turning off for now
|
||||
// as createSampleDir uses symlinks.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("hardlinks on Windows")
|
||||
}
|
||||
srcDir, err := ioutil.TempDir("", "docker-test-srcDir")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(srcDir)
|
||||
|
||||
destDir, err := ioutil.TempDir("", "docker-test-destDir")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(destDir)
|
||||
|
||||
creationSize, err := prepareUntarSourceDirectory(100, destDir, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
changes, err := ChangesDirs(destDir, srcDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got := ChangesSize(destDir, changes)
|
||||
if got != int64(creationSize) {
|
||||
t.Errorf("Expected %d bytes of changes, got %d", creationSize, got)
|
||||
}
|
||||
}
|
||||
|
||||
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("Expected 6 bytes of changes, got %d", size)
|
||||
}
|
||||
}
|
||||
|
||||
func checkChanges(expectedChanges, changes []Change, t *testing.T) {
|
||||
sort.Sort(changesByPath(expectedChanges))
|
||||
sort.Sort(changesByPath(changes))
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
978
vendor/github.com/containers/storage/pkg/archive/copy_unix_test.go
generated
vendored
Normal file
978
vendor/github.com/containers/storage/pkg/archive/copy_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,978 @@
|
|||
// +build !windows
|
||||
|
||||
// TODO Windows: Some of these tests may be salvagable and portable to Windows.
|
||||
|
||||
package archive
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func removeAllPaths(paths ...string) {
|
||||
for _, path := range paths {
|
||||
os.RemoveAll(path)
|
||||
}
|
||||
}
|
||||
|
||||
func getTestTempDirs(t *testing.T) (tmpDirA, tmpDirB string) {
|
||||
var err error
|
||||
|
||||
if tmpDirA, err = ioutil.TempDir("", "archive-copy-test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if tmpDirB, err = ioutil.TempDir("", "archive-copy-test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func isNotDir(err error) bool {
|
||||
return strings.Contains(err.Error(), "not a directory")
|
||||
}
|
||||
|
||||
func joinTrailingSep(pathElements ...string) string {
|
||||
joined := filepath.Join(pathElements...)
|
||||
|
||||
return fmt.Sprintf("%s%c", joined, filepath.Separator)
|
||||
}
|
||||
|
||||
func fileContentsEqual(t *testing.T, filenameA, filenameB string) (err error) {
|
||||
t.Logf("checking for equal file contents: %q and %q\n", filenameA, filenameB)
|
||||
|
||||
fileA, err := os.Open(filenameA)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fileA.Close()
|
||||
|
||||
fileB, err := os.Open(filenameB)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer fileB.Close()
|
||||
|
||||
hasher := sha256.New()
|
||||
|
||||
if _, err = io.Copy(hasher, fileA); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hashA := hasher.Sum(nil)
|
||||
hasher.Reset()
|
||||
|
||||
if _, err = io.Copy(hasher, fileB); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
hashB := hasher.Sum(nil)
|
||||
|
||||
if !bytes.Equal(hashA, hashB) {
|
||||
err = fmt.Errorf("file content hashes not equal - expected %s, got %s", hex.EncodeToString(hashA), hex.EncodeToString(hashB))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func dirContentsEqual(t *testing.T, newDir, oldDir string) (err error) {
|
||||
t.Logf("checking for equal directory contents: %q and %q\n", newDir, oldDir)
|
||||
|
||||
var changes []Change
|
||||
|
||||
if changes, err = ChangesDirs(newDir, oldDir); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(changes) != 0 {
|
||||
err = fmt.Errorf("expected no changes between directories, but got: %v", changes)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func logDirContents(t *testing.T, dirPath string) {
|
||||
logWalkedPaths := filepath.WalkFunc(func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
t.Errorf("stat error for path %q: %s", path, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if info.IsDir() {
|
||||
path = joinTrailingSep(path)
|
||||
}
|
||||
|
||||
t.Logf("\t%s", path)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
t.Logf("logging directory contents: %q", dirPath)
|
||||
|
||||
if err := filepath.Walk(dirPath, logWalkedPaths); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testCopyHelper(t *testing.T, srcPath, dstPath string) (err error) {
|
||||
t.Logf("copying from %q to %q (not follow symbol link)", srcPath, dstPath)
|
||||
|
||||
return CopyResource(srcPath, dstPath, false)
|
||||
}
|
||||
|
||||
func testCopyHelperFSym(t *testing.T, srcPath, dstPath string) (err error) {
|
||||
t.Logf("copying from %q to %q (follow symbol link)", srcPath, dstPath)
|
||||
|
||||
return CopyResource(srcPath, dstPath, true)
|
||||
}
|
||||
|
||||
// Basic assumptions about SRC and DST:
|
||||
// 1. SRC must exist.
|
||||
// 2. If SRC ends with a trailing separator, it must be a directory.
|
||||
// 3. DST parent directory must exist.
|
||||
// 4. If DST exists as a file, it must not end with a trailing separator.
|
||||
|
||||
// First get these easy error cases out of the way.
|
||||
|
||||
// Test for error when SRC does not exist.
|
||||
func TestCopyErrSrcNotExists(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
if _, err := CopyInfoSourcePath(filepath.Join(tmpDirA, "file1"), false); !os.IsNotExist(err) {
|
||||
t.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for error when SRC ends in a trailing
|
||||
// path separator but it exists as a file.
|
||||
func TestCopyErrSrcNotDir(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
|
||||
if _, err := CopyInfoSourcePath(joinTrailingSep(tmpDirA, "file1"), false); !isNotDir(err) {
|
||||
t.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for error when SRC is a valid file or directory,
|
||||
// but the DST parent directory does not exist.
|
||||
func TestCopyErrDstParentNotExists(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
|
||||
srcInfo := CopyInfo{Path: filepath.Join(tmpDirA, "file1"), Exists: true, IsDir: false}
|
||||
|
||||
// Try with a file source.
|
||||
content, err := TarResource(srcInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
defer content.Close()
|
||||
|
||||
// Copy to a file whose parent does not exist.
|
||||
if err = CopyTo(content, srcInfo, filepath.Join(tmpDirB, "fakeParentDir", "file1")); err == nil {
|
||||
t.Fatal("expected IsNotExist error, but got nil instead")
|
||||
}
|
||||
|
||||
if !os.IsNotExist(err) {
|
||||
t.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
|
||||
}
|
||||
|
||||
// Try with a directory source.
|
||||
srcInfo = CopyInfo{Path: filepath.Join(tmpDirA, "dir1"), Exists: true, IsDir: true}
|
||||
|
||||
content, err = TarResource(srcInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
defer content.Close()
|
||||
|
||||
// Copy to a directory whose parent does not exist.
|
||||
if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "fakeParentDir", "fakeDstDir")); err == nil {
|
||||
t.Fatal("expected IsNotExist error, but got nil instead")
|
||||
}
|
||||
|
||||
if !os.IsNotExist(err) {
|
||||
t.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Test for error when DST ends in a trailing
|
||||
// path separator but exists as a file.
|
||||
func TestCopyErrDstNotDir(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A and B with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
createSampleDir(t, tmpDirB)
|
||||
|
||||
// Try with a file source.
|
||||
srcInfo := CopyInfo{Path: filepath.Join(tmpDirA, "file1"), Exists: true, IsDir: false}
|
||||
|
||||
content, err := TarResource(srcInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
defer content.Close()
|
||||
|
||||
if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "file1")); err == nil {
|
||||
t.Fatal("expected IsNotDir error, but got nil instead")
|
||||
}
|
||||
|
||||
if !isNotDir(err) {
|
||||
t.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
|
||||
}
|
||||
|
||||
// Try with a directory source.
|
||||
srcInfo = CopyInfo{Path: filepath.Join(tmpDirA, "dir1"), Exists: true, IsDir: true}
|
||||
|
||||
content, err = TarResource(srcInfo)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
defer content.Close()
|
||||
|
||||
if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "file1")); err == nil {
|
||||
t.Fatal("expected IsNotDir error, but got nil instead")
|
||||
}
|
||||
|
||||
if !isNotDir(err) {
|
||||
t.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Possibilities are reduced to the remaining 10 cases:
|
||||
//
|
||||
// case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action
|
||||
// ===================================================================================================
|
||||
// A | no | - | no | - | no | create file
|
||||
// B | no | - | no | - | yes | error
|
||||
// C | no | - | yes | no | - | overwrite file
|
||||
// D | no | - | yes | yes | - | create file in dst dir
|
||||
// E | yes | no | no | - | - | create dir, copy contents
|
||||
// F | yes | no | yes | no | - | error
|
||||
// G | yes | no | yes | yes | - | copy dir and contents
|
||||
// H | yes | yes | no | - | - | create dir, copy contents
|
||||
// I | yes | yes | yes | no | - | error
|
||||
// J | yes | yes | yes | yes | - | copy dir contents
|
||||
//
|
||||
|
||||
// A. SRC specifies a file and DST (no trailing path separator) doesn't
|
||||
// exist. This should create a file with the name DST and copy the
|
||||
// contents of the source file into it.
|
||||
func TestCopyCaseA(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
|
||||
srcPath := filepath.Join(tmpDirA, "file1")
|
||||
dstPath := filepath.Join(tmpDirB, "itWorks.txt")
|
||||
|
||||
var err error
|
||||
|
||||
if err = testCopyHelper(t, srcPath, dstPath); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = fileContentsEqual(t, srcPath, dstPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
os.Remove(dstPath)
|
||||
|
||||
symlinkPath := filepath.Join(tmpDirA, "symlink3")
|
||||
symlinkPath1 := filepath.Join(tmpDirA, "symlink4")
|
||||
linkTarget := filepath.Join(tmpDirA, "file1")
|
||||
|
||||
if err = testCopyHelperFSym(t, symlinkPath, dstPath); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = fileContentsEqual(t, linkTarget, dstPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
os.Remove(dstPath)
|
||||
if err = testCopyHelperFSym(t, symlinkPath1, dstPath); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = fileContentsEqual(t, linkTarget, dstPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// B. SRC specifies a file and DST (with trailing path separator) doesn't
|
||||
// exist. This should cause an error because the copy operation cannot
|
||||
// create a directory when copying a single file.
|
||||
func TestCopyCaseB(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
|
||||
srcPath := filepath.Join(tmpDirA, "file1")
|
||||
dstDir := joinTrailingSep(tmpDirB, "testDir")
|
||||
|
||||
var err error
|
||||
|
||||
if err = testCopyHelper(t, srcPath, dstDir); err == nil {
|
||||
t.Fatal("expected ErrDirNotExists error, but got nil instead")
|
||||
}
|
||||
|
||||
if err != ErrDirNotExists {
|
||||
t.Fatalf("expected ErrDirNotExists error, but got %T: %s", err, err)
|
||||
}
|
||||
|
||||
symlinkPath := filepath.Join(tmpDirA, "symlink3")
|
||||
|
||||
if err = testCopyHelperFSym(t, symlinkPath, dstDir); err == nil {
|
||||
t.Fatal("expected ErrDirNotExists error, but got nil instead")
|
||||
}
|
||||
if err != ErrDirNotExists {
|
||||
t.Fatalf("expected ErrDirNotExists error, but got %T: %s", err, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// C. SRC specifies a file and DST exists as a file. This should overwrite
|
||||
// the file at DST with the contents of the source file.
|
||||
func TestCopyCaseC(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A and B with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
createSampleDir(t, tmpDirB)
|
||||
|
||||
srcPath := filepath.Join(tmpDirA, "file1")
|
||||
dstPath := filepath.Join(tmpDirB, "file2")
|
||||
|
||||
var err error
|
||||
|
||||
// Ensure they start out different.
|
||||
if err = fileContentsEqual(t, srcPath, dstPath); err == nil {
|
||||
t.Fatal("expected different file contents")
|
||||
}
|
||||
|
||||
if err = testCopyHelper(t, srcPath, dstPath); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = fileContentsEqual(t, srcPath, dstPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// C. Symbol link following version:
|
||||
// SRC specifies a file and DST exists as a file. This should overwrite
|
||||
// the file at DST with the contents of the source file.
|
||||
func TestCopyCaseCFSym(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A and B with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
createSampleDir(t, tmpDirB)
|
||||
|
||||
symlinkPathBad := filepath.Join(tmpDirA, "symlink1")
|
||||
symlinkPath := filepath.Join(tmpDirA, "symlink3")
|
||||
linkTarget := filepath.Join(tmpDirA, "file1")
|
||||
dstPath := filepath.Join(tmpDirB, "file2")
|
||||
|
||||
var err error
|
||||
|
||||
// first to test broken link
|
||||
if err = testCopyHelperFSym(t, symlinkPathBad, dstPath); err == nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
// test symbol link -> symbol link -> target
|
||||
// Ensure they start out different.
|
||||
if err = fileContentsEqual(t, linkTarget, dstPath); err == nil {
|
||||
t.Fatal("expected different file contents")
|
||||
}
|
||||
|
||||
if err = testCopyHelperFSym(t, symlinkPath, dstPath); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = fileContentsEqual(t, linkTarget, dstPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// D. SRC specifies a file and DST exists as a directory. This should place
|
||||
// a copy of the source file inside it using the basename from SRC. Ensure
|
||||
// this works whether DST has a trailing path separator or not.
|
||||
func TestCopyCaseD(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A and B with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
createSampleDir(t, tmpDirB)
|
||||
|
||||
srcPath := filepath.Join(tmpDirA, "file1")
|
||||
dstDir := filepath.Join(tmpDirB, "dir1")
|
||||
dstPath := filepath.Join(dstDir, "file1")
|
||||
|
||||
var err error
|
||||
|
||||
// Ensure that dstPath doesn't exist.
|
||||
if _, err = os.Stat(dstPath); !os.IsNotExist(err) {
|
||||
t.Fatalf("did not expect dstPath %q to exist", dstPath)
|
||||
}
|
||||
|
||||
if err = testCopyHelper(t, srcPath, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = fileContentsEqual(t, srcPath, dstPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
if err = os.RemoveAll(dstDir); err != nil {
|
||||
t.Fatalf("unable to remove dstDir: %s", err)
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
|
||||
t.Fatalf("unable to make dstDir: %s", err)
|
||||
}
|
||||
|
||||
dstDir = joinTrailingSep(tmpDirB, "dir1")
|
||||
|
||||
if err = testCopyHelper(t, srcPath, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = fileContentsEqual(t, srcPath, dstPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// D. Symbol link following version:
|
||||
// SRC specifies a file and DST exists as a directory. This should place
|
||||
// a copy of the source file inside it using the basename from SRC. Ensure
|
||||
// this works whether DST has a trailing path separator or not.
|
||||
func TestCopyCaseDFSym(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A and B with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
createSampleDir(t, tmpDirB)
|
||||
|
||||
srcPath := filepath.Join(tmpDirA, "symlink4")
|
||||
linkTarget := filepath.Join(tmpDirA, "file1")
|
||||
dstDir := filepath.Join(tmpDirB, "dir1")
|
||||
dstPath := filepath.Join(dstDir, "symlink4")
|
||||
|
||||
var err error
|
||||
|
||||
// Ensure that dstPath doesn't exist.
|
||||
if _, err = os.Stat(dstPath); !os.IsNotExist(err) {
|
||||
t.Fatalf("did not expect dstPath %q to exist", dstPath)
|
||||
}
|
||||
|
||||
if err = testCopyHelperFSym(t, srcPath, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = fileContentsEqual(t, linkTarget, dstPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
if err = os.RemoveAll(dstDir); err != nil {
|
||||
t.Fatalf("unable to remove dstDir: %s", err)
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
|
||||
t.Fatalf("unable to make dstDir: %s", err)
|
||||
}
|
||||
|
||||
dstDir = joinTrailingSep(tmpDirB, "dir1")
|
||||
|
||||
if err = testCopyHelperFSym(t, srcPath, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = fileContentsEqual(t, linkTarget, dstPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// E. SRC specifies a directory and DST does not exist. This should create a
|
||||
// directory at DST and copy the contents of the SRC directory into the DST
|
||||
// directory. Ensure this works whether DST has a trailing path separator or
|
||||
// not.
|
||||
func TestCopyCaseE(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
|
||||
srcDir := filepath.Join(tmpDirA, "dir1")
|
||||
dstDir := filepath.Join(tmpDirB, "testDir")
|
||||
|
||||
var err error
|
||||
|
||||
if err = testCopyHelper(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
|
||||
t.Log("dir contents not equal")
|
||||
logDirContents(t, tmpDirA)
|
||||
logDirContents(t, tmpDirB)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
if err = os.RemoveAll(dstDir); err != nil {
|
||||
t.Fatalf("unable to remove dstDir: %s", err)
|
||||
}
|
||||
|
||||
dstDir = joinTrailingSep(tmpDirB, "testDir")
|
||||
|
||||
if err = testCopyHelper(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// E. Symbol link following version:
|
||||
// SRC specifies a directory and DST does not exist. This should create a
|
||||
// directory at DST and copy the contents of the SRC directory into the DST
|
||||
// directory. Ensure this works whether DST has a trailing path separator or
|
||||
// not.
|
||||
func TestCopyCaseEFSym(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
|
||||
srcDir := filepath.Join(tmpDirA, "dirSymlink")
|
||||
linkTarget := filepath.Join(tmpDirA, "dir1")
|
||||
dstDir := filepath.Join(tmpDirB, "testDir")
|
||||
|
||||
var err error
|
||||
|
||||
if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
|
||||
t.Log("dir contents not equal")
|
||||
logDirContents(t, tmpDirA)
|
||||
logDirContents(t, tmpDirB)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
if err = os.RemoveAll(dstDir); err != nil {
|
||||
t.Fatalf("unable to remove dstDir: %s", err)
|
||||
}
|
||||
|
||||
dstDir = joinTrailingSep(tmpDirB, "testDir")
|
||||
|
||||
if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// F. SRC specifies a directory and DST exists as a file. This should cause an
|
||||
// error as it is not possible to overwrite a file with a directory.
|
||||
func TestCopyCaseF(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A and B with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
createSampleDir(t, tmpDirB)
|
||||
|
||||
srcDir := filepath.Join(tmpDirA, "dir1")
|
||||
symSrcDir := filepath.Join(tmpDirA, "dirSymlink")
|
||||
dstFile := filepath.Join(tmpDirB, "file1")
|
||||
|
||||
var err error
|
||||
|
||||
if err = testCopyHelper(t, srcDir, dstFile); err == nil {
|
||||
t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
|
||||
}
|
||||
|
||||
if err != ErrCannotCopyDir {
|
||||
t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
|
||||
}
|
||||
|
||||
// now test with symbol link
|
||||
if err = testCopyHelperFSym(t, symSrcDir, dstFile); err == nil {
|
||||
t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
|
||||
}
|
||||
|
||||
if err != ErrCannotCopyDir {
|
||||
t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
|
||||
}
|
||||
}
|
||||
|
||||
// G. SRC specifies a directory and DST exists as a directory. This should copy
|
||||
// the SRC directory and all its contents to the DST directory. Ensure this
|
||||
// works whether DST has a trailing path separator or not.
|
||||
func TestCopyCaseG(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A and B with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
createSampleDir(t, tmpDirB)
|
||||
|
||||
srcDir := filepath.Join(tmpDirA, "dir1")
|
||||
dstDir := filepath.Join(tmpDirB, "dir2")
|
||||
resultDir := filepath.Join(dstDir, "dir1")
|
||||
|
||||
var err error
|
||||
|
||||
if err = testCopyHelper(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, resultDir, srcDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
if err = os.RemoveAll(dstDir); err != nil {
|
||||
t.Fatalf("unable to remove dstDir: %s", err)
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
|
||||
t.Fatalf("unable to make dstDir: %s", err)
|
||||
}
|
||||
|
||||
dstDir = joinTrailingSep(tmpDirB, "dir2")
|
||||
|
||||
if err = testCopyHelper(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, resultDir, srcDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// G. Symbol link version:
|
||||
// SRC specifies a directory and DST exists as a directory. This should copy
|
||||
// the SRC directory and all its contents to the DST directory. Ensure this
|
||||
// works whether DST has a trailing path separator or not.
|
||||
func TestCopyCaseGFSym(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A and B with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
createSampleDir(t, tmpDirB)
|
||||
|
||||
srcDir := filepath.Join(tmpDirA, "dirSymlink")
|
||||
linkTarget := filepath.Join(tmpDirA, "dir1")
|
||||
dstDir := filepath.Join(tmpDirB, "dir2")
|
||||
resultDir := filepath.Join(dstDir, "dirSymlink")
|
||||
|
||||
var err error
|
||||
|
||||
if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, resultDir, linkTarget); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
if err = os.RemoveAll(dstDir); err != nil {
|
||||
t.Fatalf("unable to remove dstDir: %s", err)
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
|
||||
t.Fatalf("unable to make dstDir: %s", err)
|
||||
}
|
||||
|
||||
dstDir = joinTrailingSep(tmpDirB, "dir2")
|
||||
|
||||
if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, resultDir, linkTarget); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// H. SRC specifies a directory's contents only and DST does not exist. This
|
||||
// should create a directory at DST and copy the contents of the SRC
|
||||
// directory (but not the directory itself) into the DST directory. Ensure
|
||||
// this works whether DST has a trailing path separator or not.
|
||||
func TestCopyCaseH(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
|
||||
srcDir := joinTrailingSep(tmpDirA, "dir1") + "."
|
||||
dstDir := filepath.Join(tmpDirB, "testDir")
|
||||
|
||||
var err error
|
||||
|
||||
if err = testCopyHelper(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
|
||||
t.Log("dir contents not equal")
|
||||
logDirContents(t, tmpDirA)
|
||||
logDirContents(t, tmpDirB)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
if err = os.RemoveAll(dstDir); err != nil {
|
||||
t.Fatalf("unable to remove dstDir: %s", err)
|
||||
}
|
||||
|
||||
dstDir = joinTrailingSep(tmpDirB, "testDir")
|
||||
|
||||
if err = testCopyHelper(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
|
||||
t.Log("dir contents not equal")
|
||||
logDirContents(t, tmpDirA)
|
||||
logDirContents(t, tmpDirB)
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// H. Symbol link following version:
|
||||
// SRC specifies a directory's contents only and DST does not exist. This
|
||||
// should create a directory at DST and copy the contents of the SRC
|
||||
// directory (but not the directory itself) into the DST directory. Ensure
|
||||
// this works whether DST has a trailing path separator or not.
|
||||
func TestCopyCaseHFSym(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
|
||||
srcDir := joinTrailingSep(tmpDirA, "dirSymlink") + "."
|
||||
linkTarget := filepath.Join(tmpDirA, "dir1")
|
||||
dstDir := filepath.Join(tmpDirB, "testDir")
|
||||
|
||||
var err error
|
||||
|
||||
if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
|
||||
t.Log("dir contents not equal")
|
||||
logDirContents(t, tmpDirA)
|
||||
logDirContents(t, tmpDirB)
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
if err = os.RemoveAll(dstDir); err != nil {
|
||||
t.Fatalf("unable to remove dstDir: %s", err)
|
||||
}
|
||||
|
||||
dstDir = joinTrailingSep(tmpDirB, "testDir")
|
||||
|
||||
if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
|
||||
t.Log("dir contents not equal")
|
||||
logDirContents(t, tmpDirA)
|
||||
logDirContents(t, tmpDirB)
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// I. SRC specifies a directory's contents only and DST exists as a file. This
|
||||
// should cause an error as it is not possible to overwrite a file with a
|
||||
// directory.
|
||||
func TestCopyCaseI(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A and B with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
createSampleDir(t, tmpDirB)
|
||||
|
||||
srcDir := joinTrailingSep(tmpDirA, "dir1") + "."
|
||||
symSrcDir := filepath.Join(tmpDirB, "dirSymlink")
|
||||
dstFile := filepath.Join(tmpDirB, "file1")
|
||||
|
||||
var err error
|
||||
|
||||
if err = testCopyHelper(t, srcDir, dstFile); err == nil {
|
||||
t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
|
||||
}
|
||||
|
||||
if err != ErrCannotCopyDir {
|
||||
t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
|
||||
}
|
||||
|
||||
// now try with symbol link of dir
|
||||
if err = testCopyHelperFSym(t, symSrcDir, dstFile); err == nil {
|
||||
t.Fatal("expected ErrCannotCopyDir error, but got nil instead")
|
||||
}
|
||||
|
||||
if err != ErrCannotCopyDir {
|
||||
t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
|
||||
}
|
||||
}
|
||||
|
||||
// J. SRC specifies a directory's contents only and DST exists as a directory.
|
||||
// This should copy the contents of the SRC directory (but not the directory
|
||||
// itself) into the DST directory. Ensure this works whether DST has a
|
||||
// trailing path separator or not.
|
||||
func TestCopyCaseJ(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A and B with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
createSampleDir(t, tmpDirB)
|
||||
|
||||
srcDir := joinTrailingSep(tmpDirA, "dir1") + "."
|
||||
dstDir := filepath.Join(tmpDirB, "dir5")
|
||||
|
||||
var err error
|
||||
|
||||
// first to create an empty dir
|
||||
if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
|
||||
t.Fatalf("unable to make dstDir: %s", err)
|
||||
}
|
||||
|
||||
if err = testCopyHelper(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
if err = os.RemoveAll(dstDir); err != nil {
|
||||
t.Fatalf("unable to remove dstDir: %s", err)
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
|
||||
t.Fatalf("unable to make dstDir: %s", err)
|
||||
}
|
||||
|
||||
dstDir = joinTrailingSep(tmpDirB, "dir5")
|
||||
|
||||
if err = testCopyHelper(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, srcDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// J. Symbol link following version:
|
||||
// SRC specifies a directory's contents only and DST exists as a directory.
|
||||
// This should copy the contents of the SRC directory (but not the directory
|
||||
// itself) into the DST directory. Ensure this works whether DST has a
|
||||
// trailing path separator or not.
|
||||
func TestCopyCaseJFSym(t *testing.T) {
|
||||
tmpDirA, tmpDirB := getTestTempDirs(t)
|
||||
defer removeAllPaths(tmpDirA, tmpDirB)
|
||||
|
||||
// Load A and B with some sample files and directories.
|
||||
createSampleDir(t, tmpDirA)
|
||||
createSampleDir(t, tmpDirB)
|
||||
|
||||
srcDir := joinTrailingSep(tmpDirA, "dirSymlink") + "."
|
||||
linkTarget := filepath.Join(tmpDirA, "dir1")
|
||||
dstDir := filepath.Join(tmpDirB, "dir5")
|
||||
|
||||
var err error
|
||||
|
||||
// first to create an empty dir
|
||||
if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
|
||||
t.Fatalf("unable to make dstDir: %s", err)
|
||||
}
|
||||
|
||||
if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Now try again but using a trailing path separator for dstDir.
|
||||
|
||||
if err = os.RemoveAll(dstDir); err != nil {
|
||||
t.Fatalf("unable to remove dstDir: %s", err)
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
|
||||
t.Fatalf("unable to make dstDir: %s", err)
|
||||
}
|
||||
|
||||
dstDir = joinTrailingSep(tmpDirB, "dir5")
|
||||
|
||||
if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil {
|
||||
t.Fatalf("unexpected error %T: %s", err, err)
|
||||
}
|
||||
|
||||
if err = dirContentsEqual(t, dstDir, linkTarget); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
2
vendor/github.com/containers/storage/pkg/archive/diff.go
generated
vendored
2
vendor/github.com/containers/storage/pkg/archive/diff.go
generated
vendored
|
@ -106,7 +106,7 @@ func UnpackLayer(dest string, layer Reader, options *TarOptions) (size int64, er
|
|||
basename := filepath.Base(hdr.Name)
|
||||
aufsHardlinks[basename] = hdr
|
||||
if aufsTempdir == "" {
|
||||
if aufsTempdir, err = ioutil.TempDir("", "dockerplnk"); err != nil {
|
||||
if aufsTempdir, err = ioutil.TempDir("", "storageplnk"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer os.RemoveAll(aufsTempdir)
|
||||
|
|
386
vendor/github.com/containers/storage/pkg/archive/diff_test.go
generated
vendored
Normal file
386
vendor/github.com/containers/storage/pkg/archive/diff_test.go
generated
vendored
Normal file
|
@ -0,0 +1,386 @@
|
|||
package archive
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"github.com/containers/storage/pkg/ioutils"
|
||||
)
|
||||
|
||||
func TestApplyLayerInvalidFilenames(t *testing.T) {
|
||||
// TODO Windows: Figure out how to fix this test.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Passes but hits breakoutError: platform and architecture is not supported")
|
||||
}
|
||||
for i, headers := range [][]*tar.Header{
|
||||
{
|
||||
{
|
||||
Name: "../victim/dotdot",
|
||||
Typeflag: tar.TypeReg,
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
// Note the leading slash
|
||||
Name: "/../victim/slash-dotdot",
|
||||
Typeflag: tar.TypeReg,
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := testBreakout("applylayer", "docker-TestApplyLayerInvalidFilenames", headers); err != nil {
|
||||
t.Fatalf("i=%d. %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyLayerInvalidHardlink(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("TypeLink support on Windows")
|
||||
}
|
||||
for i, headers := range [][]*tar.Header{
|
||||
{ // try reading victim/hello (../)
|
||||
{
|
||||
Name: "dotdot",
|
||||
Typeflag: tar.TypeLink,
|
||||
Linkname: "../victim/hello",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
{ // try reading victim/hello (/../)
|
||||
{
|
||||
Name: "slash-dotdot",
|
||||
Typeflag: tar.TypeLink,
|
||||
// Note the leading slash
|
||||
Linkname: "/../victim/hello",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
{ // try writing victim/file
|
||||
{
|
||||
Name: "loophole-victim",
|
||||
Typeflag: tar.TypeLink,
|
||||
Linkname: "../victim",
|
||||
Mode: 0755,
|
||||
},
|
||||
{
|
||||
Name: "loophole-victim/file",
|
||||
Typeflag: tar.TypeReg,
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
{ // try reading victim/hello (hardlink, symlink)
|
||||
{
|
||||
Name: "loophole-victim",
|
||||
Typeflag: tar.TypeLink,
|
||||
Linkname: "../victim",
|
||||
Mode: 0755,
|
||||
},
|
||||
{
|
||||
Name: "symlink",
|
||||
Typeflag: tar.TypeSymlink,
|
||||
Linkname: "loophole-victim/hello",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
{ // Try reading victim/hello (hardlink, hardlink)
|
||||
{
|
||||
Name: "loophole-victim",
|
||||
Typeflag: tar.TypeLink,
|
||||
Linkname: "../victim",
|
||||
Mode: 0755,
|
||||
},
|
||||
{
|
||||
Name: "hardlink",
|
||||
Typeflag: tar.TypeLink,
|
||||
Linkname: "loophole-victim/hello",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
{ // Try removing victim directory (hardlink)
|
||||
{
|
||||
Name: "loophole-victim",
|
||||
Typeflag: tar.TypeLink,
|
||||
Linkname: "../victim",
|
||||
Mode: 0755,
|
||||
},
|
||||
{
|
||||
Name: "loophole-victim",
|
||||
Typeflag: tar.TypeReg,
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := testBreakout("applylayer", "docker-TestApplyLayerInvalidHardlink", headers); err != nil {
|
||||
t.Fatalf("i=%d. %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyLayerInvalidSymlink(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("TypeSymLink support on Windows")
|
||||
}
|
||||
for i, headers := range [][]*tar.Header{
|
||||
{ // try reading victim/hello (../)
|
||||
{
|
||||
Name: "dotdot",
|
||||
Typeflag: tar.TypeSymlink,
|
||||
Linkname: "../victim/hello",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
{ // try reading victim/hello (/../)
|
||||
{
|
||||
Name: "slash-dotdot",
|
||||
Typeflag: tar.TypeSymlink,
|
||||
// Note the leading slash
|
||||
Linkname: "/../victim/hello",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
{ // try writing victim/file
|
||||
{
|
||||
Name: "loophole-victim",
|
||||
Typeflag: tar.TypeSymlink,
|
||||
Linkname: "../victim",
|
||||
Mode: 0755,
|
||||
},
|
||||
{
|
||||
Name: "loophole-victim/file",
|
||||
Typeflag: tar.TypeReg,
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
{ // try reading victim/hello (symlink, symlink)
|
||||
{
|
||||
Name: "loophole-victim",
|
||||
Typeflag: tar.TypeSymlink,
|
||||
Linkname: "../victim",
|
||||
Mode: 0755,
|
||||
},
|
||||
{
|
||||
Name: "symlink",
|
||||
Typeflag: tar.TypeSymlink,
|
||||
Linkname: "loophole-victim/hello",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
{ // try reading victim/hello (symlink, hardlink)
|
||||
{
|
||||
Name: "loophole-victim",
|
||||
Typeflag: tar.TypeSymlink,
|
||||
Linkname: "../victim",
|
||||
Mode: 0755,
|
||||
},
|
||||
{
|
||||
Name: "hardlink",
|
||||
Typeflag: tar.TypeLink,
|
||||
Linkname: "loophole-victim/hello",
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
{ // try removing victim directory (symlink)
|
||||
{
|
||||
Name: "loophole-victim",
|
||||
Typeflag: tar.TypeSymlink,
|
||||
Linkname: "../victim",
|
||||
Mode: 0755,
|
||||
},
|
||||
{
|
||||
Name: "loophole-victim",
|
||||
Typeflag: tar.TypeReg,
|
||||
Mode: 0644,
|
||||
},
|
||||
},
|
||||
} {
|
||||
if err := testBreakout("applylayer", "docker-TestApplyLayerInvalidSymlink", headers); err != nil {
|
||||
t.Fatalf("i=%d. %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyLayerWhiteouts(t *testing.T) {
|
||||
// TODO Windows: Figure out why this test fails
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Failing on Windows")
|
||||
}
|
||||
|
||||
wd, err := ioutil.TempDir("", "graphdriver-test-whiteouts")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(wd)
|
||||
|
||||
base := []string{
|
||||
".baz",
|
||||
"bar/",
|
||||
"bar/bax",
|
||||
"bar/bay/",
|
||||
"baz",
|
||||
"foo/",
|
||||
"foo/.abc",
|
||||
"foo/.bcd/",
|
||||
"foo/.bcd/a",
|
||||
"foo/cde/",
|
||||
"foo/cde/def",
|
||||
"foo/cde/efg",
|
||||
"foo/fgh",
|
||||
"foobar",
|
||||
}
|
||||
|
||||
type tcase struct {
|
||||
change, expected []string
|
||||
}
|
||||
|
||||
tcases := []tcase{
|
||||
{
|
||||
base,
|
||||
base,
|
||||
},
|
||||
{
|
||||
[]string{
|
||||
".bay",
|
||||
".wh.baz",
|
||||
"foo/",
|
||||
"foo/.bce",
|
||||
"foo/.wh..wh..opq",
|
||||
"foo/cde/",
|
||||
"foo/cde/efg",
|
||||
},
|
||||
[]string{
|
||||
".bay",
|
||||
".baz",
|
||||
"bar/",
|
||||
"bar/bax",
|
||||
"bar/bay/",
|
||||
"foo/",
|
||||
"foo/.bce",
|
||||
"foo/cde/",
|
||||
"foo/cde/efg",
|
||||
"foobar",
|
||||
},
|
||||
},
|
||||
{
|
||||
[]string{
|
||||
".bay",
|
||||
".wh..baz",
|
||||
".wh.foobar",
|
||||
"foo/",
|
||||
"foo/.abc",
|
||||
"foo/.wh.cde",
|
||||
"bar/",
|
||||
},
|
||||
[]string{
|
||||
".bay",
|
||||
"bar/",
|
||||
"bar/bax",
|
||||
"bar/bay/",
|
||||
"foo/",
|
||||
"foo/.abc",
|
||||
"foo/.bce",
|
||||
},
|
||||
},
|
||||
{
|
||||
[]string{
|
||||
".abc",
|
||||
".wh..wh..opq",
|
||||
"foobar",
|
||||
},
|
||||
[]string{
|
||||
".abc",
|
||||
"foobar",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tcases {
|
||||
l, err := makeTestLayer(tc.change)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = UnpackLayer(wd, l, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = l.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
paths, err := readDirContents(wd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tc.expected, paths) {
|
||||
t.Fatalf("invalid files for layer %d: expected %q, got %q", i, tc.expected, paths)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func makeTestLayer(paths []string) (rc io.ReadCloser, err error) {
|
||||
tmpDir, err := ioutil.TempDir("", "graphdriver-test-mklayer")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
os.RemoveAll(tmpDir)
|
||||
}
|
||||
}()
|
||||
for _, p := range paths {
|
||||
if p[len(p)-1] == filepath.Separator {
|
||||
if err = os.MkdirAll(filepath.Join(tmpDir, p), 0700); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if err = ioutil.WriteFile(filepath.Join(tmpDir, p), nil, 0600); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
archive, err := Tar(tmpDir, Uncompressed)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return ioutils.NewReadCloserWrapper(archive, func() error {
|
||||
err := archive.Close()
|
||||
os.RemoveAll(tmpDir)
|
||||
return err
|
||||
}), nil
|
||||
}
|
||||
|
||||
func readDirContents(root string) ([]string, error) {
|
||||
var files []string
|
||||
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if path == root {
|
||||
return nil
|
||||
}
|
||||
rel, err := filepath.Rel(root, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
rel = rel + "/"
|
||||
}
|
||||
files = append(files, rel)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return files, nil
|
||||
}
|
4
vendor/github.com/containers/storage/pkg/archive/example_changes.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/archive/example_changes.go
generated
vendored
|
@ -39,7 +39,7 @@ func main() {
|
|||
|
||||
if len(*flNewDir) == 0 {
|
||||
var err error
|
||||
newDir, err = ioutil.TempDir("", "docker-test-newDir")
|
||||
newDir, err = ioutil.TempDir("", "storage-test-newDir")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ func main() {
|
|||
}
|
||||
|
||||
if len(*flOldDir) == 0 {
|
||||
oldDir, err := ioutil.TempDir("", "docker-test-oldDir")
|
||||
oldDir, err := ioutil.TempDir("", "storage-test-oldDir")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
BIN
vendor/github.com/containers/storage/pkg/archive/testdata/broken.tar
generated
vendored
Normal file
BIN
vendor/github.com/containers/storage/pkg/archive/testdata/broken.tar
generated
vendored
Normal file
Binary file not shown.
166
vendor/github.com/containers/storage/pkg/archive/utils_test.go
generated
vendored
Normal file
166
vendor/github.com/containers/storage/pkg/archive/utils_test.go
generated
vendored
Normal file
|
@ -0,0 +1,166 @@
|
|||
package archive
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
var testUntarFns = map[string]func(string, io.Reader) error{
|
||||
"untar": func(dest string, r io.Reader) error {
|
||||
return Untar(r, dest, nil)
|
||||
},
|
||||
"applylayer": func(dest string, r io.Reader) error {
|
||||
_, err := ApplyLayer(dest, Reader(r))
|
||||
return err
|
||||
},
|
||||
}
|
||||
|
||||
// testBreakout is a helper function that, within the provided `tmpdir` directory,
|
||||
// creates a `victim` folder with a generated `hello` file in it.
|
||||
// `untar` extracts to a directory named `dest`, the tar file created from `headers`.
|
||||
//
|
||||
// Here are the tested scenarios:
|
||||
// - removed `victim` folder (write)
|
||||
// - removed files from `victim` folder (write)
|
||||
// - new files in `victim` folder (write)
|
||||
// - modified files in `victim` folder (write)
|
||||
// - file in `dest` with same content as `victim/hello` (read)
|
||||
//
|
||||
// When using testBreakout make sure you cover one of the scenarios listed above.
|
||||
func testBreakout(untarFn string, tmpdir string, headers []*tar.Header) error {
|
||||
tmpdir, err := ioutil.TempDir("", tmpdir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
dest := filepath.Join(tmpdir, "dest")
|
||||
if err := os.Mkdir(dest, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
victim := filepath.Join(tmpdir, "victim")
|
||||
if err := os.Mkdir(victim, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
hello := filepath.Join(victim, "hello")
|
||||
helloData, err := time.Now().MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(hello, helloData, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
helloStat, err := os.Stat(hello)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reader, writer := io.Pipe()
|
||||
go func() {
|
||||
t := tar.NewWriter(writer)
|
||||
for _, hdr := range headers {
|
||||
t.WriteHeader(hdr)
|
||||
}
|
||||
t.Close()
|
||||
}()
|
||||
|
||||
untar := testUntarFns[untarFn]
|
||||
if untar == nil {
|
||||
return fmt.Errorf("could not find untar function %q in testUntarFns", untarFn)
|
||||
}
|
||||
if err := untar(dest, reader); err != nil {
|
||||
if _, ok := err.(breakoutError); !ok {
|
||||
// If untar returns an error unrelated to an archive breakout,
|
||||
// then consider this an unexpected error and abort.
|
||||
return err
|
||||
}
|
||||
// Here, untar detected the breakout.
|
||||
// Let's move on verifying that indeed there was no breakout.
|
||||
fmt.Printf("breakoutError: %v\n", err)
|
||||
}
|
||||
|
||||
// Check victim folder
|
||||
f, err := os.Open(victim)
|
||||
if err != nil {
|
||||
// codepath taken if victim folder was removed
|
||||
return fmt.Errorf("archive breakout: error reading %q: %v", victim, err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Check contents of victim folder
|
||||
//
|
||||
// We are only interested in getting 2 files from the victim folder, because if all is well
|
||||
// we expect only one result, the `hello` file. If there is a second result, it cannot
|
||||
// hold the same name `hello` and we assume that a new file got created in the victim folder.
|
||||
// That is enough to detect an archive breakout.
|
||||
names, err := f.Readdirnames(2)
|
||||
if err != nil {
|
||||
// codepath taken if victim is not a folder
|
||||
return fmt.Errorf("archive breakout: error reading directory content of %q: %v", victim, err)
|
||||
}
|
||||
for _, name := range names {
|
||||
if name != "hello" {
|
||||
// codepath taken if new file was created in victim folder
|
||||
return fmt.Errorf("archive breakout: new file %q", name)
|
||||
}
|
||||
}
|
||||
|
||||
// Check victim/hello
|
||||
f, err = os.Open(hello)
|
||||
if err != nil {
|
||||
// codepath taken if read permissions were removed
|
||||
return fmt.Errorf("archive breakout: could not lstat %q: %v", hello, err)
|
||||
}
|
||||
defer f.Close()
|
||||
b, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if helloStat.IsDir() != fi.IsDir() ||
|
||||
// TODO: cannot check for fi.ModTime() change
|
||||
helloStat.Mode() != fi.Mode() ||
|
||||
helloStat.Size() != fi.Size() ||
|
||||
!bytes.Equal(helloData, b) {
|
||||
// codepath taken if hello has been modified
|
||||
return fmt.Errorf("archive breakout: file %q has been modified. Contents: expected=%q, got=%q. FileInfo: expected=%#v, got=%#v", hello, helloData, b, helloStat, fi)
|
||||
}
|
||||
|
||||
// Check that nothing in dest/ has the same content as victim/hello.
|
||||
// Since victim/hello was generated with time.Now(), it is safe to assume
|
||||
// that any file whose content matches exactly victim/hello, managed somehow
|
||||
// to access victim/hello.
|
||||
return filepath.Walk(dest, func(path string, info os.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
if err != nil {
|
||||
// skip directory if error
|
||||
return filepath.SkipDir
|
||||
}
|
||||
// enter directory
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
// skip file if error
|
||||
return nil
|
||||
}
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
// Houston, we have a problem. Aborting (space)walk.
|
||||
return err
|
||||
}
|
||||
if bytes.Equal(helloData, b) {
|
||||
return fmt.Errorf("archive breakout: file %q has been accessed via %q", hello, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
98
vendor/github.com/containers/storage/pkg/archive/wrap_test.go
generated
vendored
Normal file
98
vendor/github.com/containers/storage/pkg/archive/wrap_test.go
generated
vendored
Normal file
|
@ -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])
|
||||
}
|
||||
}
|
||||
}
|
394
vendor/github.com/containers/storage/pkg/chrootarchive/archive_test.go
generated
vendored
Normal file
394
vendor/github.com/containers/storage/pkg/chrootarchive/archive_test.go
generated
vendored
Normal file
|
@ -0,0 +1,394 @@
|
|||
package chrootarchive
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containers/storage/pkg/archive"
|
||||
"github.com/containers/storage/pkg/reexec"
|
||||
"github.com/containers/storage/pkg/system"
|
||||
)
|
||||
|
||||
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 := system.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 := system.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 := system.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 := system.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(filepath.Join(targetPath, fileName), fileData, 0700); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if makeSymLinks {
|
||||
if err := os.Symlink(filepath.Join(targetPath, fileName), filepath.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) {
|
||||
// TODO Windows: Figure out why this is failing
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Failing on Windows")
|
||||
}
|
||||
tmpdir, err := ioutil.TempDir("", "docker-TestChrootTarUntarWithSymlink")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
src := filepath.Join(tmpdir, "src")
|
||||
if err := system.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) {
|
||||
// TODO Windows: Figure out why this is failing
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Failing on Windows")
|
||||
}
|
||||
tmpdir, err := ioutil.TempDir("", "docker-TestChrootCopyWithTar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
src := filepath.Join(tmpdir, "src")
|
||||
if err := system.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 := system.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) {
|
||||
// TODO Windows: Figure out why this is failing
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Failing on Windows")
|
||||
}
|
||||
tmpdir, err := ioutil.TempDir("", "docker-TestChrootUntarPath")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
src := filepath.Join(tmpdir, "src")
|
||||
if err := system.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 := system.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 := system.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 := system.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 := system.MkdirAll(dest, 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := ApplyLayer(dest, stream); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
6
vendor/github.com/containers/storage/pkg/chrootarchive/archive_unix.go
generated
vendored
6
vendor/github.com/containers/storage/pkg/chrootarchive/archive_unix.go
generated
vendored
|
@ -16,7 +16,7 @@ import (
|
|||
"github.com/containers/storage/pkg/reexec"
|
||||
)
|
||||
|
||||
// untar is the entry-point for docker-untar on re-exec. This is not used on
|
||||
// untar is the entry-point for storage-untar on re-exec. This is not used on
|
||||
// Windows as it does not support chroot, hence no point sandboxing through
|
||||
// chroot and rexec.
|
||||
func untar() {
|
||||
|
@ -57,7 +57,7 @@ func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.T
|
|||
return fmt.Errorf("Untar pipe failure: %v", err)
|
||||
}
|
||||
|
||||
cmd := reexec.Command("docker-untar", dest)
|
||||
cmd := reexec.Command("storage-untar", dest)
|
||||
cmd.Stdin = decompressedArchive
|
||||
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, r)
|
||||
|
@ -75,7 +75,7 @@ func invokeUnpack(decompressedArchive io.Reader, dest string, options *archive.T
|
|||
w.Close()
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
// when `xz -d -c -q | docker-untar ...` failed on docker-untar side,
|
||||
// when `xz -d -c -q | storage-untar ...` failed on storage-untar side,
|
||||
// we need to exhaust `xz`'s output, otherwise the `xz` side will be
|
||||
// pending on write pipe forever
|
||||
io.Copy(ioutil.Discard, decompressedArchive)
|
||||
|
|
6
vendor/github.com/containers/storage/pkg/chrootarchive/diff_unix.go
generated
vendored
6
vendor/github.com/containers/storage/pkg/chrootarchive/diff_unix.go
generated
vendored
|
@ -21,7 +21,7 @@ type applyLayerResponse struct {
|
|||
LayerSize int64 `json:"layerSize"`
|
||||
}
|
||||
|
||||
// applyLayer is the entry-point for docker-applylayer on re-exec. This is not
|
||||
// applyLayer is the entry-point for storage-applylayer on re-exec. This is not
|
||||
// used on Windows as it does not support chroot, hence no point sandboxing
|
||||
// through chroot and rexec.
|
||||
func applyLayer() {
|
||||
|
@ -49,7 +49,7 @@ func applyLayer() {
|
|||
fatal(err)
|
||||
}
|
||||
|
||||
if tmpDir, err = ioutil.TempDir("/", "temp-docker-extract"); err != nil {
|
||||
if tmpDir, err = ioutil.TempDir("/", "temp-storage-extract"); err != nil {
|
||||
fatal(err)
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ func applyLayerHandler(dest string, layer archive.Reader, options *archive.TarOp
|
|||
return 0, fmt.Errorf("ApplyLayer json encode: %v", err)
|
||||
}
|
||||
|
||||
cmd := reexec.Command("docker-applyLayer", dest)
|
||||
cmd := reexec.Command("storage-applyLayer", dest)
|
||||
cmd.Stdin = layer
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("OPT=%s", data))
|
||||
|
||||
|
|
4
vendor/github.com/containers/storage/pkg/chrootarchive/diff_windows.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/chrootarchive/diff_windows.go
generated
vendored
|
@ -29,9 +29,9 @@ func applyLayerHandler(dest string, layer archive.Reader, options *archive.TarOp
|
|||
layer = decompressed
|
||||
}
|
||||
|
||||
tmpDir, err := ioutil.TempDir(os.Getenv("temp"), "temp-docker-extract")
|
||||
tmpDir, err := ioutil.TempDir(os.Getenv("temp"), "temp-storage-extract")
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("ApplyLayer failed to create temp-docker-extract under %s. %s", dest, err)
|
||||
return 0, fmt.Errorf("ApplyLayer failed to create temp-storage-extract under %s. %s", dest, err)
|
||||
}
|
||||
|
||||
s, err := archive.UnpackLayer(dest, layer, nil)
|
||||
|
|
4
vendor/github.com/containers/storage/pkg/chrootarchive/init_unix.go
generated
vendored
4
vendor/github.com/containers/storage/pkg/chrootarchive/init_unix.go
generated
vendored
|
@ -12,8 +12,8 @@ import (
|
|||
)
|
||||
|
||||
func init() {
|
||||
reexec.Register("docker-applyLayer", applyLayer)
|
||||
reexec.Register("docker-untar", untar)
|
||||
reexec.Register("storage-applyLayer", applyLayer)
|
||||
reexec.Register("storage-untar", untar)
|
||||
}
|
||||
|
||||
func fatal(err error) {
|
||||
|
|
192
vendor/github.com/containers/storage/pkg/directory/directory_test.go
generated
vendored
Normal file
192
vendor/github.com/containers/storage/pkg/directory/directory_test.go
generated
vendored
Normal file
|
@ -0,0 +1,192 @@
|
|||
package directory
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Size of an empty directory should be 0
|
||||
func TestSizeEmpty(t *testing.T) {
|
||||
var dir string
|
||||
var err error
|
||||
if dir, err = ioutil.TempDir(os.TempDir(), "testSizeEmptyDirectory"); err != nil {
|
||||
t.Fatalf("failed to create directory: %s", err)
|
||||
}
|
||||
|
||||
var size int64
|
||||
if size, _ = Size(dir); size != 0 {
|
||||
t.Fatalf("empty directory has size: %d", size)
|
||||
}
|
||||
}
|
||||
|
||||
// Size of a directory with one empty file should be 0
|
||||
func TestSizeEmptyFile(t *testing.T) {
|
||||
var dir string
|
||||
var err error
|
||||
if dir, err = ioutil.TempDir(os.TempDir(), "testSizeEmptyFile"); err != nil {
|
||||
t.Fatalf("failed to create directory: %s", err)
|
||||
}
|
||||
|
||||
var file *os.File
|
||||
if file, err = ioutil.TempFile(dir, "file"); err != nil {
|
||||
t.Fatalf("failed to create file: %s", err)
|
||||
}
|
||||
|
||||
var size int64
|
||||
if size, _ = Size(file.Name()); size != 0 {
|
||||
t.Fatalf("directory with one file has size: %d", size)
|
||||
}
|
||||
}
|
||||
|
||||
// Size of a directory with one 5-byte file should be 5
|
||||
func TestSizeNonemptyFile(t *testing.T) {
|
||||
var dir string
|
||||
var err error
|
||||
if dir, err = ioutil.TempDir(os.TempDir(), "testSizeNonemptyFile"); err != nil {
|
||||
t.Fatalf("failed to create directory: %s", err)
|
||||
}
|
||||
|
||||
var file *os.File
|
||||
if file, err = ioutil.TempFile(dir, "file"); err != nil {
|
||||
t.Fatalf("failed to create file: %s", err)
|
||||
}
|
||||
|
||||
d := []byte{97, 98, 99, 100, 101}
|
||||
file.Write(d)
|
||||
|
||||
var size int64
|
||||
if size, _ = Size(file.Name()); size != 5 {
|
||||
t.Fatalf("directory with one 5-byte file has size: %d", size)
|
||||
}
|
||||
}
|
||||
|
||||
// Size of a directory with one empty directory should be 0
|
||||
func TestSizeNestedDirectoryEmpty(t *testing.T) {
|
||||
var dir string
|
||||
var err error
|
||||
if dir, err = ioutil.TempDir(os.TempDir(), "testSizeNestedDirectoryEmpty"); err != nil {
|
||||
t.Fatalf("failed to create directory: %s", err)
|
||||
}
|
||||
if dir, err = ioutil.TempDir(dir, "nested"); err != nil {
|
||||
t.Fatalf("failed to create nested directory: %s", err)
|
||||
}
|
||||
|
||||
var size int64
|
||||
if size, _ = Size(dir); size != 0 {
|
||||
t.Fatalf("directory with one empty directory has size: %d", size)
|
||||
}
|
||||
}
|
||||
|
||||
// Test directory with 1 file and 1 empty directory
|
||||
func TestSizeFileAndNestedDirectoryEmpty(t *testing.T) {
|
||||
var dir string
|
||||
var err error
|
||||
if dir, err = ioutil.TempDir(os.TempDir(), "testSizeFileAndNestedDirectoryEmpty"); err != nil {
|
||||
t.Fatalf("failed to create directory: %s", err)
|
||||
}
|
||||
if dir, err = ioutil.TempDir(dir, "nested"); err != nil {
|
||||
t.Fatalf("failed to create nested directory: %s", err)
|
||||
}
|
||||
|
||||
var file *os.File
|
||||
if file, err = ioutil.TempFile(dir, "file"); err != nil {
|
||||
t.Fatalf("failed to create file: %s", err)
|
||||
}
|
||||
|
||||
d := []byte{100, 111, 99, 107, 101, 114}
|
||||
file.Write(d)
|
||||
|
||||
var size int64
|
||||
if size, _ = Size(dir); size != 6 {
|
||||
t.Fatalf("directory with 6-byte file and empty directory has size: %d", size)
|
||||
}
|
||||
}
|
||||
|
||||
// Test directory with 1 file and 1 non-empty directory
|
||||
func TestSizeFileAndNestedDirectoryNonempty(t *testing.T) {
|
||||
var dir, dirNested string
|
||||
var err error
|
||||
if dir, err = ioutil.TempDir(os.TempDir(), "TestSizeFileAndNestedDirectoryNonempty"); err != nil {
|
||||
t.Fatalf("failed to create directory: %s", err)
|
||||
}
|
||||
if dirNested, err = ioutil.TempDir(dir, "nested"); err != nil {
|
||||
t.Fatalf("failed to create nested directory: %s", err)
|
||||
}
|
||||
|
||||
var file *os.File
|
||||
if file, err = ioutil.TempFile(dir, "file"); err != nil {
|
||||
t.Fatalf("failed to create file: %s", err)
|
||||
}
|
||||
|
||||
data := []byte{100, 111, 99, 107, 101, 114}
|
||||
file.Write(data)
|
||||
|
||||
var nestedFile *os.File
|
||||
if nestedFile, err = ioutil.TempFile(dirNested, "file"); err != nil {
|
||||
t.Fatalf("failed to create file in nested directory: %s", err)
|
||||
}
|
||||
|
||||
nestedData := []byte{100, 111, 99, 107, 101, 114}
|
||||
nestedFile.Write(nestedData)
|
||||
|
||||
var size int64
|
||||
if size, _ = Size(dir); size != 12 {
|
||||
t.Fatalf("directory with 6-byte file and nested directory with 6-byte file has size: %d", size)
|
||||
}
|
||||
}
|
||||
|
||||
// Test migration of directory to a subdir underneath itself
|
||||
func TestMoveToSubdir(t *testing.T) {
|
||||
var outerDir, subDir string
|
||||
var err error
|
||||
|
||||
if outerDir, err = ioutil.TempDir(os.TempDir(), "TestMoveToSubdir"); err != nil {
|
||||
t.Fatalf("failed to create directory: %v", err)
|
||||
}
|
||||
|
||||
if subDir, err = ioutil.TempDir(outerDir, "testSub"); err != nil {
|
||||
t.Fatalf("failed to create subdirectory: %v", err)
|
||||
}
|
||||
|
||||
// write 4 temp files in the outer dir to get moved
|
||||
filesList := []string{"a", "b", "c", "d"}
|
||||
for _, fName := range filesList {
|
||||
if file, err := os.Create(filepath.Join(outerDir, fName)); err != nil {
|
||||
t.Fatalf("couldn't create temp file %q: %v", fName, err)
|
||||
} else {
|
||||
file.WriteString(fName)
|
||||
file.Close()
|
||||
}
|
||||
}
|
||||
|
||||
if err = MoveToSubdir(outerDir, filepath.Base(subDir)); err != nil {
|
||||
t.Fatalf("Error during migration of content to subdirectory: %v", err)
|
||||
}
|
||||
// validate that the files were moved to the subdirectory
|
||||
infos, err := ioutil.ReadDir(subDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(infos) != 4 {
|
||||
t.Fatalf("Should be four files in the subdir after the migration: actual length: %d", len(infos))
|
||||
}
|
||||
var results []string
|
||||
for _, info := range infos {
|
||||
results = append(results, info.Name())
|
||||
}
|
||||
sort.Sort(sort.StringSlice(results))
|
||||
if !reflect.DeepEqual(filesList, results) {
|
||||
t.Fatalf("Results after migration do not equal list of files: expected: %v, got: %v", filesList, results)
|
||||
}
|
||||
}
|
||||
|
||||
// Test a non-existing directory
|
||||
func TestSizeNonExistingDirectory(t *testing.T) {
|
||||
if _, err := Size("/thisdirectoryshouldnotexist/TestSizeNonExistingDirectory"); err == nil {
|
||||
t.Fatalf("error is expected")
|
||||
}
|
||||
}
|
585
vendor/github.com/containers/storage/pkg/fileutils/fileutils_test.go
generated
vendored
Normal file
585
vendor/github.com/containers/storage/pkg/fileutils/fileutils_test.go
generated
vendored
Normal file
|
@ -0,0 +1,585 @@
|
|||
package fileutils
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// CopyFile with invalid src
|
||||
func TestCopyFileWithInvalidSrc(t *testing.T) {
|
||||
tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
|
||||
defer os.RemoveAll(tempFolder)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bytes, err := CopyFile("/invalid/file/path", path.Join(tempFolder, "dest"))
|
||||
if err == nil {
|
||||
t.Fatal("Should have fail to copy an invalid src file")
|
||||
}
|
||||
if bytes != 0 {
|
||||
t.Fatal("Should have written 0 bytes")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// CopyFile with invalid dest
|
||||
func TestCopyFileWithInvalidDest(t *testing.T) {
|
||||
tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
|
||||
defer os.RemoveAll(tempFolder)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
src := path.Join(tempFolder, "file")
|
||||
err = ioutil.WriteFile(src, []byte("content"), 0740)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bytes, err := CopyFile(src, path.Join(tempFolder, "/invalid/dest/path"))
|
||||
if err == nil {
|
||||
t.Fatal("Should have fail to copy an invalid src file")
|
||||
}
|
||||
if bytes != 0 {
|
||||
t.Fatal("Should have written 0 bytes")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// CopyFile with same src and dest
|
||||
func TestCopyFileWithSameSrcAndDest(t *testing.T) {
|
||||
tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
|
||||
defer os.RemoveAll(tempFolder)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
file := path.Join(tempFolder, "file")
|
||||
err = ioutil.WriteFile(file, []byte("content"), 0740)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bytes, err := CopyFile(file, file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bytes != 0 {
|
||||
t.Fatal("Should have written 0 bytes as it is the same file.")
|
||||
}
|
||||
}
|
||||
|
||||
// CopyFile with same src and dest but path is different and not clean
|
||||
func TestCopyFileWithSameSrcAndDestWithPathNameDifferent(t *testing.T) {
|
||||
tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
|
||||
defer os.RemoveAll(tempFolder)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testFolder := path.Join(tempFolder, "test")
|
||||
err = os.MkdirAll(testFolder, 0740)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
file := path.Join(testFolder, "file")
|
||||
sameFile := testFolder + "/../test/file"
|
||||
err = ioutil.WriteFile(file, []byte("content"), 0740)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bytes, err := CopyFile(file, sameFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bytes != 0 {
|
||||
t.Fatal("Should have written 0 bytes as it is the same file.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyFile(t *testing.T) {
|
||||
tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
|
||||
defer os.RemoveAll(tempFolder)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
src := path.Join(tempFolder, "src")
|
||||
dest := path.Join(tempFolder, "dest")
|
||||
ioutil.WriteFile(src, []byte("content"), 0777)
|
||||
ioutil.WriteFile(dest, []byte("destContent"), 0777)
|
||||
bytes, err := CopyFile(src, dest)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if bytes != 7 {
|
||||
t.Fatalf("Should have written %d bytes but wrote %d", 7, bytes)
|
||||
}
|
||||
actual, err := ioutil.ReadFile(dest)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(actual) != "content" {
|
||||
t.Fatalf("Dest content was '%s', expected '%s'", string(actual), "content")
|
||||
}
|
||||
}
|
||||
|
||||
// Reading a symlink to a directory must return the directory
|
||||
func TestReadSymlinkedDirectoryExistingDirectory(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
var err error
|
||||
if err = os.Mkdir("/tmp/testReadSymlinkToExistingDirectory", 0777); err != nil {
|
||||
t.Errorf("failed to create directory: %s", err)
|
||||
}
|
||||
|
||||
if err = os.Symlink("/tmp/testReadSymlinkToExistingDirectory", "/tmp/dirLinkTest"); err != nil {
|
||||
t.Errorf("failed to create symlink: %s", err)
|
||||
}
|
||||
|
||||
var path string
|
||||
if path, err = ReadSymlinkedDirectory("/tmp/dirLinkTest"); err != nil {
|
||||
t.Fatalf("failed to read symlink to directory: %s", err)
|
||||
}
|
||||
|
||||
if path != "/tmp/testReadSymlinkToExistingDirectory" {
|
||||
t.Fatalf("symlink returned unexpected directory: %s", path)
|
||||
}
|
||||
|
||||
if err = os.Remove("/tmp/testReadSymlinkToExistingDirectory"); err != nil {
|
||||
t.Errorf("failed to remove temporary directory: %s", err)
|
||||
}
|
||||
|
||||
if err = os.Remove("/tmp/dirLinkTest"); err != nil {
|
||||
t.Errorf("failed to remove symlink: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Reading a non-existing symlink must fail
|
||||
func TestReadSymlinkedDirectoryNonExistingSymlink(t *testing.T) {
|
||||
var path string
|
||||
var err error
|
||||
if path, err = ReadSymlinkedDirectory("/tmp/test/foo/Non/ExistingPath"); err == nil {
|
||||
t.Fatalf("error expected for non-existing symlink")
|
||||
}
|
||||
|
||||
if path != "" {
|
||||
t.Fatalf("expected empty path, but '%s' was returned", path)
|
||||
}
|
||||
}
|
||||
|
||||
// Reading a symlink to a file must fail
|
||||
func TestReadSymlinkedDirectoryToFile(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
var err error
|
||||
var file *os.File
|
||||
|
||||
if file, err = os.Create("/tmp/testReadSymlinkToFile"); err != nil {
|
||||
t.Fatalf("failed to create file: %s", err)
|
||||
}
|
||||
|
||||
file.Close()
|
||||
|
||||
if err = os.Symlink("/tmp/testReadSymlinkToFile", "/tmp/fileLinkTest"); err != nil {
|
||||
t.Errorf("failed to create symlink: %s", err)
|
||||
}
|
||||
|
||||
var path string
|
||||
if path, err = ReadSymlinkedDirectory("/tmp/fileLinkTest"); err == nil {
|
||||
t.Fatalf("ReadSymlinkedDirectory on a symlink to a file should've failed")
|
||||
}
|
||||
|
||||
if path != "" {
|
||||
t.Fatalf("path should've been empty: %s", path)
|
||||
}
|
||||
|
||||
if err = os.Remove("/tmp/testReadSymlinkToFile"); err != nil {
|
||||
t.Errorf("failed to remove file: %s", err)
|
||||
}
|
||||
|
||||
if err = os.Remove("/tmp/fileLinkTest"); err != nil {
|
||||
t.Errorf("failed to remove symlink: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWildcardMatches(t *testing.T) {
|
||||
match, _ := Matches("fileutils.go", []string{"*"})
|
||||
if match != true {
|
||||
t.Errorf("failed to get a wildcard match, got %v", match)
|
||||
}
|
||||
}
|
||||
|
||||
// A simple pattern match should return true.
|
||||
func TestPatternMatches(t *testing.T) {
|
||||
match, _ := Matches("fileutils.go", []string{"*.go"})
|
||||
if match != true {
|
||||
t.Errorf("failed to get a match, got %v", match)
|
||||
}
|
||||
}
|
||||
|
||||
// An exclusion followed by an inclusion should return true.
|
||||
func TestExclusionPatternMatchesPatternBefore(t *testing.T) {
|
||||
match, _ := Matches("fileutils.go", []string{"!fileutils.go", "*.go"})
|
||||
if match != true {
|
||||
t.Errorf("failed to get true match on exclusion pattern, got %v", match)
|
||||
}
|
||||
}
|
||||
|
||||
// A folder pattern followed by an exception should return false.
|
||||
func TestPatternMatchesFolderExclusions(t *testing.T) {
|
||||
match, _ := Matches("docs/README.md", []string{"docs", "!docs/README.md"})
|
||||
if match != false {
|
||||
t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
|
||||
}
|
||||
}
|
||||
|
||||
// A folder pattern followed by an exception should return false.
|
||||
func TestPatternMatchesFolderWithSlashExclusions(t *testing.T) {
|
||||
match, _ := Matches("docs/README.md", []string{"docs/", "!docs/README.md"})
|
||||
if match != false {
|
||||
t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
|
||||
}
|
||||
}
|
||||
|
||||
// A folder pattern followed by an exception should return false.
|
||||
func TestPatternMatchesFolderWildcardExclusions(t *testing.T) {
|
||||
match, _ := Matches("docs/README.md", []string{"docs/*", "!docs/README.md"})
|
||||
if match != false {
|
||||
t.Errorf("failed to get a false match on exclusion pattern, got %v", match)
|
||||
}
|
||||
}
|
||||
|
||||
// A pattern followed by an exclusion should return false.
|
||||
func TestExclusionPatternMatchesPatternAfter(t *testing.T) {
|
||||
match, _ := Matches("fileutils.go", []string{"*.go", "!fileutils.go"})
|
||||
if match != false {
|
||||
t.Errorf("failed to get false match on exclusion pattern, got %v", match)
|
||||
}
|
||||
}
|
||||
|
||||
// A filename evaluating to . should return false.
|
||||
func TestExclusionPatternMatchesWholeDirectory(t *testing.T) {
|
||||
match, _ := Matches(".", []string{"*.go"})
|
||||
if match != false {
|
||||
t.Errorf("failed to get false match on ., got %v", match)
|
||||
}
|
||||
}
|
||||
|
||||
// A single ! pattern should return an error.
|
||||
func TestSingleExclamationError(t *testing.T) {
|
||||
_, err := Matches("fileutils.go", []string{"!"})
|
||||
if err == nil {
|
||||
t.Errorf("failed to get an error for a single exclamation point, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// A string preceded with a ! should return true from Exclusion.
|
||||
func TestExclusion(t *testing.T) {
|
||||
exclusion := exclusion("!")
|
||||
if !exclusion {
|
||||
t.Errorf("failed to get true for a single !, got %v", exclusion)
|
||||
}
|
||||
}
|
||||
|
||||
// Matches with no patterns
|
||||
func TestMatchesWithNoPatterns(t *testing.T) {
|
||||
matches, err := Matches("/any/path/there", []string{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if matches {
|
||||
t.Fatalf("Should not have match anything")
|
||||
}
|
||||
}
|
||||
|
||||
// Matches with malformed patterns
|
||||
func TestMatchesWithMalformedPatterns(t *testing.T) {
|
||||
matches, err := Matches("/any/path/there", []string{"["})
|
||||
if err == nil {
|
||||
t.Fatal("Should have failed because of a malformed syntax in the pattern")
|
||||
}
|
||||
if matches {
|
||||
t.Fatalf("Should not have match anything")
|
||||
}
|
||||
}
|
||||
|
||||
// Test lots of variants of patterns & strings
|
||||
func TestMatches(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
tests := []struct {
|
||||
pattern string
|
||||
text string
|
||||
pass bool
|
||||
}{
|
||||
{"**", "file", true},
|
||||
{"**", "file/", true},
|
||||
{"**/", "file", true}, // weird one
|
||||
{"**/", "file/", true},
|
||||
{"**", "/", true},
|
||||
{"**/", "/", true},
|
||||
{"**", "dir/file", true},
|
||||
{"**/", "dir/file", false},
|
||||
{"**", "dir/file/", true},
|
||||
{"**/", "dir/file/", true},
|
||||
{"**/**", "dir/file", true},
|
||||
{"**/**", "dir/file/", true},
|
||||
{"dir/**", "dir/file", true},
|
||||
{"dir/**", "dir/file/", true},
|
||||
{"dir/**", "dir/dir2/file", true},
|
||||
{"dir/**", "dir/dir2/file/", true},
|
||||
{"**/dir2/*", "dir/dir2/file", true},
|
||||
{"**/dir2/*", "dir/dir2/file/", false},
|
||||
{"**/dir2/**", "dir/dir2/dir3/file", true},
|
||||
{"**/dir2/**", "dir/dir2/dir3/file/", true},
|
||||
{"**file", "file", true},
|
||||
{"**file", "dir/file", true},
|
||||
{"**/file", "dir/file", true},
|
||||
{"**file", "dir/dir/file", true},
|
||||
{"**/file", "dir/dir/file", true},
|
||||
{"**/file*", "dir/dir/file", true},
|
||||
{"**/file*", "dir/dir/file.txt", true},
|
||||
{"**/file*txt", "dir/dir/file.txt", true},
|
||||
{"**/file*.txt", "dir/dir/file.txt", true},
|
||||
{"**/file*.txt*", "dir/dir/file.txt", true},
|
||||
{"**/**/*.txt", "dir/dir/file.txt", true},
|
||||
{"**/**/*.txt2", "dir/dir/file.txt", false},
|
||||
{"**/*.txt", "file.txt", true},
|
||||
{"**/**/*.txt", "file.txt", true},
|
||||
{"a**/*.txt", "a/file.txt", true},
|
||||
{"a**/*.txt", "a/dir/file.txt", true},
|
||||
{"a**/*.txt", "a/dir/dir/file.txt", true},
|
||||
{"a/*.txt", "a/dir/file.txt", false},
|
||||
{"a/*.txt", "a/file.txt", true},
|
||||
{"a/*.txt**", "a/file.txt", true},
|
||||
{"a[b-d]e", "ae", false},
|
||||
{"a[b-d]e", "ace", true},
|
||||
{"a[b-d]e", "aae", false},
|
||||
{"a[^b-d]e", "aze", true},
|
||||
{".*", ".foo", true},
|
||||
{".*", "foo", false},
|
||||
{"abc.def", "abcdef", false},
|
||||
{"abc.def", "abc.def", true},
|
||||
{"abc.def", "abcZdef", false},
|
||||
{"abc?def", "abcZdef", true},
|
||||
{"abc?def", "abcdef", false},
|
||||
{"a\\*b", "a*b", true},
|
||||
{"a\\", "a", false},
|
||||
{"a\\", "a\\", false},
|
||||
{"a\\\\", "a\\", true},
|
||||
{"**/foo/bar", "foo/bar", true},
|
||||
{"**/foo/bar", "dir/foo/bar", true},
|
||||
{"**/foo/bar", "dir/dir2/foo/bar", true},
|
||||
{"abc/**", "abc", false},
|
||||
{"abc/**", "abc/def", true},
|
||||
{"abc/**", "abc/def/ghi", true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
res, _ := regexpMatch(test.pattern, test.text)
|
||||
if res != test.pass {
|
||||
t.Fatalf("Failed: %v - res:%v", test, res)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An empty string should return true from Empty.
|
||||
func TestEmpty(t *testing.T) {
|
||||
empty := empty("")
|
||||
if !empty {
|
||||
t.Errorf("failed to get true for an empty string, got %v", empty)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanPatterns(t *testing.T) {
|
||||
cleaned, _, _, _ := CleanPatterns([]string{"docs", "config"})
|
||||
if len(cleaned) != 2 {
|
||||
t.Errorf("expected 2 element slice, got %v", len(cleaned))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanPatternsStripEmptyPatterns(t *testing.T) {
|
||||
cleaned, _, _, _ := CleanPatterns([]string{"docs", "config", ""})
|
||||
if len(cleaned) != 2 {
|
||||
t.Errorf("expected 2 element slice, got %v", len(cleaned))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanPatternsExceptionFlag(t *testing.T) {
|
||||
_, _, exceptions, _ := CleanPatterns([]string{"docs", "!docs/README.md"})
|
||||
if !exceptions {
|
||||
t.Errorf("expected exceptions to be true, got %v", exceptions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanPatternsLeadingSpaceTrimmed(t *testing.T) {
|
||||
_, _, exceptions, _ := CleanPatterns([]string{"docs", " !docs/README.md"})
|
||||
if !exceptions {
|
||||
t.Errorf("expected exceptions to be true, got %v", exceptions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanPatternsTrailingSpaceTrimmed(t *testing.T) {
|
||||
_, _, exceptions, _ := CleanPatterns([]string{"docs", "!docs/README.md "})
|
||||
if !exceptions {
|
||||
t.Errorf("expected exceptions to be true, got %v", exceptions)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanPatternsErrorSingleException(t *testing.T) {
|
||||
_, _, _, err := CleanPatterns([]string{"!"})
|
||||
if err == nil {
|
||||
t.Errorf("expected error on single exclamation point, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCleanPatternsFolderSplit(t *testing.T) {
|
||||
_, dirs, _, _ := CleanPatterns([]string{"docs/config/CONFIG.md"})
|
||||
if dirs[0][0] != "docs" {
|
||||
t.Errorf("expected first element in dirs slice to be docs, got %v", dirs[0][1])
|
||||
}
|
||||
if dirs[0][1] != "config" {
|
||||
t.Errorf("expected first element in dirs slice to be config, got %v", dirs[0][1])
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateIfNotExistsDir(t *testing.T) {
|
||||
tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tempFolder)
|
||||
|
||||
folderToCreate := filepath.Join(tempFolder, "tocreate")
|
||||
|
||||
if err := CreateIfNotExists(folderToCreate, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fileinfo, err := os.Stat(folderToCreate)
|
||||
if err != nil {
|
||||
t.Fatalf("Should have create a folder, got %v", err)
|
||||
}
|
||||
|
||||
if !fileinfo.IsDir() {
|
||||
t.Fatalf("Should have been a dir, seems it's not")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateIfNotExistsFile(t *testing.T) {
|
||||
tempFolder, err := ioutil.TempDir("", "docker-fileutils-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tempFolder)
|
||||
|
||||
fileToCreate := filepath.Join(tempFolder, "file/to/create")
|
||||
|
||||
if err := CreateIfNotExists(fileToCreate, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fileinfo, err := os.Stat(fileToCreate)
|
||||
if err != nil {
|
||||
t.Fatalf("Should have create a file, got %v", err)
|
||||
}
|
||||
|
||||
if fileinfo.IsDir() {
|
||||
t.Fatalf("Should have been a file, seems it's not")
|
||||
}
|
||||
}
|
||||
|
||||
// These matchTests are stolen from go's filepath Match tests.
|
||||
type matchTest struct {
|
||||
pattern, s string
|
||||
match bool
|
||||
err error
|
||||
}
|
||||
|
||||
var matchTests = []matchTest{
|
||||
{"abc", "abc", true, nil},
|
||||
{"*", "abc", true, nil},
|
||||
{"*c", "abc", true, nil},
|
||||
{"a*", "a", true, nil},
|
||||
{"a*", "abc", true, nil},
|
||||
{"a*", "ab/c", false, nil},
|
||||
{"a*/b", "abc/b", true, nil},
|
||||
{"a*/b", "a/c/b", false, nil},
|
||||
{"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
|
||||
{"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
|
||||
{"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
|
||||
{"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
|
||||
{"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
|
||||
{"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
|
||||
{"ab[c]", "abc", true, nil},
|
||||
{"ab[b-d]", "abc", true, nil},
|
||||
{"ab[e-g]", "abc", false, nil},
|
||||
{"ab[^c]", "abc", false, nil},
|
||||
{"ab[^b-d]", "abc", false, nil},
|
||||
{"ab[^e-g]", "abc", true, nil},
|
||||
{"a\\*b", "a*b", true, nil},
|
||||
{"a\\*b", "ab", false, nil},
|
||||
{"a?b", "a☺b", true, nil},
|
||||
{"a[^a]b", "a☺b", true, nil},
|
||||
{"a???b", "a☺b", false, nil},
|
||||
{"a[^a][^a][^a]b", "a☺b", false, nil},
|
||||
{"[a-ζ]*", "α", true, nil},
|
||||
{"*[a-ζ]", "A", false, nil},
|
||||
{"a?b", "a/b", false, nil},
|
||||
{"a*b", "a/b", false, nil},
|
||||
{"[\\]a]", "]", true, nil},
|
||||
{"[\\-]", "-", true, nil},
|
||||
{"[x\\-]", "x", true, nil},
|
||||
{"[x\\-]", "-", true, nil},
|
||||
{"[x\\-]", "z", false, nil},
|
||||
{"[\\-x]", "x", true, nil},
|
||||
{"[\\-x]", "-", true, nil},
|
||||
{"[\\-x]", "a", false, nil},
|
||||
{"[]a]", "]", false, filepath.ErrBadPattern},
|
||||
{"[-]", "-", false, filepath.ErrBadPattern},
|
||||
{"[x-]", "x", false, filepath.ErrBadPattern},
|
||||
{"[x-]", "-", false, filepath.ErrBadPattern},
|
||||
{"[x-]", "z", false, filepath.ErrBadPattern},
|
||||
{"[-x]", "x", false, filepath.ErrBadPattern},
|
||||
{"[-x]", "-", false, filepath.ErrBadPattern},
|
||||
{"[-x]", "a", false, filepath.ErrBadPattern},
|
||||
{"\\", "a", false, filepath.ErrBadPattern},
|
||||
{"[a-b-c]", "a", false, filepath.ErrBadPattern},
|
||||
{"[", "a", false, filepath.ErrBadPattern},
|
||||
{"[^", "a", false, filepath.ErrBadPattern},
|
||||
{"[^bc", "a", false, filepath.ErrBadPattern},
|
||||
{"a[", "a", false, filepath.ErrBadPattern}, // was nil but IMO its wrong
|
||||
{"a[", "ab", false, filepath.ErrBadPattern},
|
||||
{"*x", "xxx", true, nil},
|
||||
}
|
||||
|
||||
func errp(e error) string {
|
||||
if e == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
return e.Error()
|
||||
}
|
||||
|
||||
// TestMatch test's our version of filepath.Match, called regexpMatch.
|
||||
func TestMatch(t *testing.T) {
|
||||
for _, tt := range matchTests {
|
||||
pattern := tt.pattern
|
||||
s := tt.s
|
||||
if runtime.GOOS == "windows" {
|
||||
if strings.Index(pattern, "\\") >= 0 {
|
||||
// no escape allowed on windows.
|
||||
continue
|
||||
}
|
||||
pattern = filepath.Clean(pattern)
|
||||
s = filepath.Clean(s)
|
||||
}
|
||||
ok, err := regexpMatch(pattern, s)
|
||||
if ok != tt.match || err != tt.err {
|
||||
t.Fatalf("Match(%#q, %#q) = %v, %q want %v, %q", pattern, s, ok, errp(err), tt.match, errp(tt.err))
|
||||
}
|
||||
}
|
||||
}
|
24
vendor/github.com/containers/storage/pkg/homedir/homedir_test.go
generated
vendored
Normal file
24
vendor/github.com/containers/storage/pkg/homedir/homedir_test.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
package homedir
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
home := Get()
|
||||
if home == "" {
|
||||
t.Fatal("returned home directory is empty")
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(home) {
|
||||
t.Fatalf("returned path is not absolute: %s", home)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetShortcutString(t *testing.T) {
|
||||
shortcut := GetShortcutString()
|
||||
if shortcut == "" {
|
||||
t.Fatal("returned shortcut string is empty")
|
||||
}
|
||||
}
|
271
vendor/github.com/containers/storage/pkg/idtools/idtools_unix_test.go
generated
vendored
Normal file
271
vendor/github.com/containers/storage/pkg/idtools/idtools_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,271 @@
|
|||
// +build !windows
|
||||
|
||||
package idtools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type node struct {
|
||||
uid int
|
||||
gid int
|
||||
}
|
||||
|
||||
func TestMkdirAllAs(t *testing.T) {
|
||||
dirName, err := ioutil.TempDir("", "mkdirall")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
testTree := map[string]node{
|
||||
"usr": {0, 0},
|
||||
"usr/bin": {0, 0},
|
||||
"lib": {33, 33},
|
||||
"lib/x86_64": {45, 45},
|
||||
"lib/x86_64/share": {1, 1},
|
||||
}
|
||||
|
||||
if err := buildTree(dirName, testTree); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
|
||||
if err := MkdirAllAs(filepath.Join(dirName, "usr", "share"), 0755, 99, 99); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["usr/share"] = node{99, 99}
|
||||
verifyTree, err := readTree(dirName, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := compareTrees(testTree, verifyTree); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// test 2-deep new directories--both should be owned by the uid/gid pair
|
||||
if err := MkdirAllAs(filepath.Join(dirName, "lib", "some", "other"), 0755, 101, 101); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["lib/some"] = node{101, 101}
|
||||
testTree["lib/some/other"] = node{101, 101}
|
||||
verifyTree, err = readTree(dirName, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := compareTrees(testTree, verifyTree); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// test a directory that already exists; should be chowned, but nothing else
|
||||
if err := MkdirAllAs(filepath.Join(dirName, "usr"), 0755, 102, 102); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["usr"] = node{102, 102}
|
||||
verifyTree, err = readTree(dirName, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := compareTrees(testTree, verifyTree); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMkdirAllNewAs(t *testing.T) {
|
||||
|
||||
dirName, err := ioutil.TempDir("", "mkdirnew")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
testTree := map[string]node{
|
||||
"usr": {0, 0},
|
||||
"usr/bin": {0, 0},
|
||||
"lib": {33, 33},
|
||||
"lib/x86_64": {45, 45},
|
||||
"lib/x86_64/share": {1, 1},
|
||||
}
|
||||
|
||||
if err := buildTree(dirName, testTree); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
|
||||
if err := MkdirAllNewAs(filepath.Join(dirName, "usr", "share"), 0755, 99, 99); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["usr/share"] = node{99, 99}
|
||||
verifyTree, err := readTree(dirName, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := compareTrees(testTree, verifyTree); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// test 2-deep new directories--both should be owned by the uid/gid pair
|
||||
if err := MkdirAllNewAs(filepath.Join(dirName, "lib", "some", "other"), 0755, 101, 101); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["lib/some"] = node{101, 101}
|
||||
testTree["lib/some/other"] = node{101, 101}
|
||||
verifyTree, err = readTree(dirName, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := compareTrees(testTree, verifyTree); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// test a directory that already exists; should NOT be chowned
|
||||
if err := MkdirAllNewAs(filepath.Join(dirName, "usr"), 0755, 102, 102); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
verifyTree, err = readTree(dirName, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := compareTrees(testTree, verifyTree); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMkdirAs(t *testing.T) {
|
||||
|
||||
dirName, err := ioutil.TempDir("", "mkdir")
|
||||
if err != nil {
|
||||
t.Fatalf("Couldn't create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dirName)
|
||||
|
||||
testTree := map[string]node{
|
||||
"usr": {0, 0},
|
||||
}
|
||||
if err := buildTree(dirName, testTree); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// test a directory that already exists; should just chown to the requested uid/gid
|
||||
if err := MkdirAs(filepath.Join(dirName, "usr"), 0755, 99, 99); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["usr"] = node{99, 99}
|
||||
verifyTree, err := readTree(dirName, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := compareTrees(testTree, verifyTree); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// create a subdir under a dir which doesn't exist--should fail
|
||||
if err := MkdirAs(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, 102, 102); err == nil {
|
||||
t.Fatalf("Trying to create a directory with Mkdir where the parent doesn't exist should have failed")
|
||||
}
|
||||
|
||||
// create a subdir under an existing dir; should only change the ownership of the new subdir
|
||||
if err := MkdirAs(filepath.Join(dirName, "usr", "bin"), 0755, 102, 102); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testTree["usr/bin"] = node{102, 102}
|
||||
verifyTree, err = readTree(dirName, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := compareTrees(testTree, verifyTree); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func buildTree(base string, tree map[string]node) error {
|
||||
for path, node := range tree {
|
||||
fullPath := filepath.Join(base, path)
|
||||
if err := os.MkdirAll(fullPath, 0755); err != nil {
|
||||
return fmt.Errorf("Couldn't create path: %s; error: %v", fullPath, err)
|
||||
}
|
||||
if err := os.Chown(fullPath, node.uid, node.gid); err != nil {
|
||||
return fmt.Errorf("Couldn't chown path: %s; error: %v", fullPath, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readTree(base, root string) (map[string]node, error) {
|
||||
tree := make(map[string]node)
|
||||
|
||||
dirInfos, err := ioutil.ReadDir(base)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Couldn't read directory entries for %q: %v", base, err)
|
||||
}
|
||||
|
||||
for _, info := range dirInfos {
|
||||
s := &syscall.Stat_t{}
|
||||
if err := syscall.Stat(filepath.Join(base, info.Name()), s); err != nil {
|
||||
return nil, fmt.Errorf("Can't stat file %q: %v", filepath.Join(base, info.Name()), err)
|
||||
}
|
||||
tree[filepath.Join(root, info.Name())] = node{int(s.Uid), int(s.Gid)}
|
||||
if info.IsDir() {
|
||||
// read the subdirectory
|
||||
subtree, err := readTree(filepath.Join(base, info.Name()), filepath.Join(root, info.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for path, nodeinfo := range subtree {
|
||||
tree[path] = nodeinfo
|
||||
}
|
||||
}
|
||||
}
|
||||
return tree, nil
|
||||
}
|
||||
|
||||
func compareTrees(left, right map[string]node) error {
|
||||
if len(left) != len(right) {
|
||||
return fmt.Errorf("Trees aren't the same size")
|
||||
}
|
||||
for path, nodeLeft := range left {
|
||||
if nodeRight, ok := right[path]; ok {
|
||||
if nodeRight.uid != nodeLeft.uid || nodeRight.gid != nodeLeft.gid {
|
||||
// mismatch
|
||||
return fmt.Errorf("mismatched ownership for %q: expected: %d:%d, got: %d:%d", path,
|
||||
nodeLeft.uid, nodeLeft.gid, nodeRight.uid, nodeRight.gid)
|
||||
}
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("right tree didn't contain path %q", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestParseSubidFileWithNewlinesAndComments(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "parsesubid")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fnamePath := filepath.Join(tmpDir, "testsubuid")
|
||||
fcontent := `tss:100000:65536
|
||||
# empty default subuid/subgid file
|
||||
|
||||
dockremap:231072:65536`
|
||||
if err := ioutil.WriteFile(fnamePath, []byte(fcontent), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ranges, err := parseSubidFile(fnamePath, "dockremap")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(ranges) != 1 {
|
||||
t.Fatalf("wanted 1 element in ranges, got %d instead", len(ranges))
|
||||
}
|
||||
if ranges[0].Start != 231072 {
|
||||
t.Fatalf("wanted 231072, got %d instead", ranges[0].Start)
|
||||
}
|
||||
if ranges[0].Length != 65536 {
|
||||
t.Fatalf("wanted 65536, got %d instead", ranges[0].Length)
|
||||
}
|
||||
}
|
46
vendor/github.com/containers/storage/pkg/integration/checker/checker.go
generated
vendored
Normal file
46
vendor/github.com/containers/storage/pkg/integration/checker/checker.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Package checker provides Docker specific implementations of the go-check.Checker interface.
|
||||
package checker
|
||||
|
||||
import (
|
||||
"github.com/go-check/check"
|
||||
"github.com/vdemeester/shakers"
|
||||
)
|
||||
|
||||
// As a commodity, we bring all check.Checker variables into the current namespace to avoid having
|
||||
// to think about check.X versus checker.X.
|
||||
var (
|
||||
DeepEquals = check.DeepEquals
|
||||
ErrorMatches = check.ErrorMatches
|
||||
FitsTypeOf = check.FitsTypeOf
|
||||
HasLen = check.HasLen
|
||||
Implements = check.Implements
|
||||
IsNil = check.IsNil
|
||||
Matches = check.Matches
|
||||
Not = check.Not
|
||||
NotNil = check.NotNil
|
||||
PanicMatches = check.PanicMatches
|
||||
Panics = check.Panics
|
||||
|
||||
Contains = shakers.Contains
|
||||
ContainsAny = shakers.ContainsAny
|
||||
Count = shakers.Count
|
||||
Equals = shakers.Equals
|
||||
EqualFold = shakers.EqualFold
|
||||
False = shakers.False
|
||||
GreaterOrEqualThan = shakers.GreaterOrEqualThan
|
||||
GreaterThan = shakers.GreaterThan
|
||||
HasPrefix = shakers.HasPrefix
|
||||
HasSuffix = shakers.HasSuffix
|
||||
Index = shakers.Index
|
||||
IndexAny = shakers.IndexAny
|
||||
IsAfter = shakers.IsAfter
|
||||
IsBefore = shakers.IsBefore
|
||||
IsBetween = shakers.IsBetween
|
||||
IsLower = shakers.IsLower
|
||||
IsUpper = shakers.IsUpper
|
||||
LessOrEqualThan = shakers.LessOrEqualThan
|
||||
LessThan = shakers.LessThan
|
||||
TimeEquals = shakers.TimeEquals
|
||||
True = shakers.True
|
||||
TimeIgnore = shakers.TimeIgnore
|
||||
)
|
78
vendor/github.com/containers/storage/pkg/integration/dockerCmd_utils.go
generated
vendored
Normal file
78
vendor/github.com/containers/storage/pkg/integration/dockerCmd_utils.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
// We use the elongated quote mechanism for quoting error returns as
|
||||
// the use of strconv.Quote or %q in fmt.Errorf will escape characters. This
|
||||
// has a big downside on Windows where the args include paths, so instead
|
||||
// of something like c:\directory\file.txt, the output would be
|
||||
// c:\\directory\\file.txt. This is highly misleading.
|
||||
const quote = `"`
|
||||
|
||||
var execCommand = exec.Command
|
||||
|
||||
// DockerCmdWithError executes a docker command that is supposed to fail and returns
|
||||
// the output, the exit code and the error.
|
||||
func DockerCmdWithError(dockerBinary string, args ...string) (string, int, error) {
|
||||
return RunCommandWithOutput(execCommand(dockerBinary, args...))
|
||||
}
|
||||
|
||||
// DockerCmdWithStdoutStderr executes a docker command and returns the content of the
|
||||
// stdout, stderr and the exit code. If a check.C is passed, it will fail and stop tests
|
||||
// if the error is not nil.
|
||||
func DockerCmdWithStdoutStderr(dockerBinary string, c *check.C, args ...string) (string, string, int) {
|
||||
stdout, stderr, status, err := RunCommandWithStdoutStderr(execCommand(dockerBinary, args...))
|
||||
if c != nil {
|
||||
c.Assert(err, check.IsNil, check.Commentf(quote+"%v"+quote+" failed with errors: %s, %v", strings.Join(args, " "), stderr, err))
|
||||
}
|
||||
return stdout, stderr, status
|
||||
}
|
||||
|
||||
// DockerCmd executes a docker command and returns the output and the exit code. If the
|
||||
// command returns an error, it will fail and stop the tests.
|
||||
func DockerCmd(dockerBinary string, c *check.C, args ...string) (string, int) {
|
||||
out, status, err := RunCommandWithOutput(execCommand(dockerBinary, args...))
|
||||
c.Assert(err, check.IsNil, check.Commentf(quote+"%v"+quote+" failed with errors: %s, %v", strings.Join(args, " "), out, err))
|
||||
return out, status
|
||||
}
|
||||
|
||||
// DockerCmdWithTimeout executes a docker command with a timeout, and returns the output,
|
||||
// the exit code and the error (if any).
|
||||
func DockerCmdWithTimeout(dockerBinary string, timeout time.Duration, args ...string) (string, int, error) {
|
||||
out, status, err := RunCommandWithOutputAndTimeout(execCommand(dockerBinary, args...), timeout)
|
||||
if err != nil {
|
||||
return out, status, fmt.Errorf(quote+"%v"+quote+" failed with errors: %v : %q", strings.Join(args, " "), err, out)
|
||||
}
|
||||
return out, status, err
|
||||
}
|
||||
|
||||
// DockerCmdInDir executes a docker command in a directory and returns the output, the
|
||||
// exit code and the error (if any).
|
||||
func DockerCmdInDir(dockerBinary string, path string, args ...string) (string, int, error) {
|
||||
dockerCommand := execCommand(dockerBinary, args...)
|
||||
dockerCommand.Dir = path
|
||||
out, status, err := RunCommandWithOutput(dockerCommand)
|
||||
if err != nil {
|
||||
return out, status, fmt.Errorf(quote+"%v"+quote+" failed with errors: %v : %q", strings.Join(args, " "), err, out)
|
||||
}
|
||||
return out, status, err
|
||||
}
|
||||
|
||||
// DockerCmdInDirWithTimeout executes a docker command in a directory with a timeout and
|
||||
// returns the output, the exit code and the error (if any).
|
||||
func DockerCmdInDirWithTimeout(dockerBinary string, timeout time.Duration, path string, args ...string) (string, int, error) {
|
||||
dockerCommand := execCommand(dockerBinary, args...)
|
||||
dockerCommand.Dir = path
|
||||
out, status, err := RunCommandWithOutputAndTimeout(dockerCommand, timeout)
|
||||
if err != nil {
|
||||
return out, status, fmt.Errorf(quote+"%v"+quote+" failed with errors: %v : %q", strings.Join(args, " "), err, out)
|
||||
}
|
||||
return out, status, err
|
||||
}
|
405
vendor/github.com/containers/storage/pkg/integration/dockerCmd_utils_test.go
generated
vendored
Normal file
405
vendor/github.com/containers/storage/pkg/integration/dockerCmd_utils_test.go
generated
vendored
Normal file
|
@ -0,0 +1,405 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"testing"
|
||||
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
const dockerBinary = "docker"
|
||||
|
||||
// Setup go-check for this test
|
||||
func Test(t *testing.T) {
|
||||
check.TestingT(t)
|
||||
}
|
||||
|
||||
func init() {
|
||||
check.Suite(&DockerCmdSuite{})
|
||||
}
|
||||
|
||||
type DockerCmdSuite struct{}
|
||||
|
||||
// Fake the exec.Command to use our mock.
|
||||
func (s *DockerCmdSuite) SetUpTest(c *check.C) {
|
||||
execCommand = fakeExecCommand
|
||||
}
|
||||
|
||||
// And bring it back to normal after the test.
|
||||
func (s *DockerCmdSuite) TearDownTest(c *check.C) {
|
||||
execCommand = exec.Command
|
||||
}
|
||||
|
||||
// DockerCmdWithError tests
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdWithError(c *check.C) {
|
||||
cmds := []struct {
|
||||
binary string
|
||||
args []string
|
||||
expectedOut string
|
||||
expectedExitCode int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
"doesnotexists",
|
||||
[]string{},
|
||||
"Command doesnotexists not found.",
|
||||
1,
|
||||
fmt.Errorf("exit status 1"),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"an", "error"},
|
||||
"an error has occurred",
|
||||
1,
|
||||
fmt.Errorf("exit status 1"),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"an", "exitCode", "127"},
|
||||
"an error has occurred with exitCode 127",
|
||||
127,
|
||||
fmt.Errorf("exit status 127"),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"run", "-ti", "ubuntu", "echo", "hello"},
|
||||
"hello",
|
||||
0,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
for _, cmd := range cmds {
|
||||
out, exitCode, error := DockerCmdWithError(cmd.binary, cmd.args...)
|
||||
c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
|
||||
c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
|
||||
if cmd.expectedError != nil {
|
||||
c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
|
||||
c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
|
||||
} else {
|
||||
c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DockerCmdWithStdoutStderr tests
|
||||
|
||||
type dockerCmdWithStdoutStderrErrorSuite struct{}
|
||||
|
||||
func (s *dockerCmdWithStdoutStderrErrorSuite) Test(c *check.C) {
|
||||
// Should fail, the test too
|
||||
DockerCmdWithStdoutStderr(dockerBinary, c, "an", "error")
|
||||
}
|
||||
|
||||
type dockerCmdWithStdoutStderrSuccessSuite struct{}
|
||||
|
||||
func (s *dockerCmdWithStdoutStderrSuccessSuite) Test(c *check.C) {
|
||||
stdout, stderr, exitCode := DockerCmdWithStdoutStderr(dockerBinary, c, "run", "-ti", "ubuntu", "echo", "hello")
|
||||
c.Assert(stdout, check.Equals, "hello")
|
||||
c.Assert(stderr, check.Equals, "")
|
||||
c.Assert(exitCode, check.Equals, 0)
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdWithStdoutStderrError(c *check.C) {
|
||||
// Run error suite, should fail.
|
||||
output := String{}
|
||||
result := check.Run(&dockerCmdWithStdoutStderrErrorSuite{}, &check.RunConf{Output: &output})
|
||||
c.Check(result.Succeeded, check.Equals, 0)
|
||||
c.Check(result.Failed, check.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdWithStdoutStderrSuccess(c *check.C) {
|
||||
// Run error suite, should fail.
|
||||
output := String{}
|
||||
result := check.Run(&dockerCmdWithStdoutStderrSuccessSuite{}, &check.RunConf{Output: &output})
|
||||
c.Check(result.Succeeded, check.Equals, 1)
|
||||
c.Check(result.Failed, check.Equals, 0)
|
||||
}
|
||||
|
||||
// DockerCmd tests
|
||||
|
||||
type dockerCmdErrorSuite struct{}
|
||||
|
||||
func (s *dockerCmdErrorSuite) Test(c *check.C) {
|
||||
// Should fail, the test too
|
||||
DockerCmd(dockerBinary, c, "an", "error")
|
||||
}
|
||||
|
||||
type dockerCmdSuccessSuite struct{}
|
||||
|
||||
func (s *dockerCmdSuccessSuite) Test(c *check.C) {
|
||||
stdout, exitCode := DockerCmd(dockerBinary, c, "run", "-ti", "ubuntu", "echo", "hello")
|
||||
c.Assert(stdout, check.Equals, "hello")
|
||||
c.Assert(exitCode, check.Equals, 0)
|
||||
|
||||
}
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdError(c *check.C) {
|
||||
// Run error suite, should fail.
|
||||
output := String{}
|
||||
result := check.Run(&dockerCmdErrorSuite{}, &check.RunConf{Output: &output})
|
||||
c.Check(result.Succeeded, check.Equals, 0)
|
||||
c.Check(result.Failed, check.Equals, 1)
|
||||
}
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdSuccess(c *check.C) {
|
||||
// Run error suite, should fail.
|
||||
output := String{}
|
||||
result := check.Run(&dockerCmdSuccessSuite{}, &check.RunConf{Output: &output})
|
||||
c.Check(result.Succeeded, check.Equals, 1)
|
||||
c.Check(result.Failed, check.Equals, 0)
|
||||
}
|
||||
|
||||
// DockerCmdWithTimeout tests
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdWithTimeout(c *check.C) {
|
||||
cmds := []struct {
|
||||
binary string
|
||||
args []string
|
||||
timeout time.Duration
|
||||
expectedOut string
|
||||
expectedExitCode int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
"doesnotexists",
|
||||
[]string{},
|
||||
200 * time.Millisecond,
|
||||
`Command doesnotexists not found.`,
|
||||
1,
|
||||
fmt.Errorf(`"" failed with errors: exit status 1 : "Command doesnotexists not found."`),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"an", "error"},
|
||||
200 * time.Millisecond,
|
||||
`an error has occurred`,
|
||||
1,
|
||||
fmt.Errorf(`"an error" failed with errors: exit status 1 : "an error has occurred"`),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"a", "command", "that", "times", "out"},
|
||||
5 * time.Millisecond,
|
||||
"",
|
||||
0,
|
||||
fmt.Errorf(`"a command that times out" failed with errors: command timed out : ""`),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"run", "-ti", "ubuntu", "echo", "hello"},
|
||||
200 * time.Millisecond,
|
||||
"hello",
|
||||
0,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
for _, cmd := range cmds {
|
||||
out, exitCode, error := DockerCmdWithTimeout(cmd.binary, cmd.timeout, cmd.args...)
|
||||
c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
|
||||
c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
|
||||
if cmd.expectedError != nil {
|
||||
c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
|
||||
c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
|
||||
} else {
|
||||
c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DockerCmdInDir tests
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdInDir(c *check.C) {
|
||||
tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
cmds := []struct {
|
||||
binary string
|
||||
args []string
|
||||
expectedOut string
|
||||
expectedExitCode int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
"doesnotexists",
|
||||
[]string{},
|
||||
`Command doesnotexists not found.`,
|
||||
1,
|
||||
fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"an", "error"},
|
||||
`an error has occurred`,
|
||||
1,
|
||||
fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"run", "-ti", "ubuntu", "echo", "hello"},
|
||||
"hello",
|
||||
0,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
for _, cmd := range cmds {
|
||||
// We prepend the arguments with dir:thefolder.. the fake command will check
|
||||
// that the current workdir is the same as the one we are passing.
|
||||
args := append([]string{"dir:" + tempFolder}, cmd.args...)
|
||||
out, exitCode, error := DockerCmdInDir(cmd.binary, tempFolder, args...)
|
||||
c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
|
||||
c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
|
||||
if cmd.expectedError != nil {
|
||||
c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
|
||||
c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
|
||||
} else {
|
||||
c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DockerCmdInDirWithTimeout tests
|
||||
|
||||
func (s *DockerCmdSuite) TestDockerCmdInDirWithTimeout(c *check.C) {
|
||||
tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir")
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
cmds := []struct {
|
||||
binary string
|
||||
args []string
|
||||
timeout time.Duration
|
||||
expectedOut string
|
||||
expectedExitCode int
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
"doesnotexists",
|
||||
[]string{},
|
||||
200 * time.Millisecond,
|
||||
`Command doesnotexists not found.`,
|
||||
1,
|
||||
fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"an", "error"},
|
||||
200 * time.Millisecond,
|
||||
`an error has occurred`,
|
||||
1,
|
||||
fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"a", "command", "that", "times", "out"},
|
||||
5 * time.Millisecond,
|
||||
"",
|
||||
0,
|
||||
fmt.Errorf(`"dir:%s a command that times out" failed with errors: command timed out : ""`, tempFolder),
|
||||
},
|
||||
{
|
||||
dockerBinary,
|
||||
[]string{"run", "-ti", "ubuntu", "echo", "hello"},
|
||||
200 * time.Millisecond,
|
||||
"hello",
|
||||
0,
|
||||
nil,
|
||||
},
|
||||
}
|
||||
for _, cmd := range cmds {
|
||||
// We prepend the arguments with dir:thefolder.. the fake command will check
|
||||
// that the current workdir is the same as the one we are passing.
|
||||
args := append([]string{"dir:" + tempFolder}, cmd.args...)
|
||||
out, exitCode, error := DockerCmdInDirWithTimeout(cmd.binary, cmd.timeout, tempFolder, args...)
|
||||
c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out))
|
||||
c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode))
|
||||
if cmd.expectedError != nil {
|
||||
c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError))
|
||||
c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error()))
|
||||
} else {
|
||||
c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers :)
|
||||
|
||||
// Type implementing the io.Writer interface for analyzing output.
|
||||
type String struct {
|
||||
value string
|
||||
}
|
||||
|
||||
// The only function required by the io.Writer interface. Will append
|
||||
// written data to the String.value string.
|
||||
func (s *String) Write(p []byte) (n int, err error) {
|
||||
s.value += string(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Helper function that mock the exec.Command call (and call the test binary)
|
||||
func fakeExecCommand(command string, args ...string) *exec.Cmd {
|
||||
cs := []string{"-test.run=TestHelperProcess", "--", command}
|
||||
cs = append(cs, args...)
|
||||
cmd := exec.Command(os.Args[0], cs...)
|
||||
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
|
||||
return cmd
|
||||
}
|
||||
|
||||
func TestHelperProcess(t *testing.T) {
|
||||
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
|
||||
return
|
||||
}
|
||||
args := os.Args
|
||||
|
||||
// Previous arguments are tests stuff, that looks like :
|
||||
// /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess --
|
||||
cmd, args := args[3], args[4:]
|
||||
// Handle the case where args[0] is dir:...
|
||||
if len(args) > 0 && strings.HasPrefix(args[0], "dir:") {
|
||||
expectedCwd := args[0][4:]
|
||||
if len(args) > 1 {
|
||||
args = args[1:]
|
||||
}
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to get workingdir: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
// This checks that the given path is the same as the currend working dire
|
||||
if expectedCwd != cwd {
|
||||
fmt.Fprintf(os.Stderr, "Current workdir should be %q, but is %q", expectedCwd, cwd)
|
||||
}
|
||||
}
|
||||
switch cmd {
|
||||
case dockerBinary:
|
||||
argsStr := strings.Join(args, " ")
|
||||
switch argsStr {
|
||||
case "an exitCode 127":
|
||||
fmt.Fprintf(os.Stderr, "an error has occurred with exitCode 127")
|
||||
os.Exit(127)
|
||||
case "an error":
|
||||
fmt.Fprintf(os.Stderr, "an error has occurred")
|
||||
os.Exit(1)
|
||||
case "a command that times out":
|
||||
time.Sleep(10 * time.Second)
|
||||
fmt.Fprintf(os.Stdout, "too long, should be killed")
|
||||
// A random exit code (that should never happened in tests)
|
||||
os.Exit(7)
|
||||
case "run -ti ubuntu echo hello":
|
||||
fmt.Fprintf(os.Stdout, "hello")
|
||||
default:
|
||||
fmt.Fprintf(os.Stdout, "no arguments")
|
||||
}
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "Command %s not found.", cmd)
|
||||
os.Exit(1)
|
||||
}
|
||||
// some code here to check arguments perhaps?
|
||||
os.Exit(0)
|
||||
}
|
361
vendor/github.com/containers/storage/pkg/integration/utils.go
generated
vendored
Normal file
361
vendor/github.com/containers/storage/pkg/integration/utils.go
generated
vendored
Normal file
|
@ -0,0 +1,361 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containers/storage/pkg/stringutils"
|
||||
)
|
||||
|
||||
// GetExitCode returns the ExitStatus of the specified error if its type is
|
||||
// exec.ExitError, returns 0 and an error otherwise.
|
||||
func GetExitCode(err error) (int, error) {
|
||||
exitCode := 0
|
||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||
if procExit, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||
return procExit.ExitStatus(), nil
|
||||
}
|
||||
}
|
||||
return exitCode, fmt.Errorf("failed to get exit code")
|
||||
}
|
||||
|
||||
// ProcessExitCode process the specified error and returns the exit status code
|
||||
// if the error was of type exec.ExitError, returns nothing otherwise.
|
||||
func ProcessExitCode(err error) (exitCode int) {
|
||||
if err != nil {
|
||||
var exiterr error
|
||||
if exitCode, exiterr = GetExitCode(err); exiterr != nil {
|
||||
// TODO: Fix this so we check the error's text.
|
||||
// we've failed to retrieve exit code, so we set it to 127
|
||||
exitCode = 127
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// IsKilled process the specified error and returns whether the process was killed or not.
|
||||
func IsKilled(err error) bool {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
status, ok := exitErr.Sys().(syscall.WaitStatus)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
// status.ExitStatus() is required on Windows because it does not
|
||||
// implement Signal() nor Signaled(). Just check it had a bad exit
|
||||
// status could mean it was killed (and in tests we do kill)
|
||||
return (status.Signaled() && status.Signal() == os.Kill) || status.ExitStatus() != 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RunCommandWithOutput runs the specified command and returns the combined output (stdout/stderr)
|
||||
// with the exitCode different from 0 and the error if something bad happened
|
||||
func RunCommandWithOutput(cmd *exec.Cmd) (output string, exitCode int, err error) {
|
||||
exitCode = 0
|
||||
out, err := cmd.CombinedOutput()
|
||||
exitCode = ProcessExitCode(err)
|
||||
output = string(out)
|
||||
return
|
||||
}
|
||||
|
||||
// RunCommandWithStdoutStderr runs the specified command and returns stdout and stderr separately
|
||||
// with the exitCode different from 0 and the error if something bad happened
|
||||
func RunCommandWithStdoutStderr(cmd *exec.Cmd) (stdout string, stderr string, exitCode int, err error) {
|
||||
var (
|
||||
stderrBuffer, stdoutBuffer bytes.Buffer
|
||||
)
|
||||
exitCode = 0
|
||||
cmd.Stderr = &stderrBuffer
|
||||
cmd.Stdout = &stdoutBuffer
|
||||
err = cmd.Run()
|
||||
exitCode = ProcessExitCode(err)
|
||||
|
||||
stdout = stdoutBuffer.String()
|
||||
stderr = stderrBuffer.String()
|
||||
return
|
||||
}
|
||||
|
||||
// RunCommandWithOutputForDuration runs the specified command "timeboxed" by the specified duration.
|
||||
// If the process is still running when the timebox is finished, the process will be killed and .
|
||||
// It will returns the output with the exitCode different from 0 and the error if something bad happened
|
||||
// and a boolean whether it has been killed or not.
|
||||
func RunCommandWithOutputForDuration(cmd *exec.Cmd, duration time.Duration) (output string, exitCode int, timedOut bool, err error) {
|
||||
var outputBuffer bytes.Buffer
|
||||
if cmd.Stdout != nil {
|
||||
err = errors.New("cmd.Stdout already set")
|
||||
return
|
||||
}
|
||||
cmd.Stdout = &outputBuffer
|
||||
|
||||
if cmd.Stderr != nil {
|
||||
err = errors.New("cmd.Stderr already set")
|
||||
return
|
||||
}
|
||||
cmd.Stderr = &outputBuffer
|
||||
|
||||
// Start the command in the main thread..
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Fail to start command %v : %v", cmd, err)
|
||||
}
|
||||
|
||||
type exitInfo struct {
|
||||
exitErr error
|
||||
exitCode int
|
||||
}
|
||||
|
||||
done := make(chan exitInfo, 1)
|
||||
|
||||
go func() {
|
||||
// And wait for it to exit in the goroutine :)
|
||||
info := exitInfo{}
|
||||
info.exitErr = cmd.Wait()
|
||||
info.exitCode = ProcessExitCode(info.exitErr)
|
||||
done <- info
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(duration):
|
||||
killErr := cmd.Process.Kill()
|
||||
if killErr != nil {
|
||||
fmt.Printf("failed to kill (pid=%d): %v\n", cmd.Process.Pid, killErr)
|
||||
}
|
||||
timedOut = true
|
||||
case info := <-done:
|
||||
err = info.exitErr
|
||||
exitCode = info.exitCode
|
||||
}
|
||||
output = outputBuffer.String()
|
||||
return
|
||||
}
|
||||
|
||||
var errCmdTimeout = fmt.Errorf("command timed out")
|
||||
|
||||
// RunCommandWithOutputAndTimeout runs the specified command "timeboxed" by the specified duration.
|
||||
// It returns the output with the exitCode different from 0 and the error if something bad happened or
|
||||
// if the process timed out (and has been killed).
|
||||
func RunCommandWithOutputAndTimeout(cmd *exec.Cmd, timeout time.Duration) (output string, exitCode int, err error) {
|
||||
var timedOut bool
|
||||
output, exitCode, timedOut, err = RunCommandWithOutputForDuration(cmd, timeout)
|
||||
if timedOut {
|
||||
err = errCmdTimeout
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RunCommand runs the specified command and returns the exitCode different from 0
|
||||
// and the error if something bad happened.
|
||||
func RunCommand(cmd *exec.Cmd) (exitCode int, err error) {
|
||||
exitCode = 0
|
||||
err = cmd.Run()
|
||||
exitCode = ProcessExitCode(err)
|
||||
return
|
||||
}
|
||||
|
||||
// RunCommandPipelineWithOutput runs the array of commands with the output
|
||||
// of each pipelined with the following (like cmd1 | cmd2 | cmd3 would do).
|
||||
// It returns the final output, the exitCode different from 0 and the error
|
||||
// if something bad happened.
|
||||
func RunCommandPipelineWithOutput(cmds ...*exec.Cmd) (output string, exitCode int, err error) {
|
||||
if len(cmds) < 2 {
|
||||
return "", 0, errors.New("pipeline does not have multiple cmds")
|
||||
}
|
||||
|
||||
// connect stdin of each cmd to stdout pipe of previous cmd
|
||||
for i, cmd := range cmds {
|
||||
if i > 0 {
|
||||
prevCmd := cmds[i-1]
|
||||
cmd.Stdin, err = prevCmd.StdoutPipe()
|
||||
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("cannot set stdout pipe for %s: %v", cmd.Path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// start all cmds except the last
|
||||
for _, cmd := range cmds[:len(cmds)-1] {
|
||||
if err = cmd.Start(); err != nil {
|
||||
return "", 0, fmt.Errorf("starting %s failed with error: %v", cmd.Path, err)
|
||||
}
|
||||
}
|
||||
|
||||
var pipelineError error
|
||||
defer func() {
|
||||
// wait all cmds except the last to release their resources
|
||||
for _, cmd := range cmds[:len(cmds)-1] {
|
||||
if err := cmd.Wait(); err != nil {
|
||||
pipelineError = fmt.Errorf("command %s failed with error: %v", cmd.Path, err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
if pipelineError != nil {
|
||||
return "", 0, pipelineError
|
||||
}
|
||||
|
||||
// wait on last cmd
|
||||
return RunCommandWithOutput(cmds[len(cmds)-1])
|
||||
}
|
||||
|
||||
// UnmarshalJSON deserialize a JSON in the given interface.
|
||||
func UnmarshalJSON(data []byte, result interface{}) error {
|
||||
if err := json.Unmarshal(data, result); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConvertSliceOfStringsToMap converts a slices of string in a map
|
||||
// with the strings as key and an empty string as values.
|
||||
func ConvertSliceOfStringsToMap(input []string) map[string]struct{} {
|
||||
output := make(map[string]struct{})
|
||||
for _, v := range input {
|
||||
output[v] = struct{}{}
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
// CompareDirectoryEntries compares two sets of FileInfo (usually taken from a directory)
|
||||
// and returns an error if different.
|
||||
func CompareDirectoryEntries(e1 []os.FileInfo, e2 []os.FileInfo) error {
|
||||
var (
|
||||
e1Entries = make(map[string]struct{})
|
||||
e2Entries = make(map[string]struct{})
|
||||
)
|
||||
for _, e := range e1 {
|
||||
e1Entries[e.Name()] = struct{}{}
|
||||
}
|
||||
for _, e := range e2 {
|
||||
e2Entries[e.Name()] = struct{}{}
|
||||
}
|
||||
if !reflect.DeepEqual(e1Entries, e2Entries) {
|
||||
return fmt.Errorf("entries differ")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListTar lists the entries of a tar.
|
||||
func ListTar(f io.Reader) ([]string, error) {
|
||||
tr := tar.NewReader(f)
|
||||
var entries []string
|
||||
|
||||
for {
|
||||
th, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
// end of tar archive
|
||||
return entries, nil
|
||||
}
|
||||
if err != nil {
|
||||
return entries, err
|
||||
}
|
||||
entries = append(entries, th.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// RandomTmpDirPath provides a temporary path with rand string appended.
|
||||
// does not create or checks if it exists.
|
||||
func RandomTmpDirPath(s string, platform string) string {
|
||||
tmp := "/tmp"
|
||||
if platform == "windows" {
|
||||
tmp = os.Getenv("TEMP")
|
||||
}
|
||||
path := filepath.Join(tmp, fmt.Sprintf("%s.%s", s, stringutils.GenerateRandomAlphaOnlyString(10)))
|
||||
if platform == "windows" {
|
||||
return filepath.FromSlash(path) // Using \
|
||||
}
|
||||
return filepath.ToSlash(path) // Using /
|
||||
}
|
||||
|
||||
// ConsumeWithSpeed reads chunkSize bytes from reader before sleeping
|
||||
// for interval duration. Returns total read bytes. Send true to the
|
||||
// stop channel to return before reading to EOF on the reader.
|
||||
func ConsumeWithSpeed(reader io.Reader, chunkSize int, interval time.Duration, stop chan bool) (n int, err error) {
|
||||
buffer := make([]byte, chunkSize)
|
||||
for {
|
||||
var readBytes int
|
||||
readBytes, err = reader.Read(buffer)
|
||||
n += readBytes
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
select {
|
||||
case <-stop:
|
||||
return
|
||||
case <-time.After(interval):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ParseCgroupPaths parses 'procCgroupData', which is output of '/proc/<pid>/cgroup', and returns
|
||||
// a map which cgroup name as key and path as value.
|
||||
func ParseCgroupPaths(procCgroupData string) map[string]string {
|
||||
cgroupPaths := map[string]string{}
|
||||
for _, line := range strings.Split(procCgroupData, "\n") {
|
||||
parts := strings.Split(line, ":")
|
||||
if len(parts) != 3 {
|
||||
continue
|
||||
}
|
||||
cgroupPaths[parts[1]] = parts[2]
|
||||
}
|
||||
return cgroupPaths
|
||||
}
|
||||
|
||||
// ChannelBuffer holds a chan of byte array that can be populate in a goroutine.
|
||||
type ChannelBuffer struct {
|
||||
C chan []byte
|
||||
}
|
||||
|
||||
// Write implements Writer.
|
||||
func (c *ChannelBuffer) Write(b []byte) (int, error) {
|
||||
c.C <- b
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
// Close closes the go channel.
|
||||
func (c *ChannelBuffer) Close() error {
|
||||
close(c.C)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadTimeout reads the content of the channel in the specified byte array with
|
||||
// the specified duration as timeout.
|
||||
func (c *ChannelBuffer) ReadTimeout(p []byte, n time.Duration) (int, error) {
|
||||
select {
|
||||
case b := <-c.C:
|
||||
return copy(p[0:], b), nil
|
||||
case <-time.After(n):
|
||||
return -1, fmt.Errorf("timeout reading from channel")
|
||||
}
|
||||
}
|
||||
|
||||
// RunAtDifferentDate runs the specified function with the given time.
|
||||
// It changes the date of the system, which can led to weird behaviors.
|
||||
func RunAtDifferentDate(date time.Time, block func()) {
|
||||
// Layout for date. MMDDhhmmYYYY
|
||||
const timeLayout = "010203042006"
|
||||
// Ensure we bring time back to now
|
||||
now := time.Now().Format(timeLayout)
|
||||
dateReset := exec.Command("date", now)
|
||||
defer RunCommand(dateReset)
|
||||
|
||||
dateChange := exec.Command("date", date.Format(timeLayout))
|
||||
RunCommand(dateChange)
|
||||
block()
|
||||
return
|
||||
}
|
572
vendor/github.com/containers/storage/pkg/integration/utils_test.go
generated
vendored
Normal file
572
vendor/github.com/containers/storage/pkg/integration/utils_test.go
generated
vendored
Normal file
|
@ -0,0 +1,572 @@
|
|||
package integration
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestIsKilledFalseWithNonKilledProcess(t *testing.T) {
|
||||
var lsCmd *exec.Cmd
|
||||
if runtime.GOOS != "windows" {
|
||||
lsCmd = exec.Command("ls")
|
||||
} else {
|
||||
lsCmd = exec.Command("cmd", "/c", "dir")
|
||||
}
|
||||
|
||||
err := lsCmd.Run()
|
||||
if IsKilled(err) {
|
||||
t.Fatalf("Expected the ls command to not be killed, was.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsKilledTrueWithKilledProcess(t *testing.T) {
|
||||
var longCmd *exec.Cmd
|
||||
if runtime.GOOS != "windows" {
|
||||
longCmd = exec.Command("top")
|
||||
} else {
|
||||
longCmd = exec.Command("powershell", "while ($true) { sleep 1 }")
|
||||
}
|
||||
|
||||
// Start a command
|
||||
err := longCmd.Start()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Capture the error when *dying*
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- longCmd.Wait()
|
||||
}()
|
||||
// Then kill it
|
||||
longCmd.Process.Kill()
|
||||
// Get the error
|
||||
err = <-done
|
||||
if !IsKilled(err) {
|
||||
t.Fatalf("Expected the command to be killed, was not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutput(t *testing.T) {
|
||||
var (
|
||||
echoHelloWorldCmd *exec.Cmd
|
||||
expected string
|
||||
)
|
||||
if runtime.GOOS != "windows" {
|
||||
echoHelloWorldCmd = exec.Command("echo", "hello", "world")
|
||||
expected = "hello world\n"
|
||||
} else {
|
||||
echoHelloWorldCmd = exec.Command("cmd", "/s", "/c", "echo", "hello", "world")
|
||||
expected = "hello world\r\n"
|
||||
}
|
||||
|
||||
out, exitCode, err := RunCommandWithOutput(echoHelloWorldCmd)
|
||||
if out != expected || exitCode != 0 || err != nil {
|
||||
t.Fatalf("Expected command to output %s, got %s, %v with exitCode %v", expected, out, err, exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputError(t *testing.T) {
|
||||
var (
|
||||
p string
|
||||
wrongCmd *exec.Cmd
|
||||
expected string
|
||||
expectedExitCode int
|
||||
)
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
p = "$PATH"
|
||||
wrongCmd = exec.Command("ls", "-z")
|
||||
expected = `ls: invalid option -- 'z'
|
||||
Try 'ls --help' for more information.
|
||||
`
|
||||
expectedExitCode = 2
|
||||
} else {
|
||||
p = "%PATH%"
|
||||
wrongCmd = exec.Command("cmd", "/s", "/c", "dir", "/Z")
|
||||
expected = "Invalid switch - " + strconv.Quote("Z") + ".\r\n"
|
||||
expectedExitCode = 1
|
||||
}
|
||||
cmd := exec.Command("doesnotexists")
|
||||
out, exitCode, err := RunCommandWithOutput(cmd)
|
||||
expectedError := `exec: "doesnotexists": executable file not found in ` + p
|
||||
if out != "" || exitCode != 127 || err == nil || err.Error() != expectedError {
|
||||
t.Fatalf("Expected command to output %s, got %s, %v with exitCode %v", expectedError, out, err, exitCode)
|
||||
}
|
||||
|
||||
out, exitCode, err = RunCommandWithOutput(wrongCmd)
|
||||
|
||||
if out != expected || exitCode != expectedExitCode || err == nil || !strings.Contains(err.Error(), "exit status "+strconv.Itoa(expectedExitCode)) {
|
||||
t.Fatalf("Expected command to output %s, got out:xxx%sxxx, err:%v with exitCode %v", expected, out, err, exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithStdoutStderr(t *testing.T) {
|
||||
echoHelloWorldCmd := exec.Command("echo", "hello", "world")
|
||||
stdout, stderr, exitCode, err := RunCommandWithStdoutStderr(echoHelloWorldCmd)
|
||||
expected := "hello world\n"
|
||||
if stdout != expected || stderr != "" || exitCode != 0 || err != nil {
|
||||
t.Fatalf("Expected command to output %s, got stdout:%s, stderr:%s, err:%v with exitCode %v", expected, stdout, stderr, err, exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithStdoutStderrError(t *testing.T) {
|
||||
p := "$PATH"
|
||||
if runtime.GOOS == "windows" {
|
||||
p = "%PATH%"
|
||||
}
|
||||
cmd := exec.Command("doesnotexists")
|
||||
stdout, stderr, exitCode, err := RunCommandWithStdoutStderr(cmd)
|
||||
expectedError := `exec: "doesnotexists": executable file not found in ` + p
|
||||
if stdout != "" || stderr != "" || exitCode != 127 || err == nil || err.Error() != expectedError {
|
||||
t.Fatalf("Expected command to output out:%s, stderr:%s, got stdout:%s, stderr:%s, err:%v with exitCode %v", "", "", stdout, stderr, err, exitCode)
|
||||
}
|
||||
|
||||
wrongLsCmd := exec.Command("ls", "-z")
|
||||
expected := `ls: invalid option -- 'z'
|
||||
Try 'ls --help' for more information.
|
||||
`
|
||||
|
||||
stdout, stderr, exitCode, err = RunCommandWithStdoutStderr(wrongLsCmd)
|
||||
if stdout != "" && stderr != expected || exitCode != 2 || err == nil || err.Error() != "exit status 2" {
|
||||
t.Fatalf("Expected command to output out:%s, stderr:%s, got stdout:%s, stderr:%s, err:%v with exitCode %v", "", expectedError, stdout, stderr, err, exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputForDurationFinished(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
cmd := exec.Command("ls")
|
||||
out, exitCode, timedOut, err := RunCommandWithOutputForDuration(cmd, 50*time.Millisecond)
|
||||
if out == "" || exitCode != 0 || timedOut || err != nil {
|
||||
t.Fatalf("Expected the command to run for less 50 milliseconds and thus not time out, but did not : out:[%s], exitCode:[%d], timedOut:[%v], err:[%v]", out, exitCode, timedOut, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputForDurationKilled(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
cmd := exec.Command("sh", "-c", "while true ; do echo 1 ; sleep .1 ; done")
|
||||
out, exitCode, timedOut, err := RunCommandWithOutputForDuration(cmd, 500*time.Millisecond)
|
||||
ones := strings.Split(out, "\n")
|
||||
if len(ones) != 6 || exitCode != 0 || !timedOut || err != nil {
|
||||
t.Fatalf("Expected the command to run for 500 milliseconds (and thus print six lines (five with 1, one empty) and time out, but did not : out:[%s], exitCode:%d, timedOut:%v, err:%v", out, exitCode, timedOut, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputForDurationErrors(t *testing.T) {
|
||||
cmd := exec.Command("ls")
|
||||
cmd.Stdout = os.Stdout
|
||||
if _, _, _, err := RunCommandWithOutputForDuration(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stdout already set" {
|
||||
t.Fatalf("Expected an error as cmd.Stdout was already set, did not (err:%s).", err)
|
||||
}
|
||||
cmd = exec.Command("ls")
|
||||
cmd.Stderr = os.Stderr
|
||||
if _, _, _, err := RunCommandWithOutputForDuration(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stderr already set" {
|
||||
t.Fatalf("Expected an error as cmd.Stderr was already set, did not (err:%s).", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputAndTimeoutFinished(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
cmd := exec.Command("ls")
|
||||
out, exitCode, err := RunCommandWithOutputAndTimeout(cmd, 50*time.Millisecond)
|
||||
if out == "" || exitCode != 0 || err != nil {
|
||||
t.Fatalf("Expected the command to run for less 50 milliseconds and thus not time out, but did not : out:[%s], exitCode:[%d], err:[%v]", out, exitCode, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputAndTimeoutKilled(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
cmd := exec.Command("sh", "-c", "while true ; do echo 1 ; sleep .1 ; done")
|
||||
out, exitCode, err := RunCommandWithOutputAndTimeout(cmd, 500*time.Millisecond)
|
||||
ones := strings.Split(out, "\n")
|
||||
if len(ones) != 6 || exitCode != 0 || err == nil || err.Error() != "command timed out" {
|
||||
t.Fatalf("Expected the command to run for 500 milliseconds (and thus print six lines (five with 1, one empty) and time out with an error 'command timed out', but did not : out:[%s], exitCode:%d, err:%v", out, exitCode, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandWithOutputAndTimeoutErrors(t *testing.T) {
|
||||
cmd := exec.Command("ls")
|
||||
cmd.Stdout = os.Stdout
|
||||
if _, _, err := RunCommandWithOutputAndTimeout(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stdout already set" {
|
||||
t.Fatalf("Expected an error as cmd.Stdout was already set, did not (err:%s).", err)
|
||||
}
|
||||
cmd = exec.Command("ls")
|
||||
cmd.Stderr = os.Stderr
|
||||
if _, _, err := RunCommandWithOutputAndTimeout(cmd, 1*time.Millisecond); err == nil || err.Error() != "cmd.Stderr already set" {
|
||||
t.Fatalf("Expected an error as cmd.Stderr was already set, did not (err:%s).", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommand(t *testing.T) {
|
||||
// TODO Windows: Port this test
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Needs porting to Windows")
|
||||
}
|
||||
|
||||
p := "$PATH"
|
||||
if runtime.GOOS == "windows" {
|
||||
p = "%PATH%"
|
||||
}
|
||||
lsCmd := exec.Command("ls")
|
||||
exitCode, err := RunCommand(lsCmd)
|
||||
if exitCode != 0 || err != nil {
|
||||
t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err)
|
||||
}
|
||||
|
||||
var expectedError string
|
||||
|
||||
exitCode, err = RunCommand(exec.Command("doesnotexists"))
|
||||
expectedError = `exec: "doesnotexists": executable file not found in ` + p
|
||||
if exitCode != 127 || err == nil || err.Error() != expectedError {
|
||||
t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err)
|
||||
}
|
||||
wrongLsCmd := exec.Command("ls", "-z")
|
||||
expected := 2
|
||||
expectedError = `exit status 2`
|
||||
exitCode, err = RunCommand(wrongLsCmd)
|
||||
if exitCode != expected || err == nil || err.Error() != expectedError {
|
||||
t.Fatalf("Expected runCommand to run the command successfully, got: exitCode:%d, err:%v", exitCode, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandPipelineWithOutputWithNotEnoughCmds(t *testing.T) {
|
||||
_, _, err := RunCommandPipelineWithOutput(exec.Command("ls"))
|
||||
expectedError := "pipeline does not have multiple cmds"
|
||||
if err == nil || err.Error() != expectedError {
|
||||
t.Fatalf("Expected an error with %s, got err:%s", expectedError, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandPipelineWithOutputErrors(t *testing.T) {
|
||||
p := "$PATH"
|
||||
if runtime.GOOS == "windows" {
|
||||
p = "%PATH%"
|
||||
}
|
||||
cmd1 := exec.Command("ls")
|
||||
cmd1.Stdout = os.Stdout
|
||||
cmd2 := exec.Command("anything really")
|
||||
_, _, err := RunCommandPipelineWithOutput(cmd1, cmd2)
|
||||
if err == nil || err.Error() != "cannot set stdout pipe for anything really: exec: Stdout already set" {
|
||||
t.Fatalf("Expected an error, got %v", err)
|
||||
}
|
||||
|
||||
cmdWithError := exec.Command("doesnotexists")
|
||||
cmdCat := exec.Command("cat")
|
||||
_, _, err = RunCommandPipelineWithOutput(cmdWithError, cmdCat)
|
||||
if err == nil || err.Error() != `starting doesnotexists failed with error: exec: "doesnotexists": executable file not found in `+p {
|
||||
t.Fatalf("Expected an error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCommandPipelineWithOutput(t *testing.T) {
|
||||
cmds := []*exec.Cmd{
|
||||
// Print 2 characters
|
||||
exec.Command("echo", "-n", "11"),
|
||||
// Count the number or char from stdin (previous command)
|
||||
exec.Command("wc", "-m"),
|
||||
}
|
||||
out, exitCode, err := RunCommandPipelineWithOutput(cmds...)
|
||||
expectedOutput := "2\n"
|
||||
if out != expectedOutput || exitCode != 0 || err != nil {
|
||||
t.Fatalf("Expected %s for commands %v, got out:%s, exitCode:%d, err:%v", expectedOutput, cmds, out, exitCode, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Simple simple test as it is just a passthrough for json.Unmarshal
|
||||
func TestUnmarshalJSON(t *testing.T) {
|
||||
emptyResult := struct{}{}
|
||||
if err := UnmarshalJSON([]byte(""), &emptyResult); err == nil {
|
||||
t.Fatalf("Expected an error, got nothing")
|
||||
}
|
||||
result := struct{ Name string }{}
|
||||
if err := UnmarshalJSON([]byte(`{"name": "name"}`), &result); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if result.Name != "name" {
|
||||
t.Fatalf("Expected result.name to be 'name', was '%s'", result.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertSliceOfStringsToMap(t *testing.T) {
|
||||
input := []string{"a", "b"}
|
||||
actual := ConvertSliceOfStringsToMap(input)
|
||||
for _, key := range input {
|
||||
if _, ok := actual[key]; !ok {
|
||||
t.Fatalf("Expected output to contains key %s, did not: %v", key, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompareDirectoryEntries(t *testing.T) {
|
||||
tmpFolder, err := ioutil.TempDir("", "integration-cli-utils-compare-directories")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpFolder)
|
||||
|
||||
file1 := filepath.Join(tmpFolder, "file1")
|
||||
file2 := filepath.Join(tmpFolder, "file2")
|
||||
os.Create(file1)
|
||||
os.Create(file2)
|
||||
|
||||
fi1, err := os.Stat(file1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fi1bis, err := os.Stat(file1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fi2, err := os.Stat(file2)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
e1 []os.FileInfo
|
||||
e2 []os.FileInfo
|
||||
shouldError bool
|
||||
}{
|
||||
// Empty directories
|
||||
{
|
||||
[]os.FileInfo{},
|
||||
[]os.FileInfo{},
|
||||
false,
|
||||
},
|
||||
// Same FileInfos
|
||||
{
|
||||
[]os.FileInfo{fi1},
|
||||
[]os.FileInfo{fi1},
|
||||
false,
|
||||
},
|
||||
// Different FileInfos but same names
|
||||
{
|
||||
[]os.FileInfo{fi1},
|
||||
[]os.FileInfo{fi1bis},
|
||||
false,
|
||||
},
|
||||
// Different FileInfos, different names
|
||||
{
|
||||
[]os.FileInfo{fi1},
|
||||
[]os.FileInfo{fi2},
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, elt := range cases {
|
||||
err := CompareDirectoryEntries(elt.e1, elt.e2)
|
||||
if elt.shouldError && err == nil {
|
||||
t.Fatalf("Should have return an error, did not with %v and %v", elt.e1, elt.e2)
|
||||
}
|
||||
if !elt.shouldError && err != nil {
|
||||
t.Fatalf("Should have not returned an error, but did : %v with %v and %v", err, elt.e1, elt.e2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME make an "unhappy path" test for ListTar without "panicking" :-)
|
||||
func TestListTar(t *testing.T) {
|
||||
// TODO Windows: Figure out why this fails. Should be portable.
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("Failing on Windows - needs further investigation")
|
||||
}
|
||||
tmpFolder, err := ioutil.TempDir("", "integration-cli-utils-list-tar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpFolder)
|
||||
|
||||
// Let's create a Tar file
|
||||
srcFile := filepath.Join(tmpFolder, "src")
|
||||
tarFile := filepath.Join(tmpFolder, "src.tar")
|
||||
os.Create(srcFile)
|
||||
cmd := exec.Command("sh", "-c", "tar cf "+tarFile+" "+srcFile)
|
||||
_, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
reader, err := os.Open(tarFile)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
entries, err := ListTar(reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(entries) != 1 && entries[0] != "src" {
|
||||
t.Fatalf("Expected a tar file with 1 entry (%s), got %v", srcFile, entries)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomTmpDirPath(t *testing.T) {
|
||||
path := RandomTmpDirPath("something", runtime.GOOS)
|
||||
|
||||
prefix := "/tmp/something"
|
||||
if runtime.GOOS == "windows" {
|
||||
prefix = os.Getenv("TEMP") + `\something`
|
||||
}
|
||||
expectedSize := len(prefix) + 11
|
||||
|
||||
if !strings.HasPrefix(path, prefix) {
|
||||
t.Fatalf("Expected generated path to have '%s' as prefix, got %s'", prefix, path)
|
||||
}
|
||||
if len(path) != expectedSize {
|
||||
t.Fatalf("Expected generated path to be %d, got %d", expectedSize, len(path))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConsumeWithSpeed(t *testing.T) {
|
||||
reader := strings.NewReader("1234567890")
|
||||
chunksize := 2
|
||||
|
||||
bytes1, err := ConsumeWithSpeed(reader, chunksize, 1*time.Second, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if bytes1 != 10 {
|
||||
t.Fatalf("Expected to have read 10 bytes, got %d", bytes1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestConsumeWithSpeedWithStop(t *testing.T) {
|
||||
reader := strings.NewReader("1234567890")
|
||||
chunksize := 2
|
||||
|
||||
stopIt := make(chan bool)
|
||||
|
||||
go func() {
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
stopIt <- true
|
||||
}()
|
||||
|
||||
bytes1, err := ConsumeWithSpeed(reader, chunksize, 20*time.Millisecond, stopIt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if bytes1 != 2 {
|
||||
t.Fatalf("Expected to have read 2 bytes, got %d", bytes1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestParseCgroupPathsEmpty(t *testing.T) {
|
||||
cgroupMap := ParseCgroupPaths("")
|
||||
if len(cgroupMap) != 0 {
|
||||
t.Fatalf("Expected an empty map, got %v", cgroupMap)
|
||||
}
|
||||
cgroupMap = ParseCgroupPaths("\n")
|
||||
if len(cgroupMap) != 0 {
|
||||
t.Fatalf("Expected an empty map, got %v", cgroupMap)
|
||||
}
|
||||
cgroupMap = ParseCgroupPaths("something:else\nagain:here")
|
||||
if len(cgroupMap) != 0 {
|
||||
t.Fatalf("Expected an empty map, got %v", cgroupMap)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseCgroupPaths(t *testing.T) {
|
||||
cgroupMap := ParseCgroupPaths("2:memory:/a\n1:cpuset:/b")
|
||||
if len(cgroupMap) != 2 {
|
||||
t.Fatalf("Expected a map with 2 entries, got %v", cgroupMap)
|
||||
}
|
||||
if value, ok := cgroupMap["memory"]; !ok || value != "/a" {
|
||||
t.Fatalf("Expected cgroupMap to contains an entry for 'memory' with value '/a', got %v", cgroupMap)
|
||||
}
|
||||
if value, ok := cgroupMap["cpuset"]; !ok || value != "/b" {
|
||||
t.Fatalf("Expected cgroupMap to contains an entry for 'cpuset' with value '/b', got %v", cgroupMap)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChannelBufferTimeout(t *testing.T) {
|
||||
expected := "11"
|
||||
|
||||
buf := &ChannelBuffer{make(chan []byte, 1)}
|
||||
defer buf.Close()
|
||||
|
||||
done := make(chan struct{}, 1)
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
io.Copy(buf, strings.NewReader(expected))
|
||||
done <- struct{}{}
|
||||
}()
|
||||
|
||||
// Wait long enough
|
||||
b := make([]byte, 2)
|
||||
_, err := buf.ReadTimeout(b, 50*time.Millisecond)
|
||||
if err == nil && err.Error() != "timeout reading from channel" {
|
||||
t.Fatalf("Expected an error, got %s", err)
|
||||
}
|
||||
<-done
|
||||
}
|
||||
|
||||
func TestChannelBuffer(t *testing.T) {
|
||||
expected := "11"
|
||||
|
||||
buf := &ChannelBuffer{make(chan []byte, 1)}
|
||||
defer buf.Close()
|
||||
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
io.Copy(buf, strings.NewReader(expected))
|
||||
}()
|
||||
|
||||
// Wait long enough
|
||||
b := make([]byte, 2)
|
||||
_, err := buf.ReadTimeout(b, 200*time.Millisecond)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if string(b) != expected {
|
||||
t.Fatalf("Expected '%s', got '%s'", expected, string(b))
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME doesn't work
|
||||
// func TestRunAtDifferentDate(t *testing.T) {
|
||||
// var date string
|
||||
|
||||
// // Layout for date. MMDDhhmmYYYY
|
||||
// const timeLayout = "20060102"
|
||||
// expectedDate := "20100201"
|
||||
// theDate, err := time.Parse(timeLayout, expectedDate)
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
// RunAtDifferentDate(theDate, func() {
|
||||
// cmd := exec.Command("date", "+%Y%M%d")
|
||||
// out, err := cmd.Output()
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// date = string(out)
|
||||
// })
|
||||
// }
|
75
vendor/github.com/containers/storage/pkg/ioutils/buffer_test.go
generated
vendored
Normal file
75
vendor/github.com/containers/storage/pkg/ioutils/buffer_test.go
generated
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
package ioutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFixedBufferWrite(t *testing.T) {
|
||||
buf := &fixedBuffer{buf: make([]byte, 0, 64)}
|
||||
n, err := buf.Write([]byte("hello"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n != 5 {
|
||||
t.Fatalf("expected 5 bytes written, got %d", n)
|
||||
}
|
||||
|
||||
if string(buf.buf[:5]) != "hello" {
|
||||
t.Fatalf("expected \"hello\", got %q", string(buf.buf[:5]))
|
||||
}
|
||||
|
||||
n, err = buf.Write(bytes.Repeat([]byte{1}, 64))
|
||||
if err != errBufferFull {
|
||||
t.Fatalf("expected errBufferFull, got %v - %v", err, buf.buf[:64])
|
||||
}
|
||||
}
|
||||
|
||||
func TestFixedBufferRead(t *testing.T) {
|
||||
buf := &fixedBuffer{buf: make([]byte, 0, 64)}
|
||||
if _, err := buf.Write([]byte("hello world")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
b := make([]byte, 5)
|
||||
n, err := buf.Read(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n != 5 {
|
||||
t.Fatalf("expected 5 bytes read, got %d - %s", n, buf.String())
|
||||
}
|
||||
|
||||
if string(b) != "hello" {
|
||||
t.Fatalf("expected \"hello\", got %q", string(b))
|
||||
}
|
||||
|
||||
n, err = buf.Read(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n != 5 {
|
||||
t.Fatalf("expected 5 bytes read, got %d", n)
|
||||
}
|
||||
|
||||
if string(b) != " worl" {
|
||||
t.Fatalf("expected \" worl\", got %s", string(b))
|
||||
}
|
||||
|
||||
b = b[:1]
|
||||
n, err = buf.Read(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if n != 1 {
|
||||
t.Fatalf("expected 1 byte read, got %d - %s", n, buf.String())
|
||||
}
|
||||
|
||||
if string(b) != "d" {
|
||||
t.Fatalf("expected \"d\", got %s", string(b))
|
||||
}
|
||||
}
|
17
vendor/github.com/containers/storage/pkg/ioutils/fmt_test.go
generated
vendored
Normal file
17
vendor/github.com/containers/storage/pkg/ioutils/fmt_test.go
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
package ioutils
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestFprintfIfNotEmpty(t *testing.T) {
|
||||
wc := NewWriteCounter(&NopWriter{})
|
||||
n, _ := FprintfIfNotEmpty(wc, "foo%s", "")
|
||||
|
||||
if wc.Count != 0 || n != 0 {
|
||||
t.Errorf("Wrong count: %v vs. %v vs. 0", wc.Count, n)
|
||||
}
|
||||
|
||||
n, _ = FprintfIfNotEmpty(wc, "foo%s", "bar")
|
||||
if wc.Count != 6 || n != 6 {
|
||||
t.Errorf("Wrong count: %v vs. %v vs. 6", wc.Count, n)
|
||||
}
|
||||
}
|
39
vendor/github.com/containers/storage/pkg/ioutils/fswriters_test.go
generated
vendored
Normal file
39
vendor/github.com/containers/storage/pkg/ioutils/fswriters_test.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
package ioutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAtomicWriteToFile(t *testing.T) {
|
||||
tmpDir, err := ioutil.TempDir("", "atomic-writers-test")
|
||||
if err != nil {
|
||||
t.Fatalf("Error when creating temporary directory: %s", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
expected := []byte("barbaz")
|
||||
if err := AtomicWriteFile(filepath.Join(tmpDir, "foo"), expected, 0666); err != nil {
|
||||
t.Fatalf("Error writing to file: %v", err)
|
||||
}
|
||||
|
||||
actual, err := ioutil.ReadFile(filepath.Join(tmpDir, "foo"))
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading from file: %v", err)
|
||||
}
|
||||
|
||||
if bytes.Compare(actual, expected) != 0 {
|
||||
t.Fatalf("Data mismatch, expected %q, got %q", expected, actual)
|
||||
}
|
||||
|
||||
st, err := os.Stat(filepath.Join(tmpDir, "foo"))
|
||||
if err != nil {
|
||||
t.Fatalf("Error statting file: %v", err)
|
||||
}
|
||||
if expected := os.FileMode(0666); st.Mode() != expected {
|
||||
t.Fatalf("Mode mismatched, expected %o, got %o", expected, st.Mode())
|
||||
}
|
||||
}
|
149
vendor/github.com/containers/storage/pkg/ioutils/multireader_test.go
generated
vendored
Normal file
149
vendor/github.com/containers/storage/pkg/ioutils/multireader_test.go
generated
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
package ioutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMultiReadSeekerReadAll(t *testing.T) {
|
||||
str := "hello world"
|
||||
s1 := strings.NewReader(str + " 1")
|
||||
s2 := strings.NewReader(str + " 2")
|
||||
s3 := strings.NewReader(str + " 3")
|
||||
mr := MultiReadSeeker(s1, s2, s3)
|
||||
|
||||
expectedSize := int64(s1.Len() + s2.Len() + s3.Len())
|
||||
|
||||
b, err := ioutil.ReadAll(mr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := "hello world 1hello world 2hello world 3"
|
||||
if string(b) != expected {
|
||||
t.Fatalf("ReadAll failed, got: %q, expected %q", string(b), expected)
|
||||
}
|
||||
|
||||
size, err := mr.Seek(0, os.SEEK_END)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if size != expectedSize {
|
||||
t.Fatalf("reader size does not match, got %d, expected %d", size, expectedSize)
|
||||
}
|
||||
|
||||
// Reset the position and read again
|
||||
pos, err := mr.Seek(0, os.SEEK_SET)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if pos != 0 {
|
||||
t.Fatalf("expected position to be set to 0, got %d", pos)
|
||||
}
|
||||
|
||||
b, err = ioutil.ReadAll(mr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if string(b) != expected {
|
||||
t.Fatalf("ReadAll failed, got: %q, expected %q", string(b), expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiReadSeekerReadEach(t *testing.T) {
|
||||
str := "hello world"
|
||||
s1 := strings.NewReader(str + " 1")
|
||||
s2 := strings.NewReader(str + " 2")
|
||||
s3 := strings.NewReader(str + " 3")
|
||||
mr := MultiReadSeeker(s1, s2, s3)
|
||||
|
||||
var totalBytes int64
|
||||
for i, s := range []*strings.Reader{s1, s2, s3} {
|
||||
sLen := int64(s.Len())
|
||||
buf := make([]byte, s.Len())
|
||||
expected := []byte(fmt.Sprintf("%s %d", str, i+1))
|
||||
|
||||
if _, err := mr.Read(buf); err != nil && err != io.EOF {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(buf, expected) {
|
||||
t.Fatalf("expected %q to be %q", string(buf), string(expected))
|
||||
}
|
||||
|
||||
pos, err := mr.Seek(0, os.SEEK_CUR)
|
||||
if err != nil {
|
||||
t.Fatalf("iteration: %d, error: %v", i+1, err)
|
||||
}
|
||||
|
||||
// check that the total bytes read is the current position of the seeker
|
||||
totalBytes += sLen
|
||||
if pos != totalBytes {
|
||||
t.Fatalf("expected current position to be: %d, got: %d, iteration: %d", totalBytes, pos, i+1)
|
||||
}
|
||||
|
||||
// This tests not only that SEEK_SET and SEEK_CUR give the same values, but that the next iteration is in the expected position as well
|
||||
newPos, err := mr.Seek(pos, os.SEEK_SET)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if newPos != pos {
|
||||
t.Fatalf("expected to get same position when calling SEEK_SET with value from SEEK_CUR, cur: %d, set: %d", pos, newPos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiReadSeekerReadSpanningChunks(t *testing.T) {
|
||||
str := "hello world"
|
||||
s1 := strings.NewReader(str + " 1")
|
||||
s2 := strings.NewReader(str + " 2")
|
||||
s3 := strings.NewReader(str + " 3")
|
||||
mr := MultiReadSeeker(s1, s2, s3)
|
||||
|
||||
buf := make([]byte, s1.Len()+3)
|
||||
_, err := mr.Read(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// expected is the contents of s1 + 3 bytes from s2, ie, the `hel` at the end of this string
|
||||
expected := "hello world 1hel"
|
||||
if string(buf) != expected {
|
||||
t.Fatalf("expected %s to be %s", string(buf), expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultiReadSeekerNegativeSeek(t *testing.T) {
|
||||
str := "hello world"
|
||||
s1 := strings.NewReader(str + " 1")
|
||||
s2 := strings.NewReader(str + " 2")
|
||||
s3 := strings.NewReader(str + " 3")
|
||||
mr := MultiReadSeeker(s1, s2, s3)
|
||||
|
||||
s1Len := s1.Len()
|
||||
s2Len := s2.Len()
|
||||
s3Len := s3.Len()
|
||||
|
||||
s, err := mr.Seek(int64(-1*s3.Len()), os.SEEK_END)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if s != int64(s1Len+s2Len) {
|
||||
t.Fatalf("expected %d to be %d", s, s1.Len()+s2.Len())
|
||||
}
|
||||
|
||||
buf := make([]byte, s3Len)
|
||||
if _, err := mr.Read(buf); err != nil && err != io.EOF {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := fmt.Sprintf("%s %d", str, 3)
|
||||
if string(buf) != fmt.Sprintf("%s %d", str, 3) {
|
||||
t.Fatalf("expected %q to be %q", string(buf), expected)
|
||||
}
|
||||
}
|
94
vendor/github.com/containers/storage/pkg/ioutils/readers_test.go
generated
vendored
Normal file
94
vendor/github.com/containers/storage/pkg/ioutils/readers_test.go
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
package ioutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Implement io.Reader
|
||||
type errorReader struct{}
|
||||
|
||||
func (r *errorReader) Read(p []byte) (int, error) {
|
||||
return 0, fmt.Errorf("Error reader always fail.")
|
||||
}
|
||||
|
||||
func TestReadCloserWrapperClose(t *testing.T) {
|
||||
reader := strings.NewReader("A string reader")
|
||||
wrapper := NewReadCloserWrapper(reader, func() error {
|
||||
return fmt.Errorf("This will be called when closing")
|
||||
})
|
||||
err := wrapper.Close()
|
||||
if err == nil || !strings.Contains(err.Error(), "This will be called when closing") {
|
||||
t.Fatalf("readCloserWrapper should have call the anonymous func and thus, fail.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReaderErrWrapperReadOnError(t *testing.T) {
|
||||
called := false
|
||||
reader := &errorReader{}
|
||||
wrapper := NewReaderErrWrapper(reader, func() {
|
||||
called = true
|
||||
})
|
||||
_, err := wrapper.Read([]byte{})
|
||||
if err == nil || !strings.Contains(err.Error(), "Error reader always fail.") {
|
||||
t.Fatalf("readErrWrapper should returned an error")
|
||||
}
|
||||
if !called {
|
||||
t.Fatalf("readErrWrapper should have call the anonymous function on failure")
|
||||
}
|
||||
}
|
||||
|
||||
func TestReaderErrWrapperRead(t *testing.T) {
|
||||
reader := strings.NewReader("a string reader.")
|
||||
wrapper := NewReaderErrWrapper(reader, func() {
|
||||
t.Fatalf("readErrWrapper should not have called the anonymous function")
|
||||
})
|
||||
// Read 20 byte (should be ok with the string above)
|
||||
num, err := wrapper.Read(make([]byte, 20))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if num != 16 {
|
||||
t.Fatalf("readerErrWrapper should have read 16 byte, but read %d", num)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHashData(t *testing.T) {
|
||||
reader := strings.NewReader("hash-me")
|
||||
actual, err := HashData(reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := "sha256:4d11186aed035cc624d553e10db358492c84a7cd6b9670d92123c144930450aa"
|
||||
if actual != expected {
|
||||
t.Fatalf("Expecting %s, got %s", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
type perpetualReader struct{}
|
||||
|
||||
func (p *perpetualReader) Read(buf []byte) (n int, err error) {
|
||||
for i := 0; i != len(buf); i++ {
|
||||
buf[i] = 'a'
|
||||
}
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func TestCancelReadCloser(t *testing.T) {
|
||||
ctx, _ := context.WithTimeout(context.Background(), 100*time.Millisecond)
|
||||
cancelReadCloser := NewCancelReadCloser(ctx, ioutil.NopCloser(&perpetualReader{}))
|
||||
for {
|
||||
var buf [128]byte
|
||||
_, err := cancelReadCloser.Read(buf[:])
|
||||
if err == context.DeadlineExceeded {
|
||||
break
|
||||
} else if err != nil {
|
||||
t.Fatalf("got unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
65
vendor/github.com/containers/storage/pkg/ioutils/writers_test.go
generated
vendored
Normal file
65
vendor/github.com/containers/storage/pkg/ioutils/writers_test.go
generated
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
package ioutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestWriteCloserWrapperClose(t *testing.T) {
|
||||
called := false
|
||||
writer := bytes.NewBuffer([]byte{})
|
||||
wrapper := NewWriteCloserWrapper(writer, func() error {
|
||||
called = true
|
||||
return nil
|
||||
})
|
||||
if err := wrapper.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !called {
|
||||
t.Fatalf("writeCloserWrapper should have call the anonymous function.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNopWriteCloser(t *testing.T) {
|
||||
writer := bytes.NewBuffer([]byte{})
|
||||
wrapper := NopWriteCloser(writer)
|
||||
if err := wrapper.Close(); err != nil {
|
||||
t.Fatal("NopWriteCloser always return nil on Close.")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestNopWriter(t *testing.T) {
|
||||
nw := &NopWriter{}
|
||||
l, err := nw.Write([]byte{'c'})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if l != 1 {
|
||||
t.Fatalf("Expected 1 got %d", l)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteCounter(t *testing.T) {
|
||||
dummy1 := "This is a dummy string."
|
||||
dummy2 := "This is another dummy string."
|
||||
totalLength := int64(len(dummy1) + len(dummy2))
|
||||
|
||||
reader1 := strings.NewReader(dummy1)
|
||||
reader2 := strings.NewReader(dummy2)
|
||||
|
||||
var buffer bytes.Buffer
|
||||
wc := NewWriteCounter(&buffer)
|
||||
|
||||
reader1.WriteTo(wc)
|
||||
reader2.WriteTo(wc)
|
||||
|
||||
if wc.Count != totalLength {
|
||||
t.Errorf("Wrong count: %d vs. %d", wc.Count, totalLength)
|
||||
}
|
||||
|
||||
if buffer.String() != dummy1+dummy2 {
|
||||
t.Error("Wrong message written")
|
||||
}
|
||||
}
|
26
vendor/github.com/containers/storage/pkg/longpath/longpath.go
generated
vendored
Normal file
26
vendor/github.com/containers/storage/pkg/longpath/longpath.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
// longpath introduces some constants and helper functions for handling long paths
|
||||
// in Windows, which are expected to be prepended with `\\?\` and followed by either
|
||||
// a drive letter, a UNC server\share, or a volume identifier.
|
||||
|
||||
package longpath
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Prefix is the longpath prefix for Windows file paths.
|
||||
const Prefix = `\\?\`
|
||||
|
||||
// AddPrefix will add the Windows long path prefix to the path provided if
|
||||
// it does not already have it.
|
||||
func AddPrefix(path string) string {
|
||||
if !strings.HasPrefix(path, Prefix) {
|
||||
if strings.HasPrefix(path, `\\`) {
|
||||
// This is a UNC path, so we need to add 'UNC' to the path as well.
|
||||
path = Prefix + `UNC` + path[1:]
|
||||
} else {
|
||||
path = Prefix + path
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
22
vendor/github.com/containers/storage/pkg/longpath/longpath_test.go
generated
vendored
Normal file
22
vendor/github.com/containers/storage/pkg/longpath/longpath_test.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
package longpath
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStandardLongPath(t *testing.T) {
|
||||
c := `C:\simple\path`
|
||||
longC := AddPrefix(c)
|
||||
if !strings.EqualFold(longC, `\\?\C:\simple\path`) {
|
||||
t.Errorf("Wrong long path returned. Original = %s ; Long = %s", c, longC)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUNCLongPath(t *testing.T) {
|
||||
c := `\\server\share\path`
|
||||
longC := AddPrefix(c)
|
||||
if !strings.EqualFold(longC, `\\?\UNC\server\share\path`) {
|
||||
t.Errorf("Wrong UNC long path returned. Original = %s ; Long = %s", c, longC)
|
||||
}
|
||||
}
|
36
vendor/github.com/containers/storage/pkg/mflag/example/example.go
generated
vendored
Normal file
36
vendor/github.com/containers/storage/pkg/mflag/example/example.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
flag "github.com/containers/storage/pkg/mflag"
|
||||
)
|
||||
|
||||
var (
|
||||
i int
|
||||
str string
|
||||
b, b2, h bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.Bool([]string{"#hp", "#-halp"}, false, "display the halp")
|
||||
flag.BoolVar(&b, []string{"b", "#bal", "#bol", "-bal"}, false, "a simple bool")
|
||||
flag.BoolVar(&b, []string{"g", "#gil"}, false, "a simple bool")
|
||||
flag.BoolVar(&b2, []string{"#-bool"}, false, "a simple bool")
|
||||
flag.IntVar(&i, []string{"-integer", "-number"}, -1, "a simple integer")
|
||||
flag.StringVar(&str, []string{"s", "#hidden", "-string"}, "", "a simple string") //-s -hidden and --string will work, but -hidden won't be in the usage
|
||||
flag.BoolVar(&h, []string{"h", "#help", "-help"}, false, "display the help")
|
||||
flag.StringVar(&str, []string{"mode"}, "mode1", "set the mode\nmode1: use the mode1\nmode2: use the mode2\nmode3: use the mode3")
|
||||
flag.Parse()
|
||||
}
|
||||
func main() {
|
||||
if h {
|
||||
flag.PrintDefaults()
|
||||
} else {
|
||||
fmt.Printf("s/#hidden/-string: %s\n", str)
|
||||
fmt.Printf("b: %t\n", b)
|
||||
fmt.Printf("-bool: %t\n", b2)
|
||||
fmt.Printf("s/#hidden/-string(via lookup): %s\n", flag.Lookup("s").Value.String())
|
||||
fmt.Printf("ARGS: %v\n", flag.Args())
|
||||
}
|
||||
}
|
1280
vendor/github.com/containers/storage/pkg/mflag/flag.go
generated
vendored
Normal file
1280
vendor/github.com/containers/storage/pkg/mflag/flag.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
527
vendor/github.com/containers/storage/pkg/mflag/flag_test.go
generated
vendored
Normal file
527
vendor/github.com/containers/storage/pkg/mflag/flag_test.go
generated
vendored
Normal file
|
@ -0,0 +1,527 @@
|
|||
// Copyright 2014-2016 The Docker & Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package mflag
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ResetForTesting clears all flag state and sets the usage function as directed.
|
||||
// After calling ResetForTesting, parse errors in flag handling will not
|
||||
// exit the program.
|
||||
func ResetForTesting(usage func()) {
|
||||
CommandLine = NewFlagSet(os.Args[0], ContinueOnError)
|
||||
Usage = usage
|
||||
}
|
||||
func boolString(s string) string {
|
||||
if s == "0" {
|
||||
return "false"
|
||||
}
|
||||
return "true"
|
||||
}
|
||||
|
||||
func TestEverything(t *testing.T) {
|
||||
ResetForTesting(nil)
|
||||
Bool([]string{"test_bool"}, false, "bool value")
|
||||
Int([]string{"test_int"}, 0, "int value")
|
||||
Int64([]string{"test_int64"}, 0, "int64 value")
|
||||
Uint([]string{"test_uint"}, 0, "uint value")
|
||||
Uint64([]string{"test_uint64"}, 0, "uint64 value")
|
||||
String([]string{"test_string"}, "0", "string value")
|
||||
Float64([]string{"test_float64"}, 0, "float64 value")
|
||||
Duration([]string{"test_duration"}, 0, "time.Duration value")
|
||||
|
||||
m := make(map[string]*Flag)
|
||||
desired := "0"
|
||||
visitor := func(f *Flag) {
|
||||
for _, name := range f.Names {
|
||||
if len(name) > 5 && name[0:5] == "test_" {
|
||||
m[name] = f
|
||||
ok := false
|
||||
switch {
|
||||
case f.Value.String() == desired:
|
||||
ok = true
|
||||
case name == "test_bool" && f.Value.String() == boolString(desired):
|
||||
ok = true
|
||||
case name == "test_duration" && f.Value.String() == desired+"s":
|
||||
ok = true
|
||||
}
|
||||
if !ok {
|
||||
t.Error("Visit: bad value", f.Value.String(), "for", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VisitAll(visitor)
|
||||
if len(m) != 8 {
|
||||
t.Error("VisitAll misses some flags")
|
||||
for k, v := range m {
|
||||
t.Log(k, *v)
|
||||
}
|
||||
}
|
||||
m = make(map[string]*Flag)
|
||||
Visit(visitor)
|
||||
if len(m) != 0 {
|
||||
t.Errorf("Visit sees unset flags")
|
||||
for k, v := range m {
|
||||
t.Log(k, *v)
|
||||
}
|
||||
}
|
||||
// Now set all flags
|
||||
Set("test_bool", "true")
|
||||
Set("test_int", "1")
|
||||
Set("test_int64", "1")
|
||||
Set("test_uint", "1")
|
||||
Set("test_uint64", "1")
|
||||
Set("test_string", "1")
|
||||
Set("test_float64", "1")
|
||||
Set("test_duration", "1s")
|
||||
desired = "1"
|
||||
Visit(visitor)
|
||||
if len(m) != 8 {
|
||||
t.Error("Visit fails after set")
|
||||
for k, v := range m {
|
||||
t.Log(k, *v)
|
||||
}
|
||||
}
|
||||
// Now test they're visited in sort order.
|
||||
var flagNames []string
|
||||
Visit(func(f *Flag) {
|
||||
for _, name := range f.Names {
|
||||
flagNames = append(flagNames, name)
|
||||
}
|
||||
})
|
||||
if !sort.StringsAreSorted(flagNames) {
|
||||
t.Errorf("flag names not sorted: %v", flagNames)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
ResetForTesting(nil)
|
||||
Bool([]string{"test_bool"}, true, "bool value")
|
||||
Int([]string{"test_int"}, 1, "int value")
|
||||
Int64([]string{"test_int64"}, 2, "int64 value")
|
||||
Uint([]string{"test_uint"}, 3, "uint value")
|
||||
Uint64([]string{"test_uint64"}, 4, "uint64 value")
|
||||
String([]string{"test_string"}, "5", "string value")
|
||||
Float64([]string{"test_float64"}, 6, "float64 value")
|
||||
Duration([]string{"test_duration"}, 7, "time.Duration value")
|
||||
|
||||
visitor := func(f *Flag) {
|
||||
for _, name := range f.Names {
|
||||
if len(name) > 5 && name[0:5] == "test_" {
|
||||
g, ok := f.Value.(Getter)
|
||||
if !ok {
|
||||
t.Errorf("Visit: value does not satisfy Getter: %T", f.Value)
|
||||
return
|
||||
}
|
||||
switch name {
|
||||
case "test_bool":
|
||||
ok = g.Get() == true
|
||||
case "test_int":
|
||||
ok = g.Get() == int(1)
|
||||
case "test_int64":
|
||||
ok = g.Get() == int64(2)
|
||||
case "test_uint":
|
||||
ok = g.Get() == uint(3)
|
||||
case "test_uint64":
|
||||
ok = g.Get() == uint64(4)
|
||||
case "test_string":
|
||||
ok = g.Get() == "5"
|
||||
case "test_float64":
|
||||
ok = g.Get() == float64(6)
|
||||
case "test_duration":
|
||||
ok = g.Get() == time.Duration(7)
|
||||
}
|
||||
if !ok {
|
||||
t.Errorf("Visit: bad value %T(%v) for %s", g.Get(), g.Get(), name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VisitAll(visitor)
|
||||
}
|
||||
|
||||
func testParse(f *FlagSet, t *testing.T) {
|
||||
if f.Parsed() {
|
||||
t.Error("f.Parse() = true before Parse")
|
||||
}
|
||||
boolFlag := f.Bool([]string{"bool"}, false, "bool value")
|
||||
bool2Flag := f.Bool([]string{"bool2"}, false, "bool2 value")
|
||||
f.Bool([]string{"bool3"}, false, "bool3 value")
|
||||
bool4Flag := f.Bool([]string{"bool4"}, false, "bool4 value")
|
||||
intFlag := f.Int([]string{"-int"}, 0, "int value")
|
||||
int64Flag := f.Int64([]string{"-int64"}, 0, "int64 value")
|
||||
uintFlag := f.Uint([]string{"uint"}, 0, "uint value")
|
||||
uint64Flag := f.Uint64([]string{"-uint64"}, 0, "uint64 value")
|
||||
stringFlag := f.String([]string{"string"}, "0", "string value")
|
||||
f.String([]string{"string2"}, "0", "string2 value")
|
||||
singleQuoteFlag := f.String([]string{"squote"}, "", "single quoted value")
|
||||
doubleQuoteFlag := f.String([]string{"dquote"}, "", "double quoted value")
|
||||
mixedQuoteFlag := f.String([]string{"mquote"}, "", "mixed quoted value")
|
||||
mixed2QuoteFlag := f.String([]string{"mquote2"}, "", "mixed2 quoted value")
|
||||
nestedQuoteFlag := f.String([]string{"nquote"}, "", "nested quoted value")
|
||||
nested2QuoteFlag := f.String([]string{"nquote2"}, "", "nested2 quoted value")
|
||||
float64Flag := f.Float64([]string{"float64"}, 0, "float64 value")
|
||||
durationFlag := f.Duration([]string{"duration"}, 5*time.Second, "time.Duration value")
|
||||
extra := "one-extra-argument"
|
||||
args := []string{
|
||||
"-bool",
|
||||
"-bool2=true",
|
||||
"-bool4=false",
|
||||
"--int", "22",
|
||||
"--int64", "0x23",
|
||||
"-uint", "24",
|
||||
"--uint64", "25",
|
||||
"-string", "hello",
|
||||
"-squote='single'",
|
||||
`-dquote="double"`,
|
||||
`-mquote='mixed"`,
|
||||
`-mquote2="mixed2'`,
|
||||
`-nquote="'single nested'"`,
|
||||
`-nquote2='"double nested"'`,
|
||||
"-float64", "2718e28",
|
||||
"-duration", "2m",
|
||||
extra,
|
||||
}
|
||||
if err := f.Parse(args); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !f.Parsed() {
|
||||
t.Error("f.Parse() = false after Parse")
|
||||
}
|
||||
if *boolFlag != true {
|
||||
t.Error("bool flag should be true, is ", *boolFlag)
|
||||
}
|
||||
if *bool2Flag != true {
|
||||
t.Error("bool2 flag should be true, is ", *bool2Flag)
|
||||
}
|
||||
if !f.IsSet("bool2") {
|
||||
t.Error("bool2 should be marked as set")
|
||||
}
|
||||
if f.IsSet("bool3") {
|
||||
t.Error("bool3 should not be marked as set")
|
||||
}
|
||||
if !f.IsSet("bool4") {
|
||||
t.Error("bool4 should be marked as set")
|
||||
}
|
||||
if *bool4Flag != false {
|
||||
t.Error("bool4 flag should be false, is ", *bool4Flag)
|
||||
}
|
||||
if *intFlag != 22 {
|
||||
t.Error("int flag should be 22, is ", *intFlag)
|
||||
}
|
||||
if *int64Flag != 0x23 {
|
||||
t.Error("int64 flag should be 0x23, is ", *int64Flag)
|
||||
}
|
||||
if *uintFlag != 24 {
|
||||
t.Error("uint flag should be 24, is ", *uintFlag)
|
||||
}
|
||||
if *uint64Flag != 25 {
|
||||
t.Error("uint64 flag should be 25, is ", *uint64Flag)
|
||||
}
|
||||
if *stringFlag != "hello" {
|
||||
t.Error("string flag should be `hello`, is ", *stringFlag)
|
||||
}
|
||||
if !f.IsSet("string") {
|
||||
t.Error("string flag should be marked as set")
|
||||
}
|
||||
if f.IsSet("string2") {
|
||||
t.Error("string2 flag should not be marked as set")
|
||||
}
|
||||
if *singleQuoteFlag != "single" {
|
||||
t.Error("single quote string flag should be `single`, is ", *singleQuoteFlag)
|
||||
}
|
||||
if *doubleQuoteFlag != "double" {
|
||||
t.Error("double quote string flag should be `double`, is ", *doubleQuoteFlag)
|
||||
}
|
||||
if *mixedQuoteFlag != `'mixed"` {
|
||||
t.Error("mixed quote string flag should be `'mixed\"`, is ", *mixedQuoteFlag)
|
||||
}
|
||||
if *mixed2QuoteFlag != `"mixed2'` {
|
||||
t.Error("mixed2 quote string flag should be `\"mixed2'`, is ", *mixed2QuoteFlag)
|
||||
}
|
||||
if *nestedQuoteFlag != "'single nested'" {
|
||||
t.Error("nested quote string flag should be `'single nested'`, is ", *nestedQuoteFlag)
|
||||
}
|
||||
if *nested2QuoteFlag != `"double nested"` {
|
||||
t.Error("double quote string flag should be `\"double nested\"`, is ", *nested2QuoteFlag)
|
||||
}
|
||||
if *float64Flag != 2718e28 {
|
||||
t.Error("float64 flag should be 2718e28, is ", *float64Flag)
|
||||
}
|
||||
if *durationFlag != 2*time.Minute {
|
||||
t.Error("duration flag should be 2m, is ", *durationFlag)
|
||||
}
|
||||
if len(f.Args()) != 1 {
|
||||
t.Error("expected one argument, got", len(f.Args()))
|
||||
} else if f.Args()[0] != extra {
|
||||
t.Errorf("expected argument %q got %q", extra, f.Args()[0])
|
||||
}
|
||||
}
|
||||
|
||||
func testPanic(f *FlagSet, t *testing.T) {
|
||||
f.Int([]string{"-int"}, 0, "int value")
|
||||
if f.Parsed() {
|
||||
t.Error("f.Parse() = true before Parse")
|
||||
}
|
||||
args := []string{
|
||||
"-int", "21",
|
||||
}
|
||||
f.Parse(args)
|
||||
}
|
||||
|
||||
func TestParsePanic(t *testing.T) {
|
||||
ResetForTesting(func() {})
|
||||
testPanic(CommandLine, t)
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
ResetForTesting(func() { t.Error("bad parse") })
|
||||
testParse(CommandLine, t)
|
||||
}
|
||||
|
||||
func TestFlagSetParse(t *testing.T) {
|
||||
testParse(NewFlagSet("test", ContinueOnError), t)
|
||||
}
|
||||
|
||||
// Declare a user-defined flag type.
|
||||
type flagVar []string
|
||||
|
||||
func (f *flagVar) String() string {
|
||||
return fmt.Sprint([]string(*f))
|
||||
}
|
||||
|
||||
func (f *flagVar) Set(value string) error {
|
||||
*f = append(*f, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestUserDefined(t *testing.T) {
|
||||
var flags FlagSet
|
||||
flags.Init("test", ContinueOnError)
|
||||
var v flagVar
|
||||
flags.Var(&v, []string{"v"}, "usage")
|
||||
if err := flags.Parse([]string{"-v", "1", "-v", "2", "-v=3"}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(v) != 3 {
|
||||
t.Fatal("expected 3 args; got ", len(v))
|
||||
}
|
||||
expect := "[1 2 3]"
|
||||
if v.String() != expect {
|
||||
t.Errorf("expected value %q got %q", expect, v.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Declare a user-defined boolean flag type.
|
||||
type boolFlagVar struct {
|
||||
count int
|
||||
}
|
||||
|
||||
func (b *boolFlagVar) String() string {
|
||||
return fmt.Sprintf("%d", b.count)
|
||||
}
|
||||
|
||||
func (b *boolFlagVar) Set(value string) error {
|
||||
if value == "true" {
|
||||
b.count++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *boolFlagVar) IsBoolFlag() bool {
|
||||
return b.count < 4
|
||||
}
|
||||
|
||||
func TestUserDefinedBool(t *testing.T) {
|
||||
var flags FlagSet
|
||||
flags.Init("test", ContinueOnError)
|
||||
var b boolFlagVar
|
||||
var err error
|
||||
flags.Var(&b, []string{"b"}, "usage")
|
||||
if err = flags.Parse([]string{"-b", "-b", "-b", "-b=true", "-b=false", "-b", "barg", "-b"}); err != nil {
|
||||
if b.count < 4 {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
if b.count != 4 {
|
||||
t.Errorf("want: %d; got: %d", 4, b.count)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
t.Error("expected error; got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetOutput(t *testing.T) {
|
||||
var flags FlagSet
|
||||
var buf bytes.Buffer
|
||||
flags.SetOutput(&buf)
|
||||
flags.Init("test", ContinueOnError)
|
||||
flags.Parse([]string{"-unknown"})
|
||||
if out := buf.String(); !strings.Contains(out, "-unknown") {
|
||||
t.Logf("expected output mentioning unknown; got %q", out)
|
||||
}
|
||||
}
|
||||
|
||||
// This tests that one can reset the flags. This still works but not well, and is
|
||||
// superseded by FlagSet.
|
||||
func TestChangingArgs(t *testing.T) {
|
||||
ResetForTesting(func() { t.Fatal("bad parse") })
|
||||
oldArgs := os.Args
|
||||
defer func() { os.Args = oldArgs }()
|
||||
os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"}
|
||||
before := Bool([]string{"before"}, false, "")
|
||||
if err := CommandLine.Parse(os.Args[1:]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cmd := Arg(0)
|
||||
os.Args = Args()
|
||||
after := Bool([]string{"after"}, false, "")
|
||||
Parse()
|
||||
args := Args()
|
||||
|
||||
if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" {
|
||||
t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that -help invokes the usage message and returns ErrHelp.
|
||||
func TestHelp(t *testing.T) {
|
||||
var helpCalled = false
|
||||
fs := NewFlagSet("help test", ContinueOnError)
|
||||
fs.Usage = func() { helpCalled = true }
|
||||
var flag bool
|
||||
fs.BoolVar(&flag, []string{"flag"}, false, "regular flag")
|
||||
// Regular flag invocation should work
|
||||
err := fs.Parse([]string{"-flag=true"})
|
||||
if err != nil {
|
||||
t.Fatal("expected no error; got ", err)
|
||||
}
|
||||
if !flag {
|
||||
t.Error("flag was not set by -flag")
|
||||
}
|
||||
if helpCalled {
|
||||
t.Error("help called for regular flag")
|
||||
helpCalled = false // reset for next test
|
||||
}
|
||||
// Help flag should work as expected.
|
||||
err = fs.Parse([]string{"-help"})
|
||||
if err == nil {
|
||||
t.Fatal("error expected")
|
||||
}
|
||||
if err != ErrHelp {
|
||||
t.Fatal("expected ErrHelp; got ", err)
|
||||
}
|
||||
if !helpCalled {
|
||||
t.Fatal("help was not called")
|
||||
}
|
||||
// If we define a help flag, that should override.
|
||||
var help bool
|
||||
fs.BoolVar(&help, []string{"help"}, false, "help flag")
|
||||
helpCalled = false
|
||||
err = fs.Parse([]string{"-help"})
|
||||
if err != nil {
|
||||
t.Fatal("expected no error for defined -help; got ", err)
|
||||
}
|
||||
if helpCalled {
|
||||
t.Fatal("help was called; should not have been for defined help flag")
|
||||
}
|
||||
}
|
||||
|
||||
// Test the flag count functions.
|
||||
func TestFlagCounts(t *testing.T) {
|
||||
fs := NewFlagSet("help test", ContinueOnError)
|
||||
var flag bool
|
||||
fs.BoolVar(&flag, []string{"flag1"}, false, "regular flag")
|
||||
fs.BoolVar(&flag, []string{"#deprecated1"}, false, "regular flag")
|
||||
fs.BoolVar(&flag, []string{"f", "flag2"}, false, "regular flag")
|
||||
fs.BoolVar(&flag, []string{"#d", "#deprecated2"}, false, "regular flag")
|
||||
fs.BoolVar(&flag, []string{"flag3"}, false, "regular flag")
|
||||
fs.BoolVar(&flag, []string{"g", "#flag4", "-flag4"}, false, "regular flag")
|
||||
|
||||
if fs.FlagCount() != 6 {
|
||||
t.Fatal("FlagCount wrong. ", fs.FlagCount())
|
||||
}
|
||||
if fs.FlagCountUndeprecated() != 4 {
|
||||
t.Fatal("FlagCountUndeprecated wrong. ", fs.FlagCountUndeprecated())
|
||||
}
|
||||
if fs.NFlag() != 0 {
|
||||
t.Fatal("NFlag wrong. ", fs.NFlag())
|
||||
}
|
||||
err := fs.Parse([]string{"-fd", "-g", "-flag4"})
|
||||
if err != nil {
|
||||
t.Fatal("expected no error for defined -help; got ", err)
|
||||
}
|
||||
if fs.NFlag() != 4 {
|
||||
t.Fatal("NFlag wrong. ", fs.NFlag())
|
||||
}
|
||||
}
|
||||
|
||||
// Show up bug in sortFlags
|
||||
func TestSortFlags(t *testing.T) {
|
||||
fs := NewFlagSet("help TestSortFlags", ContinueOnError)
|
||||
|
||||
var err error
|
||||
|
||||
var b bool
|
||||
fs.BoolVar(&b, []string{"b", "-banana"}, false, "usage")
|
||||
|
||||
err = fs.Parse([]string{"--banana=true"})
|
||||
if err != nil {
|
||||
t.Fatal("expected no error; got ", err)
|
||||
}
|
||||
|
||||
count := 0
|
||||
|
||||
fs.VisitAll(func(flag *Flag) {
|
||||
count++
|
||||
if flag == nil {
|
||||
t.Fatal("VisitAll should not return a nil flag")
|
||||
}
|
||||
})
|
||||
flagcount := fs.FlagCount()
|
||||
if flagcount != count {
|
||||
t.Fatalf("FlagCount (%d) != number (%d) of elements visited", flagcount, count)
|
||||
}
|
||||
// Make sure its idempotent
|
||||
if flagcount != fs.FlagCount() {
|
||||
t.Fatalf("FlagCount (%d) != fs.FlagCount() (%d) of elements visited", flagcount, fs.FlagCount())
|
||||
}
|
||||
|
||||
count = 0
|
||||
fs.Visit(func(flag *Flag) {
|
||||
count++
|
||||
if flag == nil {
|
||||
t.Fatal("Visit should not return a nil flag")
|
||||
}
|
||||
})
|
||||
nflag := fs.NFlag()
|
||||
if nflag != count {
|
||||
t.Fatalf("NFlag (%d) != number (%d) of elements visited", nflag, count)
|
||||
}
|
||||
if nflag != fs.NFlag() {
|
||||
t.Fatalf("NFlag (%d) != fs.NFlag() (%d) of elements visited", nflag, fs.NFlag())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeFlags(t *testing.T) {
|
||||
base := NewFlagSet("base", ContinueOnError)
|
||||
base.String([]string{"f"}, "", "")
|
||||
|
||||
fs := NewFlagSet("test", ContinueOnError)
|
||||
Merge(fs, base)
|
||||
if len(fs.formal) != 1 {
|
||||
t.Fatalf("FlagCount (%d) != number (1) of elements merged", len(fs.formal))
|
||||
}
|
||||
}
|
162
vendor/github.com/containers/storage/pkg/mount/mount_unix_test.go
generated
vendored
Normal file
162
vendor/github.com/containers/storage/pkg/mount/mount_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,162 @@
|
|||
// +build !windows
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMountOptionsParsing(t *testing.T) {
|
||||
options := "noatime,ro,size=10k"
|
||||
|
||||
flag, data := parseOptions(options)
|
||||
|
||||
if data != "size=10k" {
|
||||
t.Fatalf("Expected size=10 got %s", data)
|
||||
}
|
||||
|
||||
expectedFlag := NOATIME | RDONLY
|
||||
|
||||
if flag != expectedFlag {
|
||||
t.Fatalf("Expected %d got %d", expectedFlag, flag)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMounted(t *testing.T) {
|
||||
tmp := path.Join(os.TempDir(), "mount-tests")
|
||||
if err := os.MkdirAll(tmp, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
var (
|
||||
sourceDir = path.Join(tmp, "source")
|
||||
targetDir = path.Join(tmp, "target")
|
||||
sourcePath = path.Join(sourceDir, "file.txt")
|
||||
targetPath = path.Join(targetDir, "file.txt")
|
||||
)
|
||||
|
||||
os.Mkdir(sourceDir, 0777)
|
||||
os.Mkdir(targetDir, 0777)
|
||||
|
||||
f, err := os.Create(sourcePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.WriteString("hello")
|
||||
f.Close()
|
||||
|
||||
f, err = os.Create(targetPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(targetDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
mounted, err := Mounted(targetDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !mounted {
|
||||
t.Fatalf("Expected %s to be mounted", targetDir)
|
||||
}
|
||||
if _, err := os.Stat(targetDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMountReadonly(t *testing.T) {
|
||||
tmp := path.Join(os.TempDir(), "mount-tests")
|
||||
if err := os.MkdirAll(tmp, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
var (
|
||||
sourceDir = path.Join(tmp, "source")
|
||||
targetDir = path.Join(tmp, "target")
|
||||
sourcePath = path.Join(sourceDir, "file.txt")
|
||||
targetPath = path.Join(targetDir, "file.txt")
|
||||
)
|
||||
|
||||
os.Mkdir(sourceDir, 0777)
|
||||
os.Mkdir(targetDir, 0777)
|
||||
|
||||
f, err := os.Create(sourcePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.WriteString("hello")
|
||||
f.Close()
|
||||
|
||||
f, err = os.Create(targetPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
if err := Mount(sourceDir, targetDir, "none", "bind,ro"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(targetDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
f, err = os.OpenFile(targetPath, os.O_RDWR, 0777)
|
||||
if err == nil {
|
||||
t.Fatal("Should not be able to open a ro file as rw")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMounts(t *testing.T) {
|
||||
mounts, err := GetMounts()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
root := false
|
||||
for _, entry := range mounts {
|
||||
if entry.Mountpoint == "/" {
|
||||
root = true
|
||||
}
|
||||
}
|
||||
|
||||
if !root {
|
||||
t.Fatal("/ should be mounted at least")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeTmpfsOptions(t *testing.T) {
|
||||
options := []string{"noatime", "ro", "size=10k", "defaults", "atime", "defaults", "rw", "rprivate", "size=1024k", "slave"}
|
||||
expected := []string{"atime", "rw", "size=1024k", "slave"}
|
||||
merged, err := MergeTmpfsOptions(options)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(expected) != len(merged) {
|
||||
t.Fatalf("Expected %s got %s", expected, merged)
|
||||
}
|
||||
for index := range merged {
|
||||
if merged[index] != expected[index] {
|
||||
t.Fatalf("Expected %s for the %dth option, got %s", expected, index, merged)
|
||||
}
|
||||
}
|
||||
|
||||
options = []string{"noatime", "ro", "size=10k", "atime", "rw", "rprivate", "size=1024k", "slave", "size"}
|
||||
_, err = MergeTmpfsOptions(options)
|
||||
if err == nil {
|
||||
t.Fatal("Expected error got nil")
|
||||
}
|
||||
}
|
476
vendor/github.com/containers/storage/pkg/mount/mountinfo_linux_test.go
generated
vendored
Normal file
476
vendor/github.com/containers/storage/pkg/mount/mountinfo_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,476 @@
|
|||
// +build linux
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
fedoraMountinfo = `15 35 0:3 / /proc rw,nosuid,nodev,noexec,relatime shared:5 - proc proc rw
|
||||
16 35 0:14 / /sys rw,nosuid,nodev,noexec,relatime shared:6 - sysfs sysfs rw,seclabel
|
||||
17 35 0:5 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,seclabel,size=8056484k,nr_inodes=2014121,mode=755
|
||||
18 16 0:15 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:7 - securityfs securityfs rw
|
||||
19 16 0:13 / /sys/fs/selinux rw,relatime shared:8 - selinuxfs selinuxfs rw
|
||||
20 17 0:16 / /dev/shm rw,nosuid,nodev shared:3 - tmpfs tmpfs rw,seclabel
|
||||
21 17 0:10 / /dev/pts rw,nosuid,noexec,relatime shared:4 - devpts devpts rw,seclabel,gid=5,mode=620,ptmxmode=000
|
||||
22 35 0:17 / /run rw,nosuid,nodev shared:21 - tmpfs tmpfs rw,seclabel,mode=755
|
||||
23 16 0:18 / /sys/fs/cgroup rw,nosuid,nodev,noexec shared:9 - tmpfs tmpfs rw,seclabel,mode=755
|
||||
24 23 0:19 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd
|
||||
25 16 0:20 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:20 - pstore pstore rw
|
||||
26 23 0:21 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,cpuset,clone_children
|
||||
27 23 0:22 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:12 - cgroup cgroup rw,cpuacct,cpu,clone_children
|
||||
28 23 0:23 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,memory,clone_children
|
||||
29 23 0:24 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,devices,clone_children
|
||||
30 23 0:25 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,freezer,clone_children
|
||||
31 23 0:26 / /sys/fs/cgroup/net_cls rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,net_cls,clone_children
|
||||
32 23 0:27 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,blkio,clone_children
|
||||
33 23 0:28 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,perf_event,clone_children
|
||||
34 23 0:29 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,hugetlb,clone_children
|
||||
35 1 253:2 / / rw,relatime shared:1 - ext4 /dev/mapper/ssd-root--f20 rw,seclabel,data=ordered
|
||||
36 15 0:30 / /proc/sys/fs/binfmt_misc rw,relatime shared:22 - autofs systemd-1 rw,fd=38,pgrp=1,timeout=300,minproto=5,maxproto=5,direct
|
||||
37 17 0:12 / /dev/mqueue rw,relatime shared:23 - mqueue mqueue rw,seclabel
|
||||
38 35 0:31 / /tmp rw shared:24 - tmpfs tmpfs rw,seclabel
|
||||
39 17 0:32 / /dev/hugepages rw,relatime shared:25 - hugetlbfs hugetlbfs rw,seclabel
|
||||
40 16 0:7 / /sys/kernel/debug rw,relatime shared:26 - debugfs debugfs rw
|
||||
41 16 0:33 / /sys/kernel/config rw,relatime shared:27 - configfs configfs rw
|
||||
42 35 0:34 / /var/lib/nfs/rpc_pipefs rw,relatime shared:28 - rpc_pipefs sunrpc rw
|
||||
43 15 0:35 / /proc/fs/nfsd rw,relatime shared:29 - nfsd sunrpc rw
|
||||
45 35 8:17 / /boot rw,relatime shared:30 - ext4 /dev/sdb1 rw,seclabel,data=ordered
|
||||
46 35 253:4 / /home rw,relatime shared:31 - ext4 /dev/mapper/ssd-home rw,seclabel,data=ordered
|
||||
47 35 253:5 / /var/lib/libvirt/images rw,noatime,nodiratime shared:32 - ext4 /dev/mapper/ssd-virt rw,seclabel,discard,data=ordered
|
||||
48 35 253:12 / /mnt/old rw,relatime shared:33 - ext4 /dev/mapper/HelpDeskRHEL6-FedoraRoot rw,seclabel,data=ordered
|
||||
121 22 0:36 / /run/user/1000/gvfs rw,nosuid,nodev,relatime shared:104 - fuse.gvfsd-fuse gvfsd-fuse rw,user_id=1000,group_id=1000
|
||||
124 16 0:37 / /sys/fs/fuse/connections rw,relatime shared:107 - fusectl fusectl rw
|
||||
165 38 253:3 / /tmp/mnt rw,relatime shared:147 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
|
||||
167 35 253:15 / /var/lib/docker/devicemapper/mnt/aae4076022f0e2b80a2afbf8fc6df450c52080191fcef7fb679a73e6f073e5c2 rw,relatime shared:149 - ext4 /dev/mapper/docker-253:2-425882-aae4076022f0e2b80a2afbf8fc6df450c52080191fcef7fb679a73e6f073e5c2 rw,seclabel,discard,stripe=16,data=ordered
|
||||
171 35 253:16 / /var/lib/docker/devicemapper/mnt/c71be651f114db95180e472f7871b74fa597ee70a58ccc35cb87139ddea15373 rw,relatime shared:153 - ext4 /dev/mapper/docker-253:2-425882-c71be651f114db95180e472f7871b74fa597ee70a58ccc35cb87139ddea15373 rw,seclabel,discard,stripe=16,data=ordered
|
||||
175 35 253:17 / /var/lib/docker/devicemapper/mnt/1bac6ab72862d2d5626560df6197cf12036b82e258c53d981fa29adce6f06c3c rw,relatime shared:157 - ext4 /dev/mapper/docker-253:2-425882-1bac6ab72862d2d5626560df6197cf12036b82e258c53d981fa29adce6f06c3c rw,seclabel,discard,stripe=16,data=ordered
|
||||
179 35 253:18 / /var/lib/docker/devicemapper/mnt/d710a357d77158e80d5b2c55710ae07c94e76d34d21ee7bae65ce5418f739b09 rw,relatime shared:161 - ext4 /dev/mapper/docker-253:2-425882-d710a357d77158e80d5b2c55710ae07c94e76d34d21ee7bae65ce5418f739b09 rw,seclabel,discard,stripe=16,data=ordered
|
||||
183 35 253:19 / /var/lib/docker/devicemapper/mnt/6479f52366114d5f518db6837254baab48fab39f2ac38d5099250e9a6ceae6c7 rw,relatime shared:165 - ext4 /dev/mapper/docker-253:2-425882-6479f52366114d5f518db6837254baab48fab39f2ac38d5099250e9a6ceae6c7 rw,seclabel,discard,stripe=16,data=ordered
|
||||
187 35 253:20 / /var/lib/docker/devicemapper/mnt/8d9df91c4cca5aef49eeb2725292aab324646f723a7feab56be34c2ad08268e1 rw,relatime shared:169 - ext4 /dev/mapper/docker-253:2-425882-8d9df91c4cca5aef49eeb2725292aab324646f723a7feab56be34c2ad08268e1 rw,seclabel,discard,stripe=16,data=ordered
|
||||
191 35 253:21 / /var/lib/docker/devicemapper/mnt/c8240b768603d32e920d365dc9d1dc2a6af46cd23e7ae819947f969e1b4ec661 rw,relatime shared:173 - ext4 /dev/mapper/docker-253:2-425882-c8240b768603d32e920d365dc9d1dc2a6af46cd23e7ae819947f969e1b4ec661 rw,seclabel,discard,stripe=16,data=ordered
|
||||
195 35 253:22 / /var/lib/docker/devicemapper/mnt/2eb3a01278380bbf3ed12d86ac629eaa70a4351301ee307a5cabe7b5f3b1615f rw,relatime shared:177 - ext4 /dev/mapper/docker-253:2-425882-2eb3a01278380bbf3ed12d86ac629eaa70a4351301ee307a5cabe7b5f3b1615f rw,seclabel,discard,stripe=16,data=ordered
|
||||
199 35 253:23 / /var/lib/docker/devicemapper/mnt/37a17fb7c9d9b80821235d5f2662879bd3483915f245f9b49cdaa0e38779b70b rw,relatime shared:181 - ext4 /dev/mapper/docker-253:2-425882-37a17fb7c9d9b80821235d5f2662879bd3483915f245f9b49cdaa0e38779b70b rw,seclabel,discard,stripe=16,data=ordered
|
||||
203 35 253:24 / /var/lib/docker/devicemapper/mnt/aea459ae930bf1de913e2f29428fd80ee678a1e962d4080019d9f9774331ee2b rw,relatime shared:185 - ext4 /dev/mapper/docker-253:2-425882-aea459ae930bf1de913e2f29428fd80ee678a1e962d4080019d9f9774331ee2b rw,seclabel,discard,stripe=16,data=ordered
|
||||
207 35 253:25 / /var/lib/docker/devicemapper/mnt/928ead0bc06c454bd9f269e8585aeae0a6bd697f46dc8754c2a91309bc810882 rw,relatime shared:189 - ext4 /dev/mapper/docker-253:2-425882-928ead0bc06c454bd9f269e8585aeae0a6bd697f46dc8754c2a91309bc810882 rw,seclabel,discard,stripe=16,data=ordered
|
||||
211 35 253:26 / /var/lib/docker/devicemapper/mnt/0f284d18481d671644706e7a7244cbcf63d590d634cc882cb8721821929d0420 rw,relatime shared:193 - ext4 /dev/mapper/docker-253:2-425882-0f284d18481d671644706e7a7244cbcf63d590d634cc882cb8721821929d0420 rw,seclabel,discard,stripe=16,data=ordered
|
||||
215 35 253:27 / /var/lib/docker/devicemapper/mnt/d9dd16722ab34c38db2733e23f69e8f4803ce59658250dd63e98adff95d04919 rw,relatime shared:197 - ext4 /dev/mapper/docker-253:2-425882-d9dd16722ab34c38db2733e23f69e8f4803ce59658250dd63e98adff95d04919 rw,seclabel,discard,stripe=16,data=ordered
|
||||
219 35 253:28 / /var/lib/docker/devicemapper/mnt/bc4500479f18c2c08c21ad5282e5f826a016a386177d9874c2764751c031d634 rw,relatime shared:201 - ext4 /dev/mapper/docker-253:2-425882-bc4500479f18c2c08c21ad5282e5f826a016a386177d9874c2764751c031d634 rw,seclabel,discard,stripe=16,data=ordered
|
||||
223 35 253:29 / /var/lib/docker/devicemapper/mnt/7770c8b24eb3d5cc159a065910076938910d307ab2f5d94e1dc3b24c06ee2c8a rw,relatime shared:205 - ext4 /dev/mapper/docker-253:2-425882-7770c8b24eb3d5cc159a065910076938910d307ab2f5d94e1dc3b24c06ee2c8a rw,seclabel,discard,stripe=16,data=ordered
|
||||
227 35 253:30 / /var/lib/docker/devicemapper/mnt/c280cd3d0bf0aa36b478b292279671624cceafc1a67eaa920fa1082601297adf rw,relatime shared:209 - ext4 /dev/mapper/docker-253:2-425882-c280cd3d0bf0aa36b478b292279671624cceafc1a67eaa920fa1082601297adf rw,seclabel,discard,stripe=16,data=ordered
|
||||
231 35 253:31 / /var/lib/docker/devicemapper/mnt/8b59a7d9340279f09fea67fd6ad89ddef711e9e7050eb647984f8b5ef006335f rw,relatime shared:213 - ext4 /dev/mapper/docker-253:2-425882-8b59a7d9340279f09fea67fd6ad89ddef711e9e7050eb647984f8b5ef006335f rw,seclabel,discard,stripe=16,data=ordered
|
||||
235 35 253:32 / /var/lib/docker/devicemapper/mnt/1a28059f29eda821578b1bb27a60cc71f76f846a551abefabce6efd0146dce9f rw,relatime shared:217 - ext4 /dev/mapper/docker-253:2-425882-1a28059f29eda821578b1bb27a60cc71f76f846a551abefabce6efd0146dce9f rw,seclabel,discard,stripe=16,data=ordered
|
||||
239 35 253:33 / /var/lib/docker/devicemapper/mnt/e9aa60c60128cad1 rw,relatime shared:221 - ext4 /dev/mapper/docker-253:2-425882-e9aa60c60128cad1 rw,seclabel,discard,stripe=16,data=ordered
|
||||
243 35 253:34 / /var/lib/docker/devicemapper/mnt/5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d-init rw,relatime shared:225 - ext4 /dev/mapper/docker-253:2-425882-5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d-init rw,seclabel,discard,stripe=16,data=ordered
|
||||
247 35 253:35 / /var/lib/docker/devicemapper/mnt/5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d rw,relatime shared:229 - ext4 /dev/mapper/docker-253:2-425882-5fec11304b6f4713fea7b6ccdcc1adc0a1966187f590fe25a8227428a8df275d rw,seclabel,discard,stripe=16,data=ordered
|
||||
31 21 0:23 / /DATA/foo_bla_bla rw,relatime - cifs //foo/BLA\040BLA\040BLA/ rw,sec=ntlm,cache=loose,unc=\\foo\BLA BLA BLA,username=my_login,domain=mydomain.com,uid=12345678,forceuid,gid=12345678,forcegid,addr=10.1.30.10,file_mode=0755,dir_mode=0755,nounix,rsize=61440,wsize=65536,actimeo=1`
|
||||
|
||||
ubuntuMountInfo = `15 20 0:14 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw
|
||||
16 20 0:3 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
|
||||
17 20 0:5 / /dev rw,relatime - devtmpfs udev rw,size=1015140k,nr_inodes=253785,mode=755
|
||||
18 17 0:11 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000
|
||||
19 20 0:15 / /run rw,nosuid,noexec,relatime - tmpfs tmpfs rw,size=205044k,mode=755
|
||||
20 1 253:0 / / rw,relatime - ext4 /dev/disk/by-label/DOROOT rw,errors=remount-ro,data=ordered
|
||||
21 15 0:16 / /sys/fs/cgroup rw,relatime - tmpfs none rw,size=4k,mode=755
|
||||
22 15 0:17 / /sys/fs/fuse/connections rw,relatime - fusectl none rw
|
||||
23 15 0:6 / /sys/kernel/debug rw,relatime - debugfs none rw
|
||||
24 15 0:10 / /sys/kernel/security rw,relatime - securityfs none rw
|
||||
25 19 0:18 / /run/lock rw,nosuid,nodev,noexec,relatime - tmpfs none rw,size=5120k
|
||||
26 21 0:19 / /sys/fs/cgroup/cpuset rw,relatime - cgroup cgroup rw,cpuset,clone_children
|
||||
27 19 0:20 / /run/shm rw,nosuid,nodev,relatime - tmpfs none rw
|
||||
28 21 0:21 / /sys/fs/cgroup/cpu rw,relatime - cgroup cgroup rw,cpu
|
||||
29 19 0:22 / /run/user rw,nosuid,nodev,noexec,relatime - tmpfs none rw,size=102400k,mode=755
|
||||
30 15 0:23 / /sys/fs/pstore rw,relatime - pstore none rw
|
||||
31 21 0:24 / /sys/fs/cgroup/cpuacct rw,relatime - cgroup cgroup rw,cpuacct
|
||||
32 21 0:25 / /sys/fs/cgroup/memory rw,relatime - cgroup cgroup rw,memory
|
||||
33 21 0:26 / /sys/fs/cgroup/devices rw,relatime - cgroup cgroup rw,devices
|
||||
34 21 0:27 / /sys/fs/cgroup/freezer rw,relatime - cgroup cgroup rw,freezer
|
||||
35 21 0:28 / /sys/fs/cgroup/blkio rw,relatime - cgroup cgroup rw,blkio
|
||||
36 21 0:29 / /sys/fs/cgroup/perf_event rw,relatime - cgroup cgroup rw,perf_event
|
||||
37 21 0:30 / /sys/fs/cgroup/hugetlb rw,relatime - cgroup cgroup rw,hugetlb
|
||||
38 21 0:31 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime - cgroup systemd rw,name=systemd
|
||||
39 20 0:32 / /var/lib/docker/aufs/mnt/b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc rw,relatime - aufs none rw,si=caafa54fdc06525
|
||||
40 20 0:33 / /var/lib/docker/aufs/mnt/2eed44ac7ce7c75af04f088ed6cb4ce9d164801e91d78c6db65d7ef6d572bba8-init rw,relatime - aufs none rw,si=caafa54f882b525
|
||||
41 20 0:34 / /var/lib/docker/aufs/mnt/2eed44ac7ce7c75af04f088ed6cb4ce9d164801e91d78c6db65d7ef6d572bba8 rw,relatime - aufs none rw,si=caafa54f8829525
|
||||
42 20 0:35 / /var/lib/docker/aufs/mnt/16f4d7e96dd612903f425bfe856762f291ff2e36a8ecd55a2209b7d7cd81c30b rw,relatime - aufs none rw,si=caafa54f882d525
|
||||
43 20 0:36 / /var/lib/docker/aufs/mnt/63ca08b75d7438a9469a5954e003f48ffede73541f6286ce1cb4d7dd4811da7e-init rw,relatime - aufs none rw,si=caafa54f882f525
|
||||
44 20 0:37 / /var/lib/docker/aufs/mnt/63ca08b75d7438a9469a5954e003f48ffede73541f6286ce1cb4d7dd4811da7e rw,relatime - aufs none rw,si=caafa54f88ba525
|
||||
45 20 0:38 / /var/lib/docker/aufs/mnt/283f35a910233c756409313be71ecd8fcfef0df57108b8d740b61b3e88860452 rw,relatime - aufs none rw,si=caafa54f88b8525
|
||||
46 20 0:39 / /var/lib/docker/aufs/mnt/2c6c7253d4090faa3886871fb21bd660609daeb0206588c0602007f7d0f254b1-init rw,relatime - aufs none rw,si=caafa54f88be525
|
||||
47 20 0:40 / /var/lib/docker/aufs/mnt/2c6c7253d4090faa3886871fb21bd660609daeb0206588c0602007f7d0f254b1 rw,relatime - aufs none rw,si=caafa54f882c525
|
||||
48 20 0:41 / /var/lib/docker/aufs/mnt/de2b538c97d6366cc80e8658547c923ea1d042f85580df379846f36a4df7049d rw,relatime - aufs none rw,si=caafa54f85bb525
|
||||
49 20 0:42 / /var/lib/docker/aufs/mnt/94a3d8ed7c27e5b0aa71eba46c736bfb2742afda038e74f2dd6035fb28415b49-init rw,relatime - aufs none rw,si=caafa54fdc00525
|
||||
50 20 0:43 / /var/lib/docker/aufs/mnt/94a3d8ed7c27e5b0aa71eba46c736bfb2742afda038e74f2dd6035fb28415b49 rw,relatime - aufs none rw,si=caafa54fbaec525
|
||||
51 20 0:44 / /var/lib/docker/aufs/mnt/6ac1cace985c9fc9bea32234de8b36dba49bdd5e29a2972b327ff939d78a6274 rw,relatime - aufs none rw,si=caafa54f8e1a525
|
||||
52 20 0:45 / /var/lib/docker/aufs/mnt/dff147033e3a0ef061e1de1ad34256b523d4a8c1fa6bba71a0ab538e8628ff0b-init rw,relatime - aufs none rw,si=caafa54f8e1d525
|
||||
53 20 0:46 / /var/lib/docker/aufs/mnt/dff147033e3a0ef061e1de1ad34256b523d4a8c1fa6bba71a0ab538e8628ff0b rw,relatime - aufs none rw,si=caafa54f8e1b525
|
||||
54 20 0:47 / /var/lib/docker/aufs/mnt/cabb117d997f0f93519185aea58389a9762770b7496ed0b74a3e4a083fa45902 rw,relatime - aufs none rw,si=caafa54f810a525
|
||||
55 20 0:48 / /var/lib/docker/aufs/mnt/e1c8a94ffaa9d532bbbdc6ef771ce8a6c2c06757806ecaf8b68e9108fec65f33-init rw,relatime - aufs none rw,si=caafa54f8529525
|
||||
56 20 0:49 / /var/lib/docker/aufs/mnt/e1c8a94ffaa9d532bbbdc6ef771ce8a6c2c06757806ecaf8b68e9108fec65f33 rw,relatime - aufs none rw,si=caafa54f852f525
|
||||
57 20 0:50 / /var/lib/docker/aufs/mnt/16a1526fa445b84ce84f89506d219e87fa488a814063baf045d88b02f21166b3 rw,relatime - aufs none rw,si=caafa54f9e1d525
|
||||
58 20 0:51 / /var/lib/docker/aufs/mnt/57b9c92e1e368fa7dbe5079f7462e917777829caae732828b003c355fe49da9f-init rw,relatime - aufs none rw,si=caafa54f854d525
|
||||
59 20 0:52 / /var/lib/docker/aufs/mnt/57b9c92e1e368fa7dbe5079f7462e917777829caae732828b003c355fe49da9f rw,relatime - aufs none rw,si=caafa54f854e525
|
||||
60 20 0:53 / /var/lib/docker/aufs/mnt/e370c3e286bea027917baa0e4d251262681a472a87056e880dfd0513516dffd9 rw,relatime - aufs none rw,si=caafa54f840a525
|
||||
61 20 0:54 / /var/lib/docker/aufs/mnt/6b00d3b4f32b41997ec07412b5e18204f82fbe643e7122251cdeb3582abd424e-init rw,relatime - aufs none rw,si=caafa54f8408525
|
||||
62 20 0:55 / /var/lib/docker/aufs/mnt/6b00d3b4f32b41997ec07412b5e18204f82fbe643e7122251cdeb3582abd424e rw,relatime - aufs none rw,si=caafa54f8409525
|
||||
63 20 0:56 / /var/lib/docker/aufs/mnt/abd0b5ea5d355a67f911475e271924a5388ee60c27185fcd60d095afc4a09dc7 rw,relatime - aufs none rw,si=caafa54f9eb1525
|
||||
64 20 0:57 / /var/lib/docker/aufs/mnt/336222effc3f7b89867bb39ff7792ae5412c35c749f127c29159d046b6feedd2-init rw,relatime - aufs none rw,si=caafa54f85bf525
|
||||
65 20 0:58 / /var/lib/docker/aufs/mnt/336222effc3f7b89867bb39ff7792ae5412c35c749f127c29159d046b6feedd2 rw,relatime - aufs none rw,si=caafa54f85b8525
|
||||
66 20 0:59 / /var/lib/docker/aufs/mnt/912e1bf28b80a09644503924a8a1a4fb8ed10b808ca847bda27a369919aa52fa rw,relatime - aufs none rw,si=caafa54fbaea525
|
||||
67 20 0:60 / /var/lib/docker/aufs/mnt/386f722875013b4a875118367abc783fc6617a3cb7cf08b2b4dcf550b4b9c576-init rw,relatime - aufs none rw,si=caafa54f8472525
|
||||
68 20 0:61 / /var/lib/docker/aufs/mnt/386f722875013b4a875118367abc783fc6617a3cb7cf08b2b4dcf550b4b9c576 rw,relatime - aufs none rw,si=caafa54f8474525
|
||||
69 20 0:62 / /var/lib/docker/aufs/mnt/5aaebb79ef3097dfca377889aeb61a0c9d5e3795117d2b08d0751473c671dfb2 rw,relatime - aufs none rw,si=caafa54f8c5e525
|
||||
70 20 0:63 / /var/lib/docker/aufs/mnt/5ba3e493279d01277d583600b81c7c079e691b73c3a2bdea8e4b12a35a418be2-init rw,relatime - aufs none rw,si=caafa54f8c3b525
|
||||
71 20 0:64 / /var/lib/docker/aufs/mnt/5ba3e493279d01277d583600b81c7c079e691b73c3a2bdea8e4b12a35a418be2 rw,relatime - aufs none rw,si=caafa54f8c3d525
|
||||
72 20 0:65 / /var/lib/docker/aufs/mnt/2777f0763da4de93f8bebbe1595cc77f739806a158657b033eca06f827b6028a rw,relatime - aufs none rw,si=caafa54f8c3e525
|
||||
73 20 0:66 / /var/lib/docker/aufs/mnt/5d7445562acf73c6f0ae34c3dd0921d7457de1ba92a587d9e06a44fa209eeb3e-init rw,relatime - aufs none rw,si=caafa54f8c39525
|
||||
74 20 0:67 / /var/lib/docker/aufs/mnt/5d7445562acf73c6f0ae34c3dd0921d7457de1ba92a587d9e06a44fa209eeb3e rw,relatime - aufs none rw,si=caafa54f854f525
|
||||
75 20 0:68 / /var/lib/docker/aufs/mnt/06400b526ec18b66639c96efc41a84f4ae0b117cb28dafd56be420651b4084a0 rw,relatime - aufs none rw,si=caafa54f840b525
|
||||
76 20 0:69 / /var/lib/docker/aufs/mnt/e051d45ec42d8e3e1cc57bb39871a40de486dc123522e9c067fbf2ca6a357785-init rw,relatime - aufs none rw,si=caafa54fdddf525
|
||||
77 20 0:70 / /var/lib/docker/aufs/mnt/e051d45ec42d8e3e1cc57bb39871a40de486dc123522e9c067fbf2ca6a357785 rw,relatime - aufs none rw,si=caafa54f854b525
|
||||
78 20 0:71 / /var/lib/docker/aufs/mnt/1ff414fa93fd61ec81b0ab7b365a841ff6545accae03cceac702833aaeaf718f rw,relatime - aufs none rw,si=caafa54f8d85525
|
||||
79 20 0:72 / /var/lib/docker/aufs/mnt/c661b2f871dd5360e46a2aebf8f970f6d39a2ff64e06979aa0361227c88128b8-init rw,relatime - aufs none rw,si=caafa54f8da3525
|
||||
80 20 0:73 / /var/lib/docker/aufs/mnt/c661b2f871dd5360e46a2aebf8f970f6d39a2ff64e06979aa0361227c88128b8 rw,relatime - aufs none rw,si=caafa54f8da2525
|
||||
81 20 0:74 / /var/lib/docker/aufs/mnt/b68b1d4fe4d30016c552398e78b379a39f651661d8e1fa5f2460c24a5e723420 rw,relatime - aufs none rw,si=caafa54f8d81525
|
||||
82 20 0:75 / /var/lib/docker/aufs/mnt/c5c5979c936cd0153a4c626fa9d69ce4fce7d924cc74fa68b025d2f585031739-init rw,relatime - aufs none rw,si=caafa54f8da1525
|
||||
83 20 0:76 / /var/lib/docker/aufs/mnt/c5c5979c936cd0153a4c626fa9d69ce4fce7d924cc74fa68b025d2f585031739 rw,relatime - aufs none rw,si=caafa54f8da0525
|
||||
84 20 0:77 / /var/lib/docker/aufs/mnt/53e10b0329afc0e0d3322d31efaed4064139dc7027fe6ae445cffd7104bcc94f rw,relatime - aufs none rw,si=caafa54f8c35525
|
||||
85 20 0:78 / /var/lib/docker/aufs/mnt/3bfafd09ff2603e2165efacc2215c1f51afabba6c42d04a68cc2df0e8cc31494-init rw,relatime - aufs none rw,si=caafa54f8db8525
|
||||
86 20 0:79 / /var/lib/docker/aufs/mnt/3bfafd09ff2603e2165efacc2215c1f51afabba6c42d04a68cc2df0e8cc31494 rw,relatime - aufs none rw,si=caafa54f8dba525
|
||||
87 20 0:80 / /var/lib/docker/aufs/mnt/90fdd2c03eeaf65311f88f4200e18aef6d2772482712d9aea01cd793c64781b5 rw,relatime - aufs none rw,si=caafa54f8315525
|
||||
88 20 0:81 / /var/lib/docker/aufs/mnt/7bdf2591c06c154ceb23f5e74b1d03b18fbf6fe96e35fbf539b82d446922442f-init rw,relatime - aufs none rw,si=caafa54f8fc6525
|
||||
89 20 0:82 / /var/lib/docker/aufs/mnt/7bdf2591c06c154ceb23f5e74b1d03b18fbf6fe96e35fbf539b82d446922442f rw,relatime - aufs none rw,si=caafa54f8468525
|
||||
90 20 0:83 / /var/lib/docker/aufs/mnt/8cf9a993f50f3305abad3da268c0fc44ff78a1e7bba595ef9de963497496c3f9 rw,relatime - aufs none rw,si=caafa54f8c59525
|
||||
91 20 0:84 / /var/lib/docker/aufs/mnt/ecc896fd74b21840a8d35e8316b92a08b1b9c83d722a12acff847e9f0ff17173-init rw,relatime - aufs none rw,si=caafa54f846a525
|
||||
92 20 0:85 / /var/lib/docker/aufs/mnt/ecc896fd74b21840a8d35e8316b92a08b1b9c83d722a12acff847e9f0ff17173 rw,relatime - aufs none rw,si=caafa54f846b525
|
||||
93 20 0:86 / /var/lib/docker/aufs/mnt/d8c8288ec920439a48b5796bab5883ee47a019240da65e8d8f33400c31bac5df rw,relatime - aufs none rw,si=caafa54f8dbf525
|
||||
94 20 0:87 / /var/lib/docker/aufs/mnt/ecba66710bcd03199b9398e46c005cd6b68d0266ec81dc8b722a29cc417997c6-init rw,relatime - aufs none rw,si=caafa54f810f525
|
||||
95 20 0:88 / /var/lib/docker/aufs/mnt/ecba66710bcd03199b9398e46c005cd6b68d0266ec81dc8b722a29cc417997c6 rw,relatime - aufs none rw,si=caafa54fbae9525
|
||||
96 20 0:89 / /var/lib/docker/aufs/mnt/befc1c67600df449dddbe796c0d06da7caff1d2bbff64cde1f0ba82d224996b5 rw,relatime - aufs none rw,si=caafa54f8dab525
|
||||
97 20 0:90 / /var/lib/docker/aufs/mnt/c9f470e73d2742629cdc4084a1b2c1a8302914f2aa0d0ec4542371df9a050562-init rw,relatime - aufs none rw,si=caafa54fdc02525
|
||||
98 20 0:91 / /var/lib/docker/aufs/mnt/c9f470e73d2742629cdc4084a1b2c1a8302914f2aa0d0ec4542371df9a050562 rw,relatime - aufs none rw,si=caafa54f9eb0525
|
||||
99 20 0:92 / /var/lib/docker/aufs/mnt/2a31f10029f04ff9d4381167a9b739609853d7220d55a56cb654779a700ee246 rw,relatime - aufs none rw,si=caafa54f8c37525
|
||||
100 20 0:93 / /var/lib/docker/aufs/mnt/8c4261b8e3e4b21ebba60389bd64b6261217e7e6b9fd09e201d5a7f6760f6927-init rw,relatime - aufs none rw,si=caafa54fd173525
|
||||
101 20 0:94 / /var/lib/docker/aufs/mnt/8c4261b8e3e4b21ebba60389bd64b6261217e7e6b9fd09e201d5a7f6760f6927 rw,relatime - aufs none rw,si=caafa54f8108525
|
||||
102 20 0:95 / /var/lib/docker/aufs/mnt/eaa0f57403a3dc685268f91df3fbcd7a8423cee50e1a9ee5c3e1688d9d676bb4 rw,relatime - aufs none rw,si=caafa54f852d525
|
||||
103 20 0:96 / /var/lib/docker/aufs/mnt/9cfe69a2cbffd9bfc7f396d4754f6fe5cc457ef417b277797be3762dfe955a6b-init rw,relatime - aufs none rw,si=caafa54f8d80525
|
||||
104 20 0:97 / /var/lib/docker/aufs/mnt/9cfe69a2cbffd9bfc7f396d4754f6fe5cc457ef417b277797be3762dfe955a6b rw,relatime - aufs none rw,si=caafa54f8fc3525
|
||||
105 20 0:98 / /var/lib/docker/aufs/mnt/d1b322ae17613c6adee84e709641a9244ac56675244a89a64dc0075075fcbb83 rw,relatime - aufs none rw,si=caafa54f8c58525
|
||||
106 20 0:99 / /var/lib/docker/aufs/mnt/d46c2a8e9da7e91ab34fd9c192851c246a4e770a46720bda09e55c7554b9dbbd-init rw,relatime - aufs none rw,si=caafa54f8c63525
|
||||
107 20 0:100 / /var/lib/docker/aufs/mnt/d46c2a8e9da7e91ab34fd9c192851c246a4e770a46720bda09e55c7554b9dbbd rw,relatime - aufs none rw,si=caafa54f8c67525
|
||||
108 20 0:101 / /var/lib/docker/aufs/mnt/bc9d2a264158f83a617a069bf17cbbf2a2ba453db7d3951d9dc63cc1558b1c2b rw,relatime - aufs none rw,si=caafa54f8dbe525
|
||||
109 20 0:102 / /var/lib/docker/aufs/mnt/9e6abb8d72bbeb4d5cf24b96018528015ba830ce42b4859965bd482cbd034e99-init rw,relatime - aufs none rw,si=caafa54f9e0d525
|
||||
110 20 0:103 / /var/lib/docker/aufs/mnt/9e6abb8d72bbeb4d5cf24b96018528015ba830ce42b4859965bd482cbd034e99 rw,relatime - aufs none rw,si=caafa54f9e1b525
|
||||
111 20 0:104 / /var/lib/docker/aufs/mnt/d4dca7b02569c732e740071e1c654d4ad282de5c41edb619af1f0aafa618be26 rw,relatime - aufs none rw,si=caafa54f8dae525
|
||||
112 20 0:105 / /var/lib/docker/aufs/mnt/fea63da40fa1c5ffbad430dde0bc64a8fc2edab09a051fff55b673c40a08f6b7-init rw,relatime - aufs none rw,si=caafa54f8c5c525
|
||||
113 20 0:106 / /var/lib/docker/aufs/mnt/fea63da40fa1c5ffbad430dde0bc64a8fc2edab09a051fff55b673c40a08f6b7 rw,relatime - aufs none rw,si=caafa54fd172525
|
||||
114 20 0:107 / /var/lib/docker/aufs/mnt/e60c57499c0b198a6734f77f660cdbbd950a5b78aa23f470ca4f0cfcc376abef rw,relatime - aufs none rw,si=caafa54909c4525
|
||||
115 20 0:108 / /var/lib/docker/aufs/mnt/099c78e7ccd9c8717471bb1bbfff838c0a9913321ba2f214fbeaf92c678e5b35-init rw,relatime - aufs none rw,si=caafa54909c3525
|
||||
116 20 0:109 / /var/lib/docker/aufs/mnt/099c78e7ccd9c8717471bb1bbfff838c0a9913321ba2f214fbeaf92c678e5b35 rw,relatime - aufs none rw,si=caafa54909c7525
|
||||
117 20 0:110 / /var/lib/docker/aufs/mnt/2997be666d58b9e71469759bcb8bd9608dad0e533a1a7570a896919ba3388825 rw,relatime - aufs none rw,si=caafa54f8557525
|
||||
118 20 0:111 / /var/lib/docker/aufs/mnt/730694eff438ef20569df38dfb38a920969d7ff2170cc9aa7cb32a7ed8147a93-init rw,relatime - aufs none rw,si=caafa54c6e88525
|
||||
119 20 0:112 / /var/lib/docker/aufs/mnt/730694eff438ef20569df38dfb38a920969d7ff2170cc9aa7cb32a7ed8147a93 rw,relatime - aufs none rw,si=caafa54c6e8e525
|
||||
120 20 0:113 / /var/lib/docker/aufs/mnt/a672a1e2f2f051f6e19ed1dfbe80860a2d774174c49f7c476695f5dd1d5b2f67 rw,relatime - aufs none rw,si=caafa54c6e15525
|
||||
121 20 0:114 / /var/lib/docker/aufs/mnt/aba3570e17859f76cf29d282d0d150659c6bd80780fdc52a465ba05245c2a420-init rw,relatime - aufs none rw,si=caafa54f8dad525
|
||||
122 20 0:115 / /var/lib/docker/aufs/mnt/aba3570e17859f76cf29d282d0d150659c6bd80780fdc52a465ba05245c2a420 rw,relatime - aufs none rw,si=caafa54f8d84525
|
||||
123 20 0:116 / /var/lib/docker/aufs/mnt/2abc86007aca46fb4a817a033e2a05ccacae40b78ea4b03f8ea616b9ada40e2e rw,relatime - aufs none rw,si=caafa54c6e8b525
|
||||
124 20 0:117 / /var/lib/docker/aufs/mnt/36352f27f7878e648367a135bd1ec3ed497adcb8ac13577ee892a0bd921d2374-init rw,relatime - aufs none rw,si=caafa54c6e8d525
|
||||
125 20 0:118 / /var/lib/docker/aufs/mnt/36352f27f7878e648367a135bd1ec3ed497adcb8ac13577ee892a0bd921d2374 rw,relatime - aufs none rw,si=caafa54f8c34525
|
||||
126 20 0:119 / /var/lib/docker/aufs/mnt/2f95ca1a629cea8363b829faa727dd52896d5561f2c96ddee4f697ea2fc872c2 rw,relatime - aufs none rw,si=caafa54c6e8a525
|
||||
127 20 0:120 / /var/lib/docker/aufs/mnt/f108c8291654f179ef143a3e07de2b5a34adbc0b28194a0ab17742b6db9a7fb2-init rw,relatime - aufs none rw,si=caafa54f8e19525
|
||||
128 20 0:121 / /var/lib/docker/aufs/mnt/f108c8291654f179ef143a3e07de2b5a34adbc0b28194a0ab17742b6db9a7fb2 rw,relatime - aufs none rw,si=caafa54fa8c6525
|
||||
129 20 0:122 / /var/lib/docker/aufs/mnt/c1d04dfdf8cccb3676d5a91e84e9b0781ce40623d127d038bcfbe4c761b27401 rw,relatime - aufs none rw,si=caafa54f8c30525
|
||||
130 20 0:123 / /var/lib/docker/aufs/mnt/3f4898ffd0e1239aeebf1d1412590cdb7254207fa3883663e2c40cf772e5f05a-init rw,relatime - aufs none rw,si=caafa54c6e1a525
|
||||
131 20 0:124 / /var/lib/docker/aufs/mnt/3f4898ffd0e1239aeebf1d1412590cdb7254207fa3883663e2c40cf772e5f05a rw,relatime - aufs none rw,si=caafa54c6e1c525
|
||||
132 20 0:125 / /var/lib/docker/aufs/mnt/5ae3b6fccb1539fc02d420e86f3e9637bef5b711fed2ca31a2f426c8f5deddbf rw,relatime - aufs none rw,si=caafa54c4fea525
|
||||
133 20 0:126 / /var/lib/docker/aufs/mnt/310bfaf80d57020f2e73b06aeffb0b9b0ca2f54895f88bf5e4d1529ccac58fe0-init rw,relatime - aufs none rw,si=caafa54c6e1e525
|
||||
134 20 0:127 / /var/lib/docker/aufs/mnt/310bfaf80d57020f2e73b06aeffb0b9b0ca2f54895f88bf5e4d1529ccac58fe0 rw,relatime - aufs none rw,si=caafa54fa8c0525
|
||||
135 20 0:128 / /var/lib/docker/aufs/mnt/f382bd5aaccaf2d04a59089ac7cb12ec87efd769fd0c14d623358fbfd2a3f896 rw,relatime - aufs none rw,si=caafa54c4fec525
|
||||
136 20 0:129 / /var/lib/docker/aufs/mnt/50d45e9bb2d779bc6362824085564c7578c231af5ae3b3da116acf7e17d00735-init rw,relatime - aufs none rw,si=caafa54c4fef525
|
||||
137 20 0:130 / /var/lib/docker/aufs/mnt/50d45e9bb2d779bc6362824085564c7578c231af5ae3b3da116acf7e17d00735 rw,relatime - aufs none rw,si=caafa54c4feb525
|
||||
138 20 0:131 / /var/lib/docker/aufs/mnt/a9c5ee0854dc083b6bf62b7eb1e5291aefbb10702289a446471ce73aba0d5d7d rw,relatime - aufs none rw,si=caafa54909c6525
|
||||
139 20 0:134 / /var/lib/docker/aufs/mnt/03a613e7bd5078819d1fd92df4e671c0127559a5e0b5a885cc8d5616875162f0-init rw,relatime - aufs none rw,si=caafa54804fe525
|
||||
140 20 0:135 / /var/lib/docker/aufs/mnt/03a613e7bd5078819d1fd92df4e671c0127559a5e0b5a885cc8d5616875162f0 rw,relatime - aufs none rw,si=caafa54804fa525
|
||||
141 20 0:136 / /var/lib/docker/aufs/mnt/7ec3277e5c04c907051caf9c9c35889f5fcd6463e5485971b25404566830bb70 rw,relatime - aufs none rw,si=caafa54804f9525
|
||||
142 20 0:139 / /var/lib/docker/aufs/mnt/26b5b5d71d79a5b2bfcf8bc4b2280ee829f261eb886745dd90997ed410f7e8b8-init rw,relatime - aufs none rw,si=caafa54c6ef6525
|
||||
143 20 0:140 / /var/lib/docker/aufs/mnt/26b5b5d71d79a5b2bfcf8bc4b2280ee829f261eb886745dd90997ed410f7e8b8 rw,relatime - aufs none rw,si=caafa54c6ef5525
|
||||
144 20 0:356 / /var/lib/docker/aufs/mnt/e6ecde9e2c18cd3c75f424c67b6d89685cfee0fc67abf2cb6bdc0867eb998026 rw,relatime - aufs none rw,si=caafa548068e525`
|
||||
|
||||
gentooMountinfo = `15 1 8:6 / / rw,noatime,nodiratime - ext4 /dev/sda6 rw,data=ordered
|
||||
16 15 0:3 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
|
||||
17 15 0:14 / /run rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=3292172k,mode=755
|
||||
18 15 0:5 / /dev rw,nosuid,relatime - devtmpfs udev rw,size=10240k,nr_inodes=4106451,mode=755
|
||||
19 18 0:12 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw
|
||||
20 18 0:10 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=000
|
||||
21 18 0:15 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw
|
||||
22 15 0:16 / /sys rw,nosuid,nodev,noexec,relatime - sysfs sysfs rw
|
||||
23 22 0:7 / /sys/kernel/debug rw,nosuid,nodev,noexec,relatime - debugfs debugfs rw
|
||||
24 22 0:17 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs cgroup_root rw,size=10240k,mode=755
|
||||
25 24 0:18 / /sys/fs/cgroup/openrc rw,nosuid,nodev,noexec,relatime - cgroup openrc rw,release_agent=/lib64/rc/sh/cgroup-release-agent.sh,name=openrc
|
||||
26 24 0:19 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime - cgroup cpuset rw,cpuset,clone_children
|
||||
27 24 0:20 / /sys/fs/cgroup/cpu rw,nosuid,nodev,noexec,relatime - cgroup cpu rw,cpu,clone_children
|
||||
28 24 0:21 / /sys/fs/cgroup/cpuacct rw,nosuid,nodev,noexec,relatime - cgroup cpuacct rw,cpuacct,clone_children
|
||||
29 24 0:22 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime - cgroup memory rw,memory,clone_children
|
||||
30 24 0:23 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime - cgroup devices rw,devices,clone_children
|
||||
31 24 0:24 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime - cgroup freezer rw,freezer,clone_children
|
||||
32 24 0:25 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime - cgroup blkio rw,blkio,clone_children
|
||||
33 15 8:1 / /boot rw,noatime,nodiratime - vfat /dev/sda1 rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro
|
||||
34 15 8:18 / /mnt/xfs rw,noatime,nodiratime - xfs /dev/sdb2 rw,attr2,inode64,noquota
|
||||
35 15 0:26 / /tmp rw,relatime - tmpfs tmpfs rw
|
||||
36 16 0:27 / /proc/sys/fs/binfmt_misc rw,nosuid,nodev,noexec,relatime - binfmt_misc binfmt_misc rw
|
||||
42 15 0:33 / /var/lib/nfs/rpc_pipefs rw,relatime - rpc_pipefs rpc_pipefs rw
|
||||
43 16 0:34 / /proc/fs/nfsd rw,nosuid,nodev,noexec,relatime - nfsd nfsd rw
|
||||
44 15 0:35 / /home/tianon/.gvfs rw,nosuid,nodev,relatime - fuse.gvfs-fuse-daemon gvfs-fuse-daemon rw,user_id=1000,group_id=1000
|
||||
68 15 0:3336 / /var/lib/docker/aufs/mnt/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd rw,relatime - aufs none rw,si=9b4a7640128db39c
|
||||
86 68 8:6 /var/lib/docker/containers/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/config.env /var/lib/docker/aufs/mnt/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/.dockerenv rw,noatime,nodiratime - ext4 /dev/sda6 rw,data=ordered
|
||||
87 68 8:6 /etc/resolv.conf /var/lib/docker/aufs/mnt/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/etc/resolv.conf rw,noatime,nodiratime - ext4 /dev/sda6 rw,data=ordered
|
||||
88 68 8:6 /var/lib/docker/containers/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/hostname /var/lib/docker/aufs/mnt/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/etc/hostname rw,noatime,nodiratime - ext4 /dev/sda6 rw,data=ordered
|
||||
89 68 8:6 /var/lib/docker/containers/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/hosts /var/lib/docker/aufs/mnt/3597a1a6d6298c1decc339ebb90aad6f7d6ba2e15af3131b1f85e7ee4787a0cd/etc/hosts rw,noatime,nodiratime - ext4 /dev/sda6 rw,data=ordered
|
||||
38 15 0:3384 / /var/lib/docker/aufs/mnt/0292005a9292401bb5197657f2b682d97d8edcb3b72b5e390d2a680139985b55 rw,relatime - aufs none rw,si=9b4a7642b584939c
|
||||
39 15 0:3385 / /var/lib/docker/aufs/mnt/59db98c889de5f71b70cfb82c40cbe47b64332f0f56042a2987a9e5df6e5e3aa rw,relatime - aufs none rw,si=9b4a7642b584e39c
|
||||
40 15 0:3386 / /var/lib/docker/aufs/mnt/0545f0f2b6548eb9601d08f35a08f5a0a385407d36027a28f58e06e9f61e0278 rw,relatime - aufs none rw,si=9b4a7642b584b39c
|
||||
41 15 0:3387 / /var/lib/docker/aufs/mnt/d882cfa16d1aa8fe0331a36e79be3d80b151e49f24fc39a39c3fed1735d5feb5 rw,relatime - aufs none rw,si=9b4a76453040039c
|
||||
45 15 0:3388 / /var/lib/docker/aufs/mnt/055ca3befcb1626e74f5344b3398724ff05c0de0e20021683d04305c9e70a3f6 rw,relatime - aufs none rw,si=9b4a76453040739c
|
||||
46 15 0:3389 / /var/lib/docker/aufs/mnt/b899e4567a351745d4285e7f1c18fdece75d877deb3041981cd290be348b7aa6 rw,relatime - aufs none rw,si=9b4a7647def4039c
|
||||
47 15 0:3390 / /var/lib/docker/aufs/mnt/067ca040292c58954c5129f953219accfae0d40faca26b4d05e76ca76a998f16 rw,relatime - aufs none rw,si=9b4a7647def4239c
|
||||
48 15 0:3391 / /var/lib/docker/aufs/mnt/8c995e7cb6e5082742daeea720e340b021d288d25d92e0412c03d200df308a11 rw,relatime - aufs none rw,si=9b4a764479c1639c
|
||||
49 15 0:3392 / /var/lib/docker/aufs/mnt/07cc54dfae5b45300efdacdd53cc72c01b9044956a86ce7bff42d087e426096d rw,relatime - aufs none rw,si=9b4a764479c1739c
|
||||
50 15 0:3393 / /var/lib/docker/aufs/mnt/0a9c95cf4c589c05b06baa79150b0cc1d8e7102759fe3ce4afaabb8247ca4f85 rw,relatime - aufs none rw,si=9b4a7644059c839c
|
||||
51 15 0:3394 / /var/lib/docker/aufs/mnt/468fa98cececcf4e226e8370f18f4f848d63faf287fb8321a07f73086441a3a0 rw,relatime - aufs none rw,si=9b4a7644059ca39c
|
||||
52 15 0:3395 / /var/lib/docker/aufs/mnt/0b826192231c5ce066fffb5beff4397337b5fc19a377aa7c6282c7c0ce7f111f rw,relatime - aufs none rw,si=9b4a764479c1339c
|
||||
53 15 0:3396 / /var/lib/docker/aufs/mnt/93b8ba1b772fbe79709b909c43ea4b2c30d712e53548f467db1ffdc7a384f196 rw,relatime - aufs none rw,si=9b4a7640798a739c
|
||||
54 15 0:3397 / /var/lib/docker/aufs/mnt/0c0d0acfb506859b12ef18cdfef9ebed0b43a611482403564224bde9149d373c rw,relatime - aufs none rw,si=9b4a7640798a039c
|
||||
55 15 0:3398 / /var/lib/docker/aufs/mnt/33648c39ab6c7c74af0243d6d6a81b052e9e25ad1e04b19892eb2dde013e358b rw,relatime - aufs none rw,si=9b4a7644b439b39c
|
||||
56 15 0:3399 / /var/lib/docker/aufs/mnt/0c12bea97a1c958a3c739fb148536c1c89351d48e885ecda8f0499b5cc44407e rw,relatime - aufs none rw,si=9b4a7640798a239c
|
||||
57 15 0:3400 / /var/lib/docker/aufs/mnt/ed443988ce125f172d7512e84a4de2627405990fd767a16adefa8ce700c19ce8 rw,relatime - aufs none rw,si=9b4a7644c8ed339c
|
||||
59 15 0:3402 / /var/lib/docker/aufs/mnt/f61612c324ff3c924d3f7a82fb00a0f8d8f73c248c41897061949e9f5ab7e3b1 rw,relatime - aufs none rw,si=9b4a76442810c39c
|
||||
60 15 0:3403 / /var/lib/docker/aufs/mnt/0f1ee55c6c4e25027b80de8e64b8b6fb542b3b41aa0caab9261da75752e22bfd rw,relatime - aufs none rw,si=9b4a76442810e39c
|
||||
61 15 0:3404 / /var/lib/docker/aufs/mnt/956f6cc4af5785cb3ee6963dcbca668219437d9b28f513290b1453ac64a34f97 rw,relatime - aufs none rw,si=9b4a7644303ec39c
|
||||
62 15 0:3405 / /var/lib/docker/aufs/mnt/1099769158c4b4773e2569e38024e8717e400f87a002c41d8cf47cb81b051ba6 rw,relatime - aufs none rw,si=9b4a7644303ee39c
|
||||
63 15 0:3406 / /var/lib/docker/aufs/mnt/11890ceb98d4442595b676085cd7b21550ab85c5df841e0fba997ff54e3d522d rw,relatime - aufs none rw,si=9b4a7644303ed39c
|
||||
64 15 0:3407 / /var/lib/docker/aufs/mnt/acdb90dc378e8ed2420b43a6d291f1c789a081cd1904018780cc038fcd7aae53 rw,relatime - aufs none rw,si=9b4a76434be2139c
|
||||
65 15 0:3408 / /var/lib/docker/aufs/mnt/120e716f19d4714fbe63cc1ed246204f2c1106eefebc6537ba2587d7e7711959 rw,relatime - aufs none rw,si=9b4a76434be2339c
|
||||
66 15 0:3409 / /var/lib/docker/aufs/mnt/b197b7fffb61d89e0ba1c40de9a9fc0d912e778b3c1bd828cf981ff37c1963bc rw,relatime - aufs none rw,si=9b4a76434be2039c
|
||||
70 15 0:3412 / /var/lib/docker/aufs/mnt/1434b69d2e1bb18a9f0b96b9cdac30132b2688f5d1379f68a39a5e120c2f93eb rw,relatime - aufs none rw,si=9b4a76434be2639c
|
||||
71 15 0:3413 / /var/lib/docker/aufs/mnt/16006e83caf33ab5eb0cd6afc92ea2ee8edeff897496b0bb3ec3a75b767374b3 rw,relatime - aufs none rw,si=9b4a7644d790439c
|
||||
72 15 0:3414 / /var/lib/docker/aufs/mnt/55bfa5f44e94d27f91f79ba901b118b15098449165c87abf1b53ffff147ff164 rw,relatime - aufs none rw,si=9b4a7644d790239c
|
||||
73 15 0:3415 / /var/lib/docker/aufs/mnt/1912b97a07ab21ccd98a2a27bc779bf3cf364a3138afa3c3e6f7f169a3c3eab5 rw,relatime - aufs none rw,si=9b4a76441822739c
|
||||
76 15 0:3418 / /var/lib/docker/aufs/mnt/1a7c3292e8879bd91ffd9282e954f643b1db5683093574c248ff14a9609f2f56 rw,relatime - aufs none rw,si=9b4a76438cb7239c
|
||||
77 15 0:3419 / /var/lib/docker/aufs/mnt/bb1faaf0d076ddba82c2318305a85f490dafa4e8a8640a8db8ed657c439120cc rw,relatime - aufs none rw,si=9b4a76438cb7339c
|
||||
78 15 0:3420 / /var/lib/docker/aufs/mnt/1ab869f21d2241a73ac840c7f988490313f909ac642eba71d092204fec66dd7c rw,relatime - aufs none rw,si=9b4a76438cb7639c
|
||||
79 15 0:3421 / /var/lib/docker/aufs/mnt/fd7245b2cfe3890fa5f5b452260e4edf9e7fb7746532ed9d83f7a0d7dbaa610e rw,relatime - aufs none rw,si=9b4a7644bdc0139c
|
||||
80 15 0:3422 / /var/lib/docker/aufs/mnt/1e5686c5301f26b9b3cd24e322c608913465cc6c5d0dcd7c5e498d1314747d61 rw,relatime - aufs none rw,si=9b4a7644bdc0639c
|
||||
81 15 0:3423 / /var/lib/docker/aufs/mnt/52edf6ee6e40bfec1e9301a4d4a92ab83d144e2ae4ce5099e99df6138cb844bf rw,relatime - aufs none rw,si=9b4a7644bdc0239c
|
||||
82 15 0:3424 / /var/lib/docker/aufs/mnt/1ea10fb7085d28cda4904657dff0454e52598d28e1d77e4f2965bbc3666e808f rw,relatime - aufs none rw,si=9b4a76438cb7139c
|
||||
83 15 0:3425 / /var/lib/docker/aufs/mnt/9c03e98c3593946dbd4087f8d83f9ca262f4a2efdc952ce60690838b9ba6c526 rw,relatime - aufs none rw,si=9b4a76443020639c
|
||||
84 15 0:3426 / /var/lib/docker/aufs/mnt/220a2344d67437602c6d2cee9a98c46be13f82c2a8063919dd2fad52bf2fb7dd rw,relatime - aufs none rw,si=9b4a76434bff339c
|
||||
94 15 0:3427 / /var/lib/docker/aufs/mnt/3b32876c5b200312c50baa476ff342248e88c8ea96e6a1032cd53a88738a1cf2 rw,relatime - aufs none rw,si=9b4a76434bff139c
|
||||
95 15 0:3428 / /var/lib/docker/aufs/mnt/23ee2b8b0d4ae8db6f6d1e168e2c6f79f8a18f953b09f65e0d22cc1e67a3a6fa rw,relatime - aufs none rw,si=9b4a7646c305c39c
|
||||
96 15 0:3429 / /var/lib/docker/aufs/mnt/e86e6daa70b61b57945fa178222615f3c3d6bcef12c9f28e9f8623d44dc2d429 rw,relatime - aufs none rw,si=9b4a7646c305f39c
|
||||
97 15 0:3430 / /var/lib/docker/aufs/mnt/2413d07623e80860bb2e9e306fbdee699afd07525785c025c591231e864aa162 rw,relatime - aufs none rw,si=9b4a76434bff039c
|
||||
98 15 0:3431 / /var/lib/docker/aufs/mnt/adfd622eb22340fc80b429e5564b125668e260bf9068096c46dd59f1386a4b7d rw,relatime - aufs none rw,si=9b4a7646a7a1039c
|
||||
102 15 0:3435 / /var/lib/docker/aufs/mnt/27cd92e7a91d02e2d6b44d16679a00fb6d169b19b88822891084e7fd1a84882d rw,relatime - aufs none rw,si=9b4a7646f25ec39c
|
||||
103 15 0:3436 / /var/lib/docker/aufs/mnt/27dfdaf94cfbf45055c748293c37dd68d9140240bff4c646cb09216015914a88 rw,relatime - aufs none rw,si=9b4a7646732f939c
|
||||
104 15 0:3437 / /var/lib/docker/aufs/mnt/5ed7524aff68dfbf0fc601cbaeac01bab14391850a973dabf3653282a627920f rw,relatime - aufs none rw,si=9b4a7646732f839c
|
||||
105 15 0:3438 / /var/lib/docker/aufs/mnt/2a0d4767e536beb5785b60e071e3ac8e5e812613ab143a9627bee77d0c9ab062 rw,relatime - aufs none rw,si=9b4a7646732fe39c
|
||||
106 15 0:3439 / /var/lib/docker/aufs/mnt/dea3fc045d9f4ae51ba952450b948a822cf85c39411489ca5224f6d9a8d02bad rw,relatime - aufs none rw,si=9b4a764012ad839c
|
||||
107 15 0:3440 / /var/lib/docker/aufs/mnt/2d140a787160798da60cb67c21b1210054ad4dafecdcf832f015995b9aa99cfd rw,relatime - aufs none rw,si=9b4a764012add39c
|
||||
108 15 0:3441 / /var/lib/docker/aufs/mnt/cb190b2a8e984475914430fbad2382e0d20b9b659f8ef83ae8d170cc672e519c rw,relatime - aufs none rw,si=9b4a76454d9c239c
|
||||
109 15 0:3442 / /var/lib/docker/aufs/mnt/2f4a012d5a7ffd90256a6e9aa479054b3dddbc3c6a343f26dafbf3196890223b rw,relatime - aufs none rw,si=9b4a76454d9c439c
|
||||
110 15 0:3443 / /var/lib/docker/aufs/mnt/63cc77904b80c4ffbf49cb974c5d8733dc52ad7640d3ae87554b325d7312d87f rw,relatime - aufs none rw,si=9b4a76454d9c339c
|
||||
111 15 0:3444 / /var/lib/docker/aufs/mnt/30333e872c451482ea2d235ff2192e875bd234006b238ae2bdde3b91a86d7522 rw,relatime - aufs none rw,si=9b4a76422cebf39c
|
||||
112 15 0:3445 / /var/lib/docker/aufs/mnt/6c54fc1125da3925cae65b5c9a98f3be55b0a2c2666082e5094a4ba71beb5bff rw,relatime - aufs none rw,si=9b4a7646dd5a439c
|
||||
113 15 0:3446 / /var/lib/docker/aufs/mnt/3087d48cb01cda9d0a83a9ca301e6ea40e8593d18c4921be4794c91a420ab9a3 rw,relatime - aufs none rw,si=9b4a7646dd5a739c
|
||||
114 15 0:3447 / /var/lib/docker/aufs/mnt/cc2607462a8f55b179a749b144c3fdbb50678e1a4f3065ea04e283e9b1f1d8e2 rw,relatime - aufs none rw,si=9b4a7646dd5a239c
|
||||
117 15 0:3450 / /var/lib/docker/aufs/mnt/310c5e8392b29e8658a22e08d96d63936633b7e2c38e8d220047928b00a03d24 rw,relatime - aufs none rw,si=9b4a7647932d739c
|
||||
118 15 0:3451 / /var/lib/docker/aufs/mnt/38a1f0029406ba9c3b6058f2f406d8a1d23c855046cf355c91d87d446fcc1460 rw,relatime - aufs none rw,si=9b4a76445abc939c
|
||||
119 15 0:3452 / /var/lib/docker/aufs/mnt/42e109ab7914ae997a11ccd860fd18e4d488c50c044c3240423ce15774b8b62e rw,relatime - aufs none rw,si=9b4a76445abca39c
|
||||
120 15 0:3453 / /var/lib/docker/aufs/mnt/365d832af0402d052b389c1e9c0d353b48487533d20cd4351df8e24ec4e4f9d8 rw,relatime - aufs none rw,si=9b4a7644066aa39c
|
||||
121 15 0:3454 / /var/lib/docker/aufs/mnt/d3fa8a24d695b6cda9b64f96188f701963d28bef0473343f8b212df1a2cf1d2b rw,relatime - aufs none rw,si=9b4a7644066af39c
|
||||
122 15 0:3455 / /var/lib/docker/aufs/mnt/37d4f491919abc49a15d0c7a7cc8383f087573525d7d288accd14f0b4af9eae0 rw,relatime - aufs none rw,si=9b4a7644066ad39c
|
||||
123 15 0:3456 / /var/lib/docker/aufs/mnt/93902707fe12cbdd0068ce73f2baad4b3a299189b1b19cb5f8a2025e106ae3f5 rw,relatime - aufs none rw,si=9b4a76444445f39c
|
||||
126 15 0:3459 / /var/lib/docker/aufs/mnt/3b49291670a625b9bbb329ffba99bf7fa7abff80cefef040f8b89e2b3aad4f9f rw,relatime - aufs none rw,si=9b4a7640798a339c
|
||||
127 15 0:3460 / /var/lib/docker/aufs/mnt/8d9c7b943cc8f854f4d0d4ec19f7c16c13b0cc4f67a41472a072648610cecb59 rw,relatime - aufs none rw,si=9b4a76427383039c
|
||||
128 15 0:3461 / /var/lib/docker/aufs/mnt/3b6c90036526c376307df71d49c9f5fce334c01b926faa6a78186842de74beac rw,relatime - aufs none rw,si=9b4a7644badd439c
|
||||
130 15 0:3463 / /var/lib/docker/aufs/mnt/7b24158eeddfb5d31b7e932e406ea4899fd728344335ff8e0765e89ddeb351dd rw,relatime - aufs none rw,si=9b4a7644badd539c
|
||||
131 15 0:3464 / /var/lib/docker/aufs/mnt/3ead6dd5773765c74850cf6c769f21fe65c29d622ffa712664f9f5b80364ce27 rw,relatime - aufs none rw,si=9b4a7642f469939c
|
||||
132 15 0:3465 / /var/lib/docker/aufs/mnt/3f825573b29547744a37b65597a9d6d15a8350be4429b7038d126a4c9a8e178f rw,relatime - aufs none rw,si=9b4a7642f469c39c
|
||||
133 15 0:3466 / /var/lib/docker/aufs/mnt/f67aaaeb3681e5dcb99a41f847087370bd1c206680cb8c7b6a9819fd6c97a331 rw,relatime - aufs none rw,si=9b4a7647cc25939c
|
||||
134 15 0:3467 / /var/lib/docker/aufs/mnt/41afe6cfb3c1fc2280b869db07699da88552786e28793f0bc048a265c01bd942 rw,relatime - aufs none rw,si=9b4a7647cc25c39c
|
||||
135 15 0:3468 / /var/lib/docker/aufs/mnt/b8092ea59da34a40b120e8718c3ae9fa8436996edc4fc50e4b99c72dfd81e1af rw,relatime - aufs none rw,si=9b4a76445abc439c
|
||||
136 15 0:3469 / /var/lib/docker/aufs/mnt/42c69d2cc179e2684458bb8596a9da6dad182c08eae9b74d5f0e615b399f75a5 rw,relatime - aufs none rw,si=9b4a76455ddbe39c
|
||||
137 15 0:3470 / /var/lib/docker/aufs/mnt/ea0871954acd2d62a211ac60e05969622044d4c74597870c4f818fbb0c56b09b rw,relatime - aufs none rw,si=9b4a76455ddbf39c
|
||||
138 15 0:3471 / /var/lib/docker/aufs/mnt/4307906b275ab3fc971786b3841ae3217ac85b6756ddeb7ad4ba09cd044c2597 rw,relatime - aufs none rw,si=9b4a76455ddb839c
|
||||
139 15 0:3472 / /var/lib/docker/aufs/mnt/4390b872928c53500a5035634f3421622ed6299dc1472b631fc45de9f56dc180 rw,relatime - aufs none rw,si=9b4a76402f2fd39c
|
||||
140 15 0:3473 / /var/lib/docker/aufs/mnt/6bb41e78863b85e4aa7da89455314855c8c3bda64e52a583bab15dc1fa2e80c2 rw,relatime - aufs none rw,si=9b4a76402f2fa39c
|
||||
141 15 0:3474 / /var/lib/docker/aufs/mnt/4444f583c2a79c66608f4673a32c9c812154f027045fbd558c2d69920c53f835 rw,relatime - aufs none rw,si=9b4a764479dbd39c
|
||||
142 15 0:3475 / /var/lib/docker/aufs/mnt/6f11883af4a05ea362e0c54df89058da4859f977efd07b6f539e1f55c1d2a668 rw,relatime - aufs none rw,si=9b4a76402f30b39c
|
||||
143 15 0:3476 / /var/lib/docker/aufs/mnt/453490dd32e7c2e9ef906f995d8fb3c2753923d1a5e0ba3fd3296e2e4dc238e7 rw,relatime - aufs none rw,si=9b4a76402f30c39c
|
||||
144 15 0:3477 / /var/lib/docker/aufs/mnt/45e5945735ee102b5e891c91650c57ec4b52bb53017d68f02d50ea8a6e230610 rw,relatime - aufs none rw,si=9b4a76423260739c
|
||||
147 15 0:3480 / /var/lib/docker/aufs/mnt/4727a64a5553a1125f315b96bed10d3073d6988225a292cce732617c925b56ab rw,relatime - aufs none rw,si=9b4a76443030339c
|
||||
150 15 0:3483 / /var/lib/docker/aufs/mnt/4e348b5187b9a567059306afc72d42e0ec5c893b0d4abd547526d5f9b6fb4590 rw,relatime - aufs none rw,si=9b4a7644f5d8c39c
|
||||
151 15 0:3484 / /var/lib/docker/aufs/mnt/4efc616bfbc3f906718b052da22e4335f8e9f91ee9b15866ed3a8029645189ef rw,relatime - aufs none rw,si=9b4a7644f5d8939c
|
||||
152 15 0:3485 / /var/lib/docker/aufs/mnt/83e730ae9754d5adb853b64735472d98dfa17136b8812ac9cfcd1eba7f4e7d2d rw,relatime - aufs none rw,si=9b4a76469aa7139c
|
||||
153 15 0:3486 / /var/lib/docker/aufs/mnt/4fc5ba8a5b333be2b7eefacccb626772eeec0ae8a6975112b56c9fb36c0d342f rw,relatime - aufs none rw,si=9b4a7640128dc39c
|
||||
154 15 0:3487 / /var/lib/docker/aufs/mnt/50200d5edff5dfe8d1ef3c78b0bbd709793ac6e936aa16d74ff66f7ea577b6f9 rw,relatime - aufs none rw,si=9b4a7640128da39c
|
||||
155 15 0:3488 / /var/lib/docker/aufs/mnt/51e5e51604361448f0b9777f38329f414bc5ba9cf238f26d465ff479bd574b61 rw,relatime - aufs none rw,si=9b4a76444f68939c
|
||||
156 15 0:3489 / /var/lib/docker/aufs/mnt/52a142149aa98bba83df8766bbb1c629a97b9799944ead90dd206c4bdf0b8385 rw,relatime - aufs none rw,si=9b4a76444f68b39c
|
||||
157 15 0:3490 / /var/lib/docker/aufs/mnt/52dd21a94a00f58a1ed489312fcfffb91578089c76c5650364476f1d5de031bc rw,relatime - aufs none rw,si=9b4a76444f68f39c
|
||||
158 15 0:3491 / /var/lib/docker/aufs/mnt/ee562415ddaad353ed22c88d0ca768a0c74bfba6333b6e25c46849ee22d990da rw,relatime - aufs none rw,si=9b4a7640128d839c
|
||||
159 15 0:3492 / /var/lib/docker/aufs/mnt/db47a9e87173f7554f550c8a01891de79cf12acdd32e01f95c1a527a08bdfb2c rw,relatime - aufs none rw,si=9b4a764405a1d39c
|
||||
160 15 0:3493 / /var/lib/docker/aufs/mnt/55e827bf6d44d930ec0b827c98356eb8b68c3301e2d60d1429aa72e05b4c17df rw,relatime - aufs none rw,si=9b4a764405a1a39c
|
||||
162 15 0:3495 / /var/lib/docker/aufs/mnt/578dc4e0a87fc37ec081ca098430499a59639c09f6f12a8f48de29828a091aa6 rw,relatime - aufs none rw,si=9b4a76406d7d439c
|
||||
163 15 0:3496 / /var/lib/docker/aufs/mnt/728cc1cb04fa4bc6f7bf7a90980beda6d8fc0beb71630874c0747b994efb0798 rw,relatime - aufs none rw,si=9b4a76444f20e39c
|
||||
164 15 0:3497 / /var/lib/docker/aufs/mnt/5850cc4bd9b55aea46c7ad598f1785117607974084ea643580f58ce3222e683a rw,relatime - aufs none rw,si=9b4a7644a824239c
|
||||
165 15 0:3498 / /var/lib/docker/aufs/mnt/89443b3f766d5a37bc8b84e29da8b84e6a3ea8486d3cf154e2aae1816516e4a8 rw,relatime - aufs none rw,si=9b4a7644a824139c
|
||||
166 15 0:3499 / /var/lib/docker/aufs/mnt/f5ae8fd5a41a337907d16515bc3162525154b59c32314c695ecd092c3b47943d rw,relatime - aufs none rw,si=9b4a7644a824439c
|
||||
167 15 0:3500 / /var/lib/docker/aufs/mnt/5a430854f2a03a9e5f7cbc9f3fb46a8ebca526a5b3f435236d8295e5998798f5 rw,relatime - aufs none rw,si=9b4a7647fc82439c
|
||||
168 15 0:3501 / /var/lib/docker/aufs/mnt/eda16901ae4cead35070c39845cbf1e10bd6b8cb0ffa7879ae2d8a186e460f91 rw,relatime - aufs none rw,si=9b4a76441e0df39c
|
||||
169 15 0:3502 / /var/lib/docker/aufs/mnt/5a593721430c2a51b119ff86a7e06ea2b37e3b4131f8f1344d402b61b0c8d868 rw,relatime - aufs none rw,si=9b4a764248bad39c
|
||||
170 15 0:3503 / /var/lib/docker/aufs/mnt/d662ad0a30fbfa902e0962108685b9330597e1ee2abb16dc9462eb5a67fdd23f rw,relatime - aufs none rw,si=9b4a764248bae39c
|
||||
171 15 0:3504 / /var/lib/docker/aufs/mnt/5bc9de5c79812843fb36eee96bef1ddba812407861f572e33242f4ee10da2c15 rw,relatime - aufs none rw,si=9b4a764248ba839c
|
||||
172 15 0:3505 / /var/lib/docker/aufs/mnt/5e763de8e9b0f7d58d2e12a341e029ab4efb3b99788b175090d8209e971156c1 rw,relatime - aufs none rw,si=9b4a764248baa39c
|
||||
173 15 0:3506 / /var/lib/docker/aufs/mnt/b4431dc2739936f1df6387e337f5a0c99cf051900c896bd7fd46a870ce61c873 rw,relatime - aufs none rw,si=9b4a76401263539c
|
||||
174 15 0:3507 / /var/lib/docker/aufs/mnt/5f37830e5a02561ab8c67ea3113137ba69f67a60e41c05cb0e7a0edaa1925b24 rw,relatime - aufs none rw,si=9b4a76401263639c
|
||||
184 15 0:3508 / /var/lib/docker/aufs/mnt/62ea10b957e6533538a4633a1e1d678502f50ddcdd354b2ca275c54dd7a7793a rw,relatime - aufs none rw,si=9b4a76401263039c
|
||||
187 15 0:3509 / /var/lib/docker/aufs/mnt/d56ee9d44195fe390e042fda75ec15af5132adb6d5c69468fa8792f4e54a6953 rw,relatime - aufs none rw,si=9b4a76401263239c
|
||||
188 15 0:3510 / /var/lib/docker/aufs/mnt/6a300930673174549c2b62f36c933f0332a20735978c007c805a301f897146c5 rw,relatime - aufs none rw,si=9b4a76455d4c539c
|
||||
189 15 0:3511 / /var/lib/docker/aufs/mnt/64496c45c84d348c24d410015456d101601c30cab4d1998c395591caf7e57a70 rw,relatime - aufs none rw,si=9b4a76455d4c639c
|
||||
190 15 0:3512 / /var/lib/docker/aufs/mnt/65a6a645883fe97a7422cd5e71ebe0bc17c8e6302a5361edf52e89747387e908 rw,relatime - aufs none rw,si=9b4a76455d4c039c
|
||||
191 15 0:3513 / /var/lib/docker/aufs/mnt/672be40695f7b6e13b0a3ed9fc996c73727dede3481f58155950fcfad57ed616 rw,relatime - aufs none rw,si=9b4a76455d4c239c
|
||||
192 15 0:3514 / /var/lib/docker/aufs/mnt/d42438acb2bfb2169e1c0d8e917fc824f7c85d336dadb0b0af36dfe0f001b3ba rw,relatime - aufs none rw,si=9b4a7642bfded39c
|
||||
193 15 0:3515 / /var/lib/docker/aufs/mnt/b48a54abf26d01cb2ddd908b1ed6034d17397c1341bf0eb2b251a3e5b79be854 rw,relatime - aufs none rw,si=9b4a7642bfdee39c
|
||||
194 15 0:3516 / /var/lib/docker/aufs/mnt/76f27134491f052bfb87f59092126e53ef875d6851990e59195a9da16a9412f8 rw,relatime - aufs none rw,si=9b4a7642bfde839c
|
||||
195 15 0:3517 / /var/lib/docker/aufs/mnt/6bd626a5462b4f8a8e1cc7d10351326dca97a59b2758e5ea549a4f6350ce8a90 rw,relatime - aufs none rw,si=9b4a7642bfdea39c
|
||||
196 15 0:3518 / /var/lib/docker/aufs/mnt/f1fe3549dbd6f5ca615e9139d9b53f0c83a3b825565df37628eacc13e70cbd6d rw,relatime - aufs none rw,si=9b4a7642bfdf539c
|
||||
197 15 0:3519 / /var/lib/docker/aufs/mnt/6d0458c8426a9e93d58d0625737e6122e725c9408488ed9e3e649a9984e15c34 rw,relatime - aufs none rw,si=9b4a7642bfdf639c
|
||||
198 15 0:3520 / /var/lib/docker/aufs/mnt/6e4c97db83aa82145c9cf2bafc20d500c0b5389643b689e3ae84188c270a48c5 rw,relatime - aufs none rw,si=9b4a7642bfdf039c
|
||||
199 15 0:3521 / /var/lib/docker/aufs/mnt/eb94d6498f2c5969eaa9fa11ac2934f1ab90ef88e2d002258dca08e5ba74ea27 rw,relatime - aufs none rw,si=9b4a7642bfdf239c
|
||||
200 15 0:3522 / /var/lib/docker/aufs/mnt/fe3f88f0c511608a2eec5f13a98703aa16e55dbf930309723d8a37101f539fe1 rw,relatime - aufs none rw,si=9b4a7642bfc3539c
|
||||
201 15 0:3523 / /var/lib/docker/aufs/mnt/6f40c229fb9cad85fabf4b64a2640a5403ec03fe5ac1a57d0609fb8b606b9c83 rw,relatime - aufs none rw,si=9b4a7642bfc3639c
|
||||
202 15 0:3524 / /var/lib/docker/aufs/mnt/7513e9131f7a8acf58ff15248237feb767c78732ca46e159f4d791e6ef031dbc rw,relatime - aufs none rw,si=9b4a7642bfc3039c
|
||||
203 15 0:3525 / /var/lib/docker/aufs/mnt/79f48b00aa713cdf809c6bb7c7cb911b66e9a8076c81d6c9d2504139984ea2da rw,relatime - aufs none rw,si=9b4a7642bfc3239c
|
||||
204 15 0:3526 / /var/lib/docker/aufs/mnt/c3680418350d11358f0a96c676bc5aa74fa00a7c89e629ef5909d3557b060300 rw,relatime - aufs none rw,si=9b4a7642f47cd39c
|
||||
205 15 0:3527 / /var/lib/docker/aufs/mnt/7a1744dd350d7fcc0cccb6f1757ca4cbe5453f203a5888b0f1014d96ad5a5ef9 rw,relatime - aufs none rw,si=9b4a7642f47ce39c
|
||||
206 15 0:3528 / /var/lib/docker/aufs/mnt/7fa99662db046be9f03c33c35251afda9ccdc0085636bbba1d90592cec3ff68d rw,relatime - aufs none rw,si=9b4a7642f47c839c
|
||||
207 15 0:3529 / /var/lib/docker/aufs/mnt/f815021ef20da9c9b056bd1d52d8aaf6e2c0c19f11122fc793eb2b04eb995e35 rw,relatime - aufs none rw,si=9b4a7642f47ca39c
|
||||
208 15 0:3530 / /var/lib/docker/aufs/mnt/801086ae3110192d601dfcebdba2db92e86ce6b6a9dba6678ea04488e4513669 rw,relatime - aufs none rw,si=9b4a7642dc6dd39c
|
||||
209 15 0:3531 / /var/lib/docker/aufs/mnt/822ba7db69f21daddda87c01cfbfbf73013fc03a879daf96d16cdde6f9b1fbd6 rw,relatime - aufs none rw,si=9b4a7642dc6de39c
|
||||
210 15 0:3532 / /var/lib/docker/aufs/mnt/834227c1a950fef8cae3827489129d0dd220541e60c6b731caaa765bf2e6a199 rw,relatime - aufs none rw,si=9b4a7642dc6d839c
|
||||
211 15 0:3533 / /var/lib/docker/aufs/mnt/83dccbc385299bd1c7cf19326e791b33a544eea7b4cdfb6db70ea94eed4389fb rw,relatime - aufs none rw,si=9b4a7642dc6da39c
|
||||
212 15 0:3534 / /var/lib/docker/aufs/mnt/f1b8e6f0e7c8928b5dcdab944db89306ebcae3e0b32f9ff40d2daa8329f21600 rw,relatime - aufs none rw,si=9b4a7645a126039c
|
||||
213 15 0:3535 / /var/lib/docker/aufs/mnt/970efb262c7a020c2404cbcc5b3259efba0d110a786079faeef05bc2952abf3a rw,relatime - aufs none rw,si=9b4a7644c8ed139c
|
||||
214 15 0:3536 / /var/lib/docker/aufs/mnt/84b6d73af7450f3117a77e15a5ca1255871fea6182cd8e8a7be6bc744be18c2c rw,relatime - aufs none rw,si=9b4a76406559139c
|
||||
215 15 0:3537 / /var/lib/docker/aufs/mnt/88be2716e026bc681b5e63fe7942068773efbd0b6e901ca7ba441412006a96b6 rw,relatime - aufs none rw,si=9b4a76406559339c
|
||||
216 15 0:3538 / /var/lib/docker/aufs/mnt/c81939aa166ce50cd8bca5cfbbcc420a78e0318dd5cd7c755209b9166a00a752 rw,relatime - aufs none rw,si=9b4a76406559239c
|
||||
217 15 0:3539 / /var/lib/docker/aufs/mnt/e0f241645d64b7dc5ff6a8414087cca226be08fb54ce987d1d1f6350c57083aa rw,relatime - aufs none rw,si=9b4a7647cfc0f39c
|
||||
218 15 0:3540 / /var/lib/docker/aufs/mnt/e10e2bf75234ed51d8a6a4bb39e465404fecbe318e54400d3879cdb2b0679c78 rw,relatime - aufs none rw,si=9b4a7647cfc0939c
|
||||
219 15 0:3541 / /var/lib/docker/aufs/mnt/8f71d74c8cfc3228b82564aa9f09b2e576cff0083ddfb6aa5cb350346063f080 rw,relatime - aufs none rw,si=9b4a7647cfc0a39c
|
||||
220 15 0:3542 / /var/lib/docker/aufs/mnt/9159f1eba2aef7f5205cc18d015cda7f5933cd29bba3b1b8aed5ccb5824c69ee rw,relatime - aufs none rw,si=9b4a76468cedd39c
|
||||
221 15 0:3543 / /var/lib/docker/aufs/mnt/932cad71e652e048e500d9fbb5b8ea4fc9a269d42a3134ce527ceef42a2be56b rw,relatime - aufs none rw,si=9b4a76468cede39c
|
||||
222 15 0:3544 / /var/lib/docker/aufs/mnt/bf1e1b5f529e8943cc0144ee86dbaaa37885c1ddffcef29537e0078ee7dd316a rw,relatime - aufs none rw,si=9b4a76468ced839c
|
||||
223 15 0:3545 / /var/lib/docker/aufs/mnt/949d93ecf3322e09f858ce81d5f4b434068ec44ff84c375de03104f7b45ee955 rw,relatime - aufs none rw,si=9b4a76468ceda39c
|
||||
224 15 0:3546 / /var/lib/docker/aufs/mnt/d65c6087f92dc2a3841b5251d2fe9ca07d4c6e5b021597692479740816e4e2a1 rw,relatime - aufs none rw,si=9b4a7645a126239c
|
||||
225 15 0:3547 / /var/lib/docker/aufs/mnt/98a0153119d0651c193d053d254f6e16a68345a141baa80c87ae487e9d33f290 rw,relatime - aufs none rw,si=9b4a7640787cf39c
|
||||
226 15 0:3548 / /var/lib/docker/aufs/mnt/99daf7fe5847c017392f6e59aa9706b3dfdd9e6d1ba11dae0f7fffde0a60b5e5 rw,relatime - aufs none rw,si=9b4a7640787c839c
|
||||
227 15 0:3549 / /var/lib/docker/aufs/mnt/9ad1f2fe8a5599d4e10c5a6effa7f03d932d4e92ee13149031a372087a359079 rw,relatime - aufs none rw,si=9b4a7640787ca39c
|
||||
228 15 0:3550 / /var/lib/docker/aufs/mnt/c26d64494da782ddac26f8370d86ac93e7c1666d88a7b99110fc86b35ea6a85d rw,relatime - aufs none rw,si=9b4a7642fc6b539c
|
||||
229 15 0:3551 / /var/lib/docker/aufs/mnt/a49e4a8275133c230ec640997f35f172312eb0ea5bd2bbe10abf34aae98f30eb rw,relatime - aufs none rw,si=9b4a7642fc6b639c
|
||||
230 15 0:3552 / /var/lib/docker/aufs/mnt/b5e2740c867ed843025f49d84e8d769de9e8e6039b3c8cb0735b5bf358994bc7 rw,relatime - aufs none rw,si=9b4a7642fc6b039c
|
||||
231 15 0:3553 / /var/lib/docker/aufs/mnt/a826fdcf3a7039b30570054579b65763db605a314275d7aef31b872c13311b4b rw,relatime - aufs none rw,si=9b4a7642fc6b239c
|
||||
232 15 0:3554 / /var/lib/docker/aufs/mnt/addf3025babf5e43b5a3f4a0da7ad863dda3c01fb8365c58fd8d28bb61dc11bc rw,relatime - aufs none rw,si=9b4a76407871d39c
|
||||
233 15 0:3555 / /var/lib/docker/aufs/mnt/c5b6c6813ab3e5ebdc6d22cb2a3d3106a62095f2c298be52b07a3b0fa20ff690 rw,relatime - aufs none rw,si=9b4a76407871e39c
|
||||
234 15 0:3556 / /var/lib/docker/aufs/mnt/af0609eaaf64e2392060cb46f5a9f3d681a219bb4c651d4f015bf573fbe6c4cf rw,relatime - aufs none rw,si=9b4a76407871839c
|
||||
235 15 0:3557 / /var/lib/docker/aufs/mnt/e7f20e3c37ecad39cd90a97cd3549466d0d106ce4f0a930b8495442634fa4a1f rw,relatime - aufs none rw,si=9b4a76407871a39c
|
||||
237 15 0:3559 / /var/lib/docker/aufs/mnt/b57a53d440ffd0c1295804fa68cdde35d2fed5409484627e71b9c37e4249fd5c rw,relatime - aufs none rw,si=9b4a76444445a39c
|
||||
238 15 0:3560 / /var/lib/docker/aufs/mnt/b5e7d7b8f35e47efbba3d80c5d722f5e7bd43e54c824e54b4a4b351714d36d42 rw,relatime - aufs none rw,si=9b4a7647932d439c
|
||||
239 15 0:3561 / /var/lib/docker/aufs/mnt/f1b136def157e9465640658f277f3347de593c6ae76412a2e79f7002f091cae2 rw,relatime - aufs none rw,si=9b4a76445abcd39c
|
||||
240 15 0:3562 / /var/lib/docker/aufs/mnt/b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc rw,relatime - aufs none rw,si=9b4a7644403b339c
|
||||
241 15 0:3563 / /var/lib/docker/aufs/mnt/b89b140cdbc95063761864e0a23346207fa27ee4c5c63a1ae85c9069a9d9cf1d rw,relatime - aufs none rw,si=9b4a7644aa19739c
|
||||
242 15 0:3564 / /var/lib/docker/aufs/mnt/bc6a69ed51c07f5228f6b4f161c892e6a949c0e7e86a9c3432049d4c0e5cd298 rw,relatime - aufs none rw,si=9b4a7644aa19139c
|
||||
243 15 0:3565 / /var/lib/docker/aufs/mnt/be4e2ba3f136933e239f7cf3d136f484fb9004f1fbdfee24a62a2c7b0ab30670 rw,relatime - aufs none rw,si=9b4a7644aa19339c
|
||||
244 15 0:3566 / /var/lib/docker/aufs/mnt/e04ca1a4a5171e30d20f0c92f90a50b8b6f8600af5459c4b4fb25e42e864dfe1 rw,relatime - aufs none rw,si=9b4a7647932d139c
|
||||
245 15 0:3567 / /var/lib/docker/aufs/mnt/be61576b31db893129aaffcd3dcb5ce35e49c4b71b30c392a78609a45c7323d8 rw,relatime - aufs none rw,si=9b4a7642d85f739c
|
||||
246 15 0:3568 / /var/lib/docker/aufs/mnt/dda42c191e56becf672327658ab84fcb563322db3764b91c2fefe4aaef04c624 rw,relatime - aufs none rw,si=9b4a7642d85f139c
|
||||
247 15 0:3569 / /var/lib/docker/aufs/mnt/c0a7995053330f3d88969247a2e72b07e2dd692133f5668a4a35ea3905561072 rw,relatime - aufs none rw,si=9b4a7642d85f339c
|
||||
249 15 0:3571 / /var/lib/docker/aufs/mnt/c3594b2e5f08c59ff5ed338a1ba1eceeeb1f7fc5d180068338110c00b1eb8502 rw,relatime - aufs none rw,si=9b4a7642738c739c
|
||||
250 15 0:3572 / /var/lib/docker/aufs/mnt/c58dce03a0ab0a7588393880379dc3bce9f96ec08ed3f99cf1555260ff0031e8 rw,relatime - aufs none rw,si=9b4a7642738c139c
|
||||
251 15 0:3573 / /var/lib/docker/aufs/mnt/c73e9f1d109c9d14cb36e1c7489df85649be3911116d76c2fd3648ec8fd94e23 rw,relatime - aufs none rw,si=9b4a7642738c339c
|
||||
252 15 0:3574 / /var/lib/docker/aufs/mnt/c9eef28c344877cd68aa09e543c0710ab2b305a0ff96dbb859bfa7808c3e8d01 rw,relatime - aufs none rw,si=9b4a7642d85f439c
|
||||
253 15 0:3575 / /var/lib/docker/aufs/mnt/feb67148f548d70cb7484f2aaad2a86051cd6867a561741a2f13b552457d666e rw,relatime - aufs none rw,si=9b4a76468c55739c
|
||||
254 15 0:3576 / /var/lib/docker/aufs/mnt/cdf1f96c36d35a96041a896bf398ec0f7dc3b0fb0643612a0f4b6ff96e04e1bb rw,relatime - aufs none rw,si=9b4a76468c55139c
|
||||
255 15 0:3577 / /var/lib/docker/aufs/mnt/ec6e505872353268451ac4bc034c1df00f3bae4a3ea2261c6e48f7bd5417c1b3 rw,relatime - aufs none rw,si=9b4a76468c55339c
|
||||
256 15 0:3578 / /var/lib/docker/aufs/mnt/d6dc8aca64efd90e0bc10274001882d0efb310d42ccbf5712b99b169053b8b1a rw,relatime - aufs none rw,si=9b4a7642738c439c
|
||||
257 15 0:3579 / /var/lib/docker/aufs/mnt/d712594e2ff6eaeb895bfd150d694bd1305fb927e7a186b2dab7df2ea95f8f81 rw,relatime - aufs none rw,si=9b4a76401268f39c
|
||||
259 15 0:3581 / /var/lib/docker/aufs/mnt/dbfa1174cd78cde2d7410eae442af0b416c4a0e6f87ed4ff1e9f169a0029abc0 rw,relatime - aufs none rw,si=9b4a76401268b39c
|
||||
260 15 0:3582 / /var/lib/docker/aufs/mnt/e883f5a82316d7856fbe93ee8c0af5a920b7079619dd95c4ffd88bbd309d28dd rw,relatime - aufs none rw,si=9b4a76468c55439c
|
||||
261 15 0:3583 / /var/lib/docker/aufs/mnt/fdec3eff581c4fc2b09f87befa2fa021f3f2d373bea636a87f1fb5b367d6347a rw,relatime - aufs none rw,si=9b4a7644aa1af39c
|
||||
262 15 0:3584 / /var/lib/docker/aufs/mnt/ef764e26712184653067ecf7afea18a80854c41331ca0f0ef03e1bacf90a6ffc rw,relatime - aufs none rw,si=9b4a7644aa1a939c
|
||||
263 15 0:3585 / /var/lib/docker/aufs/mnt/f3176b40c41fce8ce6942936359a2001a6f1b5c1bb40ee224186db0789ec2f76 rw,relatime - aufs none rw,si=9b4a7644aa1ab39c
|
||||
264 15 0:3586 / /var/lib/docker/aufs/mnt/f5daf06785d3565c6dd18ea7d953d9a8b9606107781e63270fe0514508736e6a rw,relatime - aufs none rw,si=9b4a76401268c39c
|
||||
58 15 0:3587 / /var/lib/docker/aufs/mnt/cde8c40f6524b7361af4f5ad05bb857dc9ee247c20852ba666195c0739e3a2b8-init rw,relatime - aufs none rw,si=9b4a76444445839c
|
||||
67 15 0:3588 / /var/lib/docker/aufs/mnt/cde8c40f6524b7361af4f5ad05bb857dc9ee247c20852ba666195c0739e3a2b8 rw,relatime - aufs none rw,si=9b4a7644badd339c
|
||||
265 15 0:3610 / /var/lib/docker/aufs/mnt/e812472cd2c8c4748d1ef71fac4e77e50d661b9349abe66ce3e23511ed44f414 rw,relatime - aufs none rw,si=9b4a76427937d39c
|
||||
270 15 0:3615 / /var/lib/docker/aufs/mnt/997636e7c5c9d0d1376a217e295c14c205350b62bc12052804fb5f90abe6f183 rw,relatime - aufs none rw,si=9b4a76406540739c
|
||||
273 15 0:3618 / /var/lib/docker/aufs/mnt/d5794d080417b6e52e69227c3873e0e4c1ff0d5a845ebe3860ec2f89a47a2a1e rw,relatime - aufs none rw,si=9b4a76454814039c
|
||||
278 15 0:3623 / /var/lib/docker/aufs/mnt/586bdd48baced671bb19bc4d294ec325f26c55545ae267db426424f157d59c48 rw,relatime - aufs none rw,si=9b4a7644b439f39c
|
||||
281 15 0:3626 / /var/lib/docker/aufs/mnt/69739d022f89f8586908bbd5edbbdd95ea5256356f177f9ffcc6ef9c0ea752d2 rw,relatime - aufs none rw,si=9b4a7644a0f1b39c
|
||||
286 15 0:3631 / /var/lib/docker/aufs/mnt/ff28c27d5f894363993622de26d5dd352dba072f219e4691d6498c19bbbc15a9 rw,relatime - aufs none rw,si=9b4a7642265b339c
|
||||
289 15 0:3634 / /var/lib/docker/aufs/mnt/aa128fe0e64fdede333aa48fd9de39530c91a9244a0f0649a3c411c61e372daa rw,relatime - aufs none rw,si=9b4a764012ada39c
|
||||
99 15 8:33 / /media/REMOVE\040ME rw,nosuid,nodev,relatime - fuseblk /dev/sdc1 rw,user_id=0,group_id=0,allow_other,blksize=4096`
|
||||
)
|
||||
|
||||
func TestParseFedoraMountinfo(t *testing.T) {
|
||||
r := bytes.NewBuffer([]byte(fedoraMountinfo))
|
||||
_, err := parseInfoFile(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseUbuntuMountinfo(t *testing.T) {
|
||||
r := bytes.NewBuffer([]byte(ubuntuMountInfo))
|
||||
_, err := parseInfoFile(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseGentooMountinfo(t *testing.T) {
|
||||
r := bytes.NewBuffer([]byte(gentooMountinfo))
|
||||
_, err := parseInfoFile(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFedoraMountinfoFields(t *testing.T) {
|
||||
r := bytes.NewBuffer([]byte(fedoraMountinfo))
|
||||
infos, err := parseInfoFile(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectedLength := 58
|
||||
if len(infos) != expectedLength {
|
||||
t.Fatalf("Expected %d entries, got %d", expectedLength, len(infos))
|
||||
}
|
||||
mi := Info{
|
||||
ID: 15,
|
||||
Parent: 35,
|
||||
Major: 0,
|
||||
Minor: 3,
|
||||
Root: "/",
|
||||
Mountpoint: "/proc",
|
||||
Opts: "rw,nosuid,nodev,noexec,relatime",
|
||||
Optional: "shared:5",
|
||||
Fstype: "proc",
|
||||
Source: "proc",
|
||||
VfsOpts: "rw",
|
||||
}
|
||||
|
||||
if *infos[0] != mi {
|
||||
t.Fatalf("expected %#v, got %#v", mi, infos[0])
|
||||
}
|
||||
}
|
331
vendor/github.com/containers/storage/pkg/mount/sharedsubtree_linux_test.go
generated
vendored
Normal file
331
vendor/github.com/containers/storage/pkg/mount/sharedsubtree_linux_test.go
generated
vendored
Normal file
|
@ -0,0 +1,331 @@
|
|||
// +build linux
|
||||
|
||||
package mount
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// nothing is propagated in or out
|
||||
func TestSubtreePrivate(t *testing.T) {
|
||||
tmp := path.Join(os.TempDir(), "mount-tests")
|
||||
if err := os.MkdirAll(tmp, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
var (
|
||||
sourceDir = path.Join(tmp, "source")
|
||||
targetDir = path.Join(tmp, "target")
|
||||
outside1Dir = path.Join(tmp, "outside1")
|
||||
outside2Dir = path.Join(tmp, "outside2")
|
||||
|
||||
outside1Path = path.Join(outside1Dir, "file.txt")
|
||||
outside2Path = path.Join(outside2Dir, "file.txt")
|
||||
outside1CheckPath = path.Join(targetDir, "a", "file.txt")
|
||||
outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
|
||||
)
|
||||
if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Mkdir(targetDir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Mkdir(outside1Dir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Mkdir(outside2Dir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := createFile(outside1Path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := createFile(outside2Path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// mount the shared directory to a target
|
||||
if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(targetDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// next, make the target private
|
||||
if err := MakePrivate(targetDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(targetDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// mount in an outside path to a mounted path inside the _source_
|
||||
if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(path.Join(sourceDir, "a")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// check that this file _does_not_ show in the _target_
|
||||
if _, err := os.Stat(outside1CheckPath); err != nil && !os.IsNotExist(err) {
|
||||
t.Fatal(err)
|
||||
} else if err == nil {
|
||||
t.Fatalf("%q should not be visible, but is", outside1CheckPath)
|
||||
}
|
||||
|
||||
// next mount outside2Dir into the _target_
|
||||
if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(path.Join(targetDir, "b")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// check that this file _does_not_ show in the _source_
|
||||
if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
|
||||
t.Fatal(err)
|
||||
} else if err == nil {
|
||||
t.Fatalf("%q should not be visible, but is", outside2CheckPath)
|
||||
}
|
||||
}
|
||||
|
||||
// Testing that when a target is a shared mount,
|
||||
// then child mounts propagate to the source
|
||||
func TestSubtreeShared(t *testing.T) {
|
||||
tmp := path.Join(os.TempDir(), "mount-tests")
|
||||
if err := os.MkdirAll(tmp, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
var (
|
||||
sourceDir = path.Join(tmp, "source")
|
||||
targetDir = path.Join(tmp, "target")
|
||||
outsideDir = path.Join(tmp, "outside")
|
||||
|
||||
outsidePath = path.Join(outsideDir, "file.txt")
|
||||
sourceCheckPath = path.Join(sourceDir, "a", "file.txt")
|
||||
)
|
||||
|
||||
if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Mkdir(targetDir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Mkdir(outsideDir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := createFile(outsidePath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// mount the source as shared
|
||||
if err := MakeShared(sourceDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(sourceDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// mount the shared directory to a target
|
||||
if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(targetDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// mount in an outside path to a mounted path inside the target
|
||||
if err := Mount(outsideDir, path.Join(targetDir, "a"), "none", "bind,rw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(path.Join(targetDir, "a")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// NOW, check that the file from the outside directory is available in the source directory
|
||||
if _, err := os.Stat(sourceCheckPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// testing that mounts to a shared source show up in the slave target,
|
||||
// and that mounts into a slave target do _not_ show up in the shared source
|
||||
func TestSubtreeSharedSlave(t *testing.T) {
|
||||
tmp := path.Join(os.TempDir(), "mount-tests")
|
||||
if err := os.MkdirAll(tmp, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
var (
|
||||
sourceDir = path.Join(tmp, "source")
|
||||
targetDir = path.Join(tmp, "target")
|
||||
outside1Dir = path.Join(tmp, "outside1")
|
||||
outside2Dir = path.Join(tmp, "outside2")
|
||||
|
||||
outside1Path = path.Join(outside1Dir, "file.txt")
|
||||
outside2Path = path.Join(outside2Dir, "file.txt")
|
||||
outside1CheckPath = path.Join(targetDir, "a", "file.txt")
|
||||
outside2CheckPath = path.Join(sourceDir, "b", "file.txt")
|
||||
)
|
||||
if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Mkdir(targetDir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Mkdir(outside1Dir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Mkdir(outside2Dir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := createFile(outside1Path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := createFile(outside2Path); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// mount the source as shared
|
||||
if err := MakeShared(sourceDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(sourceDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// mount the shared directory to a target
|
||||
if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(targetDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// next, make the target slave
|
||||
if err := MakeSlave(targetDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(targetDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// mount in an outside path to a mounted path inside the _source_
|
||||
if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(path.Join(sourceDir, "a")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// check that this file _does_ show in the _target_
|
||||
if _, err := os.Stat(outside1CheckPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// next mount outside2Dir into the _target_
|
||||
if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(path.Join(targetDir, "b")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// check that this file _does_not_ show in the _source_
|
||||
if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) {
|
||||
t.Fatal(err)
|
||||
} else if err == nil {
|
||||
t.Fatalf("%q should not be visible, but is", outside2CheckPath)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubtreeUnbindable(t *testing.T) {
|
||||
tmp := path.Join(os.TempDir(), "mount-tests")
|
||||
if err := os.MkdirAll(tmp, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
var (
|
||||
sourceDir = path.Join(tmp, "source")
|
||||
targetDir = path.Join(tmp, "target")
|
||||
)
|
||||
if err := os.MkdirAll(sourceDir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.MkdirAll(targetDir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// next, make the source unbindable
|
||||
if err := MakeUnbindable(sourceDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(sourceDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// then attempt to mount it to target. It should fail
|
||||
if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil && err != syscall.EINVAL {
|
||||
t.Fatal(err)
|
||||
} else if err == nil {
|
||||
t.Fatalf("%q should not have been bindable", sourceDir)
|
||||
}
|
||||
defer func() {
|
||||
if err := Unmount(targetDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func createFile(path string) error {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.WriteString("hello world!")
|
||||
return f.Close()
|
||||
}
|
96
vendor/github.com/containers/storage/pkg/parsers/kernel/kernel_unix_test.go
generated
vendored
Normal file
96
vendor/github.com/containers/storage/pkg/parsers/kernel/kernel_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
// +build !windows
|
||||
|
||||
package kernel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func assertParseRelease(t *testing.T, release string, b *VersionInfo, result int) {
|
||||
var (
|
||||
a *VersionInfo
|
||||
)
|
||||
a, _ = ParseRelease(release)
|
||||
|
||||
if r := CompareKernelVersion(*a, *b); r != result {
|
||||
t.Fatalf("Unexpected kernel version comparison result for (%v,%v). Found %d, expected %d", release, b, r, result)
|
||||
}
|
||||
if a.Flavor != b.Flavor {
|
||||
t.Fatalf("Unexpected parsed kernel flavor. Found %s, expected %s", a.Flavor, b.Flavor)
|
||||
}
|
||||
}
|
||||
|
||||
// TestParseRelease tests the ParseRelease() function
|
||||
func TestParseRelease(t *testing.T) {
|
||||
assertParseRelease(t, "3.8.0", &VersionInfo{Kernel: 3, Major: 8, Minor: 0}, 0)
|
||||
assertParseRelease(t, "3.4.54.longterm-1", &VersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
||||
assertParseRelease(t, "3.4.54.longterm-1", &VersionInfo{Kernel: 3, Major: 4, Minor: 54, Flavor: ".longterm-1"}, 0)
|
||||
assertParseRelease(t, "3.8.0-19-generic", &VersionInfo{Kernel: 3, Major: 8, Minor: 0, Flavor: "-19-generic"}, 0)
|
||||
assertParseRelease(t, "3.12.8tag", &VersionInfo{Kernel: 3, Major: 12, Minor: 8, Flavor: "tag"}, 0)
|
||||
assertParseRelease(t, "3.12-1-amd64", &VersionInfo{Kernel: 3, Major: 12, Minor: 0, Flavor: "-1-amd64"}, 0)
|
||||
assertParseRelease(t, "3.8.0", &VersionInfo{Kernel: 4, Major: 8, Minor: 0}, -1)
|
||||
// Errors
|
||||
invalids := []string{
|
||||
"3",
|
||||
"a",
|
||||
"a.a",
|
||||
"a.a.a-a",
|
||||
}
|
||||
for _, invalid := range invalids {
|
||||
expectedMessage := fmt.Sprintf("Can't parse kernel version %v", invalid)
|
||||
if _, err := ParseRelease(invalid); err == nil || err.Error() != expectedMessage {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func assertKernelVersion(t *testing.T, a, b VersionInfo, result int) {
|
||||
if r := CompareKernelVersion(a, b); r != result {
|
||||
t.Fatalf("Unexpected kernel version comparison result. Found %d, expected %d", r, result)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCompareKernelVersion tests the CompareKernelVersion() function
|
||||
func TestCompareKernelVersion(t *testing.T) {
|
||||
assertKernelVersion(t,
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
0)
|
||||
assertKernelVersion(t,
|
||||
VersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
-1)
|
||||
assertKernelVersion(t,
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 2, Major: 6, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
0)
|
||||
assertKernelVersion(t,
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 5},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
VersionInfo{Kernel: 3, Major: 0, Minor: 20},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
-1)
|
||||
assertKernelVersion(t,
|
||||
VersionInfo{Kernel: 3, Major: 7, Minor: 20},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
-1)
|
||||
assertKernelVersion(t,
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 20},
|
||||
VersionInfo{Kernel: 3, Major: 7, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 20},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
1)
|
||||
assertKernelVersion(t,
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 0},
|
||||
VersionInfo{Kernel: 3, Major: 8, Minor: 20},
|
||||
-1)
|
||||
}
|
70
vendor/github.com/containers/storage/pkg/parsers/parsers_test.go
generated
vendored
Normal file
70
vendor/github.com/containers/storage/pkg/parsers/parsers_test.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
package parsers
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseKeyValueOpt(t *testing.T) {
|
||||
invalids := map[string]string{
|
||||
"": "Unable to parse key/value option: ",
|
||||
"key": "Unable to parse key/value option: key",
|
||||
}
|
||||
for invalid, expectedError := range invalids {
|
||||
if _, _, err := ParseKeyValueOpt(invalid); err == nil || err.Error() != expectedError {
|
||||
t.Fatalf("Expected error %v for %v, got %v", expectedError, invalid, err)
|
||||
}
|
||||
}
|
||||
valids := map[string][]string{
|
||||
"key=value": {"key", "value"},
|
||||
" key = value ": {"key", "value"},
|
||||
"key=value1=value2": {"key", "value1=value2"},
|
||||
" key = value1 = value2 ": {"key", "value1 = value2"},
|
||||
}
|
||||
for valid, expectedKeyValue := range valids {
|
||||
key, value, err := ParseKeyValueOpt(valid)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key != expectedKeyValue[0] || value != expectedKeyValue[1] {
|
||||
t.Fatalf("Expected {%v: %v} got {%v: %v}", expectedKeyValue[0], expectedKeyValue[1], key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseUintList(t *testing.T) {
|
||||
valids := map[string]map[int]bool{
|
||||
"": {},
|
||||
"7": {7: true},
|
||||
"1-6": {1: true, 2: true, 3: true, 4: true, 5: true, 6: true},
|
||||
"0-7": {0: true, 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true},
|
||||
"0,3-4,7,8-10": {0: true, 3: true, 4: true, 7: true, 8: true, 9: true, 10: true},
|
||||
"0-0,0,1-4": {0: true, 1: true, 2: true, 3: true, 4: true},
|
||||
"03,1-3": {1: true, 2: true, 3: true},
|
||||
"3,2,1": {1: true, 2: true, 3: true},
|
||||
"0-2,3,1": {0: true, 1: true, 2: true, 3: true},
|
||||
}
|
||||
for k, v := range valids {
|
||||
out, err := ParseUintList(k)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected not to fail, got %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(out, v) {
|
||||
t.Fatalf("Expected %v, got %v", v, out)
|
||||
}
|
||||
}
|
||||
|
||||
invalids := []string{
|
||||
"this",
|
||||
"1--",
|
||||
"1-10,,10",
|
||||
"10-1",
|
||||
"-1",
|
||||
"-1,0",
|
||||
}
|
||||
for _, v := range invalids {
|
||||
if out, err := ParseUintList(v); err == nil {
|
||||
t.Fatalf("Expected failure with %s but got %v", v, out)
|
||||
}
|
||||
}
|
||||
}
|
188
vendor/github.com/containers/storage/pkg/plugins/client.go
generated
vendored
Normal file
188
vendor/github.com/containers/storage/pkg/plugins/client.go
generated
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
package plugins
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/containers/storage/pkg/plugins/transport"
|
||||
"github.com/docker/go-connections/sockets"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultTimeOut = 30
|
||||
)
|
||||
|
||||
// NewClient creates a new plugin client (http).
|
||||
func NewClient(addr string, tlsConfig *tlsconfig.Options) (*Client, error) {
|
||||
tr := &http.Transport{}
|
||||
|
||||
if tlsConfig != nil {
|
||||
c, err := tlsconfig.Client(*tlsConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tr.TLSClientConfig = c
|
||||
}
|
||||
|
||||
u, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
socket := u.Host
|
||||
if socket == "" {
|
||||
// valid local socket addresses have the host empty.
|
||||
socket = u.Path
|
||||
}
|
||||
if err := sockets.ConfigureTransport(tr, u.Scheme, socket); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scheme := httpScheme(u)
|
||||
|
||||
clientTransport := transport.NewHTTPTransport(tr, scheme, socket)
|
||||
return NewClientWithTransport(clientTransport), nil
|
||||
}
|
||||
|
||||
// NewClientWithTransport creates a new plugin client with a given transport.
|
||||
func NewClientWithTransport(tr transport.Transport) *Client {
|
||||
return &Client{
|
||||
http: &http.Client{
|
||||
Transport: tr,
|
||||
},
|
||||
requestFactory: tr,
|
||||
}
|
||||
}
|
||||
|
||||
// Client represents a plugin client.
|
||||
type Client struct {
|
||||
http *http.Client // http client to use
|
||||
requestFactory transport.RequestFactory
|
||||
}
|
||||
|
||||
// Call calls the specified method with the specified arguments for the plugin.
|
||||
// It will retry for 30 seconds if a failure occurs when calling.
|
||||
func (c *Client) Call(serviceMethod string, args interface{}, ret interface{}) error {
|
||||
var buf bytes.Buffer
|
||||
if args != nil {
|
||||
if err := json.NewEncoder(&buf).Encode(args); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
body, err := c.callWithRetry(serviceMethod, &buf, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer body.Close()
|
||||
if ret != nil {
|
||||
if err := json.NewDecoder(body).Decode(&ret); err != nil {
|
||||
logrus.Errorf("%s: error reading plugin resp: %v", serviceMethod, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stream calls the specified method with the specified arguments for the plugin and returns the response body
|
||||
func (c *Client) Stream(serviceMethod string, args interface{}) (io.ReadCloser, error) {
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.callWithRetry(serviceMethod, &buf, true)
|
||||
}
|
||||
|
||||
// SendFile calls the specified method, and passes through the IO stream
|
||||
func (c *Client) SendFile(serviceMethod string, data io.Reader, ret interface{}) error {
|
||||
body, err := c.callWithRetry(serviceMethod, data, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer body.Close()
|
||||
if err := json.NewDecoder(body).Decode(&ret); err != nil {
|
||||
logrus.Errorf("%s: error reading plugin resp: %v", serviceMethod, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) callWithRetry(serviceMethod string, data io.Reader, retry bool) (io.ReadCloser, error) {
|
||||
req, err := c.requestFactory.NewRequest(serviceMethod, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var retries int
|
||||
start := time.Now()
|
||||
|
||||
for {
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
if !retry {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
timeOff := backoff(retries)
|
||||
if abort(start, timeOff) {
|
||||
return nil, err
|
||||
}
|
||||
retries++
|
||||
logrus.Warnf("Unable to connect to plugin: %s%s: %v, retrying in %v", req.URL.Host, req.URL.Path, err, timeOff)
|
||||
time.Sleep(timeOff)
|
||||
continue
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
return nil, &statusError{resp.StatusCode, serviceMethod, err.Error()}
|
||||
}
|
||||
|
||||
// Plugins' Response(s) should have an Err field indicating what went
|
||||
// wrong. Try to unmarshal into ResponseErr. Otherwise fallback to just
|
||||
// return the string(body)
|
||||
type responseErr struct {
|
||||
Err string
|
||||
}
|
||||
remoteErr := responseErr{}
|
||||
if err := json.Unmarshal(b, &remoteErr); err == nil {
|
||||
if remoteErr.Err != "" {
|
||||
return nil, &statusError{resp.StatusCode, serviceMethod, remoteErr.Err}
|
||||
}
|
||||
}
|
||||
// old way...
|
||||
return nil, &statusError{resp.StatusCode, serviceMethod, string(b)}
|
||||
}
|
||||
return resp.Body, nil
|
||||
}
|
||||
}
|
||||
|
||||
func backoff(retries int) time.Duration {
|
||||
b, max := 1, defaultTimeOut
|
||||
for b < max && retries > 0 {
|
||||
b *= 2
|
||||
retries--
|
||||
}
|
||||
if b > max {
|
||||
b = max
|
||||
}
|
||||
return time.Duration(b) * time.Second
|
||||
}
|
||||
|
||||
func abort(start time.Time, timeOff time.Duration) bool {
|
||||
return timeOff+time.Since(start) >= time.Duration(defaultTimeOut)*time.Second
|
||||
}
|
||||
|
||||
func httpScheme(u *url.URL) string {
|
||||
scheme := u.Scheme
|
||||
if scheme != "https" {
|
||||
scheme = "http"
|
||||
}
|
||||
return scheme
|
||||
}
|
134
vendor/github.com/containers/storage/pkg/plugins/client_test.go
generated
vendored
Normal file
134
vendor/github.com/containers/storage/pkg/plugins/client_test.go
generated
vendored
Normal file
|
@ -0,0 +1,134 @@
|
|||
package plugins
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containers/storage/pkg/plugins/transport"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
)
|
||||
|
||||
var (
|
||||
mux *http.ServeMux
|
||||
server *httptest.Server
|
||||
)
|
||||
|
||||
func setupRemotePluginServer() string {
|
||||
mux = http.NewServeMux()
|
||||
server = httptest.NewServer(mux)
|
||||
return server.URL
|
||||
}
|
||||
|
||||
func teardownRemotePluginServer() {
|
||||
if server != nil {
|
||||
server.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFailedConnection(t *testing.T) {
|
||||
c, _ := NewClient("tcp://127.0.0.1:1", &tlsconfig.Options{InsecureSkipVerify: true})
|
||||
_, err := c.callWithRetry("Service.Method", nil, false)
|
||||
if err == nil {
|
||||
t.Fatal("Unexpected successful connection")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEchoInputOutput(t *testing.T) {
|
||||
addr := setupRemotePluginServer()
|
||||
defer teardownRemotePluginServer()
|
||||
|
||||
m := Manifest{[]string{"VolumeDriver", "NetworkDriver"}}
|
||||
|
||||
mux.HandleFunc("/Test.Echo", func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
t.Fatalf("Expected POST, got %s\n", r.Method)
|
||||
}
|
||||
|
||||
header := w.Header()
|
||||
header.Set("Content-Type", transport.VersionMimetype)
|
||||
|
||||
io.Copy(w, r.Body)
|
||||
})
|
||||
|
||||
c, _ := NewClient(addr, &tlsconfig.Options{InsecureSkipVerify: true})
|
||||
var output Manifest
|
||||
err := c.Call("Test.Echo", m, &output)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(output, m) {
|
||||
t.Fatalf("Expected %v, was %v\n", m, output)
|
||||
}
|
||||
err = c.Call("Test.Echo", nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackoff(t *testing.T) {
|
||||
cases := []struct {
|
||||
retries int
|
||||
expTimeOff time.Duration
|
||||
}{
|
||||
{0, time.Duration(1)},
|
||||
{1, time.Duration(2)},
|
||||
{2, time.Duration(4)},
|
||||
{4, time.Duration(16)},
|
||||
{6, time.Duration(30)},
|
||||
{10, time.Duration(30)},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
s := c.expTimeOff * time.Second
|
||||
if d := backoff(c.retries); d != s {
|
||||
t.Fatalf("Retry %v, expected %v, was %v\n", c.retries, s, d)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAbortRetry(t *testing.T) {
|
||||
cases := []struct {
|
||||
timeOff time.Duration
|
||||
expAbort bool
|
||||
}{
|
||||
{time.Duration(1), false},
|
||||
{time.Duration(2), false},
|
||||
{time.Duration(10), false},
|
||||
{time.Duration(30), true},
|
||||
{time.Duration(40), true},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
s := c.timeOff * time.Second
|
||||
if a := abort(time.Now(), s); a != c.expAbort {
|
||||
t.Fatalf("Duration %v, expected %v, was %v\n", c.timeOff, s, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientScheme(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
"tcp://127.0.0.1:8080": "http",
|
||||
"unix:///usr/local/plugins/foo": "http",
|
||||
"http://127.0.0.1:8080": "http",
|
||||
"https://127.0.0.1:8080": "https",
|
||||
}
|
||||
|
||||
for addr, scheme := range cases {
|
||||
u, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s := httpScheme(u)
|
||||
|
||||
if s != scheme {
|
||||
t.Fatalf("URL scheme mismatch, expected %s, got %s", scheme, s)
|
||||
}
|
||||
}
|
||||
}
|
132
vendor/github.com/containers/storage/pkg/plugins/discovery.go
generated
vendored
Normal file
132
vendor/github.com/containers/storage/pkg/plugins/discovery.go
generated
vendored
Normal file
|
@ -0,0 +1,132 @@
|
|||
package plugins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotFound plugin not found
|
||||
ErrNotFound = errors.New("plugin not found")
|
||||
socketsPath = "/run/oci-storage/plugins"
|
||||
specsPaths = []string{"/etc/oci-storage/plugins", "/usr/lib/oci-storage/plugins"}
|
||||
)
|
||||
|
||||
// localRegistry defines a registry that is local (using unix socket).
|
||||
type localRegistry struct{}
|
||||
|
||||
func newLocalRegistry() localRegistry {
|
||||
return localRegistry{}
|
||||
}
|
||||
|
||||
// Scan scans all the plugin paths and returns all the names it found
|
||||
func Scan() ([]string, error) {
|
||||
var names []string
|
||||
if err := filepath.Walk(socketsPath, func(path string, fi os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if fi.Mode()&os.ModeSocket != 0 {
|
||||
name := strings.TrimSuffix(fi.Name(), filepath.Ext(fi.Name()))
|
||||
names = append(names, name)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, path := range specsPaths {
|
||||
if err := filepath.Walk(path, func(p string, fi os.FileInfo, err error) error {
|
||||
if err != nil || fi.IsDir() {
|
||||
return nil
|
||||
}
|
||||
name := strings.TrimSuffix(fi.Name(), filepath.Ext(fi.Name()))
|
||||
names = append(names, name)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return names, nil
|
||||
}
|
||||
|
||||
// Plugin returns the plugin registered with the given name (or returns an error).
|
||||
func (l *localRegistry) Plugin(name string) (*Plugin, error) {
|
||||
socketpaths := pluginPaths(socketsPath, name, ".sock")
|
||||
|
||||
for _, p := range socketpaths {
|
||||
if fi, err := os.Stat(p); err == nil && fi.Mode()&os.ModeSocket != 0 {
|
||||
return NewLocalPlugin(name, "unix://"+p), nil
|
||||
}
|
||||
}
|
||||
|
||||
var txtspecpaths []string
|
||||
for _, p := range specsPaths {
|
||||
txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".spec")...)
|
||||
txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".json")...)
|
||||
}
|
||||
|
||||
for _, p := range txtspecpaths {
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
if strings.HasSuffix(p, ".json") {
|
||||
return readPluginJSONInfo(name, p)
|
||||
}
|
||||
return readPluginInfo(name, p)
|
||||
}
|
||||
}
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
|
||||
func readPluginInfo(name, path string) (*Plugin, error) {
|
||||
content, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addr := strings.TrimSpace(string(content))
|
||||
|
||||
u, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(u.Scheme) == 0 {
|
||||
return nil, fmt.Errorf("Unknown protocol")
|
||||
}
|
||||
|
||||
return NewLocalPlugin(name, addr), nil
|
||||
}
|
||||
|
||||
func readPluginJSONInfo(name, path string) (*Plugin, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var p Plugin
|
||||
if err := json.NewDecoder(f).Decode(&p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.name = name
|
||||
if len(p.TLSConfig.CAFile) == 0 {
|
||||
p.TLSConfig.InsecureSkipVerify = true
|
||||
}
|
||||
p.activateWait = sync.NewCond(&sync.Mutex{})
|
||||
|
||||
return &p, nil
|
||||
}
|
||||
|
||||
func pluginPaths(base, name, ext string) []string {
|
||||
return []string{
|
||||
filepath.Join(base, name+ext),
|
||||
filepath.Join(base, name, name+ext),
|
||||
}
|
||||
}
|
119
vendor/github.com/containers/storage/pkg/plugins/discovery_test.go
generated
vendored
Normal file
119
vendor/github.com/containers/storage/pkg/plugins/discovery_test.go
generated
vendored
Normal file
|
@ -0,0 +1,119 @@
|
|||
package plugins
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Setup(t *testing.T) (string, func()) {
|
||||
tmpdir, err := ioutil.TempDir("", "docker-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
backup := socketsPath
|
||||
socketsPath = tmpdir
|
||||
specsPaths = []string{tmpdir}
|
||||
|
||||
return tmpdir, func() {
|
||||
socketsPath = backup
|
||||
os.RemoveAll(tmpdir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileSpecPlugin(t *testing.T) {
|
||||
tmpdir, unregister := Setup(t)
|
||||
defer unregister()
|
||||
|
||||
cases := []struct {
|
||||
path string
|
||||
name string
|
||||
addr string
|
||||
fail bool
|
||||
}{
|
||||
// TODO Windows: Factor out the unix:// variants.
|
||||
{filepath.Join(tmpdir, "echo.spec"), "echo", "unix://var/lib/oci-storage/plugins/echo.sock", false},
|
||||
{filepath.Join(tmpdir, "echo", "echo.spec"), "echo", "unix://var/lib/oci-storage/plugins/echo.sock", false},
|
||||
{filepath.Join(tmpdir, "foo.spec"), "foo", "tcp://localhost:8080", false},
|
||||
{filepath.Join(tmpdir, "foo", "foo.spec"), "foo", "tcp://localhost:8080", false},
|
||||
{filepath.Join(tmpdir, "bar.spec"), "bar", "localhost:8080", true}, // unknown transport
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
if err := os.MkdirAll(filepath.Dir(c.path), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(c.path, []byte(c.addr), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := newLocalRegistry()
|
||||
p, err := r.Plugin(c.name)
|
||||
if c.fail && err == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if p.name != c.name {
|
||||
t.Fatalf("Expected plugin `%s`, got %s\n", c.name, p.Name)
|
||||
}
|
||||
|
||||
if p.Addr != c.addr {
|
||||
t.Fatalf("Expected plugin addr `%s`, got %s\n", c.addr, p.Addr)
|
||||
}
|
||||
|
||||
if p.TLSConfig.InsecureSkipVerify != true {
|
||||
t.Fatalf("Expected TLS verification to be skipped")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileJSONSpecPlugin(t *testing.T) {
|
||||
tmpdir, unregister := Setup(t)
|
||||
defer unregister()
|
||||
|
||||
p := filepath.Join(tmpdir, "example.json")
|
||||
spec := `{
|
||||
"Name": "plugin-example",
|
||||
"Addr": "https://example.com/oci-storage/plugin",
|
||||
"TLSConfig": {
|
||||
"CAFile": "/usr/shared/oci-storage/certs/example-ca.pem",
|
||||
"CertFile": "/usr/shared/oci-storage/certs/example-cert.pem",
|
||||
"KeyFile": "/usr/shared/oci-storage/certs/example-key.pem"
|
||||
}
|
||||
}`
|
||||
|
||||
if err := ioutil.WriteFile(p, []byte(spec), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := newLocalRegistry()
|
||||
plugin, err := r.Plugin("example")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if plugin.name != "example" {
|
||||
t.Fatalf("Expected plugin `plugin-example`, got %s\n", plugin.Name)
|
||||
}
|
||||
|
||||
if plugin.Addr != "https://example.com/oci-storage/plugin" {
|
||||
t.Fatalf("Expected plugin addr `https://example.com/oci-storage/plugin`, got %s\n", plugin.Addr)
|
||||
}
|
||||
|
||||
if plugin.TLSConfig.CAFile != "/usr/shared/oci-storage/certs/example-ca.pem" {
|
||||
t.Fatalf("Expected plugin CA `/usr/shared/oci-storage/certs/example-ca.pem`, got %s\n", plugin.TLSConfig.CAFile)
|
||||
}
|
||||
|
||||
if plugin.TLSConfig.CertFile != "/usr/shared/oci-storage/certs/example-cert.pem" {
|
||||
t.Fatalf("Expected plugin Certificate `/usr/shared/oci-storage/certs/example-cert.pem`, got %s\n", plugin.TLSConfig.CertFile)
|
||||
}
|
||||
|
||||
if plugin.TLSConfig.KeyFile != "/usr/shared/oci-storage/certs/example-key.pem" {
|
||||
t.Fatalf("Expected plugin Key `/usr/shared/oci-storage/certs/example-key.pem`, got %s\n", plugin.TLSConfig.KeyFile)
|
||||
}
|
||||
}
|
61
vendor/github.com/containers/storage/pkg/plugins/discovery_unix_test.go
generated
vendored
Normal file
61
vendor/github.com/containers/storage/pkg/plugins/discovery_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
// +build !windows
|
||||
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLocalSocket(t *testing.T) {
|
||||
// TODO Windows: Enable a similar version for Windows named pipes
|
||||
tmpdir, unregister := Setup(t)
|
||||
defer unregister()
|
||||
|
||||
cases := []string{
|
||||
filepath.Join(tmpdir, "echo.sock"),
|
||||
filepath.Join(tmpdir, "echo", "echo.sock"),
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
if err := os.MkdirAll(filepath.Dir(c), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
l, err := net.Listen("unix", c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
r := newLocalRegistry()
|
||||
p, err := r.Plugin("echo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
pp, err := r.Plugin("echo")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(p, pp) {
|
||||
t.Fatalf("Expected %v, was %v\n", p, pp)
|
||||
}
|
||||
|
||||
if p.name != "echo" {
|
||||
t.Fatalf("Expected plugin `echo`, got %s\n", p.Name)
|
||||
}
|
||||
|
||||
addr := fmt.Sprintf("unix://%s", c)
|
||||
if p.Addr != addr {
|
||||
t.Fatalf("Expected plugin addr `%s`, got %s\n", addr, p.Addr)
|
||||
}
|
||||
if p.TLSConfig.InsecureSkipVerify != true {
|
||||
t.Fatalf("Expected TLS verification to be skipped")
|
||||
}
|
||||
l.Close()
|
||||
}
|
||||
}
|
33
vendor/github.com/containers/storage/pkg/plugins/errors.go
generated
vendored
Normal file
33
vendor/github.com/containers/storage/pkg/plugins/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
package plugins
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type statusError struct {
|
||||
status int
|
||||
method string
|
||||
err string
|
||||
}
|
||||
|
||||
// Error returns a formatted string for this error type
|
||||
func (e *statusError) Error() string {
|
||||
return fmt.Sprintf("%s: %v", e.method, e.err)
|
||||
}
|
||||
|
||||
// IsNotFound indicates if the passed in error is from an http.StatusNotFound from the plugin
|
||||
func IsNotFound(err error) bool {
|
||||
return isStatusError(err, http.StatusNotFound)
|
||||
}
|
||||
|
||||
func isStatusError(err error, status int) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
e, ok := err.(*statusError)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return e.status == status
|
||||
}
|
89
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/fixtures/foo.go
generated
vendored
Normal file
89
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/fixtures/foo.go
generated
vendored
Normal file
|
@ -0,0 +1,89 @@
|
|||
package foo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
aliasedio "io"
|
||||
|
||||
"github.com/containers/storage/pkg/plugins/pluginrpc-gen/fixtures/otherfixture"
|
||||
)
|
||||
|
||||
var (
|
||||
errFakeImport = fmt.Errorf("just to import fmt for imports tests")
|
||||
)
|
||||
|
||||
type wobble struct {
|
||||
Some string
|
||||
Val string
|
||||
Inception *wobble
|
||||
}
|
||||
|
||||
// Fooer is an empty interface used for tests.
|
||||
type Fooer interface{}
|
||||
|
||||
// Fooer2 is an interface used for tests.
|
||||
type Fooer2 interface {
|
||||
Foo()
|
||||
}
|
||||
|
||||
// Fooer3 is an interface used for tests.
|
||||
type Fooer3 interface {
|
||||
Foo()
|
||||
Bar(a string)
|
||||
Baz(a string) (err error)
|
||||
Qux(a, b string) (val string, err error)
|
||||
Wobble() (w *wobble)
|
||||
Wiggle() (w wobble)
|
||||
WiggleWobble(a []*wobble, b []wobble, c map[string]*wobble, d map[*wobble]wobble, e map[string][]wobble, f []*otherfixture.Spaceship) (g map[*wobble]wobble, h [][]*wobble, i otherfixture.Spaceship, j *otherfixture.Spaceship, k map[*otherfixture.Spaceship]otherfixture.Spaceship, l []otherfixture.Spaceship)
|
||||
}
|
||||
|
||||
// Fooer4 is an interface used for tests.
|
||||
type Fooer4 interface {
|
||||
Foo() error
|
||||
}
|
||||
|
||||
// Bar is an interface used for tests.
|
||||
type Bar interface {
|
||||
Boo(a string, b string) (s string, err error)
|
||||
}
|
||||
|
||||
// Fooer5 is an interface used for tests.
|
||||
type Fooer5 interface {
|
||||
Foo()
|
||||
Bar
|
||||
}
|
||||
|
||||
// Fooer6 is an interface used for tests.
|
||||
type Fooer6 interface {
|
||||
Foo(a otherfixture.Spaceship)
|
||||
}
|
||||
|
||||
// Fooer7 is an interface used for tests.
|
||||
type Fooer7 interface {
|
||||
Foo(a *otherfixture.Spaceship)
|
||||
}
|
||||
|
||||
// Fooer8 is an interface used for tests.
|
||||
type Fooer8 interface {
|
||||
Foo(a map[string]otherfixture.Spaceship)
|
||||
}
|
||||
|
||||
// Fooer9 is an interface used for tests.
|
||||
type Fooer9 interface {
|
||||
Foo(a map[string]*otherfixture.Spaceship)
|
||||
}
|
||||
|
||||
// Fooer10 is an interface used for tests.
|
||||
type Fooer10 interface {
|
||||
Foo(a []otherfixture.Spaceship)
|
||||
}
|
||||
|
||||
// Fooer11 is an interface used for tests.
|
||||
type Fooer11 interface {
|
||||
Foo(a []*otherfixture.Spaceship)
|
||||
}
|
||||
|
||||
// Fooer12 is an interface used for tests.
|
||||
type Fooer12 interface {
|
||||
Foo(a aliasedio.Reader)
|
||||
}
|
4
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/fixtures/otherfixture/spaceship.go
generated
vendored
Normal file
4
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/fixtures/otherfixture/spaceship.go
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
package otherfixture
|
||||
|
||||
// Spaceship is a fixture for tests
|
||||
type Spaceship struct{}
|
91
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/main.go
generated
vendored
Normal file
91
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/main.go
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type stringSet struct {
|
||||
values map[string]struct{}
|
||||
}
|
||||
|
||||
func (s stringSet) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s stringSet) Set(value string) error {
|
||||
s.values[value] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
func (s stringSet) GetValues() map[string]struct{} {
|
||||
return s.values
|
||||
}
|
||||
|
||||
var (
|
||||
typeName = flag.String("type", "", "interface type to generate plugin rpc proxy for")
|
||||
rpcName = flag.String("name", *typeName, "RPC name, set if different from type")
|
||||
inputFile = flag.String("i", "", "input file path")
|
||||
outputFile = flag.String("o", *inputFile+"_proxy.go", "output file path")
|
||||
|
||||
skipFuncs map[string]struct{}
|
||||
flSkipFuncs = stringSet{make(map[string]struct{})}
|
||||
|
||||
flBuildTags = stringSet{make(map[string]struct{})}
|
||||
)
|
||||
|
||||
func errorOut(msg string, err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s: %v\n", msg, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func checkFlags() error {
|
||||
if *outputFile == "" {
|
||||
return fmt.Errorf("missing required flag `-o`")
|
||||
}
|
||||
if *inputFile == "" {
|
||||
return fmt.Errorf("missing required flag `-i`")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Var(flSkipFuncs, "skip", "skip parsing for function")
|
||||
flag.Var(flBuildTags, "tag", "build tags to add to generated files")
|
||||
flag.Parse()
|
||||
skipFuncs = flSkipFuncs.GetValues()
|
||||
|
||||
errorOut("error", checkFlags())
|
||||
|
||||
pkg, err := Parse(*inputFile, *typeName)
|
||||
errorOut(fmt.Sprintf("error parsing requested type %s", *typeName), err)
|
||||
|
||||
var analysis = struct {
|
||||
InterfaceType string
|
||||
RPCName string
|
||||
BuildTags map[string]struct{}
|
||||
*ParsedPkg
|
||||
}{toLower(*typeName), *rpcName, flBuildTags.GetValues(), pkg}
|
||||
var buf bytes.Buffer
|
||||
|
||||
errorOut("parser error", generatedTempl.Execute(&buf, analysis))
|
||||
src, err := format.Source(buf.Bytes())
|
||||
errorOut("error formatting generated source:\n"+buf.String(), err)
|
||||
errorOut("error writing file", ioutil.WriteFile(*outputFile, src, 0644))
|
||||
}
|
||||
|
||||
func toLower(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
r, n := utf8.DecodeRuneInString(s)
|
||||
return string(unicode.ToLower(r)) + s[n:]
|
||||
}
|
263
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/parser.go
generated
vendored
Normal file
263
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/parser.go
generated
vendored
Normal file
|
@ -0,0 +1,263 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var errBadReturn = errors.New("found return arg with no name: all args must be named")
|
||||
|
||||
type errUnexpectedType struct {
|
||||
expected string
|
||||
actual interface{}
|
||||
}
|
||||
|
||||
func (e errUnexpectedType) Error() string {
|
||||
return fmt.Sprintf("got wrong type expecting %s, got: %v", e.expected, reflect.TypeOf(e.actual))
|
||||
}
|
||||
|
||||
// ParsedPkg holds information about a package that has been parsed,
|
||||
// its name and the list of functions.
|
||||
type ParsedPkg struct {
|
||||
Name string
|
||||
Functions []function
|
||||
Imports []importSpec
|
||||
}
|
||||
|
||||
type function struct {
|
||||
Name string
|
||||
Args []arg
|
||||
Returns []arg
|
||||
Doc string
|
||||
}
|
||||
|
||||
type arg struct {
|
||||
Name string
|
||||
ArgType string
|
||||
PackageSelector string
|
||||
}
|
||||
|
||||
func (a *arg) String() string {
|
||||
return a.Name + " " + a.ArgType
|
||||
}
|
||||
|
||||
type importSpec struct {
|
||||
Name string
|
||||
Path string
|
||||
}
|
||||
|
||||
func (s *importSpec) String() string {
|
||||
var ss string
|
||||
if len(s.Name) != 0 {
|
||||
ss += s.Name
|
||||
}
|
||||
ss += s.Path
|
||||
return ss
|
||||
}
|
||||
|
||||
// Parse parses the given file for an interface definition with the given name.
|
||||
func Parse(filePath string, objName string) (*ParsedPkg, error) {
|
||||
fs := token.NewFileSet()
|
||||
pkg, err := parser.ParseFile(fs, filePath, nil, parser.AllErrors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := &ParsedPkg{}
|
||||
p.Name = pkg.Name.Name
|
||||
obj, exists := pkg.Scope.Objects[objName]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("could not find object %s in %s", objName, filePath)
|
||||
}
|
||||
if obj.Kind != ast.Typ {
|
||||
return nil, fmt.Errorf("exected type, got %s", obj.Kind)
|
||||
}
|
||||
spec, ok := obj.Decl.(*ast.TypeSpec)
|
||||
if !ok {
|
||||
return nil, errUnexpectedType{"*ast.TypeSpec", obj.Decl}
|
||||
}
|
||||
iface, ok := spec.Type.(*ast.InterfaceType)
|
||||
if !ok {
|
||||
return nil, errUnexpectedType{"*ast.InterfaceType", spec.Type}
|
||||
}
|
||||
|
||||
p.Functions, err = parseInterface(iface)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// figure out what imports will be needed
|
||||
imports := make(map[string]importSpec)
|
||||
for _, f := range p.Functions {
|
||||
args := append(f.Args, f.Returns...)
|
||||
for _, arg := range args {
|
||||
if len(arg.PackageSelector) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, i := range pkg.Imports {
|
||||
if i.Name != nil {
|
||||
if i.Name.Name != arg.PackageSelector {
|
||||
continue
|
||||
}
|
||||
imports[i.Path.Value] = importSpec{Name: arg.PackageSelector, Path: i.Path.Value}
|
||||
break
|
||||
}
|
||||
|
||||
_, name := path.Split(i.Path.Value)
|
||||
splitName := strings.Split(name, "-")
|
||||
if len(splitName) > 1 {
|
||||
name = splitName[len(splitName)-1]
|
||||
}
|
||||
// import paths have quotes already added in, so need to remove them for name comparison
|
||||
name = strings.TrimPrefix(name, `"`)
|
||||
name = strings.TrimSuffix(name, `"`)
|
||||
if name == arg.PackageSelector {
|
||||
imports[i.Path.Value] = importSpec{Path: i.Path.Value}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, spec := range imports {
|
||||
p.Imports = append(p.Imports, spec)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func parseInterface(iface *ast.InterfaceType) ([]function, error) {
|
||||
var functions []function
|
||||
for _, field := range iface.Methods.List {
|
||||
switch f := field.Type.(type) {
|
||||
case *ast.FuncType:
|
||||
method, err := parseFunc(field)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if method == nil {
|
||||
continue
|
||||
}
|
||||
functions = append(functions, *method)
|
||||
case *ast.Ident:
|
||||
spec, ok := f.Obj.Decl.(*ast.TypeSpec)
|
||||
if !ok {
|
||||
return nil, errUnexpectedType{"*ast.TypeSpec", f.Obj.Decl}
|
||||
}
|
||||
iface, ok := spec.Type.(*ast.InterfaceType)
|
||||
if !ok {
|
||||
return nil, errUnexpectedType{"*ast.TypeSpec", spec.Type}
|
||||
}
|
||||
funcs, err := parseInterface(iface)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
functions = append(functions, funcs...)
|
||||
default:
|
||||
return nil, errUnexpectedType{"*astFuncType or *ast.Ident", f}
|
||||
}
|
||||
}
|
||||
return functions, nil
|
||||
}
|
||||
|
||||
func parseFunc(field *ast.Field) (*function, error) {
|
||||
f := field.Type.(*ast.FuncType)
|
||||
method := &function{Name: field.Names[0].Name}
|
||||
if _, exists := skipFuncs[method.Name]; exists {
|
||||
fmt.Println("skipping:", method.Name)
|
||||
return nil, nil
|
||||
}
|
||||
if f.Params != nil {
|
||||
args, err := parseArgs(f.Params.List)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
method.Args = args
|
||||
}
|
||||
if f.Results != nil {
|
||||
returns, err := parseArgs(f.Results.List)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing function returns for %q: %v", method.Name, err)
|
||||
}
|
||||
method.Returns = returns
|
||||
}
|
||||
return method, nil
|
||||
}
|
||||
|
||||
func parseArgs(fields []*ast.Field) ([]arg, error) {
|
||||
var args []arg
|
||||
for _, f := range fields {
|
||||
if len(f.Names) == 0 {
|
||||
return nil, errBadReturn
|
||||
}
|
||||
for _, name := range f.Names {
|
||||
p, err := parseExpr(f.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args = append(args, arg{name.Name, p.value, p.pkg})
|
||||
}
|
||||
}
|
||||
return args, nil
|
||||
}
|
||||
|
||||
type parsedExpr struct {
|
||||
value string
|
||||
pkg string
|
||||
}
|
||||
|
||||
func parseExpr(e ast.Expr) (parsedExpr, error) {
|
||||
var parsed parsedExpr
|
||||
switch i := e.(type) {
|
||||
case *ast.Ident:
|
||||
parsed.value += i.Name
|
||||
case *ast.StarExpr:
|
||||
p, err := parseExpr(i.X)
|
||||
if err != nil {
|
||||
return parsed, err
|
||||
}
|
||||
parsed.value += "*"
|
||||
parsed.value += p.value
|
||||
parsed.pkg = p.pkg
|
||||
case *ast.SelectorExpr:
|
||||
p, err := parseExpr(i.X)
|
||||
if err != nil {
|
||||
return parsed, err
|
||||
}
|
||||
parsed.pkg = p.value
|
||||
parsed.value += p.value + "."
|
||||
parsed.value += i.Sel.Name
|
||||
case *ast.MapType:
|
||||
parsed.value += "map["
|
||||
p, err := parseExpr(i.Key)
|
||||
if err != nil {
|
||||
return parsed, err
|
||||
}
|
||||
parsed.value += p.value
|
||||
parsed.value += "]"
|
||||
p, err = parseExpr(i.Value)
|
||||
if err != nil {
|
||||
return parsed, err
|
||||
}
|
||||
parsed.value += p.value
|
||||
parsed.pkg = p.pkg
|
||||
case *ast.ArrayType:
|
||||
parsed.value += "[]"
|
||||
p, err := parseExpr(i.Elt)
|
||||
if err != nil {
|
||||
return parsed, err
|
||||
}
|
||||
parsed.value += p.value
|
||||
parsed.pkg = p.pkg
|
||||
default:
|
||||
return parsed, errUnexpectedType{"*ast.Ident or *ast.StarExpr", i}
|
||||
}
|
||||
return parsed, nil
|
||||
}
|
222
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/parser_test.go
generated
vendored
Normal file
222
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/parser_test.go
generated
vendored
Normal file
|
@ -0,0 +1,222 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const testFixture = "fixtures/foo.go"
|
||||
|
||||
func TestParseEmptyInterface(t *testing.T) {
|
||||
pkg, err := Parse(testFixture, "Fooer")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertName(t, "foo", pkg.Name)
|
||||
assertNum(t, 0, len(pkg.Functions))
|
||||
}
|
||||
|
||||
func TestParseNonInterfaceType(t *testing.T) {
|
||||
_, err := Parse(testFixture, "wobble")
|
||||
if _, ok := err.(errUnexpectedType); !ok {
|
||||
t.Fatal("expected type error when parsing non-interface type")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseWithOneFunction(t *testing.T) {
|
||||
pkg, err := Parse(testFixture, "Fooer2")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertName(t, "foo", pkg.Name)
|
||||
assertNum(t, 1, len(pkg.Functions))
|
||||
assertName(t, "Foo", pkg.Functions[0].Name)
|
||||
assertNum(t, 0, len(pkg.Functions[0].Args))
|
||||
assertNum(t, 0, len(pkg.Functions[0].Returns))
|
||||
}
|
||||
|
||||
func TestParseWithMultipleFuncs(t *testing.T) {
|
||||
pkg, err := Parse(testFixture, "Fooer3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertName(t, "foo", pkg.Name)
|
||||
assertNum(t, 7, len(pkg.Functions))
|
||||
|
||||
f := pkg.Functions[0]
|
||||
assertName(t, "Foo", f.Name)
|
||||
assertNum(t, 0, len(f.Args))
|
||||
assertNum(t, 0, len(f.Returns))
|
||||
|
||||
f = pkg.Functions[1]
|
||||
assertName(t, "Bar", f.Name)
|
||||
assertNum(t, 1, len(f.Args))
|
||||
assertNum(t, 0, len(f.Returns))
|
||||
arg := f.Args[0]
|
||||
assertName(t, "a", arg.Name)
|
||||
assertName(t, "string", arg.ArgType)
|
||||
|
||||
f = pkg.Functions[2]
|
||||
assertName(t, "Baz", f.Name)
|
||||
assertNum(t, 1, len(f.Args))
|
||||
assertNum(t, 1, len(f.Returns))
|
||||
arg = f.Args[0]
|
||||
assertName(t, "a", arg.Name)
|
||||
assertName(t, "string", arg.ArgType)
|
||||
arg = f.Returns[0]
|
||||
assertName(t, "err", arg.Name)
|
||||
assertName(t, "error", arg.ArgType)
|
||||
|
||||
f = pkg.Functions[3]
|
||||
assertName(t, "Qux", f.Name)
|
||||
assertNum(t, 2, len(f.Args))
|
||||
assertNum(t, 2, len(f.Returns))
|
||||
arg = f.Args[0]
|
||||
assertName(t, "a", f.Args[0].Name)
|
||||
assertName(t, "string", f.Args[0].ArgType)
|
||||
arg = f.Args[1]
|
||||
assertName(t, "b", arg.Name)
|
||||
assertName(t, "string", arg.ArgType)
|
||||
arg = f.Returns[0]
|
||||
assertName(t, "val", arg.Name)
|
||||
assertName(t, "string", arg.ArgType)
|
||||
arg = f.Returns[1]
|
||||
assertName(t, "err", arg.Name)
|
||||
assertName(t, "error", arg.ArgType)
|
||||
|
||||
f = pkg.Functions[4]
|
||||
assertName(t, "Wobble", f.Name)
|
||||
assertNum(t, 0, len(f.Args))
|
||||
assertNum(t, 1, len(f.Returns))
|
||||
arg = f.Returns[0]
|
||||
assertName(t, "w", arg.Name)
|
||||
assertName(t, "*wobble", arg.ArgType)
|
||||
|
||||
f = pkg.Functions[5]
|
||||
assertName(t, "Wiggle", f.Name)
|
||||
assertNum(t, 0, len(f.Args))
|
||||
assertNum(t, 1, len(f.Returns))
|
||||
arg = f.Returns[0]
|
||||
assertName(t, "w", arg.Name)
|
||||
assertName(t, "wobble", arg.ArgType)
|
||||
|
||||
f = pkg.Functions[6]
|
||||
assertName(t, "WiggleWobble", f.Name)
|
||||
assertNum(t, 6, len(f.Args))
|
||||
assertNum(t, 6, len(f.Returns))
|
||||
expectedArgs := [][]string{
|
||||
{"a", "[]*wobble"},
|
||||
{"b", "[]wobble"},
|
||||
{"c", "map[string]*wobble"},
|
||||
{"d", "map[*wobble]wobble"},
|
||||
{"e", "map[string][]wobble"},
|
||||
{"f", "[]*otherfixture.Spaceship"},
|
||||
}
|
||||
for i, arg := range f.Args {
|
||||
assertName(t, expectedArgs[i][0], arg.Name)
|
||||
assertName(t, expectedArgs[i][1], arg.ArgType)
|
||||
}
|
||||
expectedReturns := [][]string{
|
||||
{"g", "map[*wobble]wobble"},
|
||||
{"h", "[][]*wobble"},
|
||||
{"i", "otherfixture.Spaceship"},
|
||||
{"j", "*otherfixture.Spaceship"},
|
||||
{"k", "map[*otherfixture.Spaceship]otherfixture.Spaceship"},
|
||||
{"l", "[]otherfixture.Spaceship"},
|
||||
}
|
||||
for i, ret := range f.Returns {
|
||||
assertName(t, expectedReturns[i][0], ret.Name)
|
||||
assertName(t, expectedReturns[i][1], ret.ArgType)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseWithUnamedReturn(t *testing.T) {
|
||||
_, err := Parse(testFixture, "Fooer4")
|
||||
if !strings.HasSuffix(err.Error(), errBadReturn.Error()) {
|
||||
t.Fatalf("expected ErrBadReturn, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbeddedInterface(t *testing.T) {
|
||||
pkg, err := Parse(testFixture, "Fooer5")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertName(t, "foo", pkg.Name)
|
||||
assertNum(t, 2, len(pkg.Functions))
|
||||
|
||||
f := pkg.Functions[0]
|
||||
assertName(t, "Foo", f.Name)
|
||||
assertNum(t, 0, len(f.Args))
|
||||
assertNum(t, 0, len(f.Returns))
|
||||
|
||||
f = pkg.Functions[1]
|
||||
assertName(t, "Boo", f.Name)
|
||||
assertNum(t, 2, len(f.Args))
|
||||
assertNum(t, 2, len(f.Returns))
|
||||
|
||||
arg := f.Args[0]
|
||||
assertName(t, "a", arg.Name)
|
||||
assertName(t, "string", arg.ArgType)
|
||||
|
||||
arg = f.Args[1]
|
||||
assertName(t, "b", arg.Name)
|
||||
assertName(t, "string", arg.ArgType)
|
||||
|
||||
arg = f.Returns[0]
|
||||
assertName(t, "s", arg.Name)
|
||||
assertName(t, "string", arg.ArgType)
|
||||
|
||||
arg = f.Returns[1]
|
||||
assertName(t, "err", arg.Name)
|
||||
assertName(t, "error", arg.ArgType)
|
||||
}
|
||||
|
||||
func TestParsedImports(t *testing.T) {
|
||||
cases := []string{"Fooer6", "Fooer7", "Fooer8", "Fooer9", "Fooer10", "Fooer11"}
|
||||
for _, testCase := range cases {
|
||||
pkg, err := Parse(testFixture, testCase)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertNum(t, 1, len(pkg.Imports))
|
||||
importPath := strings.Split(pkg.Imports[0].Path, "/")
|
||||
assertName(t, "otherfixture\"", importPath[len(importPath)-1])
|
||||
assertName(t, "", pkg.Imports[0].Name)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAliasedImports(t *testing.T) {
|
||||
pkg, err := Parse(testFixture, "Fooer12")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assertNum(t, 1, len(pkg.Imports))
|
||||
assertName(t, "aliasedio", pkg.Imports[0].Name)
|
||||
}
|
||||
|
||||
func assertName(t *testing.T, expected, actual string) {
|
||||
if expected != actual {
|
||||
fatalOut(t, fmt.Sprintf("expected name to be `%s`, got: %s", expected, actual))
|
||||
}
|
||||
}
|
||||
|
||||
func assertNum(t *testing.T, expected, actual int) {
|
||||
if expected != actual {
|
||||
fatalOut(t, fmt.Sprintf("expected number to be %d, got: %d", expected, actual))
|
||||
}
|
||||
}
|
||||
|
||||
func fatalOut(t *testing.T, msg string) {
|
||||
_, file, ln, _ := runtime.Caller(2)
|
||||
t.Fatalf("%s:%d: %s", filepath.Base(file), ln, msg)
|
||||
}
|
118
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/template.go
generated
vendored
Normal file
118
vendor/github.com/containers/storage/pkg/plugins/pluginrpc-gen/template.go
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func printArgs(args []arg) string {
|
||||
var argStr []string
|
||||
for _, arg := range args {
|
||||
argStr = append(argStr, arg.String())
|
||||
}
|
||||
return strings.Join(argStr, ", ")
|
||||
}
|
||||
|
||||
func buildImports(specs []importSpec) string {
|
||||
if len(specs) == 0 {
|
||||
return `import "errors"`
|
||||
}
|
||||
imports := "import(\n"
|
||||
imports += "\t\"errors\"\n"
|
||||
for _, i := range specs {
|
||||
imports += "\t" + i.String() + "\n"
|
||||
}
|
||||
imports += ")"
|
||||
return imports
|
||||
}
|
||||
|
||||
func marshalType(t string) string {
|
||||
switch t {
|
||||
case "error":
|
||||
// convert error types to plain strings to ensure the values are encoded/decoded properly
|
||||
return "string"
|
||||
default:
|
||||
return t
|
||||
}
|
||||
}
|
||||
|
||||
func isErr(t string) bool {
|
||||
switch t {
|
||||
case "error":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Need to use this helper due to issues with go-vet
|
||||
func buildTag(s string) string {
|
||||
return "+build " + s
|
||||
}
|
||||
|
||||
var templFuncs = template.FuncMap{
|
||||
"printArgs": printArgs,
|
||||
"marshalType": marshalType,
|
||||
"isErr": isErr,
|
||||
"lower": strings.ToLower,
|
||||
"title": title,
|
||||
"tag": buildTag,
|
||||
"imports": buildImports,
|
||||
}
|
||||
|
||||
func title(s string) string {
|
||||
if strings.ToLower(s) == "id" {
|
||||
return "ID"
|
||||
}
|
||||
return strings.Title(s)
|
||||
}
|
||||
|
||||
var generatedTempl = template.Must(template.New("rpc_cient").Funcs(templFuncs).Parse(`
|
||||
// generated code - DO NOT EDIT
|
||||
{{ range $k, $v := .BuildTags }}
|
||||
// {{ tag $k }} {{ end }}
|
||||
|
||||
package {{ .Name }}
|
||||
|
||||
{{ imports .Imports }}
|
||||
|
||||
type client interface{
|
||||
Call(string, interface{}, interface{}) error
|
||||
}
|
||||
|
||||
type {{ .InterfaceType }}Proxy struct {
|
||||
client
|
||||
}
|
||||
|
||||
{{ range .Functions }}
|
||||
type {{ $.InterfaceType }}Proxy{{ .Name }}Request struct{
|
||||
{{ range .Args }}
|
||||
{{ title .Name }} {{ .ArgType }} {{ end }}
|
||||
}
|
||||
|
||||
type {{ $.InterfaceType }}Proxy{{ .Name }}Response struct{
|
||||
{{ range .Returns }}
|
||||
{{ title .Name }} {{ marshalType .ArgType }} {{ end }}
|
||||
}
|
||||
|
||||
func (pp *{{ $.InterfaceType }}Proxy) {{ .Name }}({{ printArgs .Args }}) ({{ printArgs .Returns }}) {
|
||||
var(
|
||||
req {{ $.InterfaceType }}Proxy{{ .Name }}Request
|
||||
ret {{ $.InterfaceType }}Proxy{{ .Name }}Response
|
||||
)
|
||||
{{ range .Args }}
|
||||
req.{{ title .Name }} = {{ lower .Name }} {{ end }}
|
||||
if err = pp.Call("{{ $.RPCName }}.{{ .Name }}", req, &ret); err != nil {
|
||||
return
|
||||
}
|
||||
{{ range $r := .Returns }}
|
||||
{{ if isErr .ArgType }}
|
||||
if ret.{{ title .Name }} != "" {
|
||||
{{ lower .Name }} = errors.New(ret.{{ title .Name }})
|
||||
} {{ end }}
|
||||
{{ if isErr .ArgType | not }} {{ lower .Name }} = ret.{{ title .Name }} {{ end }} {{ end }}
|
||||
|
||||
return
|
||||
}
|
||||
{{ end }}
|
||||
`))
|
270
vendor/github.com/containers/storage/pkg/plugins/plugins.go
generated
vendored
Normal file
270
vendor/github.com/containers/storage/pkg/plugins/plugins.go
generated
vendored
Normal file
|
@ -0,0 +1,270 @@
|
|||
// Package plugins provides structures and helper functions to manage Docker
|
||||
// plugins.
|
||||
//
|
||||
// Storage discovers plugins by looking for them in the plugin directory whenever
|
||||
// a user or container tries to use one by name. UNIX domain socket files must
|
||||
// be located under /run/oci-storage/plugins, whereas spec files can be located
|
||||
// either under /etc/oci-storage/plugins or /usr/lib/oci-storage/plugins. This
|
||||
// is handled by the Registry interface, which lets you list all plugins or get
|
||||
// a plugin by its name if it exists.
|
||||
//
|
||||
// The plugins need to implement an HTTP server and bind this to the UNIX socket
|
||||
// or the address specified in the spec files.
|
||||
// A handshake is send at /Plugin.Activate, and plugins are expected to return
|
||||
// a Manifest with a list of subsystems which this plugin implements. As of
|
||||
// this writing, the known subsystem is "GraphDriver".
|
||||
//
|
||||
// In order to use a plugins, you can use the ``Get`` with the name of the
|
||||
// plugin and the subsystem it implements.
|
||||
//
|
||||
// plugin, err := plugins.Get("example", "VolumeDriver")
|
||||
// if err != nil {
|
||||
// return fmt.Errorf("Error looking up volume plugin example: %v", err)
|
||||
// }
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotImplements is returned if the plugin does not implement the requested driver.
|
||||
ErrNotImplements = errors.New("Plugin does not implement the requested driver")
|
||||
)
|
||||
|
||||
type plugins struct {
|
||||
sync.Mutex
|
||||
plugins map[string]*Plugin
|
||||
}
|
||||
|
||||
var (
|
||||
storage = plugins{plugins: make(map[string]*Plugin)}
|
||||
extpointHandlers = make(map[string]func(string, *Client))
|
||||
)
|
||||
|
||||
// Manifest lists what a plugin implements.
|
||||
type Manifest struct {
|
||||
// List of subsystem the plugin implements.
|
||||
Implements []string
|
||||
}
|
||||
|
||||
// Plugin is the definition of a storage plugin.
|
||||
type Plugin struct {
|
||||
// Name of the plugin
|
||||
name string
|
||||
// Address of the plugin
|
||||
Addr string
|
||||
// TLS configuration of the plugin
|
||||
TLSConfig *tlsconfig.Options
|
||||
// Client attached to the plugin
|
||||
client *Client
|
||||
// Manifest of the plugin (see above)
|
||||
Manifest *Manifest `json:"-"`
|
||||
|
||||
// error produced by activation
|
||||
activateErr error
|
||||
// specifies if the activation sequence is completed (not if it is successful or not)
|
||||
activated bool
|
||||
// wait for activation to finish
|
||||
activateWait *sync.Cond
|
||||
}
|
||||
|
||||
// Name returns the name of the plugin.
|
||||
func (p *Plugin) Name() string {
|
||||
return p.name
|
||||
}
|
||||
|
||||
// Client returns a ready-to-use plugin client that can be used to communicate with the plugin.
|
||||
func (p *Plugin) Client() *Client {
|
||||
return p.client
|
||||
}
|
||||
|
||||
// NewLocalPlugin creates a new local plugin.
|
||||
func NewLocalPlugin(name, addr string) *Plugin {
|
||||
return &Plugin{
|
||||
name: name,
|
||||
Addr: addr,
|
||||
// TODO: change to nil
|
||||
TLSConfig: &tlsconfig.Options{InsecureSkipVerify: true},
|
||||
activateWait: sync.NewCond(&sync.Mutex{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) activate() error {
|
||||
p.activateWait.L.Lock()
|
||||
if p.activated {
|
||||
p.activateWait.L.Unlock()
|
||||
return p.activateErr
|
||||
}
|
||||
|
||||
p.activateErr = p.activateWithLock()
|
||||
p.activated = true
|
||||
|
||||
p.activateWait.L.Unlock()
|
||||
p.activateWait.Broadcast()
|
||||
return p.activateErr
|
||||
}
|
||||
|
||||
func (p *Plugin) activateWithLock() error {
|
||||
c, err := NewClient(p.Addr, p.TLSConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.client = c
|
||||
|
||||
m := new(Manifest)
|
||||
if err = p.client.Call("Plugin.Activate", nil, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Manifest = m
|
||||
|
||||
for _, iface := range m.Implements {
|
||||
handler, handled := extpointHandlers[iface]
|
||||
if !handled {
|
||||
continue
|
||||
}
|
||||
handler(p.name, p.client)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Plugin) waitActive() error {
|
||||
p.activateWait.L.Lock()
|
||||
for !p.activated {
|
||||
p.activateWait.Wait()
|
||||
}
|
||||
p.activateWait.L.Unlock()
|
||||
return p.activateErr
|
||||
}
|
||||
|
||||
func (p *Plugin) implements(kind string) bool {
|
||||
if err := p.waitActive(); err != nil {
|
||||
return false
|
||||
}
|
||||
for _, driver := range p.Manifest.Implements {
|
||||
if driver == kind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func load(name string) (*Plugin, error) {
|
||||
return loadWithRetry(name, true)
|
||||
}
|
||||
|
||||
func loadWithRetry(name string, retry bool) (*Plugin, error) {
|
||||
registry := newLocalRegistry()
|
||||
start := time.Now()
|
||||
|
||||
var retries int
|
||||
for {
|
||||
pl, err := registry.Plugin(name)
|
||||
if err != nil {
|
||||
if !retry {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
timeOff := backoff(retries)
|
||||
if abort(start, timeOff) {
|
||||
return nil, err
|
||||
}
|
||||
retries++
|
||||
logrus.Warnf("Unable to locate plugin: %s, retrying in %v", name, timeOff)
|
||||
time.Sleep(timeOff)
|
||||
continue
|
||||
}
|
||||
|
||||
storage.Lock()
|
||||
storage.plugins[name] = pl
|
||||
storage.Unlock()
|
||||
|
||||
err = pl.activate()
|
||||
|
||||
if err != nil {
|
||||
storage.Lock()
|
||||
delete(storage.plugins, name)
|
||||
storage.Unlock()
|
||||
}
|
||||
|
||||
return pl, err
|
||||
}
|
||||
}
|
||||
|
||||
func get(name string) (*Plugin, error) {
|
||||
storage.Lock()
|
||||
pl, ok := storage.plugins[name]
|
||||
storage.Unlock()
|
||||
if ok {
|
||||
return pl, pl.activate()
|
||||
}
|
||||
return load(name)
|
||||
}
|
||||
|
||||
// Get returns the plugin given the specified name and requested implementation.
|
||||
func Get(name, imp string) (*Plugin, error) {
|
||||
pl, err := get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pl.implements(imp) {
|
||||
logrus.Debugf("%s implements: %s", name, imp)
|
||||
return pl, nil
|
||||
}
|
||||
return nil, ErrNotImplements
|
||||
}
|
||||
|
||||
// Handle adds the specified function to the extpointHandlers.
|
||||
func Handle(iface string, fn func(string, *Client)) {
|
||||
extpointHandlers[iface] = fn
|
||||
}
|
||||
|
||||
// GetAll returns all the plugins for the specified implementation
|
||||
func GetAll(imp string) ([]*Plugin, error) {
|
||||
pluginNames, err := Scan()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
type plLoad struct {
|
||||
pl *Plugin
|
||||
err error
|
||||
}
|
||||
|
||||
chPl := make(chan *plLoad, len(pluginNames))
|
||||
var wg sync.WaitGroup
|
||||
for _, name := range pluginNames {
|
||||
if pl, ok := storage.plugins[name]; ok {
|
||||
chPl <- &plLoad{pl, nil}
|
||||
continue
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(name string) {
|
||||
defer wg.Done()
|
||||
pl, err := loadWithRetry(name, false)
|
||||
chPl <- &plLoad{pl, err}
|
||||
}(name)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(chPl)
|
||||
|
||||
var out []*Plugin
|
||||
for pl := range chPl {
|
||||
if pl.err != nil {
|
||||
logrus.Error(pl.err)
|
||||
continue
|
||||
}
|
||||
if pl.pl.implements(imp) {
|
||||
out = append(out, pl.pl)
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
36
vendor/github.com/containers/storage/pkg/plugins/transport/http.go
generated
vendored
Normal file
36
vendor/github.com/containers/storage/pkg/plugins/transport/http.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
package transport
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// httpTransport holds an http.RoundTripper
|
||||
// and information about the scheme and address the transport
|
||||
// sends request to.
|
||||
type httpTransport struct {
|
||||
http.RoundTripper
|
||||
scheme string
|
||||
addr string
|
||||
}
|
||||
|
||||
// NewHTTPTransport creates a new httpTransport.
|
||||
func NewHTTPTransport(r http.RoundTripper, scheme, addr string) Transport {
|
||||
return httpTransport{
|
||||
RoundTripper: r,
|
||||
scheme: scheme,
|
||||
addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
// NewRequest creates a new http.Request and sets the URL
|
||||
// scheme and address with the transport's fields.
|
||||
func (t httpTransport) NewRequest(path string, data io.Reader) (*http.Request, error) {
|
||||
req, err := newHTTPRequest(path, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.URL.Scheme = t.scheme
|
||||
req.URL.Host = t.addr
|
||||
return req, nil
|
||||
}
|
36
vendor/github.com/containers/storage/pkg/plugins/transport/transport.go
generated
vendored
Normal file
36
vendor/github.com/containers/storage/pkg/plugins/transport/transport.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
package transport
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// VersionMimetype is the Content-Type the engine sends to plugins.
|
||||
const VersionMimetype = "application/vnd.docker.plugins.v1.2+json"
|
||||
|
||||
// RequestFactory defines an interface that
|
||||
// transports can implement to create new requests.
|
||||
type RequestFactory interface {
|
||||
NewRequest(path string, data io.Reader) (*http.Request, error)
|
||||
}
|
||||
|
||||
// Transport defines an interface that plugin transports
|
||||
// must implement.
|
||||
type Transport interface {
|
||||
http.RoundTripper
|
||||
RequestFactory
|
||||
}
|
||||
|
||||
// newHTTPRequest creates a new request with a path and a body.
|
||||
func newHTTPRequest(path string, data io.Reader) (*http.Request, error) {
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
req, err := http.NewRequest("POST", path, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Add("Accept", VersionMimetype)
|
||||
return req, nil
|
||||
}
|
161
vendor/github.com/containers/storage/pkg/pools/pools_test.go
generated
vendored
Normal file
161
vendor/github.com/containers/storage/pkg/pools/pools_test.go
generated
vendored
Normal file
|
@ -0,0 +1,161 @@
|
|||
package pools
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"io"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBufioReaderPoolGetWithNoReaderShouldCreateOne(t *testing.T) {
|
||||
reader := BufioReader32KPool.Get(nil)
|
||||
if reader == nil {
|
||||
t.Fatalf("BufioReaderPool should have create a bufio.Reader but did not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufioReaderPoolPutAndGet(t *testing.T) {
|
||||
sr := bufio.NewReader(strings.NewReader("foobar"))
|
||||
reader := BufioReader32KPool.Get(sr)
|
||||
if reader == nil {
|
||||
t.Fatalf("BufioReaderPool should not return a nil reader.")
|
||||
}
|
||||
// verify the first 3 byte
|
||||
buf1 := make([]byte, 3)
|
||||
_, err := reader.Read(buf1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if actual := string(buf1); actual != "foo" {
|
||||
t.Fatalf("The first letter should have been 'foo' but was %v", actual)
|
||||
}
|
||||
BufioReader32KPool.Put(reader)
|
||||
// Try to read the next 3 bytes
|
||||
_, err = sr.Read(make([]byte, 3))
|
||||
if err == nil || err != io.EOF {
|
||||
t.Fatalf("The buffer should have been empty, issue an EOF error.")
|
||||
}
|
||||
}
|
||||
|
||||
type simpleReaderCloser struct {
|
||||
io.Reader
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (r *simpleReaderCloser) Close() error {
|
||||
r.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestNewReadCloserWrapperWithAReadCloser(t *testing.T) {
|
||||
br := bufio.NewReader(strings.NewReader(""))
|
||||
sr := &simpleReaderCloser{
|
||||
Reader: strings.NewReader("foobar"),
|
||||
closed: false,
|
||||
}
|
||||
reader := BufioReader32KPool.NewReadCloserWrapper(br, sr)
|
||||
if reader == nil {
|
||||
t.Fatalf("NewReadCloserWrapper should not return a nil reader.")
|
||||
}
|
||||
// Verify the content of reader
|
||||
buf := make([]byte, 3)
|
||||
_, err := reader.Read(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if actual := string(buf); actual != "foo" {
|
||||
t.Fatalf("The first 3 letter should have been 'foo' but were %v", actual)
|
||||
}
|
||||
reader.Close()
|
||||
// Read 3 more bytes "bar"
|
||||
_, err = reader.Read(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if actual := string(buf); actual != "bar" {
|
||||
t.Fatalf("The first 3 letter should have been 'bar' but were %v", actual)
|
||||
}
|
||||
if !sr.closed {
|
||||
t.Fatalf("The ReaderCloser should have been closed, it is not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufioWriterPoolGetWithNoReaderShouldCreateOne(t *testing.T) {
|
||||
writer := BufioWriter32KPool.Get(nil)
|
||||
if writer == nil {
|
||||
t.Fatalf("BufioWriterPool should have create a bufio.Writer but did not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBufioWriterPoolPutAndGet(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
bw := bufio.NewWriter(buf)
|
||||
writer := BufioWriter32KPool.Get(bw)
|
||||
if writer == nil {
|
||||
t.Fatalf("BufioReaderPool should not return a nil writer.")
|
||||
}
|
||||
written, err := writer.Write([]byte("foobar"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if written != 6 {
|
||||
t.Fatalf("Should have written 6 bytes, but wrote %v bytes", written)
|
||||
}
|
||||
// Make sure we Flush all the way ?
|
||||
writer.Flush()
|
||||
bw.Flush()
|
||||
if len(buf.Bytes()) != 6 {
|
||||
t.Fatalf("The buffer should contain 6 bytes ('foobar') but contains %v ('%v')", buf.Bytes(), string(buf.Bytes()))
|
||||
}
|
||||
// Reset the buffer
|
||||
buf.Reset()
|
||||
BufioWriter32KPool.Put(writer)
|
||||
// Try to write something
|
||||
if _, err = writer.Write([]byte("barfoo")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// If we now try to flush it, it should panic (the writer is nil)
|
||||
// recover it
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Fatal("Trying to flush the writter should have 'paniced', did not.")
|
||||
}
|
||||
}()
|
||||
writer.Flush()
|
||||
}
|
||||
|
||||
type simpleWriterCloser struct {
|
||||
io.Writer
|
||||
closed bool
|
||||
}
|
||||
|
||||
func (r *simpleWriterCloser) Close() error {
|
||||
r.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestNewWriteCloserWrapperWithAWriteCloser(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
bw := bufio.NewWriter(buf)
|
||||
sw := &simpleWriterCloser{
|
||||
Writer: new(bytes.Buffer),
|
||||
closed: false,
|
||||
}
|
||||
bw.Flush()
|
||||
writer := BufioWriter32KPool.NewWriteCloserWrapper(bw, sw)
|
||||
if writer == nil {
|
||||
t.Fatalf("BufioReaderPool should not return a nil writer.")
|
||||
}
|
||||
written, err := writer.Write([]byte("foobar"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if written != 6 {
|
||||
t.Fatalf("Should have written 6 bytes, but wrote %v bytes", written)
|
||||
}
|
||||
writer.Close()
|
||||
if !sw.closed {
|
||||
t.Fatalf("The ReaderCloser should have been closed, it is not.")
|
||||
}
|
||||
}
|
22
vendor/github.com/containers/storage/pkg/random/random_test.go
generated
vendored
Normal file
22
vendor/github.com/containers/storage/pkg/random/random_test.go
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
package random
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// for go test -v -race
|
||||
func TestConcurrency(t *testing.T) {
|
||||
rnd := rand.New(NewSource())
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
rnd.Int63()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
56
vendor/github.com/containers/storage/pkg/stringid/stringid_test.go
generated
vendored
Normal file
56
vendor/github.com/containers/storage/pkg/stringid/stringid_test.go
generated
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
package stringid
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenerateRandomID(t *testing.T) {
|
||||
id := GenerateRandomID()
|
||||
|
||||
if len(id) != 64 {
|
||||
t.Fatalf("Id returned is incorrect: %s", id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShortenId(t *testing.T) {
|
||||
id := GenerateRandomID()
|
||||
truncID := TruncateID(id)
|
||||
if len(truncID) != 12 {
|
||||
t.Fatalf("Id returned is incorrect: truncate on %s returned %s", id, truncID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShortenIdEmpty(t *testing.T) {
|
||||
id := ""
|
||||
truncID := TruncateID(id)
|
||||
if len(truncID) > len(id) {
|
||||
t.Fatalf("Id returned is incorrect: truncate on %s returned %s", id, truncID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShortenIdInvalid(t *testing.T) {
|
||||
id := "1234"
|
||||
truncID := TruncateID(id)
|
||||
if len(truncID) != len(id) {
|
||||
t.Fatalf("Id returned is incorrect: truncate on %s returned %s", id, truncID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsShortIDNonHex(t *testing.T) {
|
||||
id := "some non-hex value"
|
||||
if IsShortID(id) {
|
||||
t.Fatalf("%s is not a short ID", id)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsShortIDNotCorrectSize(t *testing.T) {
|
||||
id := strings.Repeat("a", shortLen+1)
|
||||
if IsShortID(id) {
|
||||
t.Fatalf("%s is not a short ID", id)
|
||||
}
|
||||
id = strings.Repeat("a", shortLen-1)
|
||||
if IsShortID(id) {
|
||||
t.Fatalf("%s is not a short ID", id)
|
||||
}
|
||||
}
|
87
vendor/github.com/containers/storage/pkg/stringutils/stringutils.go
generated
vendored
Normal file
87
vendor/github.com/containers/storage/pkg/stringutils/stringutils.go
generated
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Package stringutils provides helper functions for dealing with strings.
|
||||
package stringutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/rand"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/storage/pkg/random"
|
||||
)
|
||||
|
||||
// GenerateRandomAlphaOnlyString generates an alphabetical random string with length n.
|
||||
func GenerateRandomAlphaOnlyString(n int) string {
|
||||
// make a really long string
|
||||
letters := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||
b := make([]byte, n)
|
||||
for i := range b {
|
||||
b[i] = letters[random.Rand.Intn(len(letters))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// GenerateRandomASCIIString generates an ASCII random string with length n.
|
||||
func GenerateRandomASCIIString(n int) string {
|
||||
chars := "abcdefghijklmnopqrstuvwxyz" +
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
||||
"~!@#$%^&*()-_+={}[]\\|<,>.?/\"';:` "
|
||||
res := make([]byte, n)
|
||||
for i := 0; i < n; i++ {
|
||||
res[i] = chars[rand.Intn(len(chars))]
|
||||
}
|
||||
return string(res)
|
||||
}
|
||||
|
||||
// Truncate truncates a string to maxlen.
|
||||
func Truncate(s string, maxlen int) string {
|
||||
if len(s) <= maxlen {
|
||||
return s
|
||||
}
|
||||
return s[:maxlen]
|
||||
}
|
||||
|
||||
// InSlice tests whether a string is contained in a slice of strings or not.
|
||||
// Comparison is case insensitive
|
||||
func InSlice(slice []string, s string) bool {
|
||||
for _, ss := range slice {
|
||||
if strings.ToLower(s) == strings.ToLower(ss) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func quote(word string, buf *bytes.Buffer) {
|
||||
// Bail out early for "simple" strings
|
||||
if word != "" && !strings.ContainsAny(word, "\\'\"`${[|&;<>()~*?! \t\n") {
|
||||
buf.WriteString(word)
|
||||
return
|
||||
}
|
||||
|
||||
buf.WriteString("'")
|
||||
|
||||
for i := 0; i < len(word); i++ {
|
||||
b := word[i]
|
||||
if b == '\'' {
|
||||
// Replace literal ' with a close ', a \', and a open '
|
||||
buf.WriteString("'\\''")
|
||||
} else {
|
||||
buf.WriteByte(b)
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString("'")
|
||||
}
|
||||
|
||||
// ShellQuoteArguments takes a list of strings and escapes them so they will be
|
||||
// handled right when passed as arguments to a program via a shell
|
||||
func ShellQuoteArguments(args []string) string {
|
||||
var buf bytes.Buffer
|
||||
for i, arg := range args {
|
||||
if i != 0 {
|
||||
buf.WriteByte(' ')
|
||||
}
|
||||
quote(arg, &buf)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
105
vendor/github.com/containers/storage/pkg/stringutils/stringutils_test.go
generated
vendored
Normal file
105
vendor/github.com/containers/storage/pkg/stringutils/stringutils_test.go
generated
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
package stringutils
|
||||
|
||||
import "testing"
|
||||
|
||||
func testLengthHelper(generator func(int) string, t *testing.T) {
|
||||
expectedLength := 20
|
||||
s := generator(expectedLength)
|
||||
if len(s) != expectedLength {
|
||||
t.Fatalf("Length of %s was %d but expected length %d", s, len(s), expectedLength)
|
||||
}
|
||||
}
|
||||
|
||||
func testUniquenessHelper(generator func(int) string, t *testing.T) {
|
||||
repeats := 25
|
||||
set := make(map[string]struct{}, repeats)
|
||||
for i := 0; i < repeats; i = i + 1 {
|
||||
str := generator(64)
|
||||
if len(str) != 64 {
|
||||
t.Fatalf("Id returned is incorrect: %s", str)
|
||||
}
|
||||
if _, ok := set[str]; ok {
|
||||
t.Fatalf("Random number is repeated")
|
||||
}
|
||||
set[str] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
func isASCII(s string) bool {
|
||||
for _, c := range s {
|
||||
if c > 127 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func TestGenerateRandomAlphaOnlyStringLength(t *testing.T) {
|
||||
testLengthHelper(GenerateRandomAlphaOnlyString, t)
|
||||
}
|
||||
|
||||
func TestGenerateRandomAlphaOnlyStringUniqueness(t *testing.T) {
|
||||
testUniquenessHelper(GenerateRandomAlphaOnlyString, t)
|
||||
}
|
||||
|
||||
func TestGenerateRandomAsciiStringLength(t *testing.T) {
|
||||
testLengthHelper(GenerateRandomASCIIString, t)
|
||||
}
|
||||
|
||||
func TestGenerateRandomAsciiStringUniqueness(t *testing.T) {
|
||||
testUniquenessHelper(GenerateRandomASCIIString, t)
|
||||
}
|
||||
|
||||
func TestGenerateRandomAsciiStringIsAscii(t *testing.T) {
|
||||
str := GenerateRandomASCIIString(64)
|
||||
if !isASCII(str) {
|
||||
t.Fatalf("%s contained non-ascii characters", str)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTruncate(t *testing.T) {
|
||||
str := "teststring"
|
||||
newstr := Truncate(str, 4)
|
||||
if newstr != "test" {
|
||||
t.Fatalf("Expected test, got %s", newstr)
|
||||
}
|
||||
newstr = Truncate(str, 20)
|
||||
if newstr != "teststring" {
|
||||
t.Fatalf("Expected teststring, got %s", newstr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInSlice(t *testing.T) {
|
||||
slice := []string{"test", "in", "slice"}
|
||||
|
||||
test := InSlice(slice, "test")
|
||||
if !test {
|
||||
t.Fatalf("Expected string test to be in slice")
|
||||
}
|
||||
test = InSlice(slice, "SLICE")
|
||||
if !test {
|
||||
t.Fatalf("Expected string SLICE to be in slice")
|
||||
}
|
||||
test = InSlice(slice, "notinslice")
|
||||
if test {
|
||||
t.Fatalf("Expected string notinslice not to be in slice")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellQuoteArgumentsEmpty(t *testing.T) {
|
||||
actual := ShellQuoteArguments([]string{})
|
||||
expected := ""
|
||||
if actual != expected {
|
||||
t.Fatalf("Expected an empty string")
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellQuoteArguments(t *testing.T) {
|
||||
simpleString := "simpleString"
|
||||
complexString := "This is a 'more' complex $tring with some special char *"
|
||||
actual := ShellQuoteArguments([]string{simpleString, complexString})
|
||||
expected := "simpleString 'This is a '\\''more'\\'' complex $tring with some special char *'"
|
||||
if actual != expected {
|
||||
t.Fatalf("Expected \"%v\", got \"%v\"", expected, actual)
|
||||
}
|
||||
}
|
94
vendor/github.com/containers/storage/pkg/system/chtimes_test.go
generated
vendored
Normal file
94
vendor/github.com/containers/storage/pkg/system/chtimes_test.go
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
package system
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// prepareTempFile creates a temporary file in a temporary directory.
|
||||
func prepareTempFile(t *testing.T) (string, string) {
|
||||
dir, err := ioutil.TempDir("", "docker-system-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
file := filepath.Join(dir, "exist")
|
||||
if err := ioutil.WriteFile(file, []byte("hello"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return file, dir
|
||||
}
|
||||
|
||||
// TestChtimes tests Chtimes on a tempfile. Test only mTime, because aTime is OS dependent
|
||||
func TestChtimes(t *testing.T) {
|
||||
file, dir := prepareTempFile(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second)
|
||||
unixEpochTime := time.Unix(0, 0)
|
||||
afterUnixEpochTime := time.Unix(100, 0)
|
||||
unixMaxTime := maxTime
|
||||
|
||||
// Test both aTime and mTime set to Unix Epoch
|
||||
Chtimes(file, unixEpochTime, unixEpochTime)
|
||||
|
||||
f, err := os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if f.ModTime() != unixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime())
|
||||
}
|
||||
|
||||
// Test aTime before Unix Epoch and mTime set to Unix Epoch
|
||||
Chtimes(file, beforeUnixEpochTime, unixEpochTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if f.ModTime() != unixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime())
|
||||
}
|
||||
|
||||
// Test aTime set to Unix Epoch and mTime before Unix Epoch
|
||||
Chtimes(file, unixEpochTime, beforeUnixEpochTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if f.ModTime() != unixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", unixEpochTime, f.ModTime())
|
||||
}
|
||||
|
||||
// Test both aTime and mTime set to after Unix Epoch (valid time)
|
||||
Chtimes(file, afterUnixEpochTime, afterUnixEpochTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if f.ModTime() != afterUnixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, f.ModTime())
|
||||
}
|
||||
|
||||
// Test both aTime and mTime set to Unix max time
|
||||
Chtimes(file, unixMaxTime, unixMaxTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if f.ModTime().Truncate(time.Second) != unixMaxTime.Truncate(time.Second) {
|
||||
t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), f.ModTime().Truncate(time.Second))
|
||||
}
|
||||
}
|
91
vendor/github.com/containers/storage/pkg/system/chtimes_unix_test.go
generated
vendored
Normal file
91
vendor/github.com/containers/storage/pkg/system/chtimes_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,91 @@
|
|||
// +build !windows
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestChtimes tests Chtimes access time on a tempfile on Linux
|
||||
func TestChtimesLinux(t *testing.T) {
|
||||
file, dir := prepareTempFile(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second)
|
||||
unixEpochTime := time.Unix(0, 0)
|
||||
afterUnixEpochTime := time.Unix(100, 0)
|
||||
unixMaxTime := maxTime
|
||||
|
||||
// Test both aTime and mTime set to Unix Epoch
|
||||
Chtimes(file, unixEpochTime, unixEpochTime)
|
||||
|
||||
f, err := os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stat := f.Sys().(*syscall.Stat_t)
|
||||
aTime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
|
||||
if aTime != unixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
|
||||
}
|
||||
|
||||
// Test aTime before Unix Epoch and mTime set to Unix Epoch
|
||||
Chtimes(file, beforeUnixEpochTime, unixEpochTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stat = f.Sys().(*syscall.Stat_t)
|
||||
aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
|
||||
if aTime != unixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
|
||||
}
|
||||
|
||||
// Test aTime set to Unix Epoch and mTime before Unix Epoch
|
||||
Chtimes(file, unixEpochTime, beforeUnixEpochTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stat = f.Sys().(*syscall.Stat_t)
|
||||
aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
|
||||
if aTime != unixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
|
||||
}
|
||||
|
||||
// Test both aTime and mTime set to after Unix Epoch (valid time)
|
||||
Chtimes(file, afterUnixEpochTime, afterUnixEpochTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stat = f.Sys().(*syscall.Stat_t)
|
||||
aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
|
||||
if aTime != afterUnixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, aTime)
|
||||
}
|
||||
|
||||
// Test both aTime and mTime set to Unix max time
|
||||
Chtimes(file, unixMaxTime, unixMaxTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
stat = f.Sys().(*syscall.Stat_t)
|
||||
aTime = time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec))
|
||||
if aTime.Truncate(time.Second) != unixMaxTime.Truncate(time.Second) {
|
||||
t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), aTime.Truncate(time.Second))
|
||||
}
|
||||
}
|
86
vendor/github.com/containers/storage/pkg/system/chtimes_windows_test.go
generated
vendored
Normal file
86
vendor/github.com/containers/storage/pkg/system/chtimes_windows_test.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
// +build windows
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestChtimes tests Chtimes access time on a tempfile on Windows
|
||||
func TestChtimesWindows(t *testing.T) {
|
||||
file, dir := prepareTempFile(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
beforeUnixEpochTime := time.Unix(0, 0).Add(-100 * time.Second)
|
||||
unixEpochTime := time.Unix(0, 0)
|
||||
afterUnixEpochTime := time.Unix(100, 0)
|
||||
unixMaxTime := maxTime
|
||||
|
||||
// Test both aTime and mTime set to Unix Epoch
|
||||
Chtimes(file, unixEpochTime, unixEpochTime)
|
||||
|
||||
f, err := os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
aTime := time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
|
||||
if aTime != unixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
|
||||
}
|
||||
|
||||
// Test aTime before Unix Epoch and mTime set to Unix Epoch
|
||||
Chtimes(file, beforeUnixEpochTime, unixEpochTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
|
||||
if aTime != unixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
|
||||
}
|
||||
|
||||
// Test aTime set to Unix Epoch and mTime before Unix Epoch
|
||||
Chtimes(file, unixEpochTime, beforeUnixEpochTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
|
||||
if aTime != unixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", unixEpochTime, aTime)
|
||||
}
|
||||
|
||||
// Test both aTime and mTime set to after Unix Epoch (valid time)
|
||||
Chtimes(file, afterUnixEpochTime, afterUnixEpochTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
|
||||
if aTime != afterUnixEpochTime {
|
||||
t.Fatalf("Expected: %s, got: %s", afterUnixEpochTime, aTime)
|
||||
}
|
||||
|
||||
// Test both aTime and mTime set to Unix max time
|
||||
Chtimes(file, unixMaxTime, unixMaxTime)
|
||||
|
||||
f, err = os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
aTime = time.Unix(0, f.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
|
||||
if aTime.Truncate(time.Second) != unixMaxTime.Truncate(time.Second) {
|
||||
t.Fatalf("Expected: %s, got: %s", unixMaxTime.Truncate(time.Second), aTime.Truncate(time.Second))
|
||||
}
|
||||
}
|
30
vendor/github.com/containers/storage/pkg/system/lstat_unix_test.go
generated
vendored
Normal file
30
vendor/github.com/containers/storage/pkg/system/lstat_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
// +build linux freebsd
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestLstat tests Lstat for existing and non existing files
|
||||
func TestLstat(t *testing.T) {
|
||||
file, invalid, _, dir := prepareFiles(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
statFile, err := Lstat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if statFile == nil {
|
||||
t.Fatal("returned empty stat for existing file")
|
||||
}
|
||||
|
||||
statInvalid, err := Lstat(invalid)
|
||||
if err == nil {
|
||||
t.Fatal("did not return error for non-existing file")
|
||||
}
|
||||
if statInvalid != nil {
|
||||
t.Fatal("returned non-nil stat for non-existing file")
|
||||
}
|
||||
}
|
40
vendor/github.com/containers/storage/pkg/system/meminfo_unix_test.go
generated
vendored
Normal file
40
vendor/github.com/containers/storage/pkg/system/meminfo_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
// +build linux freebsd
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
)
|
||||
|
||||
// TestMemInfo tests parseMemInfo with a static meminfo string
|
||||
func TestMemInfo(t *testing.T) {
|
||||
const input = `
|
||||
MemTotal: 1 kB
|
||||
MemFree: 2 kB
|
||||
SwapTotal: 3 kB
|
||||
SwapFree: 4 kB
|
||||
Malformed1:
|
||||
Malformed2: 1
|
||||
Malformed3: 2 MB
|
||||
Malformed4: X kB
|
||||
`
|
||||
meminfo, err := parseMemInfo(strings.NewReader(input))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if meminfo.MemTotal != 1*units.KiB {
|
||||
t.Fatalf("Unexpected MemTotal: %d", meminfo.MemTotal)
|
||||
}
|
||||
if meminfo.MemFree != 2*units.KiB {
|
||||
t.Fatalf("Unexpected MemFree: %d", meminfo.MemFree)
|
||||
}
|
||||
if meminfo.SwapTotal != 3*units.KiB {
|
||||
t.Fatalf("Unexpected SwapTotal: %d", meminfo.SwapTotal)
|
||||
}
|
||||
if meminfo.SwapFree != 4*units.KiB {
|
||||
t.Fatalf("Unexpected SwapFree: %d", meminfo.SwapFree)
|
||||
}
|
||||
}
|
78
vendor/github.com/containers/storage/pkg/system/path_windows_test.go
generated
vendored
Normal file
78
vendor/github.com/containers/storage/pkg/system/path_windows_test.go
generated
vendored
Normal file
|
@ -0,0 +1,78 @@
|
|||
// +build windows
|
||||
|
||||
package system
|
||||
|
||||
import "testing"
|
||||
|
||||
// TestCheckSystemDriveAndRemoveDriveLetter tests CheckSystemDriveAndRemoveDriveLetter
|
||||
func TestCheckSystemDriveAndRemoveDriveLetter(t *testing.T) {
|
||||
// Fails if not C drive.
|
||||
path, err := CheckSystemDriveAndRemoveDriveLetter(`d:\`)
|
||||
if err == nil || (err != nil && err.Error() != "The specified path is not on the system drive (C:)") {
|
||||
t.Fatalf("Expected error for d:")
|
||||
}
|
||||
|
||||
// Single character is unchanged
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter("z"); err != nil {
|
||||
t.Fatalf("Single character should pass")
|
||||
}
|
||||
if path != "z" {
|
||||
t.Fatalf("Single character should be unchanged")
|
||||
}
|
||||
|
||||
// Two characters without colon is unchanged
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter("AB"); err != nil {
|
||||
t.Fatalf("2 characters without colon should pass")
|
||||
}
|
||||
if path != "AB" {
|
||||
t.Fatalf("2 characters without colon should be unchanged")
|
||||
}
|
||||
|
||||
// Abs path without drive letter
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`\l`); err != nil {
|
||||
t.Fatalf("abs path no drive letter should pass")
|
||||
}
|
||||
if path != `\l` {
|
||||
t.Fatalf("abs path without drive letter should be unchanged")
|
||||
}
|
||||
|
||||
// Abs path without drive letter, linux style
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`/l`); err != nil {
|
||||
t.Fatalf("abs path no drive letter linux style should pass")
|
||||
}
|
||||
if path != `\l` {
|
||||
t.Fatalf("abs path without drive letter linux failed %s", path)
|
||||
}
|
||||
|
||||
// Drive-colon should be stripped
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`c:\`); err != nil {
|
||||
t.Fatalf("An absolute path should pass")
|
||||
}
|
||||
if path != `\` {
|
||||
t.Fatalf(`An absolute path should have been shortened to \ %s`, path)
|
||||
}
|
||||
|
||||
// Verify with a linux-style path
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`c:/`); err != nil {
|
||||
t.Fatalf("An absolute path should pass")
|
||||
}
|
||||
if path != `\` {
|
||||
t.Fatalf(`A linux style absolute path should have been shortened to \ %s`, path)
|
||||
}
|
||||
|
||||
// Failure on c:
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`c:`); err == nil {
|
||||
t.Fatalf("c: should fail")
|
||||
}
|
||||
if err.Error() != `No relative path specified in "c:"` {
|
||||
t.Fatalf(path, err)
|
||||
}
|
||||
|
||||
// Failure on d:
|
||||
if path, err = CheckSystemDriveAndRemoveDriveLetter(`d:`); err == nil {
|
||||
t.Fatalf("c: should fail")
|
||||
}
|
||||
if err.Error() != `No relative path specified in "d:"` {
|
||||
t.Fatalf(path, err)
|
||||
}
|
||||
}
|
39
vendor/github.com/containers/storage/pkg/system/stat_unix_test.go
generated
vendored
Normal file
39
vendor/github.com/containers/storage/pkg/system/stat_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// +build linux freebsd
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestFromStatT tests fromStatT for a tempfile
|
||||
func TestFromStatT(t *testing.T) {
|
||||
file, _, _, dir := prepareFiles(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
stat := &syscall.Stat_t{}
|
||||
err := syscall.Lstat(file, stat)
|
||||
|
||||
s, err := fromStatT(stat)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if stat.Mode != s.Mode() {
|
||||
t.Fatal("got invalid mode")
|
||||
}
|
||||
if stat.Uid != s.UID() {
|
||||
t.Fatal("got invalid uid")
|
||||
}
|
||||
if stat.Gid != s.GID() {
|
||||
t.Fatal("got invalid gid")
|
||||
}
|
||||
if stat.Rdev != s.Rdev() {
|
||||
t.Fatal("got invalid rdev")
|
||||
}
|
||||
if stat.Mtim != s.Mtim() {
|
||||
t.Fatal("got invalid mtim")
|
||||
}
|
||||
}
|
9
vendor/github.com/containers/storage/pkg/system/syscall_windows_test.go
generated
vendored
Normal file
9
vendor/github.com/containers/storage/pkg/system/syscall_windows_test.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
package system
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestHasWin32KSupport(t *testing.T) {
|
||||
s := HasWin32KSupport() // make sure this doesn't panic
|
||||
|
||||
t.Logf("win32k: %v", s) // will be different on different platforms -- informative only
|
||||
}
|
68
vendor/github.com/containers/storage/pkg/system/utimes_unix_test.go
generated
vendored
Normal file
68
vendor/github.com/containers/storage/pkg/system/utimes_unix_test.go
generated
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
// +build linux freebsd
|
||||
|
||||
package system
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// prepareFiles creates files for testing in the temp directory
|
||||
func prepareFiles(t *testing.T) (string, string, string, string) {
|
||||
dir, err := ioutil.TempDir("", "docker-system-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
file := filepath.Join(dir, "exist")
|
||||
if err := ioutil.WriteFile(file, []byte("hello"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
invalid := filepath.Join(dir, "doesnt-exist")
|
||||
|
||||
symlink := filepath.Join(dir, "symlink")
|
||||
if err := os.Symlink(file, symlink); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return file, invalid, symlink, dir
|
||||
}
|
||||
|
||||
func TestLUtimesNano(t *testing.T) {
|
||||
file, invalid, symlink, dir := prepareFiles(t)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
before, err := os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ts := []syscall.Timespec{{0, 0}, {0, 0}}
|
||||
if err := LUtimesNano(symlink, ts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
symlinkInfo, err := os.Lstat(symlink)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if before.ModTime().Unix() == symlinkInfo.ModTime().Unix() {
|
||||
t.Fatal("The modification time of the symlink should be different")
|
||||
}
|
||||
|
||||
fileInfo, err := os.Stat(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if before.ModTime().Unix() != fileInfo.ModTime().Unix() {
|
||||
t.Fatal("The modification time of the file should be same")
|
||||
}
|
||||
|
||||
if err := LUtimesNano(invalid, ts); err == nil {
|
||||
t.Fatal("Doesn't return an error on a non-existing file")
|
||||
}
|
||||
}
|
70
vendor/github.com/containers/storage/pkg/testutil/assert/assert.go
generated
vendored
Normal file
70
vendor/github.com/containers/storage/pkg/testutil/assert/assert.go
generated
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Package assert contains functions for making assertions in unit tests
|
||||
package assert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TestingT is an interface which defines the methods of testing.T that are
|
||||
// required by this package
|
||||
type TestingT interface {
|
||||
Fatalf(string, ...interface{})
|
||||
}
|
||||
|
||||
// Equal compare the actual value to the expected value and fails the test if
|
||||
// they are not equal.
|
||||
func Equal(t TestingT, actual, expected interface{}) {
|
||||
if expected != actual {
|
||||
fatal(t, fmt.Sprintf("Expected '%v' (%T) got '%v' (%T)", expected, expected, actual, actual))
|
||||
}
|
||||
}
|
||||
|
||||
//EqualStringSlice compares two slices and fails the test if they do not contain
|
||||
// the same items.
|
||||
func EqualStringSlice(t TestingT, actual, expected []string) {
|
||||
if len(actual) != len(expected) {
|
||||
t.Fatalf("Expected (length %d): %q\nActual (length %d): %q",
|
||||
len(expected), expected, len(actual), actual)
|
||||
}
|
||||
for i, item := range actual {
|
||||
if item != expected[i] {
|
||||
t.Fatalf("Slices differ at element %d, expected %q got %q",
|
||||
i, expected[i], item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NilError asserts that the error is nil, otherwise it fails the test.
|
||||
func NilError(t TestingT, err error) {
|
||||
if err != nil {
|
||||
fatal(t, fmt.Sprintf("Expected no error, got: %s", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
// Error asserts that error is not nil, and contains the expected text,
|
||||
// otherwise it fails the test.
|
||||
func Error(t TestingT, err error, contains string) {
|
||||
if err == nil {
|
||||
fatal(t, "Expected an error, but error was nil")
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), contains) {
|
||||
fatal(t, fmt.Sprintf("Expected error to contain '%s', got '%s'", contains, err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
// Contains asserts that the string contains a substring, otherwise it fails the
|
||||
// test.
|
||||
func Contains(t TestingT, actual, contains string) {
|
||||
if !strings.Contains(actual, contains) {
|
||||
fatal(t, fmt.Sprintf("Expected '%s' to contain '%s'", actual, contains))
|
||||
}
|
||||
}
|
||||
|
||||
func fatal(t TestingT, msg string) {
|
||||
_, file, line, _ := runtime.Caller(2)
|
||||
t.Fatalf("%s:%d: %s", filepath.Base(file), line, msg)
|
||||
}
|
1
vendor/github.com/containers/storage/pkg/testutil/pkg.go
generated
vendored
Normal file
1
vendor/github.com/containers/storage/pkg/testutil/pkg.go
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
package testutil
|
Loading…
Add table
Add a link
Reference in a new issue