~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/state/migration_internal_test.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

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 state
 
5
 
 
6
import (
 
7
        "reflect"
 
8
 
 
9
        "github.com/juju/utils/set"
 
10
        gc "gopkg.in/check.v1"
 
11
        "gopkg.in/juju/charm.v6-unstable"
 
12
)
 
13
 
 
14
type MigrationSuite struct{}
 
15
 
 
16
var _ = gc.Suite(&MigrationSuite{})
 
17
 
 
18
func (s *MigrationSuite) TestKnownCollections(c *gc.C) {
 
19
        completedCollections := set.NewStrings(
 
20
                annotationsC,
 
21
                blocksC,
 
22
                constraintsC,
 
23
                modelsC,
 
24
                modelUsersC,
 
25
                modelUserLastConnectionC,
 
26
                settingsC,
 
27
                sequenceC,
 
28
                statusesC,
 
29
                statusesHistoryC,
 
30
 
 
31
                // machine
 
32
                instanceDataC,
 
33
                machinesC,
 
34
                openedPortsC,
 
35
 
 
36
                // service / unit
 
37
                leasesC,
 
38
                servicesC,
 
39
                unitsC,
 
40
                meterStatusC, // red / green status for metrics of units
 
41
 
 
42
                // settings reference counts are only used for services
 
43
                settingsrefsC,
 
44
 
 
45
                // relation
 
46
                relationsC,
 
47
                relationScopesC,
 
48
        )
 
49
 
 
50
        ignoredCollections := set.NewStrings(
 
51
                // Precheck ensures that there are no cleanup docs.
 
52
                cleanupsC,
 
53
                // We don't export the controller model at this stage.
 
54
                controllersC,
 
55
                // This is controller global, and related to the system state of the
 
56
                // embedded GUI.
 
57
                guimetadataC,
 
58
                // Users aren't migrated.
 
59
                usersC,
 
60
                userLastLoginC,
 
61
                // userenvnameC is just to provide a unique key constraint.
 
62
                usermodelnameC,
 
63
                // Metrics aren't migrated.
 
64
                metricsC,
 
65
                // leaseC is deprecated in favour of leasesC.
 
66
                leaseC,
 
67
                // Backup and restore information is not migrated.
 
68
                restoreInfoC,
 
69
                // upgradeInfoC is used to coordinate upgrades and schema migrations,
 
70
                // and aren't needed for model migrations.
 
71
                upgradeInfoC,
 
72
                // Not exported, but the tools will possibly need to be either bundled
 
73
                // with the representation or sent separately.
 
74
                toolsmetadataC,
 
75
                // Transaction stuff.
 
76
                "txns",
 
77
                "txns.log",
 
78
 
 
79
                // We don't import any of the migration collections.
 
80
                modelMigrationsC,
 
81
                modelMigrationStatusC,
 
82
                modelMigrationsActiveC,
 
83
 
 
84
                // The container ref document is primarily there to keep track
 
85
                // of a particular machine's containers. The migration format
 
86
                // uses object containment for this purpose.
 
87
                containerRefsC,
 
88
                // The min units collection is only used to trigger a watcher
 
89
                // in order to have the service add or remove units if the minimum
 
90
                // number of units is changed. The Service doc has all we need
 
91
                // for migratino.
 
92
                minUnitsC,
 
93
                // This is a transitory collection of units that need to be assigned
 
94
                // to machines.
 
95
                assignUnitC,
 
96
 
 
97
                // This has been deprecated in 2.0, and should not contain any data
 
98
                // we actually care about migrating.
 
99
                legacyipaddressesC,
 
100
        )
 
101
 
 
102
        // THIS SET WILL BE REMOVED WHEN MIGRATIONS ARE COMPLETE
 
103
        todoCollections := set.NewStrings(
 
104
                // model
 
105
                cloudimagemetadataC,
 
106
 
 
107
                // machine
 
108
                rebootC,
 
109
 
 
110
                // service / unit
 
111
                charmsC,
 
112
                "payloads",
 
113
                "resources",
 
114
                endpointBindingsC,
 
115
 
 
116
                // storage
 
117
                blockDevicesC,
 
118
                filesystemsC,
 
119
                filesystemAttachmentsC,
 
120
                storageInstancesC,
 
121
                storageAttachmentsC,
 
122
                storageConstraintsC,
 
123
                volumesC,
 
124
                volumeAttachmentsC,
 
125
 
 
126
                // network
 
127
                ipAddressesC,
 
128
                linkLayerDevicesC,
 
129
                linkLayerDevicesRefsC,
 
130
                networksC,
 
131
                networkInterfacesC,
 
132
                requestedNetworksC,
 
133
                subnetsC,
 
134
                spacesC,
 
135
 
 
136
                // actions
 
137
                actionsC,
 
138
                actionNotificationsC,
 
139
                actionresultsC,
 
140
 
 
141
                // uncategorised
 
142
                metricsManagerC, // should really be copied across
 
143
        )
 
144
 
 
145
        envCollections := set.NewStrings()
 
146
        for name := range allCollections() {
 
147
                envCollections.Add(name)
 
148
        }
 
149
 
 
150
        known := completedCollections.Union(ignoredCollections)
 
151
 
 
152
        remainder := envCollections.Difference(known)
 
153
        remainder = remainder.Difference(todoCollections)
 
154
 
 
155
        // If this test fails, it means that a new collection has been added
 
156
        // but migrations for it has not been done. This is a Bad Thing™.
 
157
        c.Assert(remainder, gc.HasLen, 0)
 
158
}
 
