github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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  	"github.com/juju/errors"
     8  	"github.com/juju/testing"
     9  	jc "github.com/juju/testing/checkers"
    10  	"github.com/juju/txn"
    11  	txntesting "github.com/juju/txn/testing"
    12  	gc "gopkg.in/check.v1"
    13  	"gopkg.in/mgo.v2"
    14  
    15  	"github.com/juju/juju/mongo"
    16  	"github.com/juju/juju/state/cloudimagemetadata"
    17  )
    18  
    19  type cloudImageMetadataSuite struct {
    20  	testing.IsolatedMgoSuite
    21  
    22  	access  *TestMongo
    23  	storage cloudimagemetadata.Storage
    24  }
    25  
    26  var _ = gc.Suite(&cloudImageMetadataSuite{})
    27  
    28  const (
    29  	envName        = "test-env"
    30  	collectionName = "test-collection"
    31  )
    32  
    33  func (s *cloudImageMetadataSuite) SetUpTest(c *gc.C) {
    34  	s.IsolatedMgoSuite.SetUpTest(c)
    35  
    36  	db := s.MgoSuite.Session.DB("juju")
    37  
    38  	s.access = NewTestMongo(db)
    39  	s.storage = cloudimagemetadata.NewStorage(envName, collectionName, s.access)
    40  }
    41  
    42  func (s *cloudImageMetadataSuite) TestSaveMetadata(c *gc.C) {
    43  	attrs := cloudimagemetadata.MetadataAttributes{
    44  		Stream:          "stream",
    45  		Region:          "region-test",
    46  		Series:          "series",
    47  		Arch:            "arch",
    48  		VirtType:        "virtType-test",
    49  		RootStorageType: "rootStorageType-test"}
    50  
    51  	added := cloudimagemetadata.Metadata{attrs, "1"}
    52  	s.assertRecordMetadata(c, added)
    53  	s.assertMetadataRecorded(c, attrs, added)
    54  
    55  }
    56  
    57  func (s *cloudImageMetadataSuite) TestFindMetadataNotFound(c *gc.C) {
    58  	// No metadata is stored yet.
    59  	// So when looking for all and none is found, err.
    60  	found, err := s.storage.FindMetadata(cloudimagemetadata.MetadataFilter{})
    61  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
    62  	c.Assert(err, gc.ErrorMatches, "matching cloud image metadata not found")
    63  	c.Assert(found, gc.HasLen, 0)
    64  
    65  	// insert something...
    66  	attrs := cloudimagemetadata.MetadataAttributes{
    67  		Stream:          "stream",
    68  		Region:          "region",
    69  		Series:          "series",
    70  		Arch:            "arch",
    71  		VirtType:        "virtType",
    72  		RootStorageType: "rootStorageType"}
    73  	m := cloudimagemetadata.Metadata{attrs, "1"}
    74  	s.assertRecordMetadata(c, m)
    75  
    76  	// ...but look for something else.
    77  	none, err := s.storage.FindMetadata(cloudimagemetadata.MetadataFilter{
    78  		Stream: "something else",
    79  	})
    80  	// Make sure that we are explicit that we could not find what we wanted.
    81  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
    82  	c.Assert(err, gc.ErrorMatches, "matching cloud image metadata not found")
    83  	c.Assert(none, gc.HasLen, 0)
    84  }
    85  
    86  func buildAttributesFilter(attrs cloudimagemetadata.MetadataAttributes) cloudimagemetadata.MetadataFilter {
    87  	filter := cloudimagemetadata.MetadataFilter{
    88  		Stream:          attrs.Stream,
    89  		Region:          attrs.Region,
    90  		VirtType:        attrs.VirtType,
    91  		RootStorageType: attrs.RootStorageType}
    92  	if attrs.Series != "" {
    93  		filter.Series = []string{attrs.Series}
    94  	}
    95  	if attrs.Arch != "" {
    96  		filter.Arches = []string{attrs.Arch}
    97  	}
    98  	return filter
    99  }
   100  
   101  func (s *cloudImageMetadataSuite) TestFindMetadata(c *gc.C) {
   102  	attrs := cloudimagemetadata.MetadataAttributes{
   103  		Stream:          "stream",
   104  		Region:          "region",
   105  		Series:          "series",
   106  		Arch:            "arch",
   107  		VirtType:        "virtType",
   108  		RootStorageType: "rootStorageType"}
   109  
   110  	m := cloudimagemetadata.Metadata{attrs, "1"}
   111  
   112  	_, err := s.storage.FindMetadata(buildAttributesFilter(attrs))
   113  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   114  
   115  	s.assertRecordMetadata(c, m)
   116  	expected := []cloudimagemetadata.Metadata{m}
   117  	s.assertMetadataRecorded(c, attrs, expected...)
   118  
   119  	attrs.Stream = "another_stream"
   120  	m = cloudimagemetadata.Metadata{attrs, "2"}
   121  	s.assertRecordMetadata(c, m)
   122  
   123  	expected = append(expected, m)
   124  	// Should find both
   125  	s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{Region: "region"}, expected...)
   126  }
   127  
   128  func (s *cloudImageMetadataSuite) TestSaveMetadataUpdateSameAttrsAndImages(c *gc.C) {
   129  	attrs := cloudimagemetadata.MetadataAttributes{
   130  		Stream: "stream",
   131  		Series: "series",
   132  		Arch:   "arch",
   133  	}
   134  	metadata0 := cloudimagemetadata.Metadata{attrs, "1"}
   135  	metadata1 := cloudimagemetadata.Metadata{attrs, "1"}
   136  
   137  	s.assertRecordMetadata(c, metadata0)
   138  	s.assertRecordMetadata(c, metadata1)
   139  	s.assertMetadataRecorded(c, attrs, metadata1)
   140  }
   141  
   142  func (s *cloudImageMetadataSuite) TestSaveMetadataUpdateSameAttrsDiffImages(c *gc.C) {
   143  	attrs := cloudimagemetadata.MetadataAttributes{
   144  		Stream: "stream",
   145  		Series: "series",
   146  		Arch:   "arch",
   147  	}
   148  	metadata0 := cloudimagemetadata.Metadata{attrs, "1"}
   149  	metadata1 := cloudimagemetadata.Metadata{attrs, "12"}
   150  
   151  	s.assertRecordMetadata(c, metadata0)
   152  	s.assertMetadataRecorded(c, attrs, metadata0)
   153  	s.assertRecordMetadata(c, metadata1)
   154  	s.assertMetadataRecorded(c, attrs, metadata1)
   155  	s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{}, metadata1)
   156  }
   157  
   158  func (s *cloudImageMetadataSuite) TestSaveDiffMetadataConcurrentlyAndOrderByDateCreated(c *gc.C) {
   159  	attrs := cloudimagemetadata.MetadataAttributes{
   160  		Stream: "stream",
   161  		Series: "series",
   162  		Arch:   "arch",
   163  	}
   164  	metadata0 := cloudimagemetadata.Metadata{attrs, "0"}
   165  	metadata1 := cloudimagemetadata.Metadata{attrs, "1"}
   166  	metadata1.Stream = "scream"
   167  
   168  	s.assertConcurrentSave(c,
   169  		metadata0, // add this one
   170  		metadata1, // add this one
   171  		// last added should be first as order is by date created
   172  		metadata1, // verify it's in the list
   173  		metadata0, // verify it's in the list
   174  	)
   175  }
   176  
   177  func (s *cloudImageMetadataSuite) TestSaveSameMetadataDiffImageConcurrently(c *gc.C) {
   178  	attrs := cloudimagemetadata.MetadataAttributes{
   179  		Stream: "stream",
   180  		Series: "series",
   181  		Arch:   "arch",
   182  	}
   183  	metadata0 := cloudimagemetadata.Metadata{attrs, "0"}
   184  	metadata1 := cloudimagemetadata.Metadata{attrs, "1"}
   185  
   186  	s.assertConcurrentSave(c,
   187  		metadata0, // add this one
   188  		metadata1, // overwrite it with this one
   189  		metadata1, // verify only the last one is in the list
   190  	)
   191  }
   192  
   193  func (s *cloudImageMetadataSuite) TestSaveSameMetadataSameImageConcurrently(c *gc.C) {
   194  	attrs := cloudimagemetadata.MetadataAttributes{
   195  		Stream: "stream",
   196  		Series: "series",
   197  		Arch:   "arch",
   198  	}
   199  	metadata0 := cloudimagemetadata.Metadata{attrs, "0"}
   200  
   201  	s.assertConcurrentSave(c,
   202  		metadata0, // add this one
   203  		metadata0, // add it again
   204  		metadata0, // varify only one is in the list
   205  	)
   206  }
   207  
   208  func (s *cloudImageMetadataSuite) TestSaveSameMetadataSameImageDiffSourceConcurrently(c *gc.C) {
   209  	attrs := cloudimagemetadata.MetadataAttributes{
   210  		Stream: "stream",
   211  		Series: "series",
   212  		Arch:   "arch",
   213  		Source: cloudimagemetadata.Public,
   214  	}
   215  	metadata0 := cloudimagemetadata.Metadata{attrs, "0"}
   216  
   217  	attrs.Source = cloudimagemetadata.Custom
   218  	metadata1 := cloudimagemetadata.Metadata{attrs, "0"}
   219  
   220  	s.assertConcurrentSave(c,
   221  		metadata0,
   222  		metadata1,
   223  		metadata0,
   224  		metadata1,
   225  	)
   226  }
   227  
   228  func (s *cloudImageMetadataSuite) assertConcurrentSave(c *gc.C, metadata0, metadata1 cloudimagemetadata.Metadata, expected ...cloudimagemetadata.Metadata) {
   229  	addMetadata := func() {
   230  		s.assertRecordMetadata(c, metadata0)
   231  	}
   232  	defer txntesting.SetBeforeHooks(c, s.access.runner, addMetadata).Check()
   233  	s.assertRecordMetadata(c, metadata1)
   234  	s.assertMetadataRecorded(c, cloudimagemetadata.MetadataAttributes{}, expected...)
   235  }
   236  
   237  func (s *cloudImageMetadataSuite) assertRecordMetadata(c *gc.C, m cloudimagemetadata.Metadata) {
   238  	err := s.storage.SaveMetadata(m)
   239  	c.Assert(err, jc.ErrorIsNil)
   240  }
   241  
   242  func (s *cloudImageMetadataSuite) assertMetadataRecorded(c *gc.C, criteria cloudimagemetadata.MetadataAttributes, expected ...cloudimagemetadata.Metadata) {
   243  	metadata, err := s.storage.FindMetadata(buildAttributesFilter(criteria))
   244  	c.Assert(err, jc.ErrorIsNil)
   245  
   246  	groups := make(map[cloudimagemetadata.SourceType][]cloudimagemetadata.Metadata)
   247  	for _, one := range expected {
   248  		groups[one.Source] = append(groups[one.Source], one)
   249  	}
   250  	c.Assert(metadata, jc.DeepEquals, groups)
   251  }
   252  
   253  type TestMongo struct {
   254  	database *mgo.Database
   255  	runner   txn.Runner
   256  }
   257  
   258  func NewTestMongo(database *mgo.Database) *TestMongo {
   259  	return &TestMongo{
   260  		database: database,
   261  		runner: txn.NewRunner(txn.RunnerParams{
   262  			Database: database,
   263  		}),
   264  	}
   265  }
   266  
   267  func (m *TestMongo) GetCollection(name string) (mongo.Collection, func()) {
   268  	return mongo.CollectionFromName(m.database, name)
   269  }
   270  
   271  func (m *TestMongo) RunTransaction(getTxn txn.TransactionSource) error {
   272  	return m.runner.Run(getTxn)
   273  }