github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/state/cloudimagemetadata/image_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package cloudimagemetadata_test 5 6 import ( 7 "regexp" 8 9 "github.com/juju/errors" 10 "github.com/juju/testing" 11 jc "github.com/juju/testing/checkers" 12 "github.com/juju/txn" 13 txntesting "github.com/juju/txn/testing" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/mgo.v2" 16 17 "github.com/juju/juju/mongo" 18 "github.com/juju/juju/state/cloudimagemetadata" 19 ) 20 21 type cloudImageMetadataSuite struct { 22 testing.IsolatedMgoSuite 23 24 access *TestMongo 25 storage cloudimagemetadata.Storage 26 } 27 28 var _ = gc.Suite(&cloudImageMetadataSuite{}) 29 30 const ( 31 envName = "test-model" 32 collectionName = "test-collection" 33 ) 34 35 func (s *cloudImageMetadataSuite) SetUpTest(c *gc.C) { 36 s.IsolatedMgoSuite.SetUpTest(c) 37 38 db := s.MgoSuite.Session.DB("juju") 39 40 s.access = NewTestMongo(db) 41 s.storage = cloudimagemetadata.NewStorage(envName, collectionName, s.access) 42 } 43 44 func (s *cloudImageMetadataSuite) TestSaveMetadata(c *gc.C) { 45 attrs1 := cloudimagemetadata.MetadataAttributes{ 46 Stream: "stream", 47 Region: "region-test", 48 Version: "14.04", 49 Series: "trusty", 50 Arch: "arch", 51 VirtType: "virtType-test", 52 RootStorageType: "rootStorageType-test", 53 } 54 attrs2 := cloudimagemetadata.MetadataAttributes{ 55 Stream: "chalk", 56 Region: "nether", 57 Version: "12.04", 58 Series: "precise", 59 Arch: "amd64", 60 } 61 added := []cloudimagemetadata.Metadata{ 62 {attrs1, 0, "1"}, 63 {attrs2, 0, "2"}, 64 } 65 s.assertRecordMetadata(c, added[0]) 66 s.assertRecordMetadata(c, added[1]) 67 s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{}, added...) 68 } 69 70 func (s *cloudImageMetadataSuite) TestFindMetadataNotFound(c *gc.C) { 71 s.assertNoMetadata(c) 72 73 // insert something... 74 attrs := cloudimagemetadata.MetadataAttributes{ 75 Stream: "stream", 76 Region: "region", 77 Version: "14.04", 78 Series: "trusty", 79 Arch: "arch", 80 VirtType: "virtType", 81 RootStorageType: "rootStorageType"} 82 m := cloudimagemetadata.Metadata{attrs, 0, "1"} 83 s.assertRecordMetadata(c, m) 84 85 // ...but look for something else. 86 none, err := s.storage.FindMetadata(cloudimagemetadata.MetadataFilter{ 87 Stream: "something else", 88 }) 89 // Make sure that we are explicit that we could not find what we wanted. 90 c.Assert(err, jc.Satisfies, errors.IsNotFound) 91 c.Assert(err, gc.ErrorMatches, "matching cloud image metadata not found") 92 c.Assert(none, gc.HasLen, 0) 93 } 94 95 func buildAttributesFilter(attrs cloudimagemetadata.MetadataAttributes) cloudimagemetadata.MetadataFilter { 96 filter := cloudimagemetadata.MetadataFilter{ 97 Stream: attrs.Stream, 98 Region: attrs.Region, 99 VirtType: attrs.VirtType, 100 RootStorageType: attrs.RootStorageType} 101 if attrs.Series != "" { 102 filter.Series = []string{attrs.Series} 103 } 104 if attrs.Arch != "" { 105 filter.Arches = []string{attrs.Arch} 106 } 107 return filter 108 } 109 110 func (s *cloudImageMetadataSuite) TestFindMetadata(c *gc.C) { 111 attrs := cloudimagemetadata.MetadataAttributes{ 112 Stream: "stream", 113 Region: "region", 114 Version: "14.04", 115 Series: "trusty", 116 Arch: "arch", 117 VirtType: "virtType", 118 RootStorageType: "rootStorageType"} 119 120 m := cloudimagemetadata.Metadata{attrs, 0, "1"} 121 122 _, err := s.storage.FindMetadata(buildAttributesFilter(attrs)) 123 c.Assert(err, jc.Satisfies, errors.IsNotFound) 124 125 s.assertRecordMetadata(c, m) 126 expected := []cloudimagemetadata.Metadata{m} 127 s.assertMetadataRecorded(c, attrs, expected...) 128 129 attrs.Stream = "another_stream" 130 m = cloudimagemetadata.Metadata{attrs, 0, "2"} 131 s.assertRecordMetadata(c, m) 132 133 expected = append(expected, m) 134 // Should find both 135 s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{Region: "region"}, expected...) 136 } 137 138 func (s *cloudImageMetadataSuite) TestSaveMetadataUpdateSameAttrsAndImages(c *gc.C) { 139 attrs := cloudimagemetadata.MetadataAttributes{ 140 Stream: "stream", 141 Version: "14.04", 142 Series: "trusty", 143 Arch: "arch", 144 } 145 metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1"} 146 metadata1 := cloudimagemetadata.Metadata{attrs, 0, "1"} 147 148 s.assertRecordMetadata(c, metadata0) 149 s.assertRecordMetadata(c, metadata1) 150 s.assertMetadataRecorded(c, attrs, metadata1) 151 } 152 153 func (s *cloudImageMetadataSuite) TestSaveMetadataUpdateSameAttrsDiffImages(c *gc.C) { 154 attrs := cloudimagemetadata.MetadataAttributes{ 155 Stream: "stream", 156 Version: "14.04", 157 Series: "trusty", 158 Arch: "arch", 159 } 160 metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1"} 161 metadata1 := cloudimagemetadata.Metadata{attrs, 0, "12"} 162 163 s.assertRecordMetadata(c, metadata0) 164 s.assertMetadataRecorded(c, attrs, metadata0) 165 s.assertRecordMetadata(c, metadata1) 166 s.assertMetadataRecorded(c, attrs, metadata1) 167 s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{}, metadata1) 168 } 169 170 func (s *cloudImageMetadataSuite) TestSaveDiffMetadataConcurrentlyAndOrderByDateCreated(c *gc.C) { 171 attrs := cloudimagemetadata.MetadataAttributes{ 172 Stream: "stream", 173 Version: "14.04", 174 Series: "trusty", 175 Arch: "arch", 176 } 177 metadata0 := cloudimagemetadata.Metadata{attrs, 0, "0"} 178 metadata1 := cloudimagemetadata.Metadata{attrs, 0, "1"} 179 metadata1.Stream = "scream" 180 181 s.assertConcurrentSave(c, 182 metadata0, // add this one 183 metadata1, // add this one 184 // last added should be first as order is by date created 185 metadata1, // verify it's in the list 186 metadata0, // verify it's in the list 187 ) 188 } 189 190 func (s *cloudImageMetadataSuite) TestSaveSameMetadataDiffImageConcurrently(c *gc.C) { 191 attrs := cloudimagemetadata.MetadataAttributes{ 192 Stream: "stream", 193 Version: "14.04", 194 Series: "trusty", 195 Arch: "arch", 196 } 197 metadata0 := cloudimagemetadata.Metadata{attrs, 0, "0"} 198 metadata1 := cloudimagemetadata.Metadata{attrs, 0, "1"} 199 200 s.assertConcurrentSave(c, 201 metadata0, // add this one 202 metadata1, // overwrite it with this one 203 metadata1, // verify only the last one is in the list 204 ) 205 } 206 207 func (s *cloudImageMetadataSuite) TestSaveSameMetadataSameImageConcurrently(c *gc.C) { 208 attrs := cloudimagemetadata.MetadataAttributes{ 209 Stream: "stream", 210 Version: "14.04", 211 Series: "trusty", 212 Arch: "arch", 213 } 214 metadata0 := cloudimagemetadata.Metadata{attrs, 0, "0"} 215 216 s.assertConcurrentSave(c, 217 metadata0, // add this one 218 metadata0, // add it again 219 metadata0, // varify only one is in the list 220 ) 221 } 222 223 func (s *cloudImageMetadataSuite) TestSaveSameMetadataSameImageDiffSourceConcurrently(c *gc.C) { 224 attrs := cloudimagemetadata.MetadataAttributes{ 225 Stream: "stream", 226 Version: "14.04", 227 Series: "trusty", 228 Arch: "arch", 229 Source: "public", 230 } 231 metadata0 := cloudimagemetadata.Metadata{attrs, 0, "0"} 232 233 attrs.Source = "custom" 234 metadata1 := cloudimagemetadata.Metadata{attrs, 0, "0"} 235 236 s.assertConcurrentSave(c, 237 metadata0, 238 metadata1, 239 metadata0, 240 metadata1, 241 ) 242 } 243 244 func (s *cloudImageMetadataSuite) TestSaveMetadataNoVersionPassed(c *gc.C) { 245 attrs := cloudimagemetadata.MetadataAttributes{ 246 Stream: "stream", 247 Series: "trusty", 248 Arch: "arch", 249 } 250 metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1"} 251 s.assertRecordMetadata(c, metadata0) 252 } 253 254 func (s *cloudImageMetadataSuite) TestSaveMetadataNoSeriesPassed(c *gc.C) { 255 attrs := cloudimagemetadata.MetadataAttributes{ 256 Stream: "stream", 257 Arch: "arch", 258 } 259 metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1"} 260 err := s.storage.SaveMetadata([]cloudimagemetadata.Metadata{metadata0}) 261 c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`missing series: metadata for image 1 not valid`)) 262 } 263 264 func (s *cloudImageMetadataSuite) TestSaveMetadataUnsupportedSeriesPassed(c *gc.C) { 265 attrs := cloudimagemetadata.MetadataAttributes{ 266 Stream: "stream", 267 Series: "blah", 268 Arch: "arch", 269 } 270 metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1"} 271 err := s.storage.SaveMetadata([]cloudimagemetadata.Metadata{metadata0}) 272 c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`unknown version for series: "blah"`)) 273 } 274 275 func (s *cloudImageMetadataSuite) assertConcurrentSave(c *gc.C, metadata0, metadata1 cloudimagemetadata.Metadata, expected ...cloudimagemetadata.Metadata) { 276 addMetadata := func() { 277 s.assertRecordMetadata(c, metadata0) 278 } 279 defer txntesting.SetBeforeHooks(c, s.access.runner, addMetadata).Check() 280 s.assertRecordMetadata(c, metadata1) 281 s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{}, expected...) 282 } 283 284 func (s *cloudImageMetadataSuite) assertRecordMetadata(c *gc.C, m cloudimagemetadata.Metadata) { 285 err := s.storage.SaveMetadata([]cloudimagemetadata.Metadata{m}) 286 c.Assert(err, jc.ErrorIsNil) 287 } 288 289 func (s *cloudImageMetadataSuite) assertMetadataRecorded(c *gc.C, criteria cloudimagemetadata.MetadataAttributes, expected ...cloudimagemetadata.Metadata) { 290 metadata, err := s.storage.FindMetadata(buildAttributesFilter(criteria)) 291 c.Assert(err, jc.ErrorIsNil) 292 293 groups := make(map[string][]cloudimagemetadata.Metadata) 294 for _, one := range expected { 295 groups[one.Source] = append(groups[one.Source], one) 296 } 297 c.Assert(metadata, jc.DeepEquals, groups) 298 } 299 300 func (s *cloudImageMetadataSuite) TestSupportedArchitectures(c *gc.C) { 301 stream := "stream" 302 region := "region-test" 303 304 arch1 := "arch" 305 attrs := cloudimagemetadata.MetadataAttributes{ 306 Stream: stream, 307 Region: region, 308 Version: "14.04", 309 Series: "trusty", 310 Arch: arch1, 311 VirtType: "virtType-test", 312 RootStorageType: "rootStorageType-test"} 313 314 added := cloudimagemetadata.Metadata{attrs, 0, "1"} 315 s.assertRecordMetadata(c, added) 316 s.assertMetadataRecorded(c, attrs, added) 317 318 addedNonUnique := cloudimagemetadata.Metadata{attrs, 0, "21"} 319 s.assertRecordMetadata(c, addedNonUnique) 320 s.assertMetadataRecorded(c, attrs, addedNonUnique) 321 322 arch2 := "anotherArch" 323 attrs.Arch = arch2 324 added2 := cloudimagemetadata.Metadata{attrs, 0, "21"} 325 s.assertRecordMetadata(c, added2) 326 s.assertMetadataRecorded(c, attrs, added2) 327 328 expected := []string{arch1, arch2} 329 uniqueArches, err := s.storage.SupportedArchitectures( 330 cloudimagemetadata.MetadataFilter{Stream: stream, Region: region}) 331 c.Assert(err, jc.ErrorIsNil) 332 c.Assert(uniqueArches, gc.DeepEquals, expected) 333 } 334 335 func (s *cloudImageMetadataSuite) TestSupportedArchitecturesUnmatchedStreams(c *gc.C) { 336 stream := "stream" 337 region := "region-test" 338 339 attrs := cloudimagemetadata.MetadataAttributes{ 340 Stream: "new-stream", 341 Region: region, 342 Version: "14.04", 343 Series: "trusty", 344 Arch: "arch", 345 VirtType: "virtType-test", 346 RootStorageType: "rootStorageType-test"} 347 348 added := cloudimagemetadata.Metadata{attrs, 0, "1"} 349 s.assertRecordMetadata(c, added) 350 s.assertMetadataRecorded(c, attrs, added) 351 352 uniqueArches, err := s.storage.SupportedArchitectures( 353 cloudimagemetadata.MetadataFilter{Stream: stream, Region: region}) 354 c.Assert(err, jc.ErrorIsNil) 355 c.Assert(uniqueArches, gc.DeepEquals, []string{}) 356 } 357 358 func (s *cloudImageMetadataSuite) TestSupportedArchitecturesUnmatchedRegions(c *gc.C) { 359 stream := "stream" 360 region := "region-test" 361 362 attrs := cloudimagemetadata.MetadataAttributes{ 363 Stream: stream, 364 Region: "new-region", 365 Version: "14.04", 366 Series: "trusty", 367 Arch: "arch", 368 VirtType: "virtType-test", 369 RootStorageType: "rootStorageType-test"} 370 371 added := cloudimagemetadata.Metadata{attrs, 0, "1"} 372 s.assertRecordMetadata(c, added) 373 s.assertMetadataRecorded(c, attrs, added) 374 375 uniqueArches, err := s.storage.SupportedArchitectures( 376 cloudimagemetadata.MetadataFilter{Stream: stream, Region: region}) 377 c.Assert(err, jc.ErrorIsNil) 378 c.Assert(uniqueArches, gc.DeepEquals, []string{}) 379 } 380 381 func (s *cloudImageMetadataSuite) TestSupportedArchitecturesUnmatchedStreamsAndRegions(c *gc.C) { 382 stream := "stream" 383 region := "region-test" 384 385 attrs := cloudimagemetadata.MetadataAttributes{ 386 Stream: "new-stream", 387 Region: "new-region", 388 Version: "14.04", 389 Series: "trusty", 390 Arch: "arch", 391 VirtType: "virtType-test", 392 RootStorageType: "rootStorageType-test"} 393 394 added := cloudimagemetadata.Metadata{attrs, 0, "1"} 395 s.assertRecordMetadata(c, added) 396 s.assertMetadataRecorded(c, attrs, added) 397 398 uniqueArches, err := s.storage.SupportedArchitectures( 399 cloudimagemetadata.MetadataFilter{Stream: stream, Region: region}) 400 c.Assert(err, jc.ErrorIsNil) 401 c.Assert(uniqueArches, gc.DeepEquals, []string{}) 402 } 403 404 func (s *cloudImageMetadataSuite) TestDeleteMetadata(c *gc.C) { 405 imageId := "ok-to-delete" 406 s.addTestImageMetadata(c, imageId) 407 s.assertDeleteMetadata(c, imageId) 408 s.assertNoMetadata(c) 409 410 // calling delete on it again should be a no-op 411 s.assertDeleteMetadata(c, imageId) 412 // make sure log has "nothing to delete" message 413 c.Assert(c.GetTestLog(), jc.Contains, "no metadata for image ID ok-to-delete to delete") 414 } 415 416 func (s *cloudImageMetadataSuite) TestDeleteDiffMetadataConcurrently(c *gc.C) { 417 imageId := "ok-to-delete" 418 s.addTestImageMetadata(c, imageId) 419 420 diffImageId := "ok-to-delete-too" 421 s.addTestImageMetadata(c, diffImageId) 422 423 s.assertConcurrentDelete(c, imageId, diffImageId) 424 } 425 426 func (s *cloudImageMetadataSuite) TestDeleteSameMetadataConcurrently(c *gc.C) { 427 imageId := "ok-to-delete" 428 s.addTestImageMetadata(c, imageId) 429 430 s.assertConcurrentDelete(c, imageId, imageId) 431 } 432 433 func (s *cloudImageMetadataSuite) assertConcurrentDelete(c *gc.C, imageId0, imageId1 string) { 434 deleteMetadata := func() { 435 s.assertDeleteMetadata(c, imageId0) 436 } 437 defer txntesting.SetBeforeHooks(c, s.access.runner, deleteMetadata).Check() 438 s.assertDeleteMetadata(c, imageId1) 439 s.assertNoMetadata(c) 440 } 441 442 func (s *cloudImageMetadataSuite) addTestImageMetadata(c *gc.C, imageId string) { 443 attrs := cloudimagemetadata.MetadataAttributes{ 444 Stream: "stream", 445 Region: "region-test", 446 Version: "14.04", 447 Series: "trusty", 448 Arch: "arch", 449 VirtType: "virtType-test", 450 RootStorageType: "rootStorageType-test"} 451 452 added := cloudimagemetadata.Metadata{attrs, 0, imageId} 453 s.assertRecordMetadata(c, added) 454 s.assertMetadataRecorded(c, attrs, added) 455 } 456 457 func (s *cloudImageMetadataSuite) assertDeleteMetadata(c *gc.C, imageId string) { 458 err := s.storage.DeleteMetadata(imageId) 459 c.Assert(err, jc.ErrorIsNil) 460 } 461 462 func (s *cloudImageMetadataSuite) assertNoMetadata(c *gc.C) { 463 // No metadata should be in store. 464 // So when looking for all and none is found, err. 465 found, err := s.storage.FindMetadata(cloudimagemetadata.MetadataFilter{}) 466 c.Assert(err, jc.Satisfies, errors.IsNotFound) 467 c.Assert(err, gc.ErrorMatches, "matching cloud image metadata not found") 468 c.Assert(found, gc.HasLen, 0) 469 } 470 471 type TestMongo struct { 472 database *mgo.Database 473 runner txn.Runner 474 } 475 476 func NewTestMongo(database *mgo.Database) *TestMongo { 477 return &TestMongo{ 478 database: database, 479 runner: txn.NewRunner(txn.RunnerParams{ 480 Database: database, 481 }), 482 } 483 } 484 485 func (m *TestMongo) GetCollection(name string) (mongo.Collection, func()) { 486 return mongo.CollectionFromName(m.database, name) 487 } 488 489 func (m *TestMongo) RunTransaction(getTxn txn.TransactionSource) error { 490 return m.runner.Run(getTxn) 491 }