159
 
 
160
func (s *MigrationSuite) TestModelDocFields(c *gc.C) {
 
161
        fields := set.NewStrings(
 
162
                // UUID and Mame are constructed from the model config.
 
163
                "UUID",
 
164
                "Name",
 
165
                // Life will always be alive, or we won't be migrating.
 
166
                "Life",
 
167
                "Owner",
 
168
                "LatestAvailableTools",
 
169
                // ServerUUID is recreated when the new model is created in the
 
170
                // new controller (yay name changes).
 
171
                "ServerUUID",
 
172
                // Both of the times for dying and death are empty as the model
 
173
                // is alive.
 
174
                "TimeOfDying",
 
175
                "TimeOfDeath",
 
176
        )
 
177
        s.AssertExportedFields(c, modelDoc{}, fields)
 
178
}
 
179
 
 
180
func (s *MigrationSuite) TestEnvUserDocFields(c *gc.C) {
 
181
        fields := set.NewStrings(
 
182
                // ID is the same as UserName (but lowercased)
 
183
                "ID",
 
184
                // ModelUUID shouldn't be exported, and is inherited
 
185
                // from the model definition.
 
186
                "ModelUUID",
 
187
                // Tracked fields:
 
188
                "UserName",
 
189
                "DisplayName",
 
190
                "CreatedBy",
 
191
                "DateCreated",
 
192
                "Access",
 
193
        )
 
194
        s.AssertExportedFields(c, modelUserDoc{}, fields)
 
195
}
 
196
 
 
197
func (s *MigrationSuite) TestEnvUserLastConnectionDocFields(c *gc.C) {
 
198
        fields := set.NewStrings(
 
199
                // ID is the same as UserName (but lowercased)
 
200
                "ID",
 
201
                // ModelUUID shouldn't be exported, and is inherited
 
202
                // from the model definition.
 
203
                "ModelUUID",
 
204
                // UserName is captured in the migration.User.
 
205
                "UserName",
 
206
                "LastConnection",
 
207
        )
 
208
        s.AssertExportedFields(c, modelUserLastConnectionDoc{}, fields)
 
209
}
 
