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