github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/image/fs_test.go (about)

     1  package image
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/rand"
     6  	"crypto/sha256"
     7  	"encoding/hex"
     8  	"errors"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  	"testing"
    13  
    14  	"github.com/docker/distribution/digest"
    15  )
    16  
    17  func TestFSGetSet(t *testing.T) {
    18  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
    19  	if err != nil {
    20  		t.Fatal(err)
    21  	}
    22  	defer os.RemoveAll(tmpdir)
    23  	fs, err := NewFSStoreBackend(tmpdir)
    24  	if err != nil {
    25  		t.Fatal(err)
    26  	}
    27  
    28  	testGetSet(t, fs)
    29  }
    30  
    31  func TestFSGetInvalidData(t *testing.T) {
    32  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  	defer os.RemoveAll(tmpdir)
    37  	fs, err := NewFSStoreBackend(tmpdir)
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  
    42  	id, err := fs.Set([]byte("foobar"))
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  
    47  	dgst := digest.Digest(id)
    48  
    49  	if err := ioutil.WriteFile(filepath.Join(tmpdir, contentDirName, string(dgst.Algorithm()), dgst.Hex()), []byte("foobar2"), 0600); err != nil {
    50  		t.Fatal(err)
    51  	}
    52  
    53  	_, err = fs.Get(id)
    54  	if err == nil {
    55  		t.Fatal("Expected get to fail after data modification.")
    56  	}
    57  }
    58  
    59  func TestFSInvalidSet(t *testing.T) {
    60  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  	defer os.RemoveAll(tmpdir)
    65  	fs, err := NewFSStoreBackend(tmpdir)
    66  	if err != nil {
    67  		t.Fatal(err)
    68  	}
    69  
    70  	id := digest.FromBytes([]byte("foobar"))
    71  	err = os.Mkdir(filepath.Join(tmpdir, contentDirName, string(id.Algorithm()), id.Hex()), 0700)
    72  	if err != nil {
    73  		t.Fatal(err)
    74  	}
    75  
    76  	_, err = fs.Set([]byte("foobar"))
    77  	if err == nil {
    78  		t.Fatal("Expecting error from invalid filesystem data.")
    79  	}
    80  }
    81  
    82  func TestFSInvalidRoot(t *testing.T) {
    83  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	}
    87  	defer os.RemoveAll(tmpdir)
    88  
    89  	tcases := []struct {
    90  		root, invalidFile string
    91  	}{
    92  		{"root", "root"},
    93  		{"root", "root/content"},
    94  		{"root", "root/metadata"},
    95  	}
    96  
    97  	for _, tc := range tcases {
    98  		root := filepath.Join(tmpdir, tc.root)
    99  		filePath := filepath.Join(tmpdir, tc.invalidFile)
   100  		err := os.MkdirAll(filepath.Dir(filePath), 0700)
   101  		if err != nil {
   102  			t.Fatal(err)
   103  		}
   104  		f, err := os.Create(filePath)
   105  		if err != nil {
   106  			t.Fatal(err)
   107  		}
   108  		f.Close()
   109  
   110  		_, err = NewFSStoreBackend(root)
   111  		if err == nil {
   112  			t.Fatalf("Expected error from root %q and invlid file %q", tc.root, tc.invalidFile)
   113  		}
   114  
   115  		os.RemoveAll(root)
   116  	}
   117  
   118  }
   119  
   120  func testMetadataGetSet(t *testing.T, store StoreBackend) {
   121  	id, err := store.Set([]byte("foo"))
   122  	if err != nil {
   123  		t.Fatal(err)
   124  	}
   125  	id2, err := store.Set([]byte("bar"))
   126  	if err != nil {
   127  		t.Fatal(err)
   128  	}
   129  
   130  	tcases := []struct {
   131  		id    ID
   132  		key   string
   133  		value []byte
   134  	}{
   135  		{id, "tkey", []byte("tval1")},
   136  		{id, "tkey2", []byte("tval2")},
   137  		{id2, "tkey", []byte("tval3")},
   138  	}
   139  
   140  	for _, tc := range tcases {
   141  		err = store.SetMetadata(tc.id, tc.key, tc.value)
   142  		if err != nil {
   143  			t.Fatal(err)
   144  		}
   145  
   146  		actual, err := store.GetMetadata(tc.id, tc.key)
   147  		if err != nil {
   148  			t.Fatal(err)
   149  		}
   150  		if bytes.Compare(actual, tc.value) != 0 {
   151  			t.Fatalf("Metadata expected %q, got %q", tc.value, actual)
   152  		}
   153  	}
   154  
   155  	_, err = store.GetMetadata(id2, "tkey2")
   156  	if err == nil {
   157  		t.Fatal("Expected error for getting metadata for unknown key")
   158  	}
   159  
   160  	id3 := digest.FromBytes([]byte("baz"))
   161  	err = store.SetMetadata(ID(id3), "tkey", []byte("tval"))
   162  	if err == nil {
   163  		t.Fatal("Expected error for setting metadata for unknown ID.")
   164  	}
   165  
   166  	_, err = store.GetMetadata(ID(id3), "tkey")
   167  	if err == nil {
   168  		t.Fatal("Expected error for getting metadata for unknown ID.")
   169  	}
   170  }
   171  
   172  func TestFSMetadataGetSet(t *testing.T) {
   173  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
   174  	if err != nil {
   175  		t.Fatal(err)
   176  	}
   177  	defer os.RemoveAll(tmpdir)
   178  	fs, err := NewFSStoreBackend(tmpdir)
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  
   183  	testMetadataGetSet(t, fs)
   184  }
   185  
   186  func TestFSDelete(t *testing.T) {
   187  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
   188  	if err != nil {
   189  		t.Fatal(err)
   190  	}
   191  	defer os.RemoveAll(tmpdir)
   192  	fs, err := NewFSStoreBackend(tmpdir)
   193  	if err != nil {
   194  		t.Fatal(err)
   195  	}
   196  
   197  	testDelete(t, fs)
   198  }
   199  
   200  func TestFSWalker(t *testing.T) {
   201  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
   202  	if err != nil {
   203  		t.Fatal(err)
   204  	}
   205  	defer os.RemoveAll(tmpdir)
   206  	fs, err := NewFSStoreBackend(tmpdir)
   207  	if err != nil {
   208  		t.Fatal(err)
   209  	}
   210  
   211  	testWalker(t, fs)
   212  }
   213  
   214  func TestFSInvalidWalker(t *testing.T) {
   215  	tmpdir, err := ioutil.TempDir("", "images-fs-store")
   216  	if err != nil {
   217  		t.Fatal(err)
   218  	}
   219  	defer os.RemoveAll(tmpdir)
   220  	fs, err := NewFSStoreBackend(tmpdir)
   221  	if err != nil {
   222  		t.Fatal(err)
   223  	}
   224  
   225  	fooID, err := fs.Set([]byte("foo"))
   226  	if err != nil {
   227  		t.Fatal(err)
   228  	}
   229  
   230  	if err := ioutil.WriteFile(filepath.Join(tmpdir, contentDirName, "sha256/foobar"), []byte("foobar"), 0600); err != nil {
   231  		t.Fatal(err)
   232  	}
   233  
   234  	n := 0
   235  	err = fs.Walk(func(id ID) error {
   236  		if id != fooID {
   237  			t.Fatalf("Invalid walker ID %q, expected %q", id, fooID)
   238  		}
   239  		n++
   240  		return nil
   241  	})
   242  	if err != nil {
   243  		t.Fatalf("Invalid data should not have caused walker error, got %v", err)
   244  	}
   245  	if n != 1 {
   246  		t.Fatalf("Expected 1 walk initialization, got %d", n)
   247  	}
   248  }
   249  
   250  func testGetSet(t *testing.T, store StoreBackend) {
   251  	type tcase struct {
   252  		input    []byte
   253  		expected ID
   254  	}
   255  	tcases := []tcase{
   256  		{[]byte("foobar"), ID("sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")},
   257  	}
   258  
   259  	randomInput := make([]byte, 8*1024)
   260  	_, err := rand.Read(randomInput)
   261  	if err != nil {
   262  		t.Fatal(err)
   263  	}
   264  	// skipping use of digest pkg because its used by the implementation
   265  	h := sha256.New()
   266  	_, err = h.Write(randomInput)
   267  	if err != nil {
   268  		t.Fatal(err)
   269  	}
   270  	tcases = append(tcases, tcase{
   271  		input:    randomInput,
   272  		expected: ID("sha256:" + hex.EncodeToString(h.Sum(nil))),
   273  	})
   274  
   275  	for _, tc := range tcases {
   276  		id, err := store.Set([]byte(tc.input))
   277  		if err != nil {
   278  			t.Fatal(err)
   279  		}
   280  		if id != tc.expected {
   281  			t.Fatalf("Expected ID %q, got %q", tc.expected, id)
   282  		}
   283  	}
   284  
   285  	for _, emptyData := range [][]byte{nil, {}} {
   286  		_, err := store.Set(emptyData)
   287  		if err == nil {
   288  			t.Fatal("Expected error for nil input.")
   289  		}
   290  	}
   291  
   292  	for _, tc := range tcases {
   293  		data, err := store.Get(tc.expected)
   294  		if err != nil {
   295  			t.Fatal(err)
   296  		}
   297  		if bytes.Compare(data, tc.input) != 0 {
   298  			t.Fatalf("Expected data %q, got %q", tc.input, data)
   299  		}
   300  	}
   301  
   302  	for _, key := range []ID{"foobar:abc", "sha256:abc", "sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2a"} {
   303  		_, err := store.Get(key)
   304  		if err == nil {
   305  			t.Fatalf("Expected error for ID %q.", key)
   306  		}
   307  	}
   308  
   309  }
   310  
   311  func testDelete(t *testing.T, store StoreBackend) {
   312  	id, err := store.Set([]byte("foo"))
   313  	if err != nil {
   314  		t.Fatal(err)
   315  	}
   316  	id2, err := store.Set([]byte("bar"))
   317  	if err != nil {
   318  		t.Fatal(err)
   319  	}
   320  
   321  	err = store.Delete(id)
   322  	if err != nil {
   323  		t.Fatal(err)
   324  	}
   325  
   326  	_, err = store.Get(id)
   327  	if err == nil {
   328  		t.Fatalf("Expected getting deleted item %q to fail", id)
   329  	}
   330  	_, err = store.Get(id2)
   331  	if err != nil {
   332  		t.Fatal(err)
   333  	}
   334  
   335  	err = store.Delete(id2)
   336  	if err != nil {
   337  		t.Fatal(err)
   338  	}
   339  	_, err = store.Get(id2)
   340  	if err == nil {
   341  		t.Fatalf("Expected getting deleted item %q to fail", id2)
   342  	}
   343  }
   344  
   345  func testWalker(t *testing.T, store StoreBackend) {
   346  	id, err := store.Set([]byte("foo"))
   347  	if err != nil {
   348  		t.Fatal(err)
   349  	}
   350  	id2, err := store.Set([]byte("bar"))
   351  	if err != nil {
   352  		t.Fatal(err)
   353  	}
   354  
   355  	tcases := make(map[ID]struct{})
   356  	tcases[id] = struct{}{}
   357  	tcases[id2] = struct{}{}
   358  	n := 0
   359  	err = store.Walk(func(id ID) error {
   360  		delete(tcases, id)
   361  		n++
   362  		return nil
   363  	})
   364  	if err != nil {
   365  		t.Fatal(err)
   366  	}
   367  
   368  	if n != 2 {
   369  		t.Fatalf("Expected 2 walk initializations, got %d", n)
   370  	}
   371  	if len(tcases) != 0 {
   372  		t.Fatalf("Expected empty unwalked set, got %+v", tcases)
   373  	}
   374  
   375  	// stop on error
   376  	tcases = make(map[ID]struct{})
   377  	tcases[id] = struct{}{}
   378  	err = store.Walk(func(id ID) error {
   379  		return errors.New("")
   380  	})
   381  	if err == nil {
   382  		t.Fatalf("Exected error from walker.")
   383  	}
   384  }