210
 
 
211
func (s *MigrationSuite) TestMachineDocFields(c *gc.C) {
 
212
        fields := set.NewStrings(
 
213
                // DocID is the env + machine id
 
214
                "DocID",
 
215
                // ID is the machine id
 
216
                "Id",
 
217
                // ModelUUID shouldn't be exported, and is inherited
 
218
                // from the model definition.
 
219
                "ModelUUID",
 
220
                // Life is always alive, confirmed by export precheck.
 
221
                "Life",
 
222
 
 
223
                "Addresses",
 
224
                "ContainerType",
 
225
                "Jobs",
 
226
                "MachineAddresses",
 
227
                "Nonce",
 
228
                "PasswordHash",
 
229
                "Placement",
 
230
                "PreferredPrivateAddress",
 
231
                "PreferredPublicAddress",
 
232
                "Series",
 
233
                "SupportedContainers",
 
234
                "SupportedContainersKnown",
 
235
                "Tools",
 
236
 
 
237
                // Ignored at this stage, could be an issue if mongo 3.0 isn't
 
238
                // available.
 
239
                "StopMongoUntilVersion",
 
240
        )
 
241
        todo := set.NewStrings(
 
242
                "Principals",
 
243
                "Volumes",
 
244
                "NoVote",
 
245
                "Clean",
 
246
                "Filesystems",
 
247
                "HasVote",
 
248
        )
 
249
        s.AssertExportedFields(c, machineDoc{}, fields.Union(todo))
 
250
}
 
251
 
 
252
func (s *MigrationSuite) TestInstanceDataFields(c *gc.C) {
 
253
        fields := set.NewStrings(
 
254
                // DocID is the env + machine id
 
255
                "DocID",
 
256
                "MachineId",
 
257
                // ModelUUID shouldn't be exported, and is inherited
 
258
                // from the model definition.
 
259
                "ModelUUID",
 
260
 
 
261
                "InstanceId",
 
262
                "Status",
 
263
                "Arch",
 
264
                "Mem",
 
265
                "RootDisk",
 
266
                "CpuCores",
 
267
                "CpuPower",
 
268
                "Tags",
 
269
                "AvailZone",
 
270
        )
 
271
        s.AssertExportedFields(c, instanceData{}, fields)
 
272
}
 
273
 
 
274
func (s *MigrationSuite) TestServiceDocFields(c *gc.C) {
 
275
        ignored := set.NewStrings(
 
276
                // DocID is the env + name
 
277
                "DocID",
 
278
                // ModelUUID shouldn't be exported, and is inherited
 
279
                // from the model definition.
 
280
                "ModelUUID",
 
281
                // Always alive, not explicitly exported.
 
282
                "Life",
 
283
                // OwnerTag is deprecated and should be deleted.
 
284
                "OwnerTag",
 
285
                // TxnRevno is mgo internals and should not be migrated.
 
286
                "TxnRevno",
 
287
                // UnitCount is handled by the number of units for the exported service.
 
288
                "UnitCount",
 
289
                // RelationCount is handled by the number of times the service name
 
290
                // appears in relation endpoints.
 
291
                "RelationCount",
 
292
        )
 
293
        migrated := set.NewStrings(
 
294
                "Name",
 
295
                "Series",
 
296
                "Subordinate",
 
297
                "CharmURL",
 
298
                "CharmModifiedVersion",
 
299
                "ForceCharm",
 
300
                "Exposed",
 
301
                "MinUnits",
 
302
                "MetricCredentials",
 
303
        )
 
304
        s.AssertExportedFields(c, serviceDoc{}, migrated.Union(ignored))
 
305
}
 
306
 
 
307
func (s *MigrationSuite) TestSettingsRefsDocFields(c *gc.C) {
 
308
        fields := set.NewStrings(
 
309
                // ModelUUID shouldn't be exported, and is inherited
 
310
                // from the model definition.
 
311
                "ModelUUID",
 
312
 
 
313
                "RefCount",
 
314
        )
 
315
        s.AssertExportedFields(c, settingsRefsDoc{}, fields)
 
316
}
 
