github.com/coreos/rocket@v1.30.1-0.20200224141603-171c416fac02/store/treestore/tree_test.go (about)

     1  // Copyright 2015 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package treestore
    16  
    17  import (
    18  	"archive/tar"
    19  	"io/ioutil"
    20  	"os"
    21  	"path/filepath"
    22  	"testing"
    23  
    24  	"github.com/rkt/rkt/pkg/aci"
    25  	"github.com/rkt/rkt/pkg/aci/acitest"
    26  	"github.com/rkt/rkt/pkg/sys"
    27  	"github.com/rkt/rkt/store/imagestore"
    28  )
    29  
    30  const tstprefix = "treestore-test"
    31  
    32  // TODO(sgotti) when the TreeStore will use an interface, change it to a
    33  // test implementation without relying on store/imagestore
    34  func testStoreWriteACI(dir string, s *imagestore.Store) (string, error) {
    35  	imj, err := acitest.ImageManifestString(nil)
    36  	if err != nil {
    37  		return "", err
    38  	}
    39  
    40  	entries := []*aci.ACIEntry{
    41  		// An empty dir
    42  		{
    43  			Header: &tar.Header{
    44  				Name:     "rootfs/a",
    45  				Typeflag: tar.TypeDir,
    46  			},
    47  		},
    48  		{
    49  			Contents: "hello",
    50  			Header: &tar.Header{
    51  				Name: "hello.txt",
    52  				Size: 5,
    53  			},
    54  		},
    55  		{
    56  			Header: &tar.Header{
    57  				Name:     "rootfs/link.txt",
    58  				Linkname: "rootfs/hello.txt",
    59  				Typeflag: tar.TypeSymlink,
    60  			},
    61  		},
    62  		// dangling symlink
    63  		{
    64  			Header: &tar.Header{
    65  				Name:     "rootfs/link2.txt",
    66  				Linkname: "rootfs/missingfile.txt",
    67  				Typeflag: tar.TypeSymlink,
    68  			},
    69  		},
    70  		{
    71  			Header: &tar.Header{
    72  				Name:     "rootfs/fifo",
    73  				Typeflag: tar.TypeFifo,
    74  			},
    75  		},
    76  	}
    77  	aci, err := aci.NewACI(dir, imj, entries)
    78  	if err != nil {
    79  		return "", err
    80  	}
    81  	defer aci.Close()
    82  
    83  	// Rewind the ACI
    84  	if _, err := aci.Seek(0, 0); err != nil {
    85  		return "", err
    86  	}
    87  
    88  	// Import the new ACI
    89  	key, err := s.WriteACI(aci, imagestore.ACIFetchInfo{Latest: false})
    90  	if err != nil {
    91  		return "", err
    92  	}
    93  	return key, nil
    94  }
    95  
    96  func TestTreeStoreRender(t *testing.T) {
    97  	if !sys.HasChrootCapability() {
    98  		t.Skipf("chroot capability not available. Disabling test.")
    99  	}
   100  
   101  	dir, err := ioutil.TempDir("", tstprefix)
   102  	if err != nil {
   103  		t.Fatalf("error creating tempdir: %v", err)
   104  	}
   105  	defer os.RemoveAll(dir)
   106  
   107  	s, err := imagestore.NewStore(dir)
   108  	if err != nil {
   109  		t.Fatalf("unexpected error: %v", err)
   110  	}
   111  	ts, err := NewStore(dir, s)
   112  	if err != nil {
   113  		t.Fatalf("unexpected error: %v", err)
   114  	}
   115  
   116  	key, err := testStoreWriteACI(dir, s)
   117  	if err != nil {
   118  		t.Fatalf("unexpected error: %v", err)
   119  	}
   120  
   121  	id := "treestoreid01"
   122  
   123  	_, err = ts.render(id, key)
   124  	if err != nil {
   125  		t.Fatalf("unexpected error: %v", err)
   126  	}
   127  
   128  	// Verify image Hash. Should be the same.
   129  	_, err = ts.Check(id)
   130  	if err != nil {
   131  		t.Fatalf("unexpected error: %v", err)
   132  	}
   133  }
   134  
   135  func TestTreeStoreRemove(t *testing.T) {
   136  	if !sys.HasChrootCapability() {
   137  		t.Skipf("chroot capability not available. Disabling test.")
   138  	}
   139  
   140  	dir, err := ioutil.TempDir("", tstprefix)
   141  	if err != nil {
   142  		t.Fatalf("error creating tempdir: %v", err)
   143  	}
   144  	defer os.RemoveAll(dir)
   145  
   146  	s, err := imagestore.NewStore(dir)
   147  	if err != nil {
   148  		t.Fatalf("unexpected error: %v", err)
   149  	}
   150  	ts, err := NewStore(dir, s)
   151  	if err != nil {
   152  		t.Fatalf("unexpected error: %v", err)
   153  	}
   154  
   155  	key, err := testStoreWriteACI(dir, s)
   156  	if err != nil {
   157  		t.Fatalf("unexpected error: %v", err)
   158  	}
   159  
   160  	id := "treestoreid01"
   161  
   162  	// Test non existent dir
   163  	err = ts.remove(id)
   164  	if err != nil {
   165  		t.Fatalf("unexpected error: %v", err)
   166  	}
   167  
   168  	// Test rendered tree
   169  	_, err = ts.render(id, key)
   170  	if err != nil {
   171  		t.Fatalf("unexpected error: %v", err)
   172  	}
   173  
   174  	err = ts.remove(id)
   175  	if err != nil {
   176  		t.Fatalf("unexpected error: %v", err)
   177  	}
   178  }
   179  
   180  func TestTreeStore(t *testing.T) {
   181  	if !sys.HasChrootCapability() {
   182  		t.Skipf("chroot capability not available. Disabling test.")
   183  	}
   184  
   185  	dir, err := ioutil.TempDir("", tstprefix)
   186  	if err != nil {
   187  		t.Fatalf("error creating tempdir: %v", err)
   188  	}
   189  	defer os.RemoveAll(dir)
   190  
   191  	s, err := imagestore.NewStore(dir)
   192  	if err != nil {
   193  		t.Fatalf("unexpected error: %v", err)
   194  	}
   195  	ts, err := NewStore(dir, s)
   196  	if err != nil {
   197  		t.Fatalf("unexpected error: %v", err)
   198  	}
   199  
   200  	imj, err := acitest.ImageManifestString(nil)
   201  	if err != nil {
   202  		t.Fatalf("unexpected error: %v", err)
   203  	}
   204  
   205  	entries := []*aci.ACIEntry{
   206  		// An empty dir
   207  		{
   208  			Header: &tar.Header{
   209  				Name:     "rootfs/a",
   210  				Typeflag: tar.TypeDir,
   211  			},
   212  		},
   213  		{
   214  			Contents: "hello",
   215  			Header: &tar.Header{
   216  				Name: "hello.txt",
   217  				Size: 5,
   218  			},
   219  		},
   220  		{
   221  			Header: &tar.Header{
   222  				Name:     "rootfs/link.txt",
   223  				Linkname: "rootfs/hello.txt",
   224  				Typeflag: tar.TypeSymlink,
   225  			},
   226  		},
   227  		// dangling symlink
   228  		{
   229  			Header: &tar.Header{
   230  				Name:     "rootfs/link2.txt",
   231  				Linkname: "rootfs/missingfile.txt",
   232  				Typeflag: tar.TypeSymlink,
   233  			},
   234  		},
   235  		{
   236  			Header: &tar.Header{
   237  				Name:     "rootfs/fifo",
   238  				Typeflag: tar.TypeFifo,
   239  			},
   240  		},
   241  	}
   242  	aci, err := aci.NewACI(dir, imj, entries)
   243  	if err != nil {
   244  		t.Fatalf("error creating test tar: %v", err)
   245  	}
   246  	defer aci.Close()
   247  
   248  	// Rewind the ACI
   249  	if _, err := aci.Seek(0, 0); err != nil {
   250  		t.Fatalf("unexpected error: %v", err)
   251  	}
   252  
   253  	// Import the new ACI
   254  	key, err := s.WriteACI(aci, imagestore.ACIFetchInfo{Latest: false})
   255  	if err != nil {
   256  		t.Fatalf("unexpected error: %v", err)
   257  	}
   258  
   259  	// Ask the store to render the treestore
   260  	id, _, err := ts.Render(key, false)
   261  	if err != nil {
   262  		t.Fatalf("unexpected error: %v", err)
   263  	}
   264  
   265  	// Verify image Hash. Should be the same.
   266  	_, err = ts.Check(id)
   267  	if err != nil {
   268  		t.Fatalf("unexpected error: %v", err)
   269  	}
   270  
   271  	// Change a file permission
   272  	rootfs := ts.GetRootFS(id)
   273  	err = os.Chmod(filepath.Join(rootfs, "a"), 0600)
   274  	if err != nil {
   275  		t.Fatalf("unexpected error: %v", err)
   276  	}
   277  
   278  	// Verify image Hash. Should be different
   279  	_, err = ts.Check(id)
   280  	if err == nil {
   281  		t.Errorf("expected non-nil error!")
   282  	}
   283  
   284  	// rebuild the tree
   285  	prevID := id
   286  	id, _, err = ts.Render(key, true)
   287  	if err != nil {
   288  		t.Fatalf("unexpected error: %v", err)
   289  	}
   290  
   291  	if id != prevID {
   292  		t.Fatalf("unexpected different IDs. prevID: %s, id: %s", prevID, id)
   293  	}
   294  
   295  	// Add a file
   296  	rootfs = ts.GetRootFS(id)
   297  	err = ioutil.WriteFile(filepath.Join(rootfs, "newfile"), []byte("newfile"), 0644)
   298  	if err != nil {
   299  		t.Fatalf("unexpected error: %v", err)
   300  	}
   301  
   302  	// Verify image Hash. Should be different
   303  	_, err = ts.Check(id)
   304  	if err == nil {
   305  		t.Errorf("expected non-nil error!")
   306  	}
   307  }