~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/state/cloudimagemetadata/image_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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(
 
290
        c *gc.C,
 
291
        criteria cloudimagemetadata.MetadataAttributes,
 
292
        expected ...cloudimagemetadata.Metadata,
 
293
) {
 
294
        metadata, err := s.storage.FindMetadata(buildAttributesFilter(criteria))
 
295
        c.Assert(err, jc.ErrorIsNil)
 
296
 
 
297
        // Collate expected into a map
 
298
        groups := make(map[string][]cloudimagemetadata.Metadata)
 
299
        for _, expectedMetadata := range expected {
 
300
                groups[expectedMetadata.Source] = append(groups[expectedMetadata.Source], expectedMetadata)
 
301
        }
 
302
 
 
303
        // Compare maps by key; order of slices does not matter
 
304
        c.Assert(groups, gc.HasLen, len(metadata))
 
305
        for source, expectedMetadata := range groups {
 
306
                c.Assert(metadata[source], jc.SameContents, expectedMetadata)
 
307
        }
 
308
}
 
309
 
 
310
func (s *cloudImageMetadataSuite) TestSupportedArchitectures(c *gc.C) {
 
311
        stream := "stream"
 
312
        region := "region-test"
 
313
 
 
314
        arch1 := "arch"
 
315
        attrs := cloudimagemetadata.MetadataAttributes{
 
316
                Stream:          stream,
 
317
                Region:          region,
 
318
                Version:         "14.04",
 
319
                Series:          "trusty",
 
320
                Arch:            arch1,
 
321
                VirtType:        "virtType-test",
 
322
                RootStorageType: "rootStorageType-test"}
 
323
 
 
324
        added := cloudimagemetadata.Metadata{attrs, 0, "1"}
 
325
        s.assertRecordMetadata(c, added)
 
326
        s.assertMetadataRecorded(c, attrs, added)
 
327
 
 
328
        addedNonUnique := cloudimagemetadata.Metadata{attrs, 0, "21"}
 
329
        s.assertRecordMetadata(c, addedNonUnique)
 
330
        s.assertMetadataRecorded(c, attrs, addedNonUnique)
 
331
 
 
332
        arch2 := "anotherArch"
 
333
        attrs.Arch = arch2
 
334
        added2 := cloudimagemetadata.Metadata{attrs, 0, "21"}
 
335
        s.assertRecordMetadata(c, added2)
 
336
        s.assertMetadataRecorded(c, attrs, added2)
 
337
 
 
338
        expected := []string{arch1, arch2}
 
339
        uniqueArches, err := s.storage.SupportedArchitectures(
 
340
                cloudimagemetadata.MetadataFilter{Stream: stream, Region: region})
 
341
        c.Assert(err, jc.ErrorIsNil)
 
342
        c.Assert(uniqueArches, gc.DeepEquals, expected)
 
343
}
 
344
 
 
345
func (s *cloudImageMetadataSuite) TestSupportedArchitecturesUnmatchedStreams(c *gc.C) {
 
346
        stream := "stream"
 
347
        region := "region-test"
 
348
 
 
349
        attrs := cloudimagemetadata.MetadataAttributes{
 
350
                Stream:          "new-stream",
 
351
                Region:          region,
 
352
                Version:         "14.04",
 
353
                Series:          "trusty",
 
354
                Arch:            "arch",
 
355
                VirtType:        "virtType-test",
 
356
                RootStorageType: "rootStorageType-test"}
 
357
 
 
358
        added := cloudimagemetadata.Metadata{attrs, 0, "1"}
 
359
        s.assertRecordMetadata(c, added)
 
360
        s.assertMetadataRecorded(c, attrs, added)
 
361
 
 
362
        uniqueArches, err := s.storage.SupportedArchitectures(
 
363
                cloudimagemetadata.MetadataFilter{Stream: stream, Region: region})
 
364
        c.Assert(err, jc.ErrorIsNil)
 
365
        c.Assert(uniqueArches, gc.DeepEquals, []string{})
 
366
}
 
367
 
 
368
func (s *cloudImageMetadataSuite) TestSupportedArchitecturesUnmatchedRegions(c *gc.C) {
 
369
        stream := "stream"
 
370
        region := "region-test"
 
371
 
 
372
        attrs := cloudimagemetadata.MetadataAttributes{
 
373
                Stream:          stream,
 
374
                Region:          "new-region",
 
375
                Version:         "14.04",
 
376
                Series:          "trusty",
 
377
                Arch:            "arch",
 
378
                VirtType:        "virtType-test",
 
379
                RootStorageType: "rootStorageType-test"}
 
380
 
 
381
        added := cloudimagemetadata.Metadata{attrs, 0, "1"}
 
382
        s.assertRecordMetadata(c, added)
 
383
        s.assertMetadataRecorded(c, attrs, added)
 
384
 
 
385
        uniqueArches, err := s.storage.SupportedArchitectures(
 
386
                cloudimagemetadata.MetadataFilter{Stream: stream, Region: region})
 
387
        c.Assert(err, jc.ErrorIsNil)
 
388
        c.Assert(uniqueArches, gc.DeepEquals, []string{})
 
389
}
 
