...

Source file src/github.com/containerd/continuity/fs/fstest/testsuite.go

Documentation: github.com/containerd/continuity/fs/fstest

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package fstest
    18  
    19  import (
    20  	"context"
    21  	"os"
    22  	"testing"
    23  )
    24  
    25  // TestApplier applies the test context
    26  type TestApplier interface {
    27  	TestContext(context.Context) (context.Context, func(), error)
    28  	Apply(context.Context, Applier) (string, func(), error)
    29  }
    30  
    31  // FSSuite runs the path test suite
    32  func FSSuite(t *testing.T, a TestApplier) {
    33  	t.Run("Basic", makeTest(t, a, basicTest))
    34  	t.Run("Deletion", makeTest(t, a, deletionTest))
    35  	t.Run("Update", makeTest(t, a, updateTest))
    36  	t.Run("DirectoryPermission", makeTest(t, a, directoryPermissionsTest))
    37  	t.Run("ParentDirectoryPermission", makeTest(t, a, parentDirectoryPermissionsTest))
    38  	t.Run("HardlinkUnmodified", makeTest(t, a, hardlinkUnmodified))
    39  	t.Run("HardlinkBeforeUnmodified", makeTest(t, a, hardlinkBeforeUnmodified))
    40  	t.Run("HardlinkBeforeModified", makeTest(t, a, hardlinkBeforeModified))
    41  }
    42  
    43  func makeTest(t *testing.T, ta TestApplier, as []Applier) func(t *testing.T) {
    44  	return func(t *testing.T) {
    45  		ctx, cleanup, err := ta.TestContext(context.Background())
    46  		if err != nil {
    47  			t.Fatalf("Unable to get test context: %+v", err)
    48  		}
    49  		defer cleanup()
    50  
    51  		applyDir, err := os.MkdirTemp("", "test-expected-")
    52  		if err != nil {
    53  			t.Fatalf("Unable to make temp directory: %+v", err)
    54  		}
    55  		defer os.RemoveAll(applyDir)
    56  
    57  		for i, a := range as {
    58  			testDir, c, err := ta.Apply(ctx, a)
    59  			if err != nil {
    60  				t.Fatalf("Apply failed at %d: %+v", i, err)
    61  			}
    62  			if err := a.Apply(applyDir); err != nil {
    63  				if c != nil {
    64  					c()
    65  				}
    66  				t.Fatalf("Error applying change to apply directory: %+v", err)
    67  			}
    68  
    69  			err = CheckDirectoryEqual(applyDir, testDir)
    70  			if c != nil {
    71  				c()
    72  			}
    73  			if err != nil {
    74  				t.Fatalf("Directories not equal at %d (expected <> tested): %+v", i, err)
    75  			}
    76  		}
    77  	}
    78  }
    79  
    80  var (
    81  	// baseApplier creates a basic filesystem layout
    82  	// with multiple types of files for basic tests.
    83  	baseApplier = Apply(
    84  		CreateDir("/etc/", 0o755),
    85  		CreateFile("/etc/hosts", []byte("127.0.0.1 localhost"), 0o644),
    86  		Link("/etc/hosts", "/etc/hosts.allow"),
    87  		CreateDir("/usr/local/lib", 0o755),
    88  		CreateFile("/usr/local/lib/libnothing.so", []byte{0x00, 0x00}, 0o755),
    89  		Symlink("libnothing.so", "/usr/local/lib/libnothing.so.2"),
    90  		CreateDir("/home", 0o755),
    91  		CreateDir("/home/derek", 0o700),
    92  		// TODO: CreateSocket: how should Sockets be handled in continuity?
    93  	)
    94  
    95  	// basicTest covers basic operations
    96  	basicTest = []Applier{
    97  		baseApplier,
    98  		Apply(
    99  			CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0o644),
   100  			CreateFile("/etc/fstab", []byte("/dev/sda1\t/\text4\tdefaults 1 1\n"), 0o600),
   101  			CreateFile("/etc/badfile", []byte(""), 0o666),
   102  			CreateFile("/home/derek/.zshrc", []byte("#ZSH is just better\n"), 0o640),
   103  		),
   104  		Apply(
   105  			Remove("/etc/badfile"),
   106  			Rename("/home/derek", "/home/notderek"),
   107  		),
   108  		Apply(
   109  			RemoveAll("/usr"),
   110  			Remove("/etc/hosts.allow"),
   111  		),
   112  		Apply(
   113  			RemoveAll("/home"),
   114  			CreateDir("/home/derek", 0o700),
   115  			CreateFile("/home/derek/.bashrc", []byte("#not going away\n"), 0o640),
   116  			Link("/etc/hosts", "/etc/hosts.allow"),
   117  		),
   118  	}
   119  
   120  	// deletionTest covers various deletion scenarios to ensure
   121  	// deletions are properly picked up and applied
   122  	deletionTest = []Applier{
   123  		Apply(
   124  			CreateDir("/test/somedir", 0o755),
   125  			CreateDir("/lib", 0o700),
   126  			CreateFile("/lib/hidden", []byte{}, 0o644),
   127  		),
   128  		Apply(
   129  			CreateFile("/test/a", []byte{}, 0o644),
   130  			CreateFile("/test/b", []byte{}, 0o644),
   131  			CreateDir("/test/otherdir", 0o755),
   132  			CreateFile("/test/otherdir/.empty", []byte{}, 0o644),
   133  			RemoveAll("/lib"),
   134  			CreateDir("/lib", 0o700),
   135  			CreateFile("/lib/not-hidden", []byte{}, 0o644),
   136  		),
   137  		Apply(
   138  			Remove("/test/a"),
   139  			Remove("/test/b"),
   140  			RemoveAll("/test/otherdir"),
   141  			CreateFile("/lib/newfile", []byte{}, 0o644),
   142  		),
   143  	}
   144  
   145  	// updateTest covers file updates for content and permission
   146  	updateTest = []Applier{
   147  		Apply(
   148  			CreateDir("/d1", 0o755),
   149  			CreateDir("/d2", 0o700),
   150  			CreateFile("/d1/f1", []byte("something..."), 0o644),
   151  			CreateFile("/d1/f2", []byte("else..."), 0o644),
   152  			CreateFile("/d1/f3", []byte("entirely..."), 0o644),
   153  		),
   154  		Apply(
   155  			CreateFile("/d1/f1", []byte("file content of a different length"), 0o664),
   156  			Remove("/d1/f3"),
   157  			CreateFile("/d1/f3", []byte("updated content"), 0o664),
   158  			Chmod("/d1/f2", 0o766),
   159  			Chmod("/d2", 0o777),
   160  		),
   161  	}
   162  
   163  	// directoryPermissionsTest covers directory permissions on update
   164  	directoryPermissionsTest = []Applier{
   165  		Apply(
   166  			CreateDir("/d1", 0o700),
   167  			CreateDir("/d2", 0o751),
   168  			CreateDir("/d3", 0o777),
   169  		),
   170  		Apply(
   171  			CreateFile("/d1/f", []byte("irrelevant"), 0o644),
   172  			CreateDir("/d1/d", 0o700),
   173  			CreateFile("/d1/d/f", []byte("irrelevant"), 0o644),
   174  			CreateFile("/d2/f", []byte("irrelevant"), 0o644),
   175  			CreateFile("/d3/f", []byte("irrelevant"), 0o644),
   176  		),
   177  	}
   178  
   179  	// parentDirectoryPermissionsTest covers directory permissions for updated
   180  	// files
   181  	parentDirectoryPermissionsTest = []Applier{
   182  		Apply(
   183  			CreateDir("/d1", 0o700),
   184  			CreateDir("/d1/a", 0o700),
   185  			CreateDir("/d1/a/b", 0o700),
   186  			CreateDir("/d1/a/b/c", 0o700),
   187  			CreateFile("/d1/a/b/f", []byte("content1"), 0o644),
   188  			CreateDir("/d2", 0o751),
   189  			CreateDir("/d2/a/b", 0o751),
   190  			CreateDir("/d2/a/b/c", 0o751),
   191  			CreateFile("/d2/a/b/f", []byte("content1"), 0o644),
   192  		),
   193  		Apply(
   194  			CreateFile("/d1/a/b/f", []byte("content1"), 0o644),
   195  			Chmod("/d1/a/b/c", 0o700),
   196  			CreateFile("/d2/a/b/f", []byte("content2"), 0o644),
   197  			Chmod("/d2/a/b/c", 0o751),
   198  		),
   199  	}
   200  
   201  	hardlinkUnmodified = []Applier{
   202  		baseApplier,
   203  		Apply(
   204  			CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0o644),
   205  		),
   206  		Apply(
   207  			Link("/etc/hosts", "/etc/hosts.deny"),
   208  		),
   209  	}
   210  
   211  	// Hardlink name before with modification
   212  	// Tests link is created for unmodified files when a new hard linked file is seen first
   213  	hardlinkBeforeUnmodified = []Applier{
   214  		baseApplier,
   215  		Apply(
   216  			CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0o644),
   217  		),
   218  		Apply(
   219  			Link("/etc/hosts", "/etc/before-hosts"),
   220  		),
   221  	}
   222  
   223  	// Hardlink name after without modification
   224  	// tests link is created for modified file with new hardlink
   225  	hardlinkBeforeModified = []Applier{
   226  		baseApplier,
   227  		Apply(
   228  			CreateFile("/etc/hosts", []byte("127.0.0.1 localhost.localdomain"), 0o644),
   229  		),
   230  		Apply(
   231  			Remove("/etc/hosts"),
   232  			CreateFile("/etc/hosts", []byte("127.0.0.1 localhost"), 0o644),
   233  			Link("/etc/hosts", "/etc/before-hosts"),
   234  		),
   235  	}
   236  )
   237  

View as plain text