317
 
 
318
func (s *MigrationSuite) TestUnitDocFields(c *gc.C) {
 
319
        fields := set.NewStrings(
 
320
                // DocID itself isn't migrated
 
321
                "DocID",
 
322
                "Name",
 
323
                // ModelUUID shouldn't be exported, and is inherited
 
324
                // from the model definition.
 
325
                "ModelUUID",
 
326
                // Service is implicit in the migration structure through containment.
 
327
                "Service",
 
328
                // Series and CharmURL also come from the service.
 
329
                "Series",
 
330
                "CharmURL",
 
331
                "Principal",
 
332
                "Subordinates",
 
333
                "MachineId",
 
334
                // Resolved is not migrated as we check that all is good before we start.
 
335
                "Resolved",
 
336
                "Tools",
 
337
                // Life isn't migrated as we only migrate live things.
 
338
                "Life",
 
339
                // TxnRevno isn't migrated.
 
340
                "TxnRevno",
 
341
                "PasswordHash",
 
342
                // Obsolete and not migrated.
 
343
                "Ports",
 
344
                "PublicAddress",
 
345
                "PrivateAddress",
 
346
        )
 
347
        todo := set.NewStrings(
 
348
                "StorageAttachmentCount",
 
349
        )
 
350
 
 
351
        s.AssertExportedFields(c, unitDoc{}, fields.Union(todo))
 
352
}
 
353
 
 
354
func (s *MigrationSuite) TestPortsDocFields(c *gc.C) {
 
355
        fields := set.NewStrings(
 
356
                // DocID itself isn't migrated
 
357
                "DocID",
 
358
                // ModelUUID shouldn't be exported, and is inherited
 
359
                // from the model definition.
 
360
                "ModelUUID",
 
361
                // MachineId is implicit in the migration structure through containment.
 
362
                "MachineID",
 
363
                "NetworkName",
 
364
                "Ports",
 
365
                // TxnRevno isn't migrated.
 
366
                "TxnRevno",
 
367
        )
 
368
        s.AssertExportedFields(c, portsDoc{}, fields)
 
369
}
 
370
 
 
371
func (s *MigrationSuite) TestMeterStatusDocFields(c *gc.C) {
 
372
        fields := set.NewStrings(
 
373
                // DocID itself isn't migrated
 
374
                "DocID",
 
375
                // ModelUUID shouldn't be exported, and is inherited
 
376
                // from the model definition.
 
377
                "ModelUUID",
 
378
                "Code",
 
379
                "Info",
 
380
        )
 
381
        s.AssertExportedFields(c, meterStatusDoc{}, fields)
 
382
}
 
383
 
 
384
func (s *MigrationSuite) TestRelationDocFields(c *gc.C) {
 
385
        fields := set.NewStrings(
 
386
                // DocID itself isn't migrated
 
387
                "DocID",
 
388
                // ModelUUID shouldn't be exported, and is inherited
 
389
                // from the model definition.
 
390
                "ModelUUID",
 
391
                "Key",
 
392
                "Id",
 
393
                "Endpoints",
 
394
                // Life isn't exported, only alive.
 
395
                "Life",
 
396
                // UnitCount isn't explicitly exported, but defined by the stored
 
397
                // unit settings data for the relation endpoint.
 
398
                "UnitCount",
 
399
        )
 
400
        s.AssertExportedFields(c, relationDoc{}, fields)
 
401
        // We also need to check the Endpoint and nested charm.Relation field.
 
402
        endpointFields := set.NewStrings("ServiceName", "Relation")
 
403
        s.AssertExportedFields(c, Endpoint{}, endpointFields)
 
404
        charmRelationFields := set.NewStrings(
 
405
                "Name",
 
406
                "Role",
 
407
                "Interface",
 
408
                "Optional",
 
409
                "Limit",
 
410
                "Scope",
 
411
        )
 
412
        s.AssertExportedFields(c, charm.Relation{}, charmRelationFields)
 
413
}
 
414
 
 
415
func (s *MigrationSuite) TestRelationScopeDocFields(c *gc.C) {
 
416
        fields := set.NewStrings(
 
417
                // DocID itself isn't migrated
 
418
                "DocID",
 
419
                // ModelUUID shouldn't be exported, and is inherited
 
420
                // from the model definition.
 
421
                "ModelUUID",
 
422
                "Key",
 
423
                // Departing isn't exported as we only deal with live, stable systems.
 
424
                "Departing",
 
425
        )
 
426
        s.AssertExportedFields(c, relationScopeDoc{}, fields)
 
427
}
 
