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 }