containerd/fs/fstest/testsuite.go
Derek McGowan ba10e497b9
Emit unmodified change events for directories
When a file changes, emit events for the seen parent
directories to ensure that those parents are included
in change streams such as archives. The parents are
needed accurately recreate diff representation apart
from a parent (such as overlay and aufs graph drivers
in Docker).

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
2017-12-04 18:37:00 -08:00

221 lines
6.1 KiB
Go

package fstest
import (
"context"
"io/ioutil"
"os"
"testing"
)
// TestApplier applies the test context
type TestApplier interface {
TestContext(context.Context) (context.Context, func(), error)
Apply(context.Context, Applier) (string, func(), error)
}
// FSSuite runs the path test suite
func FSSuite(t *testing.T, a TestApplier) {
t.Run("Basic", makeTest(t, a, basicTest))
t.Run("Deletion", makeTest(t, a, deletionTest))
t.Run("Update", makeTest(t, a, updateTest))
t.Run("DirectoryPermission", makeTest(t, a, directoryPermissionsTest))
t.Run("ParentDirectoryPermission", makeTest(t, a, parentDirectoryPermissionsTest))
t.Run("HardlinkUnmodified", makeTest(t, a, hardlinkUnmodified))
t.Run("HardlinkBeforeUnmodified", makeTest(t, a, hardlinkBeforeUnmodified))
t.Run("HardlinkBeforeModified", makeTest(t, a, hardlinkBeforeModified))
}
func makeTest(t *testing.T, ta TestApplier, as []Applier) func(t *testing.T) {
return func(t *testing.T) {
ctx, cleanup, err := ta.TestContext(context.Background())
if err != nil {
t.Fatalf("Unable to get test context: %+v", err)
}
defer cleanup()
applyDir, err := ioutil.TempDir("", "test-expected-")
if err != nil {
t.Fatalf("Unable to make temp directory: %+v", err)
}
defer os.RemoveAll(applyDir)
for i, a := range as {
testDir, c, err := ta.Apply(ctx, a)
if err != nil {
t.Fatalf("Apply failed at %d: %+v", i, err)
}
if err := a.Apply(applyDir); err != nil {
if c != nil {
c()
}
t.Fatalf("Error applying change to apply directory: %+v", err)
}
err = CheckDirectoryEqual(applyDir, testDir)
if c != nil {
c()
}
if err != nil {
t.Fatalf("Directories not equal at %d (expected <> tested): %+v", i, err)
}
}
}
}
var (
// baseApplier creates a basic filesystem layout
// with multiple types of files for basic tests.
baseApplier = Apply(
CreateDir("/etc/", 0755),
CreateFile("/etc/hosts", []byte("127.0.0.1 localhost"), 0644),
Link("/etc/hosts", "/etc/hosts.allow"),
CreateDir("/usr/local/lib", 0755),
CreateFile("/usr/local/lib/libnothing.so", []byte{0x00, 0x00}, 0755),
Symlink("libnothing.so", "/usr/local/lib/libnothing.so.2"),
CreateDir("/home", 0755),
CreateDir("/home/derek", 0700),
)
// basicTest covers basic operations
basicTest = []Applier{
baseApplier,
Apply(
CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0644),
CreateFile("/etc/fstab", []byte("/dev/sda1\t/\text4\tdefaults 1 1\n"), 0600),
CreateFile("/etc/badfile", []byte(""), 0666),
CreateFile("/home/derek/.zshrc", []byte("#ZSH is just better\n"), 0640),
),
Apply(
Remove("/etc/badfile"),
Rename("/home/derek", "/home/notderek"),
),
Apply(
RemoveAll("/usr"),
Remove("/etc/hosts.allow"),
),
Apply(
RemoveAll("/home"),
CreateDir("/home/derek", 0700),
CreateFile("/home/derek/.bashrc", []byte("#not going away\n"), 0640),
Link("/etc/hosts", "/etc/hosts.allow"),
),
}
// deletionTest covers various deletion scenarios to ensure
// deletions are properly picked up and applied
deletionTest = []Applier{
Apply(
CreateDir("/test/somedir", 0755),
CreateDir("/lib", 0700),
CreateFile("/lib/hidden", []byte{}, 0644),
),
Apply(
CreateFile("/test/a", []byte{}, 0644),
CreateFile("/test/b", []byte{}, 0644),
CreateDir("/test/otherdir", 0755),
CreateFile("/test/otherdir/.empty", []byte{}, 0644),
RemoveAll("/lib"),
CreateDir("/lib", 0700),
CreateFile("/lib/not-hidden", []byte{}, 0644),
),
Apply(
Remove("/test/a"),
Remove("/test/b"),
RemoveAll("/test/otherdir"),
CreateFile("/lib/newfile", []byte{}, 0644),
),
}
// updateTest covers file updates for content and permission
updateTest = []Applier{
Apply(
CreateDir("/d1", 0755),
CreateDir("/d2", 0700),
CreateFile("/d1/f1", []byte("something..."), 0644),
CreateFile("/d1/f2", []byte("else..."), 0644),
CreateFile("/d1/f3", []byte("entirely..."), 0644),
),
Apply(
CreateFile("/d1/f1", []byte("file content of a different length"), 0664),
Remove("/d1/f3"),
CreateFile("/d1/f3", []byte("updated content"), 0664),
Chmod("/d1/f2", 0766),
Chmod("/d2", 0777),
),
}
// directoryPermissionsTest covers directory permissions on update
directoryPermissionsTest = []Applier{
Apply(
CreateDir("/d1", 0700),
CreateDir("/d2", 0751),
CreateDir("/d3", 0777),
),
Apply(
CreateFile("/d1/f", []byte("irrelevant"), 0644),
CreateDir("/d1/d", 0700),
CreateFile("/d1/d/f", []byte("irrelevant"), 0644),
CreateFile("/d2/f", []byte("irrelevant"), 0644),
CreateFile("/d3/f", []byte("irrelevant"), 0644),
),
}
// parentDirectoryPermissionsTest covers directory permissions for updated
// files
parentDirectoryPermissionsTest = []Applier{
Apply(
CreateDir("/d1", 0700),
CreateDir("/d1/a", 0700),
CreateDir("/d1/a/b", 0700),
CreateDir("/d1/a/b/c", 0700),
CreateFile("/d1/a/b/f", []byte("content1"), 0644),
CreateDir("/d2", 0751),
CreateDir("/d2/a/b", 0751),
CreateDir("/d2/a/b/c", 0751),
CreateFile("/d2/a/b/f", []byte("content1"), 0644),
),
Apply(
CreateFile("/d1/a/b/f", []byte("content1"), 0644),
Chmod("/d1/a/b/c", 0700),
CreateFile("/d2/a/b/f", []byte("content2"), 0644),
Chmod("/d2/a/b/c", 0751),
),
}
hardlinkUnmodified = []Applier{
baseApplier,
Apply(
CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0644),
),
Apply(
Link("/etc/hosts", "/etc/hosts.deny"),
),
}
// Hardlink name before with modification
// Tests link is created for unmodified files when new hardlinked file is seen first
hardlinkBeforeUnmodified = []Applier{
baseApplier,
Apply(
CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0644),
),
Apply(
Link("/etc/hosts", "/etc/before-hosts"),
),
}
// Hardlink name after without modification
// tests link is created for modified file with new hardlink
hardlinkBeforeModified = []Applier{
baseApplier,
Apply(
CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0644),
),
Apply(
Remove("/etc/hosts"),
CreateFile("/etc/hosts", []byte("127.0.0.1 localhost"), 0644),
Link("/etc/hosts", "/etc/before-hosts"),
),
}
)