390
 
 
391
func (s *cloudImageMetadataSuite) TestSupportedArchitecturesUnmatchedStreamsAndRegions(c *gc.C) {
 
392
        stream := "stream"
 
393
        region := "region-test"
 
394
 
 
395
        attrs := cloudimagemetadata.MetadataAttributes{
 
396
                Stream:          "new-stream",
 
397
                Region:          "new-region",
 
398
                Version:         "14.04",
 
399
                Series:          "trusty",
 
400
                Arch:            "arch",
 
401
                VirtType:        "virtType-test",
 
402
                RootStorageType: "rootStorageType-test"}
 
403
 
 
404
        added := cloudimagemetadata.Metadata{attrs, 0, "1"}
 
405
        s.assertRecordMetadata(c, added)
 
406
        s.assertMetadataRecorded(c, attrs, added)
 
407
 
 
408
        uniqueArches, err := s.storage.SupportedArchitectures(
 
409
                cloudimagemetadata.MetadataFilter{Stream: stream, Region: region})
 
410
        c.Assert(err, jc.ErrorIsNil)
 
411
        c.Assert(uniqueArches, gc.DeepEquals, []string{})
 
412
}
 
413
 
 
414
func (s *cloudImageMetadataSuite) TestDeleteMetadata(c *gc.C) {
 
415
        imageId := "ok-to-delete"
 
416
        s.addTestImageMetadata(c, imageId)
 
417
        s.assertDeleteMetadata(c, imageId)
 
418
        s.assertNoMetadata(c)
 
419
 
 
420
        // calling delete on it again should be a no-op
 
421
        s.assertDeleteMetadata(c, imageId)
 
422
        // make sure log has "nothing to delete" message
 
423
        c.Assert(c.GetTestLog(), jc.Contains, "no metadata for image ID ok-to-delete to delete")
 
424
}
 
425
 
 
426
func (s *cloudImageMetadataSuite) TestDeleteDiffMetadataConcurrently(c *gc.C) {
 
427
        imageId := "ok-to-delete"
 
428
        s.addTestImageMetadata(c, imageId)
 
429
 
 
430
        diffImageId := "ok-to-delete-too"
 
431
        s.addTestImageMetadata(c, diffImageId)
 
432
 
 
433
        s.assertConcurrentDelete(c, imageId, diffImageId)
 
434
}
 
435
 
 
436
func (s *cloudImageMetadataSuite) TestDeleteSameMetadataConcurrently(c *gc.C) {
 
437
        imageId := "ok-to-delete"
 
438
        s.addTestImageMetadata(c, imageId)
 
439
 
 
440
        s.assertConcurrentDelete(c, imageId, imageId)
 
441
}
 
442
 
 
443
func (s *cloudImageMetadataSuite) assertConcurrentDelete(c *gc.C, imageId0, imageId1 string) {
 
444
        deleteMetadata := func() {
 
445
                s.assertDeleteMetadata(c, imageId0)
 
446
        }
 
447
        defer txntesting.SetBeforeHooks(c, s.access.runner, deleteMetadata).Check()
 
448
        s.assertDeleteMetadata(c, imageId1)
 
449
        s.assertNoMetadata(c)
 
450
}
 
451
 
 
452
func (s *cloudImageMetadataSuite) addTestImageMetadata(c *gc.C, imageId string) {
 
453
        attrs := cloudimagemetadata.MetadataAttributes{
 
454
                Stream:          "stream",
 
455
                Region:          "region-test",
 
456
                Version:         "14.04",
 
457
                Series:          "trusty",
 
458
                Arch:            "arch",
 
459
                VirtType:        "virtType-test",
 
460
                RootStorageType: "rootStorageType-test"}
 
461
 
 
462
        added := cloudimagemetadata.Metadata{attrs, 0, imageId}
 
463
        s.assertRecordMetadata(c, added)
 
464
        s.assertMetadataRecorded(c, attrs, added)
 
465
}
 
466
 
 
467
func (s *cloudImageMetadataSuite) assertDeleteMetadata(c *gc.C, imageId string) {
 
468
        err := s.storage.DeleteMetadata(imageId)
 
469
        c.Assert(err, jc.ErrorIsNil)
 
470
}
 
471
 
 
472
func (s *cloudImageMetadataSuite) assertNoMetadata(c *gc.C) {
 
473
        // No metadata should be in store.
 
474
        // So when looking for all and none is found, err.
 
475
        found, err := s.storage.FindMetadata(cloudimagemetadata.MetadataFilter{})
 
476
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
477
        c.Assert(err, gc.ErrorMatches, "matching cloud image metadata not found")
 
478
        c.Assert(found, gc.HasLen, 0)
 
479
}
 
480
 
 
481
type TestMongo struct {
 
482
        database *mgo.Database
 
483
        runner   txn.Runner
 
484
}
 
485
 
 
486
func NewTestMongo(database *mgo.Database) *TestMongo {
 
487
        return &TestMongo{
 
488
                database: database,
 
489
                runner: txn.NewRunner(txn.RunnerParams{
 
490
                        Database: database,
 
491
                }),
 
492
        }
 
493
}
 
494
 
 
495
func (m *TestMongo) GetCollection(name string) (mongo.Collection, func()) {
 
496
        return mongo.CollectionFromName(m.database, name)
 
497
}
 
498
 
 
499
func (m *TestMongo) RunTransaction(getTxn txn.TransactionSource) error {
 
500
        return m.runner.Run(getTxn)
 
501
}