238 lines
6.7 KiB
Go
238 lines
6.7 KiB
Go
/*
|
|
Copyright The containerd Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
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),
|
|
CreateDir("/var/run/socket", 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"),
|
|
),
|
|
}
|
|
)
|