github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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  	coretesting "github.com/juju/juju/testing"
    20  )
    21  
    22  type cloudImageMetadataSuite struct {
    23  	testing.IsolatedMgoSuite
    24  
    25  	access  *TestMongo
    26  	storage cloudimagemetadata.Storage
    27  }
    28  
    29  var _ = gc.Suite(&cloudImageMetadataSuite{})
    30  
    31  const (
    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(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  		Source:          "test",
    54  	}
    55  	attrs2 := cloudimagemetadata.MetadataAttributes{
    56  		Stream:  "chalk",
    57  		Region:  "nether",
    58  		Version: "12.04",
    59  		Series:  "precise",
    60  		Arch:    "amd64",
    61  		Source:  "test",
    62  	}
    63  	added := []cloudimagemetadata.Metadata{
    64  		{attrs1, 0, "1", 0},
    65  		{attrs2, 0, "2", 0},
    66  	}
    67  	s.assertRecordMetadata(c, added[0])
    68  	s.assertRecordMetadata(c, added[1])
    69  	s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{}, added...)
    70  }
    71  
    72  func (s *cloudImageMetadataSuite) TestSaveMetadataWithDateCreated(c *gc.C) {
    73  	attrs := cloudimagemetadata.MetadataAttributes{
    74  		Stream:          "stream",
    75  		Region:          "region-test",
    76  		Version:         "14.04",
    77  		Series:          "trusty",
    78  		Arch:            "arch",
    79  		VirtType:        "virtType-test",
    80  		RootStorageType: "rootStorageType-test",
    81  		Source:          "test",
    82  	}
    83  	now := coretesting.NonZeroTime().UnixNano()
    84  	metadata := cloudimagemetadata.Metadata{attrs, 0, "1", now}
    85  	s.assertRecordMetadata(c, metadata)
    86  	s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{}, metadata)
    87  }
    88  
    89  func (s *cloudImageMetadataSuite) TestFindMetadataNotFound(c *gc.C) {
    90  	s.assertNoMetadata(c)
    91  
    92  	// insert something...
    93  	attrs := cloudimagemetadata.MetadataAttributes{
    94  		Stream:          "stream",
    95  		Region:          "region",
    96  		Version:         "14.04",
    97  		Series:          "trusty",
    98  		Arch:            "arch",
    99  		VirtType:        "virtType",
   100  		Source:          "test",
   101  		RootStorageType: "rootStorageType"}
   102  	m := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   103  	s.assertRecordMetadata(c, m)
   104  
   105  	// ...but look for something else.
   106  	none, err := s.storage.FindMetadata(cloudimagemetadata.MetadataFilter{
   107  		Stream: "something else",
   108  	})
   109  	// Make sure that we are explicit that we could not find what we wanted.
   110  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   111  	c.Assert(err, gc.ErrorMatches, "matching cloud image metadata not found")
   112  	c.Assert(none, gc.HasLen, 0)
   113  }
   114  
   115  func buildAttributesFilter(attrs cloudimagemetadata.MetadataAttributes) cloudimagemetadata.MetadataFilter {
   116  	filter := cloudimagemetadata.MetadataFilter{
   117  		Stream:          attrs.Stream,
   118  		Region:          attrs.Region,
   119  		VirtType:        attrs.VirtType,
   120  		RootStorageType: attrs.RootStorageType}
   121  	if attrs.Series != "" {
   122  		filter.Series = []string{attrs.Series}
   123  	}
   124  	if attrs.Arch != "" {
   125  		filter.Arches = []string{attrs.Arch}
   126  	}
   127  	return filter
   128  }
   129  
   130  func (s *cloudImageMetadataSuite) TestFindMetadata(c *gc.C) {
   131  	attrs := cloudimagemetadata.MetadataAttributes{
   132  		Stream:          "stream",
   133  		Region:          "region",
   134  		Version:         "14.04",
   135  		Series:          "trusty",
   136  		Arch:            "arch",
   137  		VirtType:        "virtType",
   138  		Source:          "test",
   139  		RootStorageType: "rootStorageType"}
   140  
   141  	m := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   142  
   143  	_, err := s.storage.FindMetadata(buildAttributesFilter(attrs))
   144  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   145  
   146  	s.assertRecordMetadata(c, m)
   147  	expected := []cloudimagemetadata.Metadata{m}
   148  	s.assertMetadataRecorded(c, attrs, expected...)
   149  
   150  	attrs.Stream = "another_stream"
   151  	m = cloudimagemetadata.Metadata{attrs, 0, "2", 0}
   152  	s.assertRecordMetadata(c, m)
   153  
   154  	expected = append(expected, m)
   155  	// Should find both
   156  	s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{Region: "region"}, expected...)
   157  }
   158  
   159  func (s *cloudImageMetadataSuite) TestSaveMetadataUpdateSameAttrsAndImages(c *gc.C) {
   160  	attrs := cloudimagemetadata.MetadataAttributes{
   161  		Stream:  "stream",
   162  		Version: "14.04",
   163  		Series:  "trusty",
   164  		Arch:    "arch",
   165  		Source:  "test",
   166  		Region:  "wonder",
   167  	}
   168  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   169  	metadata1 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   170  
   171  	s.assertRecordMetadata(c, metadata0)
   172  	s.assertRecordMetadata(c, metadata1)
   173  	s.assertMetadataRecorded(c, attrs, metadata1)
   174  }
   175  
   176  func (s *cloudImageMetadataSuite) TestSaveMetadataUpdateSameAttrsDiffImages(c *gc.C) {
   177  	attrs := cloudimagemetadata.MetadataAttributes{
   178  		Stream:  "stream",
   179  		Version: "14.04",
   180  		Series:  "trusty",
   181  		Arch:    "arch",
   182  		Source:  "test",
   183  		Region:  "wonder",
   184  	}
   185  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   186  	metadata1 := cloudimagemetadata.Metadata{attrs, 0, "12", 0}
   187  
   188  	s.assertRecordMetadata(c, metadata0)
   189  	s.assertMetadataRecorded(c, attrs, metadata0)
   190  	s.assertRecordMetadata(c, metadata1)
   191  	s.assertMetadataRecorded(c, attrs, metadata1)
   192  	s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{}, metadata1)
   193  }
   194  
   195  func (s *cloudImageMetadataSuite) TestSaveDiffMetadataConcurrentlyAndOrderByDateCreated(c *gc.C) {
   196  	attrs := cloudimagemetadata.MetadataAttributes{
   197  		Stream:  "stream",
   198  		Version: "14.04",
   199  		Series:  "trusty",
   200  		Arch:    "arch",
   201  		Region:  "wonder",
   202  		Source:  "test",
   203  	}
   204  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "0", 0}
   205  	metadata1 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   206  	metadata1.Stream = "scream"
   207  
   208  	s.assertConcurrentSave(c,
   209  		metadata0, // add this one
   210  		metadata1, // add this one
   211  		// last added should be first as order is by date created
   212  		metadata1, // verify it's in the list
   213  		metadata0, // verify it's in the list
   214  	)
   215  }
   216  
   217  func (s *cloudImageMetadataSuite) TestSaveSameMetadataDiffImageConcurrently(c *gc.C) {
   218  	attrs := cloudimagemetadata.MetadataAttributes{
   219  		Stream:  "stream",
   220  		Version: "14.04",
   221  		Series:  "trusty",
   222  		Arch:    "arch",
   223  		Source:  "test",
   224  		Region:  "wonder",
   225  	}
   226  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "0", 0}
   227  	metadata1 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   228  
   229  	s.assertConcurrentSave(c,
   230  		metadata0, // add this one
   231  		metadata1, // overwrite it with this one
   232  		metadata1, // verify only the last one is in the list
   233  	)
   234  }
   235  
   236  func (s *cloudImageMetadataSuite) TestSaveSameMetadataSameImageConcurrently(c *gc.C) {
   237  	attrs := cloudimagemetadata.MetadataAttributes{
   238  		Stream:  "stream",
   239  		Version: "14.04",
   240  		Series:  "trusty",
   241  		Arch:    "arch",
   242  		Source:  "test",
   243  		Region:  "wonder",
   244  	}
   245  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "0", 0}
   246  
   247  	s.assertConcurrentSave(c,
   248  		metadata0, // add this one
   249  		metadata0, // add it again
   250  		metadata0, // varify only one is in the list
   251  	)
   252  }
   253  
   254  func (s *cloudImageMetadataSuite) TestSaveSameMetadataSameImageDiffSourceConcurrently(c *gc.C) {
   255  	attrs := cloudimagemetadata.MetadataAttributes{
   256  		Stream:  "stream",
   257  		Version: "14.04",
   258  		Series:  "trusty",
   259  		Arch:    "arch",
   260  		Source:  "public",
   261  		Region:  "wonder",
   262  	}
   263  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "0", 0}
   264  
   265  	attrs.Source = "custom"
   266  	metadata1 := cloudimagemetadata.Metadata{attrs, 0, "0", 0}
   267  
   268  	s.assertConcurrentSave(c,
   269  		metadata0,
   270  		metadata1,
   271  		metadata0,
   272  		metadata1,
   273  	)
   274  }
   275  
   276  func (s *cloudImageMetadataSuite) TestSaveMetadataNoVersionPassed(c *gc.C) {
   277  	attrs := cloudimagemetadata.MetadataAttributes{
   278  		Stream: "stream",
   279  		Series: "trusty",
   280  		Arch:   "arch",
   281  		Source: "test",
   282  		Region: "wonder",
   283  	}
   284  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   285  	s.assertRecordMetadata(c, metadata0)
   286  }
   287  
   288  func (s *cloudImageMetadataSuite) TestSaveMetadataNoSeriesPassed(c *gc.C) {
   289  	attrs := cloudimagemetadata.MetadataAttributes{
   290  		Stream: "stream",
   291  		Arch:   "arch",
   292  		Source: "test",
   293  		Region: "wonder",
   294  	}
   295  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   296  	err := s.storage.SaveMetadata([]cloudimagemetadata.Metadata{metadata0})
   297  	c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`missing series: metadata for image 1 not valid`))
   298  }
   299  
   300  func (s *cloudImageMetadataSuite) TestSaveMetadataUnsupportedSeriesPassed(c *gc.C) {
   301  	attrs := cloudimagemetadata.MetadataAttributes{
   302  		Stream: "stream",
   303  		Series: "blah",
   304  		Arch:   "arch",
   305  		Source: "test",
   306  	}
   307  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   308  	err := s.storage.SaveMetadata([]cloudimagemetadata.Metadata{metadata0})
   309  	c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`unknown version for series: "blah"`))
   310  }
   311  
   312  func (s *cloudImageMetadataSuite) TestSaveMetadataNoStreamPassed(c *gc.C) {
   313  	attrs := cloudimagemetadata.MetadataAttributes{
   314  		Arch:   "arch",
   315  		Source: "test",
   316  		Series: "trusty",
   317  		Region: "wonder",
   318  	}
   319  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   320  	err := s.storage.SaveMetadata([]cloudimagemetadata.Metadata{metadata0})
   321  	c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`missing stream: metadata for image 1 not valid`))
   322  }
   323  
   324  func (s *cloudImageMetadataSuite) TestSaveMetadataNoSourcePassed(c *gc.C) {
   325  	attrs := cloudimagemetadata.MetadataAttributes{
   326  		Stream: "stream",
   327  		Arch:   "arch",
   328  		Series: "trusty",
   329  		Region: "wonder",
   330  	}
   331  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   332  	err := s.storage.SaveMetadata([]cloudimagemetadata.Metadata{metadata0})
   333  	c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`missing source: metadata for image 1 not valid`))
   334  }
   335  
   336  func (s *cloudImageMetadataSuite) TestSaveMetadataNoArchitecturePassed(c *gc.C) {
   337  	attrs := cloudimagemetadata.MetadataAttributes{
   338  		Stream: "stream",
   339  		Source: "test",
   340  		Series: "trusty",
   341  		Region: "wonder",
   342  	}
   343  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   344  	err := s.storage.SaveMetadata([]cloudimagemetadata.Metadata{metadata0})
   345  	c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`missing architecture: metadata for image 1 not valid`))
   346  }
   347  
   348  func (s *cloudImageMetadataSuite) TestSaveMetadataNoRegionPassed(c *gc.C) {
   349  	attrs := cloudimagemetadata.MetadataAttributes{
   350  		Stream: "stream",
   351  		Arch:   "arch",
   352  		Source: "test",
   353  		Series: "trusty",
   354  	}
   355  	metadata0 := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   356  	err := s.storage.SaveMetadata([]cloudimagemetadata.Metadata{metadata0})
   357  	c.Assert(err, gc.ErrorMatches, regexp.QuoteMeta(`missing region: metadata for image 1 not valid`))
   358  }
   359  
   360  func (s *cloudImageMetadataSuite) assertConcurrentSave(c *gc.C, metadata0, metadata1 cloudimagemetadata.Metadata, expected ...cloudimagemetadata.Metadata) {
   361  	addMetadata := func() {
   362  		s.assertRecordMetadata(c, metadata0)
   363  	}
   364  	defer txntesting.SetBeforeHooks(c, s.access.runner, addMetadata).Check()
   365  	s.assertRecordMetadata(c, metadata1)
   366  	s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{}, expected...)
   367  }
   368  
   369  func (s *cloudImageMetadataSuite) assertRecordMetadata(c *gc.C, m cloudimagemetadata.Metadata) {
   370  	err := s.storage.SaveMetadata([]cloudimagemetadata.Metadata{m})
   371  	c.Assert(err, jc.ErrorIsNil)
   372  }
   373  
   374  func (s *cloudImageMetadataSuite) assertMetadataRecorded(
   375  	c *gc.C,
   376  	criteria cloudimagemetadata.MetadataAttributes,
   377  	expected ...cloudimagemetadata.Metadata,
   378  ) {
   379  	metadata, err := s.storage.FindMetadata(buildAttributesFilter(criteria))
   380  	c.Assert(err, jc.ErrorIsNil)
   381  
   382  	// Collate expected into a map
   383  	groups := make(map[string][]cloudimagemetadata.Metadata)
   384  	for _, expectedMetadata := range expected {
   385  		groups[expectedMetadata.Source] = append(groups[expectedMetadata.Source], expectedMetadata)
   386  	}
   387  
   388  	// Compare maps by key; order of slices does not matter
   389  	c.Assert(groups, gc.HasLen, len(metadata))
   390  	for source, expectedMetadata := range groups {
   391  		actual := metadata[source]
   392  		if len(actual) == len(expectedMetadata) {
   393  			for i, image := range actual {
   394  				if expectedMetadata[i].DateCreated == 0 {
   395  					// Copy the creation date across as this will have been
   396  					// generated.
   397  					expectedMetadata[i].DateCreated = image.DateCreated
   398  				}
   399  			}
   400  		}
   401  		c.Assert(actual, jc.SameContents, expectedMetadata)
   402  	}
   403  }
   404  
   405  func (s *cloudImageMetadataSuite) TestSupportedArchitectures(c *gc.C) {
   406  	stream := "stream"
   407  	region := "region-test"
   408  
   409  	arch1 := "arch"
   410  	attrs := cloudimagemetadata.MetadataAttributes{
   411  		Stream:          stream,
   412  		Region:          region,
   413  		Version:         "14.04",
   414  		Series:          "trusty",
   415  		Arch:            arch1,
   416  		VirtType:        "virtType-test",
   417  		Source:          "test",
   418  		RootStorageType: "rootStorageType-test"}
   419  
   420  	added := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   421  	s.assertRecordMetadata(c, added)
   422  	s.assertMetadataRecorded(c, attrs, added)
   423  
   424  	addedNonUnique := cloudimagemetadata.Metadata{attrs, 0, "21", 0}
   425  	s.assertRecordMetadata(c, addedNonUnique)
   426  	s.assertMetadataRecorded(c, attrs, addedNonUnique)
   427  
   428  	arch2 := "anotherArch"
   429  	attrs.Arch = arch2
   430  	added2 := cloudimagemetadata.Metadata{attrs, 0, "21", 0}
   431  	s.assertRecordMetadata(c, added2)
   432  	s.assertMetadataRecorded(c, attrs, added2)
   433  
   434  	expected := []string{arch1, arch2}
   435  	uniqueArches, err := s.storage.SupportedArchitectures(
   436  		cloudimagemetadata.MetadataFilter{Stream: stream, Region: region})
   437  	c.Assert(err, jc.ErrorIsNil)
   438  	c.Assert(uniqueArches, gc.DeepEquals, expected)
   439  }
   440  
   441  func (s *cloudImageMetadataSuite) TestSupportedArchitecturesUnmatchedStreams(c *gc.C) {
   442  	stream := "stream"
   443  	region := "region-test"
   444  
   445  	attrs := cloudimagemetadata.MetadataAttributes{
   446  		Stream:          "new-stream",
   447  		Region:          region,
   448  		Version:         "14.04",
   449  		Series:          "trusty",
   450  		Arch:            "arch",
   451  		VirtType:        "virtType-test",
   452  		Source:          "test",
   453  		RootStorageType: "rootStorageType-test"}
   454  
   455  	added := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   456  	s.assertRecordMetadata(c, added)
   457  	s.assertMetadataRecorded(c, attrs, added)
   458  
   459  	uniqueArches, err := s.storage.SupportedArchitectures(
   460  		cloudimagemetadata.MetadataFilter{Stream: stream, Region: region})
   461  	c.Assert(err, jc.ErrorIsNil)
   462  	c.Assert(uniqueArches, gc.DeepEquals, []string{})
   463  }
   464  
   465  func (s *cloudImageMetadataSuite) TestSupportedArchitecturesUnmatchedRegions(c *gc.C) {
   466  	stream := "stream"
   467  	region := "region-test"
   468  
   469  	attrs := cloudimagemetadata.MetadataAttributes{
   470  		Stream:          stream,
   471  		Region:          "new-region",
   472  		Version:         "14.04",
   473  		Series:          "trusty",
   474  		Arch:            "arch",
   475  		VirtType:        "virtType-test",
   476  		Source:          "test",
   477  		RootStorageType: "rootStorageType-test"}
   478  
   479  	added := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   480  	s.assertRecordMetadata(c, added)
   481  	s.assertMetadataRecorded(c, attrs, added)
   482  
   483  	uniqueArches, err := s.storage.SupportedArchitectures(
   484  		cloudimagemetadata.MetadataFilter{Stream: stream, Region: region})
   485  	c.Assert(err, jc.ErrorIsNil)
   486  	c.Assert(uniqueArches, gc.DeepEquals, []string{})
   487  }
   488  
   489  func (s *cloudImageMetadataSuite) TestSupportedArchitecturesUnmatchedStreamsAndRegions(c *gc.C) {
   490  	stream := "stream"
   491  	region := "region-test"
   492  
   493  	attrs := cloudimagemetadata.MetadataAttributes{
   494  		Stream:          "new-stream",
   495  		Region:          "new-region",
   496  		Version:         "14.04",
   497  		Series:          "trusty",
   498  		Arch:            "arch",
   499  		VirtType:        "virtType-test",
   500  		Source:          "test",
   501  		RootStorageType: "rootStorageType-test"}
   502  
   503  	added := cloudimagemetadata.Metadata{attrs, 0, "1", 0}
   504  	s.assertRecordMetadata(c, added)
   505  	s.assertMetadataRecorded(c, attrs, added)
   506  
   507  	uniqueArches, err := s.storage.SupportedArchitectures(
   508  		cloudimagemetadata.MetadataFilter{Stream: stream, Region: region})
   509  	c.Assert(err, jc.ErrorIsNil)
   510  	c.Assert(uniqueArches, gc.DeepEquals, []string{})
   511  }
   512  
   513  func (s *cloudImageMetadataSuite) TestDeleteMetadata(c *gc.C) {
   514  	imageId := "ok-to-delete"
   515  	s.addTestImageMetadata(c, imageId)
   516  	s.assertDeleteMetadata(c, imageId)
   517  	s.assertNoMetadata(c)
   518  
   519  	// calling delete on it again should be a no-op
   520  	s.assertDeleteMetadata(c, imageId)
   521  	// make sure log has "nothing to delete" message
   522  	c.Assert(c.GetTestLog(), jc.Contains, "no metadata for image ID ok-to-delete to delete")
   523  }
   524  
   525  func (s *cloudImageMetadataSuite) TestDeleteDiffMetadataConcurrently(c *gc.C) {
   526  	imageId := "ok-to-delete"
   527  	s.addTestImageMetadata(c, imageId)
   528  
   529  	diffImageId := "ok-to-delete-too"
   530  	s.addTestImageMetadata(c, diffImageId)
   531  
   532  	s.assertConcurrentDelete(c, imageId, diffImageId)
   533  }
   534  
   535  func (s *cloudImageMetadataSuite) TestDeleteSameMetadataConcurrently(c *gc.C) {
   536  	imageId := "ok-to-delete"
   537  	s.addTestImageMetadata(c, imageId)
   538  
   539  	s.assertConcurrentDelete(c, imageId, imageId)
   540  }
   541  
   542  func (s *cloudImageMetadataSuite) assertConcurrentDelete(c *gc.C, imageId0, imageId1 string) {
   543  	deleteMetadata := func() {
   544  		s.assertDeleteMetadata(c, imageId0)
   545  	}
   546  	defer txntesting.SetBeforeHooks(c, s.access.runner, deleteMetadata).Check()
   547  	s.assertDeleteMetadata(c, imageId1)
   548  	s.assertNoMetadata(c)
   549  }
   550  
   551  func (s *cloudImageMetadataSuite) addTestImageMetadata(c *gc.C, imageId string) {
   552  	attrs := cloudimagemetadata.MetadataAttributes{
   553  		Stream:          "stream",
   554  		Region:          "region-test",
   555  		Version:         "14.04",
   556  		Series:          "trusty",
   557  		Arch:            "arch",
   558  		VirtType:        "virtType-test",
   559  		Source:          "test",
   560  		RootStorageType: "rootStorageType-test"}
   561  
   562  	added := cloudimagemetadata.Metadata{attrs, 0, imageId, 0}
   563  	s.assertRecordMetadata(c, added)
   564  	s.assertMetadataRecorded(c, attrs, added)
   565  }
   566  
   567  func (s *cloudImageMetadataSuite) assertDeleteMetadata(c *gc.C, imageId string) {
   568  	err := s.storage.DeleteMetadata(imageId)
   569  	c.Assert(err, jc.ErrorIsNil)
   570  }
   571  
   572  func (s *cloudImageMetadataSuite) assertNoMetadata(c *gc.C) {
   573  	// No metadata should be in store.
   574  	// So when looking for all and none is found, err.
   575  	found, err := s.storage.FindMetadata(cloudimagemetadata.MetadataFilter{})
   576  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   577  	c.Assert(err, gc.ErrorMatches, "matching cloud image metadata not found")
   578  	c.Assert(found, gc.HasLen, 0)
   579  }
   580  
   581  type TestMongo struct {
   582  	database *mgo.Database
   583  	runner   txn.Runner
   584  }
   585  
   586  func NewTestMongo(database *mgo.Database) *TestMongo {
   587  	return &TestMongo{
   588  		database: database,
   589  		runner: txn.NewRunner(txn.RunnerParams{
   590  			Database: database,
   591  		}),
   592  	}
   593  }
   594  
   595  func (m *TestMongo) GetCollection(name string) (mongo.Collection, func()) {
   596  	return mongo.CollectionFromName(m.database, name)
   597  }
   598  
   599  func (m *TestMongo) RunTransaction(getTxn txn.TransactionSource) error {
   600  	return m.runner.Run(getTxn)
   601  }