428
 
 
429
func (s *MigrationSuite) TestAnnatatorDocFields(c *gc.C) {
 
430
        fields := set.NewStrings(
 
431
                // ModelUUID shouldn't be exported, and is inherited
 
432
                // from the model definition.
 
433
                "ModelUUID",
 
434
                "GlobalKey",
 
435
                "Tag",
 
436
                "Annotations",
 
437
        )
 
438
        s.AssertExportedFields(c, annotatorDoc{}, fields)
 
439
}
 
440
 
 
441
func (s *MigrationSuite) TestBlockDocFields(c *gc.C) {
 
442
        ignored := set.NewStrings(
 
443
                // The doc id is a sequence value that has no meaning.
 
444
                // It really doesn't need to be a sequence.
 
445
                "DocID",
 
446
                // ModelUUID shouldn't be exported, and is inherited
 
447
                // from the model definition.
 
448
                "ModelUUID",
 
449
                // Tag is just string representation of the model tag,
 
450
                // which also contains the model-uuid.
 
451
                "Tag",
 
452
        )
 
453
        migrated := set.NewStrings(
 
454
                "Type",
 
455
                "Message",
 
456
        )
 
457
        fields := migrated.Union(ignored)
 
458
        s.AssertExportedFields(c, blockDoc{}, fields)
 
459
}
 
460
 
 
461
func (s *MigrationSuite) TestSequenceDocFields(c *gc.C) {
 
462
        fields := set.NewStrings(
 
463
                // ModelUUID shouldn't be exported, and is inherited
 
464
                // from the model definition.
 
465
                "ModelUUID",
 
466
                "DocID",
 
467
                "Name",
 
468
                "Counter",
 
469
        )
 
470
        s.AssertExportedFields(c, sequenceDoc{}, fields)
 
471
}
 
472
 
 
473
func (s *MigrationSuite) TestConstraintsDocFields(c *gc.C) {
 
474
        fields := set.NewStrings(
 
475
                // ModelUUID shouldn't be exported, and is inherited
 
476
                // from the model definition.
 
477
                "ModelUUID",
 
478
                "Arch",
 
479
                "CpuCores",
 
480
                "CpuPower",
 
481
                "Mem",
 
482
                "RootDisk",
 
483
                "InstanceType",
 
484
                "Container",
 
485
                "Tags",
 
486
                "Spaces",
 
487
                // Networks is a deprecated constraint and not exported.
 
488
                "Networks",
 
489
        )
 
490
        s.AssertExportedFields(c, constraintsDoc{}, fields)
 
491
}
 
492
 
 
493
func (s *MigrationSuite) TestHistoricalStatusDocFields(c *gc.C) {
 
494
        fields := set.NewStrings(
 
495
                // ModelUUID shouldn't be exported, and is inherited
 
496
                // from the model definition.
 
497
                "ModelUUID",
 
498
                "GlobalKey",
 
499
                "Status",
 
500
                "StatusInfo",
 
501
                "StatusData",
 
502
                "Updated",
 
503
        )
 
504
        s.AssertExportedFields(c, historicalStatusDoc{}, fields)
 
505
}
 
506
 
 
507
func (s *MigrationSuite) AssertExportedFields(c *gc.C, doc interface{}, fields set.Strings) {
 
508
        expected := getExportedFields(doc)
 
509
        unknown := expected.Difference(fields)
 
510
        removed := fields.Difference(expected)
 
511
        // If this test fails, it means that extra fields have been added to the
 
512
        // doc without thinking about the migration implications.
 
513
        c.Check(unknown, gc.HasLen, 0)
 
514
        c.Assert(removed, gc.HasLen, 0)
 
515
}
 
516
 
 
517
func getExportedFields(arg interface{}) set.Strings {
 
518
        t := reflect.TypeOf(arg)
 
519
        result := set.NewStrings()
 
520
 
 
521
        count := t.NumField()
 
522
        for i := 0; i < count; i++ {
 
523
                f := t.Field(i)
 
524
                // empty PkgPath means exported field.
 
525
                // see https://golang.org/pkg/reflect/#StructField
 
526
                if f.PkgPath == "" {
 
527
                        result.Add(f.Name)
 
528
                }
 
529
        }
 
530
 
 
531
        return result
 
532
}