github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/migration_internal_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"github.com/juju/utils/set"
     8  	gc "gopkg.in/check.v1"
     9  	"gopkg.in/juju/charm.v6-unstable"
    10  
    11  	"github.com/juju/juju/testing"
    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  		cloudimagemetadataC,
    23  		constraintsC,
    24  		modelsC,
    25  		modelUsersC,
    26  		modelUserLastConnectionC,
    27  		permissionsC,
    28  		settingsC,
    29  		sequenceC,
    30  		sshHostKeysC,
    31  		statusesC,
    32  		statusesHistoryC,
    33  
    34  		// machine
    35  		instanceDataC,
    36  		machinesC,
    37  		openedPortsC,
    38  
    39  		// application / unit
    40  		leasesC,
    41  		applicationsC,
    42  		unitsC,
    43  		meterStatusC, // red / green status for metrics of units
    44  		payloadsC,
    45  
    46  		// relation
    47  		relationsC,
    48  		relationScopesC,
    49  
    50  		// networking
    51  		ipAddressesC,
    52  		spacesC,
    53  		linkLayerDevicesC,
    54  		subnetsC,
    55  
    56  		// storage
    57  		blockDevicesC,
    58  
    59  		// cloudimagemetadata
    60  		cloudimagemetadataC,
    61  
    62  		// actions
    63  		actionsC,
    64  
    65  		// storage
    66  		filesystemsC,
    67  		filesystemAttachmentsC,
    68  		storageAttachmentsC,
    69  		storageConstraintsC,
    70  		storageInstancesC,
    71  		volumesC,
    72  		volumeAttachmentsC,
    73  	)
    74  
    75  	ignoredCollections := set.NewStrings(
    76  		// Precheck ensures that there are no cleanup docs or pending
    77  		// machine removals.
    78  		cleanupsC,
    79  		machineRemovalsC,
    80  		// The autocert cache is non-critical. After migration
    81  		// you'll just need to acquire new certificates.
    82  		autocertCacheC,
    83  		// We don't export the controller model at this stage.
    84  		controllersC,
    85  		// Clouds aren't migrated. They must exist in the
    86  		// target controller already.
    87  		cloudsC,
    88  		// Cloud credentials aren't migrated. They must exist in the
    89  		// target controller already.
    90  		cloudCredentialsC,
    91  		// This is controller global, and related to the system state of the
    92  		// embedded GUI.
    93  		guimetadataC,
    94  		// This is controller global, not migrated.
    95  		guisettingsC,
    96  		// Users aren't migrated.
    97  		usersC,
    98  		userLastLoginC,
    99  		// Controller users contain extra data about users therefore
   100  		// are not migrated either.
   101  		controllerUsersC,
   102  		// userenvnameC is just to provide a unique key constraint.
   103  		usermodelnameC,
   104  		// Metrics aren't migrated.
   105  		metricsC,
   106  		// Backup and restore information is not migrated.
   107  		restoreInfoC,
   108  		// reference counts are implementation details that should be
   109  		// reconstructed on the other side.
   110  		refcountsC,
   111  		// upgradeInfoC is used to coordinate upgrades and schema migrations,
   112  		// and aren't needed for model migrations.
   113  		upgradeInfoC,
   114  		// Not exported, but the tools will possibly need to be either bundled
   115  		// with the representation or sent separately.
   116  		toolsmetadataC,
   117  		// Bakery storage items are non-critical. We store root keys for
   118  		// temporary credentials in there; after migration you'll just have
   119  		// to log back in.
   120  		bakeryStorageItemsC,
   121  		// Transaction stuff.
   122  		"txns",
   123  		"txns.log",
   124  
   125  		// We don't import any of the migration collections.
   126  		migrationsC,
   127  		migrationsStatusC,
   128  		migrationsActiveC,
   129  		migrationsMinionSyncC,
   130  
   131  		// The container ref document is primarily there to keep track
   132  		// of a particular machine's containers. The migration format
   133  		// uses object containment for this purpose.
   134  		containerRefsC,
   135  		// The min units collection is only used to trigger a watcher
   136  		// in order to have the service add or remove units if the minimum
   137  		// number of units is changed. The Service doc has all we need
   138  		// for migratino.
   139  		minUnitsC,
   140  		// This is a transitory collection of units that need to be assigned
   141  		// to machines.
   142  		assignUnitC,
   143  
   144  		// The model entity references collection will be repopulated
   145  		// after importing the model. It does not need to be migrated
   146  		// separately.
   147  		modelEntityRefsC,
   148  
   149  		// This is marked as deprecated, and should probably be removed.
   150  		actionresultsC,
   151  
   152  		// These are recreated whilst migrating other network entities.
   153  		providerIDsC,
   154  		linkLayerDevicesRefsC,
   155  
   156  		// Recreated whilst migrating actions.
   157  		actionNotificationsC,
   158  	)
   159  
   160  	// THIS SET WILL BE REMOVED WHEN MIGRATIONS ARE COMPLETE
   161  	todoCollections := set.NewStrings(
   162  		// model configuration
   163  		globalSettingsC,
   164  
   165  		// machine
   166  		rebootC,
   167  
   168  		// service / unit
   169  		charmsC,
   170  		"resources",
   171  		endpointBindingsC,
   172  
   173  		// uncategorised
   174  		metricsManagerC, // should really be copied across
   175  		auditingC,
   176  	)
   177  
   178  	envCollections := set.NewStrings()
   179  	for name := range allCollections() {
   180  		envCollections.Add(name)
   181  	}
   182  
   183  	known := completedCollections.Union(ignoredCollections)
   184  
   185  	remainder := envCollections.Difference(known)
   186  	remainder = remainder.Difference(todoCollections)
   187  
   188  	// If this test fails, it means that a new collection has been added
   189  	// but migrations for it has not been done. This is a Bad Thing™.
   190  	// Beware, if your collection is something controller-related it might
   191  	// not need migration (such as Users or ControllerUsers) in that
   192  	// case they only need to be accounted for among the ignored collections.
   193  	c.Assert(remainder, gc.HasLen, 0)
   194  }
   195  
   196  func (s *MigrationSuite) TestModelDocFields(c *gc.C) {
   197  	fields := set.NewStrings(
   198  		// UUID and Name are constructed from the model config.
   199  		"UUID",
   200  		"Name",
   201  		// Life will always be alive, or we won't be migrating.
   202  		"Life",
   203  		// ControllerUUID is recreated when the new model
   204  		// is created in the new controller (yay name changes).
   205  		"ControllerUUID",
   206  
   207  		"MigrationMode",
   208  		"Owner",
   209  		"Cloud",
   210  		"CloudRegion",
   211  		"CloudCredential",
   212  		"LatestAvailableTools",
   213  	)
   214  	s.AssertExportedFields(c, modelDoc{}, fields)
   215  }
   216  
   217  func (s *MigrationSuite) TestUserAccessDocFields(c *gc.C) {
   218  	fields := set.NewStrings(
   219  		// ID is the same as UserName (but lowercased)
   220  		"ID",
   221  		// ObjectUUID shouldn't be exported, and is inherited
   222  		// from the model definition.
   223  		"ObjectUUID",
   224  		// Tracked fields:
   225  		"UserName",
   226  		"DisplayName",
   227  		"CreatedBy",
   228  		"DateCreated",
   229  	)
   230  	s.AssertExportedFields(c, userAccessDoc{}, fields)
   231  }
   232  
   233  func (s *MigrationSuite) TestPermissionDocFields(c *gc.C) {
   234  	fields := set.NewStrings(
   235  		"ID",
   236  		"ObjectGlobalKey",
   237  		"SubjectGlobalKey",
   238  		"Access",
   239  	)
   240  	s.AssertExportedFields(c, permissionDoc{}, fields)
   241  }
   242  
   243  func (s *MigrationSuite) TestEnvUserLastConnectionDocFields(c *gc.C) {
   244  	fields := set.NewStrings(
   245  		// ID is the same as UserName (but lowercased)
   246  		"ID",
   247  		// ModelUUID shouldn't be exported, and is inherited
   248  		// from the model definition.
   249  		"ModelUUID",
   250  		// UserName is captured in the migration.User.
   251  		"UserName",
   252  		"LastConnection",
   253  	)
   254  	s.AssertExportedFields(c, modelUserLastConnectionDoc{}, fields)
   255  }
   256  
   257  func (s *MigrationSuite) TestMachineDocFields(c *gc.C) {
   258  	ignored := set.NewStrings(
   259  		// DocID is the env + machine id
   260  		"DocID",
   261  		// ID is the machine id
   262  		"Id",
   263  		// ModelUUID shouldn't be exported, and is inherited
   264  		// from the model definition.
   265  		"ModelUUID",
   266  		// Life is always alive, confirmed by export precheck.
   267  		"Life",
   268  		// NoVote and HasVote only matter for machines with manage state job
   269  		// and we don't support migrating the controller model.
   270  		"NoVote",
   271  		"HasVote",
   272  		// Ignored at this stage, could be an issue if mongo 3.0 isn't
   273  		// available.
   274  		"StopMongoUntilVersion",
   275  	)
   276  	migrated := set.NewStrings(
   277  		"Addresses",
   278  		"ContainerType",
   279  		"Jobs",
   280  		"MachineAddresses",
   281  		"Nonce",
   282  		"PasswordHash",
   283  		"Clean",
   284  		"Volumes",
   285  		"Filesystems",
   286  		"Placement",
   287  		"PreferredPrivateAddress",
   288  		"PreferredPublicAddress",
   289  		"Principals",
   290  		"Series",
   291  		"SupportedContainers",
   292  		"SupportedContainersKnown",
   293  		"Tools",
   294  	)
   295  	s.AssertExportedFields(c, machineDoc{}, migrated.Union(ignored))
   296  }
   297  
   298  func (s *MigrationSuite) TestInstanceDataFields(c *gc.C) {
   299  	fields := set.NewStrings(
   300  		// DocID is the env + machine id
   301  		"DocID",
   302  		"MachineId",
   303  		// ModelUUID shouldn't be exported, and is inherited
   304  		// from the model definition.
   305  		"ModelUUID",
   306  
   307  		"InstanceId",
   308  		"Status",
   309  		"Arch",
   310  		"Mem",
   311  		"RootDisk",
   312  		"CpuCores",
   313  		"CpuPower",
   314  		"Tags",
   315  		"AvailZone",
   316  	)
   317  	s.AssertExportedFields(c, instanceData{}, fields)
   318  }
   319  
   320  func (s *MigrationSuite) TestApplicationDocFields(c *gc.C) {
   321  	ignored := set.NewStrings(
   322  		// DocID is the env + name
   323  		"DocID",
   324  		// ModelUUID shouldn't be exported, and is inherited
   325  		// from the model definition.
   326  		"ModelUUID",
   327  		// Always alive, not explicitly exported.
   328  		"Life",
   329  		// TxnRevno is mgo internals and should not be migrated.
   330  		"TxnRevno",
   331  		// UnitCount is handled by the number of units for the exported service.
   332  		"UnitCount",
   333  		// RelationCount is handled by the number of times the application name
   334  		// appears in relation endpoints.
   335  		"RelationCount",
   336  	)
   337  	migrated := set.NewStrings(
   338  		"Name",
   339  		"Series",
   340  		"Subordinate",
   341  		"CharmURL",
   342  		"Channel",
   343  		"CharmModifiedVersion",
   344  		"ForceCharm",
   345  		"Exposed",
   346  		"MinUnits",
   347  		"MetricCredentials",
   348  	)
   349  	s.AssertExportedFields(c, applicationDoc{}, migrated.Union(ignored))
   350  }
   351  
   352  func (s *MigrationSuite) TestUnitDocFields(c *gc.C) {
   353  	ignored := set.NewStrings(
   354  		"ModelUUID",
   355  		"DocID",
   356  		"Life",
   357  		// Application is implicit in the migration structure through containment.
   358  		"Application",
   359  		// Resolved is not migrated as we check that all is good before we start.
   360  		"Resolved",
   361  		// Series and CharmURL also come from the service.
   362  		"Series",
   363  		"CharmURL",
   364  		"TxnRevno",
   365  	)
   366  	migrated := set.NewStrings(
   367  		"Name",
   368  		"Principal",
   369  		"Subordinates",
   370  		"StorageAttachmentCount",
   371  		"MachineId",
   372  		"Tools",
   373  		"PasswordHash",
   374  	)
   375  	s.AssertExportedFields(c, unitDoc{}, migrated.Union(ignored))
   376  }
   377  
   378  func (s *MigrationSuite) TestPortsDocFields(c *gc.C) {
   379  	fields := set.NewStrings(
   380  		// DocID itself isn't migrated
   381  		"DocID",
   382  		// ModelUUID shouldn't be exported, and is inherited
   383  		// from the model definition.
   384  		"ModelUUID",
   385  		// MachineID is implicit in the migration structure through containment.
   386  		"MachineID",
   387  		"SubnetID",
   388  		"Ports",
   389  		// TxnRevno isn't migrated.
   390  		"TxnRevno",
   391  	)
   392  	s.AssertExportedFields(c, portsDoc{}, fields)
   393  }
   394  
   395  func (s *MigrationSuite) TestMeterStatusDocFields(c *gc.C) {
   396  	fields := set.NewStrings(
   397  		// DocID itself isn't migrated
   398  		"DocID",
   399  		// ModelUUID shouldn't be exported, and is inherited
   400  		// from the model definition.
   401  		"ModelUUID",
   402  		"Code",
   403  		"Info",
   404  	)
   405  	s.AssertExportedFields(c, meterStatusDoc{}, fields)
   406  }
   407  
   408  func (s *MigrationSuite) TestRelationDocFields(c *gc.C) {
   409  	fields := set.NewStrings(
   410  		// DocID itself isn't migrated
   411  		"DocID",
   412  		// ModelUUID shouldn't be exported, and is inherited
   413  		// from the model definition.
   414  		"ModelUUID",
   415  		"Key",
   416  		"Id",
   417  		"Endpoints",
   418  		// Life isn't exported, only alive.
   419  		"Life",
   420  		// UnitCount isn't explicitly exported, but defined by the stored
   421  		// unit settings data for the relation endpoint.
   422  		"UnitCount",
   423  	)
   424  	s.AssertExportedFields(c, relationDoc{}, fields)
   425  	// We also need to check the Endpoint and nested charm.Relation field.
   426  	endpointFields := set.NewStrings("ApplicationName", "Relation")
   427  	s.AssertExportedFields(c, Endpoint{}, endpointFields)
   428  	charmRelationFields := set.NewStrings(
   429  		"Name",
   430  		"Role",
   431  		"Interface",
   432  		"Optional",
   433  		"Limit",
   434  		"Scope",
   435  	)
   436  	s.AssertExportedFields(c, charm.Relation{}, charmRelationFields)
   437  }
   438  
   439  func (s *MigrationSuite) TestRelationScopeDocFields(c *gc.C) {
   440  	fields := set.NewStrings(
   441  		// DocID itself isn't migrated
   442  		"DocID",
   443  		// ModelUUID shouldn't be exported, and is inherited
   444  		// from the model definition.
   445  		"ModelUUID",
   446  		"Key",
   447  		// Departing isn't exported as we only deal with live, stable systems.
   448  		"Departing",
   449  	)
   450  	s.AssertExportedFields(c, relationScopeDoc{}, fields)
   451  }
   452  
   453  func (s *MigrationSuite) TestAnnatatorDocFields(c *gc.C) {
   454  	fields := set.NewStrings(
   455  		// ModelUUID shouldn't be exported, and is inherited
   456  		// from the model definition.
   457  		"ModelUUID",
   458  		"GlobalKey",
   459  		"Tag",
   460  		"Annotations",
   461  	)
   462  	s.AssertExportedFields(c, annotatorDoc{}, fields)
   463  }
   464  
   465  func (s *MigrationSuite) TestBlockDocFields(c *gc.C) {
   466  	ignored := set.NewStrings(
   467  		// The doc id is a sequence value that has no meaning.
   468  		// It really doesn't need to be a sequence.
   469  		"DocID",
   470  		// ModelUUID shouldn't be exported, and is inherited
   471  		// from the model definition.
   472  		"ModelUUID",
   473  		// Tag is just string representation of the model tag,
   474  		// which also contains the model-uuid.
   475  		"Tag",
   476  	)
   477  	migrated := set.NewStrings(
   478  		"Type",
   479  		"Message",
   480  	)
   481  	fields := migrated.Union(ignored)
   482  	s.AssertExportedFields(c, blockDoc{}, fields)
   483  }
   484  
   485  func (s *MigrationSuite) TestSequenceDocFields(c *gc.C) {
   486  	fields := set.NewStrings(
   487  		// ModelUUID shouldn't be exported, and is inherited
   488  		// from the model definition.
   489  		"ModelUUID",
   490  		"DocID",
   491  		"Name",
   492  		"Counter",
   493  	)
   494  	s.AssertExportedFields(c, sequenceDoc{}, fields)
   495  }
   496  
   497  func (s *MigrationSuite) TestConstraintsDocFields(c *gc.C) {
   498  	fields := set.NewStrings(
   499  		// ModelUUID shouldn't be exported, and is inherited
   500  		// from the model definition.
   501  		"ModelUUID",
   502  		"Arch",
   503  		"CpuCores",
   504  		"CpuPower",
   505  		"Mem",
   506  		"RootDisk",
   507  		"InstanceType",
   508  		"Container",
   509  		"Tags",
   510  		"Spaces",
   511  		"VirtType",
   512  	)
   513  	s.AssertExportedFields(c, constraintsDoc{}, fields)
   514  }
   515  
   516  func (s *MigrationSuite) TestHistoricalStatusDocFields(c *gc.C) {
   517  	fields := set.NewStrings(
   518  		// ModelUUID shouldn't be exported, and is inherited
   519  		// from the model definition.
   520  		"ModelUUID",
   521  		"GlobalKey",
   522  		"Status",
   523  		"StatusInfo",
   524  		"StatusData",
   525  		"Updated",
   526  	)
   527  	s.AssertExportedFields(c, historicalStatusDoc{}, fields)
   528  }
   529  
   530  func (s *MigrationSuite) TestSpaceDocFields(c *gc.C) {
   531  	ignored := set.NewStrings(
   532  		// Always alive, not explicitly exported.
   533  		"Life",
   534  	)
   535  	migrated := set.NewStrings(
   536  		"Name",
   537  		"IsPublic",
   538  		"ProviderId",
   539  	)
   540  	s.AssertExportedFields(c, spaceDoc{}, migrated.Union(ignored))
   541  }
   542  
   543  func (s *MigrationSuite) TestBlockDeviceFields(c *gc.C) {
   544  	ignored := set.NewStrings(
   545  		"DocID",
   546  		"ModelUUID",
   547  		// We manage machine through containment.
   548  		"Machine",
   549  	)
   550  	migrated := set.NewStrings(
   551  		"BlockDevices",
   552  	)
   553  	s.AssertExportedFields(c, blockDevicesDoc{}, migrated.Union(ignored))
   554  	// The meat is in the type stored in "BlockDevices".
   555  	migrated = set.NewStrings(
   556  		"DeviceName",
   557  		"DeviceLinks",
   558  		"Label",
   559  		"UUID",
   560  		"HardwareId",
   561  		"BusAddress",
   562  		"Size",
   563  		"FilesystemType",
   564  		"InUse",
   565  		"MountPoint",
   566  	)
   567  	s.AssertExportedFields(c, BlockDeviceInfo{}, migrated)
   568  }
   569  
   570  func (s *MigrationSuite) TestSubnetDocFields(c *gc.C) {
   571  	ignored := set.NewStrings(
   572  		// DocID is the env + name
   573  		"DocID",
   574  		// ModelUUID shouldn't be exported, and is inherited
   575  		// from the model definition.
   576  		"ModelUUID",
   577  		// Always alive, not explicitly exported.
   578  		"Life",
   579  
   580  		// Currently unused (never set or exposed).
   581  		"IsPublic",
   582  	)
   583  	migrated := set.NewStrings(
   584  		"CIDR",
   585  		"VLANTag",
   586  		"SpaceName",
   587  		"ProviderId",
   588  		"AvailabilityZone",
   589  	)
   590  	s.AssertExportedFields(c, subnetDoc{}, migrated.Union(ignored))
   591  }
   592  
   593  func (s *MigrationSuite) TestIPAddressDocFields(c *gc.C) {
   594  	ignored := set.NewStrings(
   595  		"DocID",
   596  		"ModelUUID",
   597  	)
   598  	migrated := set.NewStrings(
   599  		"DeviceName",
   600  		"MachineID",
   601  		"DNSSearchDomains",
   602  		"GatewayAddress",
   603  		"ProviderID",
   604  		"DNSServers",
   605  		"SubnetCIDR",
   606  		"ConfigMethod",
   607  		"Value",
   608  	)
   609  	s.AssertExportedFields(c, ipAddressDoc{}, migrated.Union(ignored))
   610  }
   611  
   612  func (s *MigrationSuite) TestLinkLayerDeviceDocFields(c *gc.C) {
   613  	ignored := set.NewStrings(
   614  		"ModelUUID",
   615  		"DocID",
   616  	)
   617  	migrated := set.NewStrings(
   618  		"MachineID",
   619  		"ProviderID",
   620  		"Name",
   621  		"MTU",
   622  		"Type",
   623  		"MACAddress",
   624  		"IsAutoStart",
   625  		"IsUp",
   626  		"ParentName",
   627  	)
   628  	s.AssertExportedFields(c, linkLayerDeviceDoc{}, migrated.Union(ignored))
   629  }
   630  
   631  func (s *MigrationSuite) TestSSHHostKeyDocFields(c *gc.C) {
   632  	ignored := set.NewStrings()
   633  	migrated := set.NewStrings(
   634  		"Keys",
   635  	)
   636  	s.AssertExportedFields(c, sshHostKeysDoc{}, migrated.Union(ignored))
   637  }
   638  
   639  func (s *MigrationSuite) TestActionDocFields(c *gc.C) {
   640  	ignored := set.NewStrings(
   641  		"ModelUUID",
   642  	)
   643  	migrated := set.NewStrings(
   644  		"DocId",
   645  		"Receiver",
   646  		"Name",
   647  		"Enqueued",
   648  		"Started",
   649  		"Completed",
   650  		"Parameters",
   651  		"Results",
   652  		"Message",
   653  		"Status",
   654  	)
   655  	s.AssertExportedFields(c, actionDoc{}, migrated.Union(ignored))
   656  }
   657  
   658  func (s *MigrationSuite) TestVolumeDocFields(c *gc.C) {
   659  	ignored := set.NewStrings(
   660  		"ModelUUID",
   661  		"DocID",
   662  		"Life",
   663  	)
   664  	migrated := set.NewStrings(
   665  		"Name",
   666  		"StorageId",
   667  		"AttachmentCount", // through count of attachment instances
   668  		"Binding",
   669  		"Info",
   670  		"Params",
   671  	)
   672  	s.AssertExportedFields(c, volumeDoc{}, migrated.Union(ignored))
   673  	// The info and params fields ar structs.
   674  	s.AssertExportedFields(c, VolumeInfo{}, set.NewStrings(
   675  		"HardwareId", "Size", "Pool", "VolumeId", "Persistent"))
   676  	s.AssertExportedFields(c, VolumeParams{}, set.NewStrings(
   677  		"Size", "Pool"))
   678  }
   679  
   680  func (s *MigrationSuite) TestVolumeAttachmentDocFields(c *gc.C) {
   681  	ignored := set.NewStrings(
   682  		"ModelUUID",
   683  		"DocID",
   684  		"Life",
   685  	)
   686  	migrated := set.NewStrings(
   687  		"Volume",
   688  		"Machine",
   689  		"Info",
   690  		"Params",
   691  	)
   692  	s.AssertExportedFields(c, volumeAttachmentDoc{}, migrated.Union(ignored))
   693  	// The info and params fields ar structs.
   694  	s.AssertExportedFields(c, VolumeAttachmentInfo{}, set.NewStrings(
   695  		"DeviceName", "DeviceLink", "BusAddress", "ReadOnly"))
   696  	s.AssertExportedFields(c, VolumeAttachmentParams{}, set.NewStrings(
   697  		"ReadOnly"))
   698  }
   699  
   700  func (s *MigrationSuite) TestFilesystemDocFields(c *gc.C) {
   701  	ignored := set.NewStrings(
   702  		"ModelUUID",
   703  		"DocID",
   704  		"Life",
   705  	)
   706  	migrated := set.NewStrings(
   707  		"FilesystemId",
   708  		"StorageId",
   709  		"VolumeId",
   710  		"AttachmentCount", // through count of attachment instances
   711  		"Binding",
   712  		"Info",
   713  		"Params",
   714  	)
   715  	s.AssertExportedFields(c, filesystemDoc{}, migrated.Union(ignored))
   716  	// The info and params fields ar structs.
   717  	s.AssertExportedFields(c, FilesystemInfo{}, set.NewStrings(
   718  		"Size", "Pool", "FilesystemId"))
   719  	s.AssertExportedFields(c, FilesystemParams{}, set.NewStrings(
   720  		"Size", "Pool"))
   721  }
   722  
   723  func (s *MigrationSuite) TestFilesystemAttachmentDocFields(c *gc.C) {
   724  	ignored := set.NewStrings(
   725  		"ModelUUID",
   726  		"DocID",
   727  		"Life",
   728  	)
   729  	migrated := set.NewStrings(
   730  		"Filesystem",
   731  		"Machine",
   732  		"Info",
   733  		"Params",
   734  	)
   735  	s.AssertExportedFields(c, filesystemAttachmentDoc{}, migrated.Union(ignored))
   736  	// The info and params fields ar structs.
   737  	s.AssertExportedFields(c, FilesystemAttachmentInfo{}, set.NewStrings(
   738  		"MountPoint", "ReadOnly"))
   739  	s.AssertExportedFields(c, FilesystemAttachmentParams{}, set.NewStrings(
   740  		"Location", "ReadOnly"))
   741  }
   742  
   743  func (s *MigrationSuite) TestStorageInstanceDocFields(c *gc.C) {
   744  	ignored := set.NewStrings(
   745  		"ModelUUID",
   746  		"DocID",
   747  		"Life",
   748  	)
   749  	migrated := set.NewStrings(
   750  		"Id",
   751  		"Kind",
   752  		"Owner",
   753  		"StorageName",
   754  		"AttachmentCount", // through count of attachment instances
   755  	)
   756  	s.AssertExportedFields(c, storageInstanceDoc{}, migrated.Union(ignored))
   757  }
   758  
   759  func (s *MigrationSuite) TestStorageAttachmentDocFields(c *gc.C) {
   760  	ignored := set.NewStrings(
   761  		"ModelUUID",
   762  		"DocID",
   763  		"Life",
   764  	)
   765  	migrated := set.NewStrings(
   766  		"Unit",
   767  		"StorageInstance",
   768  	)
   769  	s.AssertExportedFields(c, storageAttachmentDoc{}, migrated.Union(ignored))
   770  }
   771  
   772  func (s *MigrationSuite) TestStorageConstraintsDocFields(c *gc.C) {
   773  	ignored := set.NewStrings(
   774  		"ModelUUID",
   775  		"DocID",
   776  	)
   777  	migrated := set.NewStrings(
   778  		"Constraints",
   779  	)
   780  	s.AssertExportedFields(c, storageConstraintsDoc{}, migrated.Union(ignored))
   781  }
   782  
   783  func (s *MigrationSuite) TestPayloadDocFields(c *gc.C) {
   784  	definedThroughContainment := set.NewStrings(
   785  		"UnitID",
   786  		"MachineID",
   787  	)
   788  	migrated := set.NewStrings(
   789  		"Name",
   790  		"Type",
   791  		"RawID",
   792  		"State",
   793  		"Labels",
   794  	)
   795  	s.AssertExportedFields(c, payloadDoc{}, migrated.Union(definedThroughContainment))
   796  }
   797  
   798  func (s *MigrationSuite) AssertExportedFields(c *gc.C, doc interface{}, fields set.Strings) {
   799  	expected := testing.GetExportedFields(doc)
   800  	unknown := expected.Difference(fields)
   801  	removed := fields.Difference(expected)
   802  	// If this test fails, it means that extra fields have been added to the
   803  	// doc without thinking about the migration implications.
   804  	c.Check(unknown, gc.HasLen, 0)
   805  	c.Assert(removed, gc.HasLen, 0)
   806  }