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

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"math/rand"
     8  	"time"
     9  
    10  	jc "github.com/juju/testing/checkers"
    11  	"github.com/juju/version"
    12  	gc "gopkg.in/check.v1"
    13  	"gopkg.in/juju/charm.v6-unstable"
    14  	"gopkg.in/juju/names.v2"
    15  
    16  	"github.com/juju/juju/constraints"
    17  	"github.com/juju/juju/core/description"
    18  	"github.com/juju/juju/network"
    19  	"github.com/juju/juju/payload"
    20  	"github.com/juju/juju/permission"
    21  	"github.com/juju/juju/provider/dummy"
    22  	"github.com/juju/juju/state"
    23  	"github.com/juju/juju/state/cloudimagemetadata"
    24  	"github.com/juju/juju/status"
    25  	"github.com/juju/juju/storage/poolmanager"
    26  	"github.com/juju/juju/storage/provider"
    27  	"github.com/juju/juju/testing/factory"
    28  )
    29  
    30  // Constraints stores megabytes by default for memory and root disk.
    31  const (
    32  	gig uint64 = 1024
    33  
    34  	addedHistoryCount = 5
    35  	// 6 for the one initial + 5 added.
    36  	expectedHistoryCount = addedHistoryCount + 1
    37  )
    38  
    39  var testAnnotations = map[string]string{
    40  	"string":  "value",
    41  	"another": "one",
    42  }
    43  
    44  type MigrationBaseSuite struct {
    45  	ConnWithWallclockSuite
    46  }
    47  
    48  func (s *MigrationBaseSuite) setLatestTools(c *gc.C, latestTools version.Number) {
    49  	dbModel, err := s.State.Model()
    50  	c.Assert(err, jc.ErrorIsNil)
    51  	err = dbModel.UpdateLatestToolsVersion(latestTools)
    52  	c.Assert(err, jc.ErrorIsNil)
    53  }
    54  
    55  func (s *MigrationBaseSuite) setRandSequenceValue(c *gc.C, name string) int {
    56  	var value int
    57  	var err error
    58  	count := rand.Intn(5) + 1
    59  	for i := 0; i < count; i++ {
    60  		value, err = state.Sequence(s.State, name)
    61  		c.Assert(err, jc.ErrorIsNil)
    62  	}
    63  	// The value stored in the doc is one higher than what it returns.
    64  	return value + 1
    65  }
    66  
    67  func (s *MigrationBaseSuite) primeStatusHistory(c *gc.C, entity statusSetter, statusVal status.Status, count int) {
    68  	primeStatusHistory(c, entity, statusVal, count, func(i int) map[string]interface{} {
    69  		return map[string]interface{}{"index": count - i}
    70  	}, 0)
    71  }
    72  
    73  func (s *MigrationBaseSuite) makeApplicationWithLeader(c *gc.C, applicationname string, count int, leader int) {
    74  	c.Assert(leader < count, jc.IsTrue)
    75  	units := make([]*state.Unit, count)
    76  	application := s.Factory.MakeApplication(c, &factory.ApplicationParams{
    77  		Name: applicationname,
    78  		Charm: s.Factory.MakeCharm(c, &factory.CharmParams{
    79  			Name: applicationname,
    80  		}),
    81  	})
    82  	for i := 0; i < count; i++ {
    83  		units[i] = s.Factory.MakeUnit(c, &factory.UnitParams{
    84  			Application: application,
    85  		})
    86  	}
    87  	err := s.State.LeadershipClaimer().ClaimLeadership(
    88  		application.Name(),
    89  		units[leader].Name(),
    90  		time.Minute)
    91  	c.Assert(err, jc.ErrorIsNil)
    92  }
    93  
    94  func (s *MigrationBaseSuite) makeUnitWithStorage(c *gc.C) (*state.Application, *state.Unit, names.StorageTag) {
    95  	pool := "loop-pool"
    96  	kind := "block"
    97  	// Create a default pool for block devices.
    98  	pm := poolmanager.New(state.NewStateSettings(s.State), dummy.StorageProviders())
    99  	_, err := pm.Create(pool, provider.LoopProviderType, map[string]interface{}{})
   100  	c.Assert(err, jc.ErrorIsNil)
   101  
   102  	// There are test charms called "storage-block" and
   103  	// "storage-filesystem" which are what you'd expect.
   104  	ch := s.AddTestingCharm(c, "storage-"+kind)
   105  	storage := map[string]state.StorageConstraints{
   106  		"data": makeStorageCons(pool, 1024, 1),
   107  	}
   108  	service := s.AddTestingServiceWithStorage(c, "storage-"+kind, ch, storage)
   109  	unit, err := service.AddUnit()
   110  
   111  	machine := s.Factory.MakeMachine(c, nil)
   112  	err = unit.AssignToMachine(machine)
   113  	c.Assert(err, jc.ErrorIsNil)
   114  
   115  	c.Assert(err, jc.ErrorIsNil)
   116  	storageTag := names.NewStorageTag("data/0")
   117  	agentVersion := version.MustParseBinary("2.0.1-quantal-and64")
   118  	err = unit.SetAgentVersion(agentVersion)
   119  	c.Assert(err, jc.ErrorIsNil)
   120  	return service, unit, storageTag
   121  }
   122  
   123  type MigrationExportSuite struct {
   124  	MigrationBaseSuite
   125  }
   126  
   127  var _ = gc.Suite(&MigrationExportSuite{})
   128  
   129  func (s *MigrationExportSuite) checkStatusHistory(c *gc.C, history []description.Status, statusVal status.Status) {
   130  	for i, st := range history {
   131  		c.Logf("status history #%d: %s", i, st.Updated())
   132  		c.Check(st.Value(), gc.Equals, string(statusVal))
   133  		c.Check(st.Message(), gc.Equals, "")
   134  		c.Check(st.Data(), jc.DeepEquals, map[string]interface{}{"index": i + 1})
   135  	}
   136  }
   137  
   138  func (s *MigrationExportSuite) TestModelInfo(c *gc.C) {
   139  	stModel, err := s.State.Model()
   140  	c.Assert(err, jc.ErrorIsNil)
   141  	err = s.State.SetAnnotations(stModel, testAnnotations)
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	latestTools := version.MustParse("2.0.1")
   144  	s.setLatestTools(c, latestTools)
   145  	err = s.State.SetModelConstraints(constraints.MustParse("arch=amd64 mem=8G"))
   146  	c.Assert(err, jc.ErrorIsNil)
   147  	machineSeq := s.setRandSequenceValue(c, "machine")
   148  	fooSeq := s.setRandSequenceValue(c, "application-foo")
   149  	s.State.SwitchBlockOn(state.ChangeBlock, "locked down")
   150  
   151  	model, err := s.State.Export()
   152  	c.Assert(err, jc.ErrorIsNil)
   153  
   154  	dbModel, err := s.State.Model()
   155  	c.Assert(err, jc.ErrorIsNil)
   156  	c.Assert(model.Tag(), gc.Equals, dbModel.ModelTag())
   157  	c.Assert(model.Owner(), gc.Equals, dbModel.Owner())
   158  	dbModelCfg, err := dbModel.Config()
   159  	c.Assert(err, jc.ErrorIsNil)
   160  	modelAttrs := dbModelCfg.AllAttrs()
   161  	modelCfg := model.Config()
   162  	// Config as read from state has resources tags coerced to a map.
   163  	modelCfg["resource-tags"] = map[string]string{}
   164  	c.Assert(modelCfg, jc.DeepEquals, modelAttrs)
   165  	c.Assert(model.LatestToolsVersion(), gc.Equals, latestTools)
   166  	c.Assert(model.Annotations(), jc.DeepEquals, testAnnotations)
   167  	constraints := model.Constraints()
   168  	c.Assert(constraints, gc.NotNil)
   169  	c.Assert(constraints.Architecture(), gc.Equals, "amd64")
   170  	c.Assert(constraints.Memory(), gc.Equals, 8*gig)
   171  	c.Assert(model.Sequences(), jc.DeepEquals, map[string]int{
   172  		"machine":         machineSeq,
   173  		"application-foo": fooSeq,
   174  		// blocks is added by the switch block on call above.
   175  		"block": 1,
   176  	})
   177  	c.Assert(model.Blocks(), jc.DeepEquals, map[string]string{
   178  		"all-changes": "locked down",
   179  	})
   180  }
   181  
   182  func (s *MigrationExportSuite) TestModelUsers(c *gc.C) {
   183  	// Make sure we have some last connection times for the admin user,
   184  	// and create a few other users.
   185  	lastConnection := s.State.NowToTheSecond()
   186  	owner, err := s.State.UserAccess(s.Owner, s.State.ModelTag())
   187  	c.Assert(err, jc.ErrorIsNil)
   188  	err = state.UpdateModelUserLastConnection(s.State, owner, lastConnection)
   189  	c.Assert(err, jc.ErrorIsNil)
   190  
   191  	bobTag := names.NewUserTag("bob@external")
   192  	bob, err := s.State.AddModelUser(s.State.ModelUUID(), state.UserAccessSpec{
   193  		User:      bobTag,
   194  		CreatedBy: s.Owner,
   195  		Access:    permission.ReadAccess,
   196  	})
   197  	c.Assert(err, jc.ErrorIsNil)
   198  	err = state.UpdateModelUserLastConnection(s.State, bob, lastConnection)
   199  	c.Assert(err, jc.ErrorIsNil)
   200  
   201  	model, err := s.State.Export()
   202  	c.Assert(err, jc.ErrorIsNil)
   203  
   204  	users := model.Users()
   205  	c.Assert(users, gc.HasLen, 2)
   206  
   207  	exportedBob := users[0]
   208  	// admin is "test-admin", and results are sorted
   209  	exportedAdmin := users[1]
   210  
   211  	c.Assert(exportedAdmin.Name(), gc.Equals, s.Owner)
   212  	c.Assert(exportedAdmin.DisplayName(), gc.Equals, owner.DisplayName)
   213  	c.Assert(exportedAdmin.CreatedBy(), gc.Equals, s.Owner)
   214  	c.Assert(exportedAdmin.DateCreated(), gc.Equals, owner.DateCreated)
   215  	c.Assert(exportedAdmin.LastConnection(), gc.Equals, lastConnection)
   216  	c.Assert(exportedAdmin.Access(), gc.Equals, "admin")
   217  
   218  	c.Assert(exportedBob.Name(), gc.Equals, bobTag)
   219  	c.Assert(exportedBob.DisplayName(), gc.Equals, "")
   220  	c.Assert(exportedBob.CreatedBy(), gc.Equals, s.Owner)
   221  	c.Assert(exportedBob.DateCreated(), gc.Equals, bob.DateCreated)
   222  	c.Assert(exportedBob.LastConnection(), gc.Equals, lastConnection)
   223  	c.Assert(exportedBob.Access(), gc.Equals, "read")
   224  }
   225  
   226  func (s *MigrationExportSuite) TestMachines(c *gc.C) {
   227  	s.assertMachinesMigrated(c, constraints.MustParse("arch=amd64 mem=8G"))
   228  }
   229  
   230  func (s *MigrationExportSuite) TestMachinesWithVirtConstraint(c *gc.C) {
   231  	s.assertMachinesMigrated(c, constraints.MustParse("arch=amd64 mem=8G virt-type=kvm"))
   232  }
   233  
   234  func (s *MigrationExportSuite) assertMachinesMigrated(c *gc.C, cons constraints.Value) {
   235  	// Add a machine with an LXC container.
   236  	machine1 := s.Factory.MakeMachine(c, &factory.MachineParams{
   237  		Constraints: cons,
   238  	})
   239  	nested := s.Factory.MakeMachineNested(c, machine1.Id(), nil)
   240  	err := s.State.SetAnnotations(machine1, testAnnotations)
   241  	c.Assert(err, jc.ErrorIsNil)
   242  	s.primeStatusHistory(c, machine1, status.Started, addedHistoryCount)
   243  
   244  	model, err := s.State.Export()
   245  	c.Assert(err, jc.ErrorIsNil)
   246  
   247  	machines := model.Machines()
   248  	c.Assert(machines, gc.HasLen, 1)
   249  
   250  	exported := machines[0]
   251  	c.Assert(exported.Tag(), gc.Equals, machine1.MachineTag())
   252  	c.Assert(exported.Series(), gc.Equals, machine1.Series())
   253  	c.Assert(exported.Annotations(), jc.DeepEquals, testAnnotations)
   254  	constraints := exported.Constraints()
   255  	c.Assert(constraints, gc.NotNil)
   256  	c.Assert(constraints.Architecture(), gc.Equals, *cons.Arch)
   257  	c.Assert(constraints.Memory(), gc.Equals, *cons.Mem)
   258  	if cons.HasVirtType() {
   259  		c.Assert(constraints.VirtType(), gc.Equals, *cons.VirtType)
   260  	}
   261  
   262  	tools, err := machine1.AgentTools()
   263  	c.Assert(err, jc.ErrorIsNil)
   264  	exTools := exported.Tools()
   265  	c.Assert(exTools, gc.NotNil)
   266  	c.Assert(exTools.Version(), jc.DeepEquals, tools.Version)
   267  
   268  	history := exported.StatusHistory()
   269  	c.Assert(history, gc.HasLen, expectedHistoryCount)
   270  	s.checkStatusHistory(c, history[:addedHistoryCount], status.Started)
   271  
   272  	containers := exported.Containers()
   273  	c.Assert(containers, gc.HasLen, 1)
   274  	container := containers[0]
   275  	c.Assert(container.Tag(), gc.Equals, nested.MachineTag())
   276  }
   277  
   278  func (s *MigrationExportSuite) TestMachineDevices(c *gc.C) {
   279  	machine := s.Factory.MakeMachine(c, nil)
   280  	// Create two devices, first with all fields set, second just to show that
   281  	// we do both.
   282  	sda := state.BlockDeviceInfo{
   283  		DeviceName:     "sda",
   284  		DeviceLinks:    []string{"some", "data"},
   285  		Label:          "sda-label",
   286  		UUID:           "some-uuid",
   287  		HardwareId:     "magic",
   288  		BusAddress:     "bus stop",
   289  		Size:           16 * 1024 * 1024 * 1024,
   290  		FilesystemType: "ext4",
   291  		InUse:          true,
   292  		MountPoint:     "/",
   293  	}
   294  	sdb := state.BlockDeviceInfo{DeviceName: "sdb", MountPoint: "/var/lib/lxd"}
   295  	err := machine.SetMachineBlockDevices(sda, sdb)
   296  	c.Assert(err, jc.ErrorIsNil)
   297  
   298  	model, err := s.State.Export()
   299  	c.Assert(err, jc.ErrorIsNil)
   300  	machines := model.Machines()
   301  	c.Assert(machines, gc.HasLen, 1)
   302  	exported := machines[0]
   303  
   304  	devices := exported.BlockDevices()
   305  	c.Assert(devices, gc.HasLen, 2)
   306  	ex1, ex2 := devices[0], devices[1]
   307  
   308  	c.Check(ex1.Name(), gc.Equals, "sda")
   309  	c.Check(ex1.Links(), jc.DeepEquals, []string{"some", "data"})
   310  	c.Check(ex1.Label(), gc.Equals, "sda-label")
   311  	c.Check(ex1.UUID(), gc.Equals, "some-uuid")
   312  	c.Check(ex1.HardwareID(), gc.Equals, "magic")
   313  	c.Check(ex1.BusAddress(), gc.Equals, "bus stop")
   314  	c.Check(ex1.Size(), gc.Equals, uint64(16*1024*1024*1024))
   315  	c.Check(ex1.FilesystemType(), gc.Equals, "ext4")
   316  	c.Check(ex1.InUse(), jc.IsTrue)
   317  	c.Check(ex1.MountPoint(), gc.Equals, "/")
   318  
   319  	c.Check(ex2.Name(), gc.Equals, "sdb")
   320  	c.Check(ex2.MountPoint(), gc.Equals, "/var/lib/lxd")
   321  }
   322  
   323  func (s *MigrationExportSuite) TestApplications(c *gc.C) {
   324  	s.assertMigrateApplications(c, constraints.MustParse("arch=amd64 mem=8G"))
   325  }
   326  
   327  func (s *MigrationExportSuite) TestApplicationsWithVirtConstraint(c *gc.C) {
   328  	s.assertMigrateApplications(c, constraints.MustParse("arch=amd64 mem=8G virt-type=kvm"))
   329  }
   330  
   331  func (s *MigrationExportSuite) assertMigrateApplications(c *gc.C, cons constraints.Value) {
   332  	application := s.Factory.MakeApplication(c, &factory.ApplicationParams{
   333  		Settings: map[string]interface{}{
   334  			"foo": "bar",
   335  		},
   336  		Constraints: cons,
   337  	})
   338  	err := application.UpdateLeaderSettings(&goodToken{}, map[string]string{
   339  		"leader": "true",
   340  	})
   341  	c.Assert(err, jc.ErrorIsNil)
   342  	err = application.SetMetricCredentials([]byte("sekrit"))
   343  	c.Assert(err, jc.ErrorIsNil)
   344  	err = s.State.SetAnnotations(application, testAnnotations)
   345  	c.Assert(err, jc.ErrorIsNil)
   346  	s.primeStatusHistory(c, application, status.Active, addedHistoryCount)
   347  
   348  	model, err := s.State.Export()
   349  	c.Assert(err, jc.ErrorIsNil)
   350  
   351  	applications := model.Applications()
   352  	c.Assert(applications, gc.HasLen, 1)
   353  
   354  	exported := applications[0]
   355  	c.Assert(exported.Name(), gc.Equals, application.Name())
   356  	c.Assert(exported.Tag(), gc.Equals, application.ApplicationTag())
   357  	c.Assert(exported.Series(), gc.Equals, application.Series())
   358  	c.Assert(exported.Annotations(), jc.DeepEquals, testAnnotations)
   359  
   360  	c.Assert(exported.Settings(), jc.DeepEquals, map[string]interface{}{
   361  		"foo": "bar",
   362  	})
   363  	c.Assert(exported.LeadershipSettings(), jc.DeepEquals, map[string]interface{}{
   364  		"leader": "true",
   365  	})
   366  	c.Assert(exported.MetricsCredentials(), jc.DeepEquals, []byte("sekrit"))
   367  
   368  	constraints := exported.Constraints()
   369  	c.Assert(constraints, gc.NotNil)
   370  	c.Assert(constraints.Architecture(), gc.Equals, *cons.Arch)
   371  	c.Assert(constraints.Memory(), gc.Equals, *cons.Mem)
   372  	if cons.HasVirtType() {
   373  		c.Assert(constraints.VirtType(), gc.Equals, *cons.VirtType)
   374  	}
   375  
   376  	history := exported.StatusHistory()
   377  	c.Assert(history, gc.HasLen, expectedHistoryCount)
   378  	s.checkStatusHistory(c, history[:addedHistoryCount], status.Active)
   379  }
   380  
   381  func (s *MigrationExportSuite) TestMultipleApplications(c *gc.C) {
   382  	s.Factory.MakeApplication(c, &factory.ApplicationParams{Name: "first"})
   383  	s.Factory.MakeApplication(c, &factory.ApplicationParams{Name: "second"})
   384  	s.Factory.MakeApplication(c, &factory.ApplicationParams{Name: "third"})
   385  
   386  	model, err := s.State.Export()
   387  	c.Assert(err, jc.ErrorIsNil)
   388  
   389  	applications := model.Applications()
   390  	c.Assert(applications, gc.HasLen, 3)
   391  }
   392  
   393  func (s *MigrationExportSuite) TestUnits(c *gc.C) {
   394  	unit := s.Factory.MakeUnit(c, &factory.UnitParams{
   395  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
   396  	})
   397  	err := unit.SetMeterStatus("GREEN", "some info")
   398  	c.Assert(err, jc.ErrorIsNil)
   399  	for _, version := range []string{"garnet", "amethyst", "pearl", "steven"} {
   400  		err = unit.SetWorkloadVersion(version)
   401  		c.Assert(err, jc.ErrorIsNil)
   402  	}
   403  	err = s.State.SetAnnotations(unit, testAnnotations)
   404  	c.Assert(err, jc.ErrorIsNil)
   405  	s.primeStatusHistory(c, unit, status.Active, addedHistoryCount)
   406  	s.primeStatusHistory(c, unit.Agent(), status.Idle, addedHistoryCount)
   407  
   408  	model, err := s.State.Export()
   409  	c.Assert(err, jc.ErrorIsNil)
   410  
   411  	applications := model.Applications()
   412  	c.Assert(applications, gc.HasLen, 1)
   413  
   414  	application := applications[0]
   415  	units := application.Units()
   416  	c.Assert(units, gc.HasLen, 1)
   417  
   418  	exported := units[0]
   419  
   420  	c.Assert(exported.Name(), gc.Equals, unit.Name())
   421  	c.Assert(exported.Tag(), gc.Equals, unit.UnitTag())
   422  	c.Assert(exported.Validate(), jc.ErrorIsNil)
   423  	c.Assert(exported.MeterStatusCode(), gc.Equals, "GREEN")
   424  	c.Assert(exported.MeterStatusInfo(), gc.Equals, "some info")
   425  	c.Assert(exported.WorkloadVersion(), gc.Equals, "steven")
   426  	c.Assert(exported.Annotations(), jc.DeepEquals, testAnnotations)
   427  	constraints := exported.Constraints()
   428  	c.Assert(constraints, gc.NotNil)
   429  	c.Assert(constraints.Architecture(), gc.Equals, "amd64")
   430  	c.Assert(constraints.Memory(), gc.Equals, 8*gig)
   431  
   432  	workloadHistory := exported.WorkloadStatusHistory()
   433  	c.Assert(workloadHistory, gc.HasLen, expectedHistoryCount)
   434  	s.checkStatusHistory(c, workloadHistory[:addedHistoryCount], status.Active)
   435  
   436  	agentHistory := exported.AgentStatusHistory()
   437  	c.Assert(agentHistory, gc.HasLen, expectedHistoryCount)
   438  	s.checkStatusHistory(c, agentHistory[:addedHistoryCount], status.Idle)
   439  
   440  	versionHistory := exported.WorkloadVersionHistory()
   441  	// There are extra entries at the start that we don't care about.
   442  	c.Assert(len(versionHistory) >= 4, jc.IsTrue)
   443  	versions := make([]string, 4)
   444  	for i, status := range versionHistory[:4] {
   445  		versions[i] = status.Message()
   446  	}
   447  	// The exporter reads history in reverse time order.
   448  	c.Assert(versions, gc.DeepEquals, []string{"steven", "pearl", "amethyst", "garnet"})
   449  }
   450  
   451  func (s *MigrationExportSuite) TestServiceLeadership(c *gc.C) {
   452  	s.makeApplicationWithLeader(c, "mysql", 2, 1)
   453  	s.makeApplicationWithLeader(c, "wordpress", 4, 2)
   454  
   455  	model, err := s.State.Export()
   456  	c.Assert(err, jc.ErrorIsNil)
   457  
   458  	leaders := make(map[string]string)
   459  	for _, application := range model.Applications() {
   460  		leaders[application.Name()] = application.Leader()
   461  	}
   462  	c.Assert(leaders, jc.DeepEquals, map[string]string{
   463  		"mysql":     "mysql/1",
   464  		"wordpress": "wordpress/2",
   465  	})
   466  }
   467  
   468  func (s *MigrationExportSuite) TestUnitsOpenPorts(c *gc.C) {
   469  	unit := s.Factory.MakeUnit(c, nil)
   470  	err := unit.OpenPorts("tcp", 1234, 2345)
   471  	c.Assert(err, jc.ErrorIsNil)
   472  
   473  	model, err := s.State.Export()
   474  	c.Assert(err, jc.ErrorIsNil)
   475  
   476  	machines := model.Machines()
   477  	c.Assert(machines, gc.HasLen, 1)
   478  
   479  	ports := machines[0].OpenedPorts()
   480  	c.Assert(ports, gc.HasLen, 1)
   481  
   482  	port := ports[0]
   483  	c.Assert(port.SubnetID(), gc.Equals, "")
   484  	opened := port.OpenPorts()
   485  	c.Assert(opened, gc.HasLen, 1)
   486  	c.Assert(opened[0].UnitName(), gc.Equals, unit.Name())
   487  }
   488  
   489  func (s *MigrationExportSuite) TestRelations(c *gc.C) {
   490  	wordpress := state.AddTestingService(c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress"))
   491  	mysql := state.AddTestingService(c, s.State, "mysql", state.AddTestingCharm(c, s.State, "mysql"))
   492  	// InferEndpoints will always return provider, requirer
   493  	eps, err := s.State.InferEndpoints("mysql", "wordpress")
   494  	c.Assert(err, jc.ErrorIsNil)
   495  	rel, err := s.State.AddRelation(eps...)
   496  	msEp, wpEp := eps[0], eps[1]
   497  	c.Assert(err, jc.ErrorIsNil)
   498  	wordpress_0 := s.Factory.MakeUnit(c, &factory.UnitParams{Application: wordpress})
   499  	mysql_0 := s.Factory.MakeUnit(c, &factory.UnitParams{Application: mysql})
   500  
   501  	ru, err := rel.Unit(wordpress_0)
   502  	c.Assert(err, jc.ErrorIsNil)
   503  	wordpressSettings := map[string]interface{}{
   504  		"name": "wordpress/0",
   505  	}
   506  	err = ru.EnterScope(wordpressSettings)
   507  	c.Assert(err, jc.ErrorIsNil)
   508  
   509  	ru, err = rel.Unit(mysql_0)
   510  	c.Assert(err, jc.ErrorIsNil)
   511  	mysqlSettings := map[string]interface{}{
   512  		"name": "mysql/0",
   513  	}
   514  	err = ru.EnterScope(mysqlSettings)
   515  	c.Assert(err, jc.ErrorIsNil)
   516  
   517  	model, err := s.State.Export()
   518  	c.Assert(err, jc.ErrorIsNil)
   519  
   520  	rels := model.Relations()
   521  	c.Assert(rels, gc.HasLen, 1)
   522  
   523  	exRel := rels[0]
   524  	c.Assert(exRel.Id(), gc.Equals, rel.Id())
   525  	c.Assert(exRel.Key(), gc.Equals, rel.String())
   526  
   527  	exEps := exRel.Endpoints()
   528  	c.Assert(exEps, gc.HasLen, 2)
   529  
   530  	checkEndpoint := func(
   531  		exEndpoint description.Endpoint,
   532  		unitName string,
   533  		ep state.Endpoint,
   534  		settings map[string]interface{},
   535  	) {
   536  		c.Logf("%#v", exEndpoint)
   537  		c.Check(exEndpoint.ApplicationName(), gc.Equals, ep.ApplicationName)
   538  		c.Check(exEndpoint.Name(), gc.Equals, ep.Name)
   539  		c.Check(exEndpoint.UnitCount(), gc.Equals, 1)
   540  		c.Check(exEndpoint.Settings(unitName), jc.DeepEquals, settings)
   541  		c.Check(exEndpoint.Role(), gc.Equals, string(ep.Role))
   542  		c.Check(exEndpoint.Interface(), gc.Equals, ep.Interface)
   543  		c.Check(exEndpoint.Optional(), gc.Equals, ep.Optional)
   544  		c.Check(exEndpoint.Limit(), gc.Equals, ep.Limit)
   545  		c.Check(exEndpoint.Scope(), gc.Equals, string(ep.Scope))
   546  	}
   547  	checkEndpoint(exEps[0], mysql_0.Name(), msEp, mysqlSettings)
   548  	checkEndpoint(exEps[1], wordpress_0.Name(), wpEp, wordpressSettings)
   549  }
   550  
   551  func (s *MigrationExportSuite) TestSpaces(c *gc.C) {
   552  	s.Factory.MakeSpace(c, &factory.SpaceParams{
   553  		Name: "one", ProviderID: network.Id("provider"), IsPublic: true})
   554  
   555  	model, err := s.State.Export()
   556  	c.Assert(err, jc.ErrorIsNil)
   557  
   558  	spaces := model.Spaces()
   559  	c.Assert(spaces, gc.HasLen, 1)
   560  	space := spaces[0]
   561  	c.Assert(space.Name(), gc.Equals, "one")
   562  	c.Assert(space.ProviderID(), gc.Equals, "provider")
   563  	c.Assert(space.Public(), jc.IsTrue)
   564  }
   565  
   566  func (s *MigrationExportSuite) TestMultipleSpaces(c *gc.C) {
   567  	s.Factory.MakeSpace(c, &factory.SpaceParams{Name: "one"})
   568  	s.Factory.MakeSpace(c, &factory.SpaceParams{Name: "two"})
   569  	s.Factory.MakeSpace(c, &factory.SpaceParams{Name: "three"})
   570  
   571  	model, err := s.State.Export()
   572  	c.Assert(err, jc.ErrorIsNil)
   573  	c.Assert(model.Spaces(), gc.HasLen, 3)
   574  }
   575  
   576  func (s *MigrationExportSuite) TestLinkLayerDevices(c *gc.C) {
   577  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
   578  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
   579  	})
   580  	deviceArgs := state.LinkLayerDeviceArgs{
   581  		Name: "foo",
   582  		Type: state.EthernetDevice,
   583  	}
   584  	err := machine.SetLinkLayerDevices(deviceArgs)
   585  	c.Assert(err, jc.ErrorIsNil)
   586  
   587  	model, err := s.State.Export()
   588  	c.Assert(err, jc.ErrorIsNil)
   589  
   590  	devices := model.LinkLayerDevices()
   591  	c.Assert(devices, gc.HasLen, 1)
   592  	device := devices[0]
   593  	c.Assert(device.Name(), gc.Equals, "foo")
   594  	c.Assert(device.Type(), gc.Equals, string(state.EthernetDevice))
   595  }
   596  
   597  func (s *MigrationExportSuite) TestSubnets(c *gc.C) {
   598  	_, err := s.State.AddSubnet(state.SubnetInfo{
   599  		CIDR:             "10.0.0.0/24",
   600  		ProviderId:       network.Id("foo"),
   601  		VLANTag:          64,
   602  		AvailabilityZone: "bar",
   603  		SpaceName:        "bam",
   604  	})
   605  	c.Assert(err, jc.ErrorIsNil)
   606  	_, err = s.State.AddSpace("bam", "", nil, true)
   607  	c.Assert(err, jc.ErrorIsNil)
   608  
   609  	model, err := s.State.Export()
   610  	c.Assert(err, jc.ErrorIsNil)
   611  
   612  	subnets := model.Subnets()
   613  	c.Assert(subnets, gc.HasLen, 1)
   614  	subnet := subnets[0]
   615  	c.Assert(subnet.CIDR(), gc.Equals, "10.0.0.0/24")
   616  	c.Assert(subnet.ProviderId(), gc.Equals, "foo")
   617  	c.Assert(subnet.VLANTag(), gc.Equals, 64)
   618  	c.Assert(subnet.AvailabilityZone(), gc.Equals, "bar")
   619  	c.Assert(subnet.SpaceName(), gc.Equals, "bam")
   620  }
   621  
   622  func (s *MigrationExportSuite) TestIPAddresses(c *gc.C) {
   623  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
   624  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
   625  	})
   626  	_, err := s.State.AddSubnet(state.SubnetInfo{CIDR: "0.1.2.0/24"})
   627  	c.Assert(err, jc.ErrorIsNil)
   628  	deviceArgs := state.LinkLayerDeviceArgs{
   629  		Name: "foo",
   630  		Type: state.EthernetDevice,
   631  	}
   632  	err = machine.SetLinkLayerDevices(deviceArgs)
   633  	c.Assert(err, jc.ErrorIsNil)
   634  	args := state.LinkLayerDeviceAddress{
   635  		DeviceName:       "foo",
   636  		ConfigMethod:     state.StaticAddress,
   637  		CIDRAddress:      "0.1.2.3/24",
   638  		ProviderID:       "bar",
   639  		DNSServers:       []string{"bam", "mam"},
   640  		DNSSearchDomains: []string{"weeee"},
   641  		GatewayAddress:   "0.1.2.1",
   642  	}
   643  	err = machine.SetDevicesAddresses(args)
   644  	c.Assert(err, jc.ErrorIsNil)
   645  
   646  	model, err := s.State.Export()
   647  	c.Assert(err, jc.ErrorIsNil)
   648  
   649  	addresses := model.IPAddresses()
   650  	c.Assert(addresses, gc.HasLen, 1)
   651  	addr := addresses[0]
   652  	c.Assert(addr.Value(), gc.Equals, "0.1.2.3")
   653  	c.Assert(addr.MachineID(), gc.Equals, machine.Id())
   654  	c.Assert(addr.DeviceName(), gc.Equals, "foo")
   655  	c.Assert(addr.ConfigMethod(), gc.Equals, string(state.StaticAddress))
   656  	c.Assert(addr.SubnetCIDR(), gc.Equals, "0.1.2.0/24")
   657  	c.Assert(addr.ProviderID(), gc.Equals, "bar")
   658  	c.Assert(addr.DNSServers(), jc.DeepEquals, []string{"bam", "mam"})
   659  	c.Assert(addr.DNSSearchDomains(), jc.DeepEquals, []string{"weeee"})
   660  	c.Assert(addr.GatewayAddress(), gc.Equals, "0.1.2.1")
   661  }
   662  
   663  func (s *MigrationExportSuite) TestSSHHostKeys(c *gc.C) {
   664  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
   665  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
   666  	})
   667  	err := s.State.SetSSHHostKeys(machine.MachineTag(), []string{"bam", "mam"})
   668  	c.Assert(err, jc.ErrorIsNil)
   669  
   670  	model, err := s.State.Export()
   671  	c.Assert(err, jc.ErrorIsNil)
   672  
   673  	keys := model.SSHHostKeys()
   674  	c.Assert(keys, gc.HasLen, 1)
   675  	key := keys[0]
   676  	c.Assert(key.MachineID(), gc.Equals, machine.Id())
   677  	c.Assert(key.Keys(), jc.DeepEquals, []string{"bam", "mam"})
   678  }
   679  
   680  func (s *MigrationExportSuite) TestCloudImageMetadatas(c *gc.C) {
   681  	storageSize := uint64(3)
   682  	attrs := cloudimagemetadata.MetadataAttributes{
   683  		Stream:          "stream",
   684  		Region:          "region-test",
   685  		Version:         "14.04",
   686  		Series:          "trusty",
   687  		Arch:            "arch",
   688  		VirtType:        "virtType-test",
   689  		RootStorageType: "rootStorageType-test",
   690  		RootStorageSize: &storageSize,
   691  		Source:          "test",
   692  	}
   693  	metadata := []cloudimagemetadata.Metadata{{attrs, 2, "1", 2}}
   694  
   695  	err := s.State.CloudImageMetadataStorage.SaveMetadata(metadata)
   696  	c.Assert(err, jc.ErrorIsNil)
   697  
   698  	model, err := s.State.Export()
   699  	c.Assert(err, jc.ErrorIsNil)
   700  
   701  	images := model.CloudImageMetadata()
   702  	c.Assert(images, gc.HasLen, 1)
   703  	image := images[0]
   704  	c.Check(image.Stream(), gc.Equals, "stream")
   705  	c.Check(image.Region(), gc.Equals, "region-test")
   706  	c.Check(image.Version(), gc.Equals, "14.04")
   707  	c.Check(image.Arch(), gc.Equals, "arch")
   708  	c.Check(image.VirtType(), gc.Equals, "virtType-test")
   709  	c.Check(image.RootStorageType(), gc.Equals, "rootStorageType-test")
   710  	value, ok := image.RootStorageSize()
   711  	c.Assert(ok, jc.IsTrue)
   712  	c.Assert(value, gc.Equals, uint64(3))
   713  	c.Check(image.Source(), gc.Equals, "test")
   714  	c.Check(image.Priority(), gc.Equals, 2)
   715  	c.Check(image.ImageId(), gc.Equals, "1")
   716  	c.Check(image.DateCreated(), gc.Equals, int64(2))
   717  }
   718  
   719  func (s *MigrationExportSuite) TestActions(c *gc.C) {
   720  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
   721  		Constraints: constraints.MustParse("arch=amd64 mem=8G"),
   722  	})
   723  	_, err := s.State.EnqueueAction(machine.MachineTag(), "foo", nil)
   724  	c.Assert(err, jc.ErrorIsNil)
   725  
   726  	model, err := s.State.Export()
   727  	c.Assert(err, jc.ErrorIsNil)
   728  
   729  	actions := model.Actions()
   730  	c.Assert(actions, gc.HasLen, 1)
   731  	action := actions[0]
   732  	c.Check(action.Receiver(), gc.Equals, machine.Id())
   733  	c.Check(action.Name(), gc.Equals, "foo")
   734  	c.Check(action.Status(), gc.Equals, "pending")
   735  	c.Check(action.Message(), gc.Equals, "")
   736  }
   737  
   738  type goodToken struct{}
   739  
   740  // Check implements leadership.Token
   741  func (*goodToken) Check(interface{}) error {
   742  	return nil
   743  }
   744  
   745  func (s *MigrationExportSuite) TestVolumes(c *gc.C) {
   746  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
   747  		Volumes: []state.MachineVolumeParams{{
   748  			Volume:     state.VolumeParams{Size: 1234},
   749  			Attachment: state.VolumeAttachmentParams{ReadOnly: true},
   750  		}, {
   751  			Volume: state.VolumeParams{Size: 4000},
   752  		}},
   753  	})
   754  	machineTag := machine.MachineTag()
   755  
   756  	// We know that the first volume is called "0/0" as it is the first volume
   757  	// (volumes use sequences), and it is bound to machine 0.
   758  	volTag := names.NewVolumeTag("0/0")
   759  	err := s.State.SetVolumeInfo(volTag, state.VolumeInfo{
   760  		HardwareId: "magic",
   761  		Size:       1500,
   762  		VolumeId:   "volume id",
   763  		Persistent: true,
   764  	})
   765  	c.Assert(err, jc.ErrorIsNil)
   766  	err = s.State.SetVolumeAttachmentInfo(machineTag, volTag, state.VolumeAttachmentInfo{
   767  		DeviceName: "device name",
   768  		DeviceLink: "device link",
   769  		BusAddress: "bus address",
   770  		ReadOnly:   true,
   771  	})
   772  	c.Assert(err, jc.ErrorIsNil)
   773  
   774  	model, err := s.State.Export()
   775  	c.Assert(err, jc.ErrorIsNil)
   776  
   777  	volumes := model.Volumes()
   778  	c.Assert(volumes, gc.HasLen, 2)
   779  	provisioned, notProvisioned := volumes[0], volumes[1]
   780  
   781  	c.Check(provisioned.Tag(), gc.Equals, volTag)
   782  	binding, err := provisioned.Binding()
   783  	c.Check(err, jc.ErrorIsNil)
   784  	c.Check(binding, gc.Equals, machineTag)
   785  	c.Check(provisioned.Provisioned(), jc.IsTrue)
   786  	c.Check(provisioned.Size(), gc.Equals, uint64(1500))
   787  	c.Check(provisioned.Pool(), gc.Equals, "loop")
   788  	c.Check(provisioned.HardwareID(), gc.Equals, "magic")
   789  	c.Check(provisioned.VolumeID(), gc.Equals, "volume id")
   790  	c.Check(provisioned.Persistent(), jc.IsTrue)
   791  	attachments := provisioned.Attachments()
   792  	c.Assert(attachments, gc.HasLen, 1)
   793  	attachment := attachments[0]
   794  	c.Check(attachment.Machine(), gc.Equals, machineTag)
   795  	c.Check(attachment.Provisioned(), jc.IsTrue)
   796  	c.Check(attachment.ReadOnly(), jc.IsTrue)
   797  	c.Check(attachment.DeviceName(), gc.Equals, "device name")
   798  	c.Check(attachment.DeviceLink(), gc.Equals, "device link")
   799  	c.Check(attachment.BusAddress(), gc.Equals, "bus address")
   800  
   801  	c.Check(notProvisioned.Tag(), gc.Equals, names.NewVolumeTag("0/1"))
   802  	binding, err = notProvisioned.Binding()
   803  	c.Check(err, jc.ErrorIsNil)
   804  	c.Check(binding, gc.Equals, machineTag)
   805  	c.Check(notProvisioned.Provisioned(), jc.IsFalse)
   806  	c.Check(notProvisioned.Size(), gc.Equals, uint64(4000))
   807  	c.Check(notProvisioned.Pool(), gc.Equals, "loop")
   808  	c.Check(notProvisioned.HardwareID(), gc.Equals, "")
   809  	c.Check(notProvisioned.VolumeID(), gc.Equals, "")
   810  	c.Check(notProvisioned.Persistent(), jc.IsFalse)
   811  	attachments = notProvisioned.Attachments()
   812  	c.Assert(attachments, gc.HasLen, 1)
   813  	attachment = attachments[0]
   814  	c.Check(attachment.Machine(), gc.Equals, machineTag)
   815  	c.Check(attachment.Provisioned(), jc.IsFalse)
   816  	c.Check(attachment.ReadOnly(), jc.IsFalse)
   817  	c.Check(attachment.DeviceName(), gc.Equals, "")
   818  	c.Check(attachment.DeviceLink(), gc.Equals, "")
   819  	c.Check(attachment.BusAddress(), gc.Equals, "")
   820  
   821  	// Make sure there is a status.
   822  	status := provisioned.Status()
   823  	c.Check(status.Value(), gc.Equals, "pending")
   824  }
   825  
   826  func (s *MigrationExportSuite) TestFilesystems(c *gc.C) {
   827  	machine := s.Factory.MakeMachine(c, &factory.MachineParams{
   828  		Filesystems: []state.MachineFilesystemParams{{
   829  			Filesystem: state.FilesystemParams{Size: 1234},
   830  			Attachment: state.FilesystemAttachmentParams{
   831  				Location: "location",
   832  				ReadOnly: true},
   833  		}, {
   834  			Filesystem: state.FilesystemParams{Size: 4000},
   835  		}},
   836  	})
   837  	machineTag := machine.MachineTag()
   838  
   839  	// We know that the first filesystem is called "0/0" as it is the first
   840  	// filesystem (filesystems use sequences), and it is bound to machine 0.
   841  	fsTag := names.NewFilesystemTag("0/0")
   842  	err := s.State.SetFilesystemInfo(fsTag, state.FilesystemInfo{
   843  		Size:         1500,
   844  		FilesystemId: "filesystem id",
   845  	})
   846  	c.Assert(err, jc.ErrorIsNil)
   847  	err = s.State.SetFilesystemAttachmentInfo(machineTag, fsTag, state.FilesystemAttachmentInfo{
   848  		MountPoint: "/mnt/foo",
   849  		ReadOnly:   true,
   850  	})
   851  	c.Assert(err, jc.ErrorIsNil)
   852  
   853  	model, err := s.State.Export()
   854  	c.Assert(err, jc.ErrorIsNil)
   855  
   856  	filesystems := model.Filesystems()
   857  	c.Assert(filesystems, gc.HasLen, 2)
   858  	provisioned, notProvisioned := filesystems[0], filesystems[1]
   859  
   860  	c.Check(provisioned.Tag(), gc.Equals, fsTag)
   861  	c.Check(provisioned.Volume(), gc.Equals, names.VolumeTag{})
   862  	c.Check(provisioned.Storage(), gc.Equals, names.StorageTag{})
   863  	binding, err := provisioned.Binding()
   864  	c.Check(err, jc.ErrorIsNil)
   865  	c.Check(binding, gc.Equals, machineTag)
   866  	c.Check(provisioned.Provisioned(), jc.IsTrue)
   867  	c.Check(provisioned.Size(), gc.Equals, uint64(1500))
   868  	c.Check(provisioned.Pool(), gc.Equals, "rootfs")
   869  	c.Check(provisioned.FilesystemID(), gc.Equals, "filesystem id")
   870  	attachments := provisioned.Attachments()
   871  	c.Assert(attachments, gc.HasLen, 1)
   872  	attachment := attachments[0]
   873  	c.Check(attachment.Machine(), gc.Equals, machineTag)
   874  	c.Check(attachment.Provisioned(), jc.IsTrue)
   875  	c.Check(attachment.ReadOnly(), jc.IsTrue)
   876  	c.Check(attachment.MountPoint(), gc.Equals, "/mnt/foo")
   877  
   878  	c.Check(notProvisioned.Tag(), gc.Equals, names.NewFilesystemTag("0/1"))
   879  	c.Check(notProvisioned.Volume(), gc.Equals, names.VolumeTag{})
   880  	c.Check(notProvisioned.Storage(), gc.Equals, names.StorageTag{})
   881  	binding, err = notProvisioned.Binding()
   882  	c.Check(err, jc.ErrorIsNil)
   883  	c.Check(binding, gc.Equals, machineTag)
   884  	c.Check(notProvisioned.Provisioned(), jc.IsFalse)
   885  	c.Check(notProvisioned.Size(), gc.Equals, uint64(4000))
   886  	c.Check(notProvisioned.Pool(), gc.Equals, "rootfs")
   887  	c.Check(notProvisioned.FilesystemID(), gc.Equals, "")
   888  	attachments = notProvisioned.Attachments()
   889  	c.Assert(attachments, gc.HasLen, 1)
   890  	attachment = attachments[0]
   891  	c.Check(attachment.Machine(), gc.Equals, machineTag)
   892  	c.Check(attachment.Provisioned(), jc.IsFalse)
   893  	c.Check(attachment.ReadOnly(), jc.IsFalse)
   894  	c.Check(attachment.MountPoint(), gc.Equals, "")
   895  
   896  	// Make sure there is a status.
   897  	status := provisioned.Status()
   898  	c.Check(status.Value(), gc.Equals, "pending")
   899  }
   900  
   901  func (s *MigrationExportSuite) TestStorage(c *gc.C) {
   902  	_, u, storageTag := s.makeUnitWithStorage(c)
   903  
   904  	model, err := s.State.Export()
   905  	c.Assert(err, jc.ErrorIsNil)
   906  
   907  	apps := model.Applications()
   908  	c.Assert(apps, gc.HasLen, 1)
   909  	constraints := apps[0].StorageConstraints()
   910  	c.Assert(constraints, gc.HasLen, 2)
   911  	cons, found := constraints["data"]
   912  	c.Assert(found, jc.IsTrue)
   913  	c.Check(cons.Pool(), gc.Equals, "loop-pool")
   914  	c.Check(cons.Size(), gc.Equals, uint64(0x400))
   915  	c.Check(cons.Count(), gc.Equals, uint64(1))
   916  	cons, found = constraints["allecto"]
   917  	c.Assert(found, jc.IsTrue)
   918  	c.Check(cons.Pool(), gc.Equals, "loop")
   919  	c.Check(cons.Size(), gc.Equals, uint64(0x400))
   920  	c.Check(cons.Count(), gc.Equals, uint64(0))
   921  
   922  	storages := model.Storages()
   923  	c.Assert(storages, gc.HasLen, 1)
   924  
   925  	storage := storages[0]
   926  
   927  	c.Check(storage.Tag(), gc.Equals, storageTag)
   928  	c.Check(storage.Kind(), gc.Equals, "block")
   929  	owner, err := storage.Owner()
   930  	c.Check(err, jc.ErrorIsNil)
   931  	c.Check(owner, gc.Equals, u.Tag())
   932  	c.Check(storage.Name(), gc.Equals, "data")
   933  	c.Check(storage.Attachments(), jc.DeepEquals, []names.UnitTag{
   934  		u.UnitTag(),
   935  	})
   936  }
   937  
   938  func (s *MigrationExportSuite) TestStoragePools(c *gc.C) {
   939  	pm := poolmanager.New(state.NewStateSettings(s.State), provider.CommonStorageProviders())
   940  	_, err := pm.Create("test-pool", provider.LoopProviderType, map[string]interface{}{
   941  		"value": 42,
   942  	})
   943  	c.Assert(err, jc.ErrorIsNil)
   944  
   945  	model, err := s.State.Export()
   946  	c.Assert(err, jc.ErrorIsNil)
   947  
   948  	pools := model.StoragePools()
   949  	c.Assert(pools, gc.HasLen, 1)
   950  	pool := pools[0]
   951  	c.Assert(pool.Name(), gc.Equals, "test-pool")
   952  	c.Assert(pool.Provider(), gc.Equals, "loop")
   953  	c.Assert(pool.Attributes(), jc.DeepEquals, map[string]interface{}{
   954  		"value": 42,
   955  	})
   956  }
   957  
   958  func (s *MigrationExportSuite) TestPayloads(c *gc.C) {
   959  	unit := s.Factory.MakeUnit(c, nil)
   960  	up, err := s.State.UnitPayloads(unit)
   961  	c.Assert(err, jc.ErrorIsNil)
   962  	original := payload.Payload{
   963  		PayloadClass: charm.PayloadClass{
   964  			Name: "something",
   965  			Type: "special",
   966  		},
   967  		ID:     "42",
   968  		Status: "running",
   969  		Labels: []string{"foo", "bar"},
   970  	}
   971  	err = up.Track(original)
   972  	c.Assert(err, jc.ErrorIsNil)
   973  
   974  	model, err := s.State.Export()
   975  	c.Assert(err, jc.ErrorIsNil)
   976  
   977  	applications := model.Applications()
   978  	c.Assert(applications, gc.HasLen, 1)
   979  
   980  	units := applications[0].Units()
   981  	c.Assert(units, gc.HasLen, 1)
   982  
   983  	payloads := units[0].Payloads()
   984  	c.Assert(payloads, gc.HasLen, 1)
   985  
   986  	payload := payloads[0]
   987  	c.Check(payload.Name(), gc.Equals, original.Name)
   988  	c.Check(payload.Type(), gc.Equals, original.Type)
   989  	c.Check(payload.RawID(), gc.Equals, original.ID)
   990  	c.Check(payload.State(), gc.Equals, original.Status)
   991  	c.Check(payload.Labels(), jc.DeepEquals, original.Labels)
   992  }