github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/store/imagestore/store_test.go (about)

     1  // Copyright 2014 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 imagestore
    16  
    17  import (
    18  	"bytes"
    19  	"database/sql"
    20  	"encoding/hex"
    21  	"io/ioutil"
    22  	"os"
    23  	"path/filepath"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/rkt/rkt/pkg/aci"
    28  	"github.com/rkt/rkt/pkg/aci/acitest"
    29  	"github.com/rkt/rkt/pkg/multicall"
    30  
    31  	"github.com/appc/spec/schema/types"
    32  )
    33  
    34  const tstprefix = "store-test"
    35  
    36  func init() {
    37  	multicall.MaybeExec()
    38  }
    39  
    40  func TestBlobStore(t *testing.T) {
    41  	dir, err := ioutil.TempDir("", tstprefix)
    42  	if err != nil {
    43  		t.Fatalf("error creating tempdir: %v", err)
    44  	}
    45  	defer os.RemoveAll(dir)
    46  	s, err := NewStore(dir)
    47  	if err != nil {
    48  		t.Fatalf("Unexpected error: %v", err)
    49  	}
    50  	defer s.Close()
    51  	for _, valueStr := range []string{
    52  		"I am a manually placed object",
    53  	} {
    54  		s.stores[blobType].Write(types.NewHashSHA512([]byte(valueStr)).String(), []byte(valueStr))
    55  	}
    56  
    57  	s.Dump(false)
    58  }
    59  
    60  func TestResolveKey(t *testing.T) {
    61  	dir, err := ioutil.TempDir("", tstprefix)
    62  	if err != nil {
    63  		t.Fatalf("error creating tempdir: %v", err)
    64  	}
    65  	defer os.RemoveAll(dir)
    66  	s, err := NewStore(dir)
    67  	if err != nil {
    68  		t.Fatalf("Unexpected error: %v", err)
    69  	}
    70  	defer s.Close()
    71  
    72  	// Return a hash key buffer from a hex string
    73  	str2key := func(s string) *bytes.Buffer {
    74  		k, _ := hex.DecodeString(s)
    75  		return bytes.NewBufferString(keyToString(k))
    76  	}
    77  
    78  	// Set up store (use key == data for simplicity)
    79  	data := []*bytes.Buffer{
    80  		str2key("12345678900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
    81  		str2key("abcdefabc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
    82  		str2key("abcabcabc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
    83  		str2key("abc01234500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
    84  		str2key("67147019a5b56f5e2ee01e989a8aa4787f56b8445960be2d8678391cf111009bc0780f31001fd181a2b61507547aee4caa44cda4b8bdb238d0e4ba830069ed2c"),
    85  	}
    86  	for _, d := range data {
    87  		// Save aciinfo
    88  		err := s.db.Do(func(tx *sql.Tx) error {
    89  			aciinfo := &ACIInfo{
    90  				BlobKey:    d.String(),
    91  				Name:       "example.com/app",
    92  				ImportTime: time.Now(),
    93  			}
    94  			return WriteACIInfo(tx, aciinfo)
    95  		})
    96  		if err != nil {
    97  			t.Fatalf("error writing to store: %v", err)
    98  		}
    99  	}
   100  
   101  	// Full key already - should return short version of the full key
   102  	fkl := "sha512-67147019a5b56f5e2ee01e989a8aa4787f56b8445960be2d8678391cf111009bc0780f31001fd181a2b61507547aee4caa44cda4b8bdb238d0e4ba830069ed2c"
   103  	fks := "sha512-67147019a5b56f5e2ee01e989a8aa4787f56b8445960be2d8678391cf111009b"
   104  	for _, k := range []string{fkl, fks} {
   105  		key, err := s.ResolveKey(k)
   106  		if key != fks {
   107  			t.Errorf("expected ResolveKey to return unaltered short key, but got %q", key)
   108  		}
   109  		if err != nil {
   110  			t.Errorf("expected err=nil, got %v", err)
   111  		}
   112  	}
   113  
   114  	// Unambiguous prefix match
   115  	k, err := s.ResolveKey("sha512-123")
   116  	if k != "sha512-1234567890000000000000000000000000000000000000000000000000000000" {
   117  		t.Errorf("expected %q, got %q", "sha512-1234567890000000000000000000000000000000000000000000000000000000", k)
   118  	}
   119  	if err != nil {
   120  		t.Errorf("expected err=nil, got %v", err)
   121  	}
   122  
   123  	// Ambiguous prefix match
   124  	k, err = s.ResolveKey("sha512-abc")
   125  	if k != "" {
   126  		t.Errorf("expected %q, got %q", "", k)
   127  	}
   128  	if err == nil {
   129  		t.Errorf("expected non-nil error!")
   130  	}
   131  
   132  	// wrong key prefix
   133  	k, err = s.ResolveKey("badprefix-1")
   134  	expectedErr := "wrong key prefix"
   135  	if err == nil {
   136  		t.Errorf("expected non-nil error!")
   137  	}
   138  	if err.Error() != expectedErr {
   139  		t.Errorf("expected err=%q, got %q", expectedErr, err)
   140  	}
   141  
   142  	// image ID too short
   143  	k, err = s.ResolveKey("sha512-1")
   144  	expectedErr = "image ID too short"
   145  	if err == nil {
   146  		t.Errorf("expected non-nil error!")
   147  	}
   148  	if err.Error() != expectedErr {
   149  		t.Errorf("expected err=%q, got %q", expectedErr, err)
   150  	}
   151  }
   152  
   153  func TestGetImageManifest(t *testing.T) {
   154  	dir, err := ioutil.TempDir("", tstprefix)
   155  	if err != nil {
   156  		t.Fatalf("error creating tempdir: %v", err)
   157  	}
   158  	defer os.RemoveAll(dir)
   159  	s, err := NewStore(dir)
   160  	if err != nil {
   161  		t.Fatalf("Unexpected error: %v", err)
   162  	}
   163  	defer s.Close()
   164  
   165  	imj, err := acitest.ImageManifestString(nil)
   166  	if err != nil {
   167  		t.Fatalf("unexpected error: %v", err)
   168  	}
   169  
   170  	aci, err := aci.NewACI(dir, imj, nil)
   171  	if err != nil {
   172  		t.Fatalf("error creating test tar: %v", err)
   173  	}
   174  	// Rewind the ACI
   175  	if _, err := aci.Seek(0, 0); err != nil {
   176  		t.Fatalf("unexpected error %v", err)
   177  	}
   178  	key, err := s.WriteACI(aci, ACIFetchInfo{Latest: false})
   179  	if err != nil {
   180  		t.Fatalf("unexpected error: %v", err)
   181  	}
   182  
   183  	wanted := "example.com/test01"
   184  	im, err := s.GetImageManifest(key)
   185  	if err != nil {
   186  		t.Fatalf("unexpected error: %v", err)
   187  	}
   188  	if im.Name.String() != wanted {
   189  		t.Errorf("expected im with name: %s, got: %s", wanted, im.Name.String())
   190  	}
   191  
   192  	// test nonexistent key
   193  	im, err = s.GetImageManifest("sha512-aaaaaaaaaaaaaaaaa")
   194  	if err == nil {
   195  		t.Fatalf("expected non-nil error!")
   196  	}
   197  }
   198  
   199  func TestGetAci(t *testing.T) {
   200  	type test struct {
   201  		name     types.ACIdentifier
   202  		labels   types.Labels
   203  		expected int // the aci index to expect or -1 if not result expected,
   204  	}
   205  
   206  	type acidef struct {
   207  		imj    string
   208  		latest bool
   209  	}
   210  
   211  	dir, err := ioutil.TempDir("", tstprefix)
   212  	if err != nil {
   213  		t.Fatalf("error creating tempdir: %v", err)
   214  	}
   215  	defer os.RemoveAll(dir)
   216  	s, err := NewStore(dir)
   217  	if err != nil {
   218  		t.Fatalf("unexpected error %v", err)
   219  	}
   220  	defer s.Close()
   221  
   222  	tests := []struct {
   223  		acidefs []acidef
   224  		tests   []test
   225  	}{
   226  		{
   227  			[]acidef{
   228  				{
   229  					`{
   230  						"acKind": "ImageManifest",
   231  						"acVersion": "0.8.11",
   232  						"name": "example.com/test01"
   233  					}`,
   234  					false,
   235  				},
   236  				{
   237  					`{
   238  						"acKind": "ImageManifest",
   239  						"acVersion": "0.8.11",
   240  						"name": "example.com/test02",
   241  						"labels": [
   242  							{
   243  								"name": "version",
   244  								"value": "1.0.0"
   245  							}
   246  						]
   247  					}`,
   248  					true,
   249  				},
   250  				{
   251  					`{
   252  						"acKind": "ImageManifest",
   253  						"acVersion": "0.8.11",
   254  						"name": "example.com/test02",
   255  						"labels": [
   256  							{
   257  								"name": "version",
   258  								"value": "2.0.0"
   259  							}
   260  						]
   261  					}`,
   262  					false,
   263  				},
   264  			},
   265  			[]test{
   266  				{
   267  					"example.com/nonexistentaci",
   268  					types.Labels{},
   269  					-1,
   270  				},
   271  				{
   272  					"example.com/test01",
   273  					types.Labels{},
   274  					0,
   275  				},
   276  				{
   277  					"example.com/test02",
   278  					// Workaround for https://github.com/golang/go/issues/6820 :
   279  					// `go vet` does not correctly detect types.Labels as a container
   280  					[]types.Label{
   281  						{
   282  							Name:  "version",
   283  							Value: "1.0.0",
   284  						},
   285  					},
   286  					1,
   287  				},
   288  				{
   289  					"example.com/test02",
   290  					[]types.Label{
   291  						{
   292  							Name:  "version",
   293  							Value: "2.0.0",
   294  						},
   295  					},
   296  					2,
   297  				},
   298  				{
   299  					"example.com/test02",
   300  					types.Labels{},
   301  					1,
   302  				},
   303  			},
   304  		},
   305  	}
   306  
   307  	for _, tt := range tests {
   308  		var keys []string
   309  		// Create ACIs
   310  		for _, ad := range tt.acidefs {
   311  			aci, err := aci.NewACI(dir, ad.imj, nil)
   312  			if err != nil {
   313  				t.Fatalf("error creating test tar: %v", err)
   314  			}
   315  
   316  			// Rewind the ACI
   317  			if _, err := aci.Seek(0, 0); err != nil {
   318  				t.Fatalf("unexpected error %v", err)
   319  			}
   320  
   321  			key, err := s.WriteACI(aci, ACIFetchInfo{Latest: ad.latest})
   322  			if err != nil {
   323  				t.Fatalf("unexpected error: %v", err)
   324  			}
   325  			keys = append(keys, key)
   326  		}
   327  
   328  		for _, test := range tt.tests {
   329  			key, err := s.GetACI(test.name, test.labels)
   330  			if test.expected == -1 {
   331  				if err == nil {
   332  					t.Fatalf("Expected no key for name %s, got %s", test.name, key)
   333  				}
   334  
   335  			} else {
   336  				if err != nil {
   337  					t.Fatalf("unexpected error on GetACI for name %s, labels: %v: %v", test.name, test.labels, err)
   338  				}
   339  				if keys[test.expected] != key {
   340  					t.Errorf("expected key: %s, got %s. GetACI with name: %s, labels: %v", key, keys[test.expected], test.name, test.labels)
   341  				}
   342  			}
   343  		}
   344  	}
   345  }
   346  
   347  func TestRemoveACI(t *testing.T) {
   348  	dir, err := ioutil.TempDir("", tstprefix)
   349  	if err != nil {
   350  		t.Fatalf("error creating tempdir: %v", err)
   351  	}
   352  	defer os.RemoveAll(dir)
   353  	s, err := NewStore(dir)
   354  	if err != nil {
   355  		t.Fatalf("Unexpected error: %v", err)
   356  	}
   357  	defer s.Close()
   358  
   359  	imj, err := acitest.ImageManifestString(nil)
   360  	if err != nil {
   361  		t.Fatalf("unexpected error: %v", err)
   362  	}
   363  
   364  	aciFile, err := aci.NewACI(dir, imj, nil)
   365  	if err != nil {
   366  		t.Fatalf("error creating test tar: %v", err)
   367  	}
   368  	// Rewind the ACI
   369  	if _, err := aciFile.Seek(0, 0); err != nil {
   370  		t.Fatalf("unexpected error %v", err)
   371  	}
   372  	key, err := s.WriteACI(aciFile, ACIFetchInfo{Latest: false})
   373  	if err != nil {
   374  		t.Fatalf("unexpected error: %v", err)
   375  	}
   376  	aciURL := "http://example.com/test01.aci"
   377  	// Create our first Remote, and simulate Store() to create row in the table
   378  	na := NewRemote(aciURL, "")
   379  	na.BlobKey = key
   380  	s.WriteRemote(na)
   381  
   382  	err = s.RemoveACI(key)
   383  	if err != nil {
   384  		t.Fatalf("unexpected error: %v", err)
   385  	}
   386  
   387  	// Verify that no remote for the specified key exists
   388  	_, err = s.GetRemote(aciURL)
   389  	if err != ErrRemoteNotFound {
   390  		t.Fatalf("unexpected error: %v", err)
   391  	}
   392  
   393  	// Try to remove a non-existent key
   394  	err = s.RemoveACI("sha512-aaaaaaaaaaaaaaaaa")
   395  	if err == nil {
   396  		t.Fatalf("expected error")
   397  	}
   398  
   399  	aciFile, err = aci.NewACI(dir, imj, nil)
   400  	if err != nil {
   401  		t.Fatalf("error creating test tar: %v", err)
   402  	}
   403  	// Rewind the ACI
   404  	if _, err := aciFile.Seek(0, 0); err != nil {
   405  		t.Fatalf("unexpected error %v", err)
   406  	}
   407  	key, err = s.WriteACI(aciFile, ACIFetchInfo{Latest: false})
   408  	if err != nil {
   409  		t.Fatalf("unexpected error: %v", err)
   410  	}
   411  	aciURL = "http://example.com/test02.aci"
   412  	// Create our first Remote, and simulate Store() to create row in the table
   413  	na = NewRemote(aciURL, "")
   414  	na.BlobKey = key
   415  	s.WriteRemote(na)
   416  
   417  	err = os.Remove(filepath.Join(dir, "blob", blockTransform(key)[0], blockTransform(key)[1], key))
   418  	if err != nil {
   419  		t.Fatalf("unexpected error: %v", err)
   420  	}
   421  
   422  	err = s.RemoveACI(key)
   423  	if err == nil {
   424  		t.Fatalf("expected error: %v", err)
   425  	}
   426  	if _, ok := err.(*StoreRemovalError); !ok {
   427  		t.Fatalf("expected StoreRemovalError got: %v", err)
   428  	}
   429  }