~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_import_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 2016 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package state_test
 
5
 
 
6
import (
 
7
        "time"
 
8
 
 
9
        "github.com/juju/errors"
 
10
        "github.com/juju/names"
 
11
        jc "github.com/juju/testing/checkers"
 
12
        "github.com/juju/utils"
 
13
        "github.com/juju/version"
 
14
        gc "gopkg.in/check.v1"
 
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/state"
 
20
        "github.com/juju/juju/status"
 
21
        "github.com/juju/juju/testing/factory"
 
22
)
 
23
 
 
24
type MigrationImportSuite struct {
 
25
        MigrationSuite
 
26
}
 
27
 
 
28
var _ = gc.Suite(&MigrationImportSuite{})
 
29
 
 
30
func (s *MigrationImportSuite) checkStatusHistory(c *gc.C, exported, imported status.StatusHistoryGetter, size int) {
 
31
        exportedHistory, err := exported.StatusHistory(size)
 
32
        c.Assert(err, jc.ErrorIsNil)
 
33
        importedHistory, err := imported.StatusHistory(size)
 
34
        c.Assert(err, jc.ErrorIsNil)
 
35
        for i := 0; i < size; i++ {
 
36
                c.Check(importedHistory[i].Status, gc.Equals, exportedHistory[i].Status)
 
37
                c.Check(importedHistory[i].Message, gc.Equals, exportedHistory[i].Message)
 
38
                c.Check(importedHistory[i].Data, jc.DeepEquals, exportedHistory[i].Data)
 
39
                c.Check(importedHistory[i].Since, jc.DeepEquals, exportedHistory[i].Since)
 
40
        }
 
41
}
 
42
 
 
43
func (s *MigrationImportSuite) TestExisting(c *gc.C) {
 
44
        out, err := s.State.Export()
 
45
        c.Assert(err, jc.ErrorIsNil)
 
46
 
 
47
        _, _, err = s.State.Import(out)
 
48
        c.Assert(err, jc.Satisfies, errors.IsAlreadyExists)
 
49
}
 
50
 
 
51
func (s *MigrationImportSuite) importModel(c *gc.C) (*state.Model, *state.State) {
 
52
        out, err := s.State.Export()
 
53
        c.Assert(err, jc.ErrorIsNil)
 
54
 
 
55
        uuid := utils.MustNewUUID().String()
 
56
        in := newModel(out, uuid, "new")
 
57
 
 
58
        newModel, newSt, err := s.State.Import(in)
 
59
        c.Assert(err, jc.ErrorIsNil)
 
60
        return newModel, newSt
 
61
}
 
62
 
 
63
func (s *MigrationImportSuite) assertAnnotations(c *gc.C, newSt *state.State, entity state.GlobalEntity) {
 
64
        annotations, err := newSt.Annotations(entity)
 
65
        c.Assert(err, jc.ErrorIsNil)
 
66
        c.Assert(annotations, jc.DeepEquals, testAnnotations)
 
67
}
 
68
 
 
69
func (s *MigrationImportSuite) TestNewModel(c *gc.C) {
 
70
        cons := constraints.MustParse("arch=amd64 mem=8G")
 
71
        latestTools := version.MustParse("2.0.1")
 
72
        s.setLatestTools(c, latestTools)
 
73
        c.Assert(s.State.SetModelConstraints(cons), jc.ErrorIsNil)
 
74
        machineSeq := s.setRandSequenceValue(c, "machine")
 
75
        fooSeq := s.setRandSequenceValue(c, "service-foo")
 
76
        s.State.SwitchBlockOn(state.ChangeBlock, "locked down")
 
77
 
 
78
        original, err := s.State.Model()
 
79
        c.Assert(err, jc.ErrorIsNil)
 
80
 
 
81
        err = s.State.SetAnnotations(original, testAnnotations)
 
82
        c.Assert(err, jc.ErrorIsNil)
 
83
 
 
84
        out, err := s.State.Export()
 
85
        c.Assert(err, jc.ErrorIsNil)
 
86
 
 
87
        uuid := utils.MustNewUUID().String()
 
88
        in := newModel(out, uuid, "new")
 
89
 
 
90
        newModel, newSt, err := s.State.Import(in)
 
91
        c.Assert(err, jc.ErrorIsNil)
 
92
        defer newSt.Close()
 
93
 
 
94
        c.Assert(newModel.Owner(), gc.Equals, original.Owner())
 
95
        c.Assert(newModel.LatestToolsVersion(), gc.Equals, latestTools)
 
96
        s.assertAnnotations(c, newSt, newModel)
 
97
 
 
98
        originalConfig, err := original.Config()
 
99
        c.Assert(err, jc.ErrorIsNil)
 
100
        originalAttrs := originalConfig.AllAttrs()
 
101
 
 
102
        newConfig, err := newModel.Config()
 
103
        c.Assert(err, jc.ErrorIsNil)
 
104
        newAttrs := newConfig.AllAttrs()
 
105
 
 
106
        c.Assert(newAttrs["uuid"], gc.Equals, uuid)
 
107
        c.Assert(newAttrs["name"], gc.Equals, "new")
 
108
 
 
109
        // Now drop the uuid and name and the rest of the attributes should match.
 
110
        delete(newAttrs, "uuid")
 
111
        delete(newAttrs, "name")
 
112
        delete(originalAttrs, "uuid")
 
113
        delete(originalAttrs, "name")
 
114
        c.Assert(newAttrs, jc.DeepEquals, originalAttrs)
 
115
 
 
116
        newCons, err := newSt.ModelConstraints()
 
117
        c.Assert(err, jc.ErrorIsNil)
 
118
        // Can't test the constraints directly, so go through the string repr.
 
119
        c.Assert(newCons.String(), gc.Equals, cons.String())
 
120
 
 
121
        seq, err := state.Sequence(newSt, "machine")
 
122
        c.Assert(err, jc.ErrorIsNil)
 
123
        c.Assert(seq, gc.Equals, machineSeq)
 
124
        seq, err = state.Sequence(newSt, "service-foo")
 
125
        c.Assert(err, jc.ErrorIsNil)
 
126
        c.Assert(seq, gc.Equals, fooSeq)
 
127
 
 
128
        blocks, err := newSt.AllBlocks()
 
129
        c.Assert(err, jc.ErrorIsNil)
 
130
        c.Assert(blocks, gc.HasLen, 1)
 
131
        c.Assert(blocks[0].Type(), gc.Equals, state.ChangeBlock)
 
132
        c.Assert(blocks[0].Message(), gc.Equals, "locked down")
 
133
}
 
134
 
 
135
func (s *MigrationImportSuite) newModelUser(c *gc.C, name string, readOnly bool, lastConnection time.Time) *state.ModelUser {
 
136
        access := state.ModelAdminAccess
 
137
        if readOnly {
 
138
                access = state.ModelReadAccess
 
139
        }
 
140
        user, err := s.State.AddModelUser(state.ModelUserSpec{
 
141
                User:      names.NewUserTag(name),
 
142
                CreatedBy: s.Owner,
 
143
                Access:    access,
 
144
        })
 
145
        c.Assert(err, jc.ErrorIsNil)
 
146
        if !lastConnection.IsZero() {
 
147
                err = state.UpdateModelUserLastConnection(user, lastConnection)
 
148
                c.Assert(err, jc.ErrorIsNil)
 
149
        }
 
150
        return user
 
151
}
 
152
 
 
153
func (s *MigrationImportSuite) AssertUserEqual(c *gc.C, newUser, oldUser *state.ModelUser) {
 
154
        c.Assert(newUser.UserName(), gc.Equals, oldUser.UserName())
 
155
        c.Assert(newUser.DisplayName(), gc.Equals, oldUser.DisplayName())
 
156
        c.Assert(newUser.CreatedBy(), gc.Equals, oldUser.CreatedBy())
 
157
        c.Assert(newUser.DateCreated(), gc.Equals, oldUser.DateCreated())
 
158
        c.Assert(newUser.ReadOnly(), gc.Equals, oldUser.ReadOnly())
 
159
 
 
160
        connTime, err := oldUser.LastConnection()
 
161
        if state.IsNeverConnectedError(err) {
 
162
                _, err := newUser.LastConnection()
 
163
                // The new user should also return an error for last connection.
 
164
                c.Assert(err, jc.Satisfies, state.IsNeverConnectedError)
 
165
        } else {
 
166
                c.Assert(err, jc.ErrorIsNil)
 
167
                newTime, err := newUser.LastConnection()
 
168
                c.Assert(err, jc.ErrorIsNil)
 
169
                c.Assert(newTime, gc.Equals, connTime)
 
170
        }
 
171
}
 
172
 
 
173
func (s *MigrationImportSuite) TestModelUsers(c *gc.C) {
 
174
        // To be sure with this test, we create three env users, and remove
 
175
        // the owner.
 
176
        err := s.State.RemoveModelUser(s.Owner)
 
177
        c.Assert(err, jc.ErrorIsNil)
 
178
 
 
179
        lastConnection := state.NowToTheSecond()
 
180
 
 
181
        bravo := s.newModelUser(c, "bravo@external", false, lastConnection)
 
182
        charlie := s.newModelUser(c, "charlie@external", true, lastConnection)
 
183
        delta := s.newModelUser(c, "delta@external", true, time.Time{})
 
184
 
 
185
        newModel, newSt := s.importModel(c)
 
186
        defer newSt.Close()
 
187
 
 
188
        // Check the import values of the users.
 
189
        for _, user := range []*state.ModelUser{bravo, charlie, delta} {
 
190
                newUser, err := newSt.ModelUser(user.UserTag())
 
191
                c.Assert(err, jc.ErrorIsNil)
 
192
                s.AssertUserEqual(c, newUser, user)
 
193
        }
 
194
 
 
195
        // Also make sure that there aren't any more.
 
196
        allUsers, err := newModel.Users()
 
197
        c.Assert(err, jc.ErrorIsNil)
 
198
        c.Assert(allUsers, gc.HasLen, 3)
 
199
}
 
200
 
 
201
func (s *MigrationImportSuite) AssertMachineEqual(c *gc.C, newMachine, oldMachine *state.Machine) {
 
202
        c.Assert(newMachine.Id(), gc.Equals, oldMachine.Id())
 
203
        c.Assert(newMachine.Principals(), jc.DeepEquals, oldMachine.Principals())
 
204
        c.Assert(newMachine.Series(), gc.Equals, oldMachine.Series())
 
205
        c.Assert(newMachine.ContainerType(), gc.Equals, oldMachine.ContainerType())
 
206
        newHardware, err := newMachine.HardwareCharacteristics()
 
207
        c.Assert(err, jc.ErrorIsNil)
 
208
        oldHardware, err := oldMachine.HardwareCharacteristics()
 
209
        c.Assert(err, jc.ErrorIsNil)
 
210
        c.Assert(newHardware, jc.DeepEquals, oldHardware)
 
211
        c.Assert(newMachine.Jobs(), jc.DeepEquals, oldMachine.Jobs())
 
212
        c.Assert(newMachine.Life(), gc.Equals, oldMachine.Life())
 
213
        newTools, err := newMachine.AgentTools()
 
214
        c.Assert(err, jc.ErrorIsNil)
 
215
        oldTools, err := oldMachine.AgentTools()
 
216
        c.Assert(err, jc.ErrorIsNil)
 
217
        c.Assert(newTools, jc.DeepEquals, oldTools)
 
218
}
 
219
 
 
220
func (s *MigrationImportSuite) TestMachines(c *gc.C) {
 
221
        // Let's add a machine with an LXC container.
 
222
        cons := constraints.MustParse("arch=amd64 mem=8G")
 
223
        machine1 := s.Factory.MakeMachine(c, &factory.MachineParams{
 
224
                Constraints: cons,
 
225
        })
 
226
        err := s.State.SetAnnotations(machine1, testAnnotations)
 
227
        c.Assert(err, jc.ErrorIsNil)
 
228
        s.primeStatusHistory(c, machine1, status.StatusStarted, 5)
 
229
 
 
230
        // machine1 should have some instance data.
 
231
        hardware, err := machine1.HardwareCharacteristics()
 
232
        c.Assert(err, jc.ErrorIsNil)
 
233
        c.Assert(hardware, gc.NotNil)
 
234
 
 
235
        _ = s.Factory.MakeMachineNested(c, machine1.Id(), nil)
 
236
 
 
237
        allMachines, err := s.State.AllMachines()
 
238
        c.Assert(err, jc.ErrorIsNil)
 
239
        c.Assert(allMachines, gc.HasLen, 2)
 
240
 
 
241
        _, newSt := s.importModel(c)
 
242
        defer newSt.Close()
 
243
 
 
244
        importedMachines, err := newSt.AllMachines()
 
245
        c.Assert(err, jc.ErrorIsNil)
 
246
        c.Assert(importedMachines, gc.HasLen, 2)
 
247
 
 
248
        // AllMachines returns the machines in the same order, yay us.
 
249
        for i, newMachine := range importedMachines {
 
250
                s.AssertMachineEqual(c, newMachine, allMachines[i])
 
251
        }
 
252
 
 
253
        // And a few extra checks.
 
254
        parent := importedMachines[0]
 
255
        container := importedMachines[1]
 
256
        containers, err := parent.Containers()
 
257
        c.Assert(err, jc.ErrorIsNil)
 
258
        c.Assert(containers, jc.DeepEquals, []string{container.Id()})
 
259
        parentId, isContainer := container.ParentId()
 
260
        c.Assert(parentId, gc.Equals, parent.Id())
 
261
        c.Assert(isContainer, jc.IsTrue)
 
262
 
 
263
        s.assertAnnotations(c, newSt, parent)
 
264
        s.checkStatusHistory(c, machine1, parent, 5)
 
265
 
 
266
        newCons, err := parent.Constraints()
 
267
        c.Assert(err, jc.ErrorIsNil)
 
268
        // Can't test the constraints directly, so go through the string repr.
 
269
        c.Assert(newCons.String(), gc.Equals, cons.String())
 
270
}
 
271
 
 
272
func (s *MigrationImportSuite) TestServices(c *gc.C) {
 
273
        // Add a service with both settings and leadership settings.
 
274
        cons := constraints.MustParse("arch=amd64 mem=8G")
 
275
        service := s.Factory.MakeService(c, &factory.ServiceParams{
 
276
                Settings: map[string]interface{}{
 
277
                        "foo": "bar",
 
278
                },
 
279
                Constraints: cons,
 
280
        })
 
281
        err := service.UpdateLeaderSettings(&goodToken{}, map[string]string{
 
282
                "leader": "true",
 
283
        })
 
284
        c.Assert(err, jc.ErrorIsNil)
 
285
        err = service.SetMetricCredentials([]byte("sekrit"))
 
286
        c.Assert(err, jc.ErrorIsNil)
 
287
        // Expose the service.
 
288
        c.Assert(service.SetExposed(), jc.ErrorIsNil)
 
289
        err = s.State.SetAnnotations(service, testAnnotations)
 
290
        c.Assert(err, jc.ErrorIsNil)
 
291
        s.primeStatusHistory(c, service, status.StatusActive, 5)
 
292
 
 
293
        allServices, err := s.State.AllServices()
 
294
        c.Assert(err, jc.ErrorIsNil)
 
295
        c.Assert(allServices, gc.HasLen, 1)
 
296
 
 
297
        _, newSt := s.importModel(c)
 
298
        defer newSt.Close()
 
299
 
 
300
        importedServices, err := newSt.AllServices()
 
301
        c.Assert(err, jc.ErrorIsNil)
 
302
        c.Assert(importedServices, gc.HasLen, 1)
 
303
 
 
304
        exported := allServices[0]
 
305
        imported := importedServices[0]
 
306
 
 
307
        c.Assert(imported.ServiceTag(), gc.Equals, exported.ServiceTag())
 
308
        c.Assert(imported.Series(), gc.Equals, exported.Series())
 
309
        c.Assert(imported.IsExposed(), gc.Equals, exported.IsExposed())
 
310
        c.Assert(imported.MetricCredentials(), jc.DeepEquals, exported.MetricCredentials())
 
311
 
 
312
        exportedConfig, err := exported.ConfigSettings()
 
313
        c.Assert(err, jc.ErrorIsNil)
 
314
        importedConfig, err := imported.ConfigSettings()
 
315
        c.Assert(err, jc.ErrorIsNil)
 
316
        c.Assert(importedConfig, jc.DeepEquals, exportedConfig)
 
317
 
 
318
        exportedLeaderSettings, err := exported.LeaderSettings()
 
319
        c.Assert(err, jc.ErrorIsNil)
 
320
        importedLeaderSettings, err := imported.LeaderSettings()
 
321
        c.Assert(err, jc.ErrorIsNil)
 
322
        c.Assert(importedLeaderSettings, jc.DeepEquals, exportedLeaderSettings)
 
323
 
 
324
        s.assertAnnotations(c, newSt, imported)
 
325
        s.checkStatusHistory(c, service, imported, 5)
 
326
 
 
327
        newCons, err := imported.Constraints()
 
328
        c.Assert(err, jc.ErrorIsNil)
 
329
        // Can't test the constraints directly, so go through the string repr.
 
330
        c.Assert(newCons.String(), gc.Equals, cons.String())
 
331
}
 
332
 
 
333
func (s *MigrationImportSuite) TestServiceLeaders(c *gc.C) {
 
334
        s.makeServiceWithLeader(c, "mysql", 2, 1)
 
335
        s.makeServiceWithLeader(c, "wordpress", 4, 2)
 
336
 
 
337
        _, newSt := s.importModel(c)
 
338
        defer newSt.Close()
 
339
 
 
340
        leaders := make(map[string]string)
 
341
        for key, value := range state.LeadershipLeases(newSt) {
 
342
                leaders[key] = value.Holder
 
343
        }
 
344
        c.Assert(leaders, jc.DeepEquals, map[string]string{
 
345
                "mysql":     "mysql/1",
 
346
                "wordpress": "wordpress/2",
 
347
        })
 
348
}
 
349
 
 
350
func (s *MigrationImportSuite) TestUnits(c *gc.C) {
 
351
        cons := constraints.MustParse("arch=amd64 mem=8G")
 
352
        exported, pwd := s.Factory.MakeUnitReturningPassword(c, &factory.UnitParams{
 
353
                Constraints: cons,
 
354
        })
 
355
        err := exported.SetMeterStatus("GREEN", "some info")
 
356
        c.Assert(err, jc.ErrorIsNil)
 
357
        err = s.State.SetAnnotations(exported, testAnnotations)
 
358
        c.Assert(err, jc.ErrorIsNil)
 
359
        s.primeStatusHistory(c, exported, status.StatusActive, 5)
 
360
        s.primeStatusHistory(c, exported.Agent(), status.StatusIdle, 5)
 
361
 
 
362
        _, newSt := s.importModel(c)
 
363
        defer newSt.Close()
 
364
 
 
365
        importedServices, err := newSt.AllServices()
 
366
        c.Assert(err, jc.ErrorIsNil)
 
367
        c.Assert(importedServices, gc.HasLen, 1)
 
368
 
 
369
        importedUnits, err := importedServices[0].AllUnits()
 
370
        c.Assert(err, jc.ErrorIsNil)
 
371
        c.Assert(importedUnits, gc.HasLen, 1)
 
372
        imported := importedUnits[0]
 
373
 
 
374
        c.Assert(imported.UnitTag(), gc.Equals, exported.UnitTag())
 
375
        c.Assert(imported.PasswordValid(pwd), jc.IsTrue)
 
376
 
 
377
        exportedMachineId, err := exported.AssignedMachineId()
 
378
        c.Assert(err, jc.ErrorIsNil)
 
379
        importedMachineId, err := imported.AssignedMachineId()
 
380
        c.Assert(err, jc.ErrorIsNil)
 
381
        c.Assert(importedMachineId, gc.Equals, exportedMachineId)
 
382
        meterStatus, err := imported.GetMeterStatus()
 
383
        c.Assert(err, jc.ErrorIsNil)
 
384
        c.Assert(meterStatus, gc.Equals, state.MeterStatus{state.MeterGreen, "some info"})
 
385
        s.assertAnnotations(c, newSt, imported)
 
386
        s.checkStatusHistory(c, exported, imported, 5)
 
387
        s.checkStatusHistory(c, exported.Agent(), imported.Agent(), 5)
 
388
 
 
389
        newCons, err := imported.Constraints()
 
390
        c.Assert(err, jc.ErrorIsNil)
 
391
        // Can't test the constraints directly, so go through the string repr.
 
392
        c.Assert(newCons.String(), gc.Equals, cons.String())
 
393
}
 
394
 
 
395
func (s *MigrationImportSuite) TestRelations(c *gc.C) {
 
396
        // Need to remove owner from service.
 
397
        ignored := s.Owner
 
398
        wordpress := state.AddTestingService(c, s.State, "wordpress", state.AddTestingCharm(c, s.State, "wordpress"), ignored)
 
399
        state.AddTestingService(c, s.State, "mysql", state.AddTestingCharm(c, s.State, "mysql"), ignored)
 
400
        eps, err := s.State.InferEndpoints("mysql", "wordpress")
 
401
        c.Assert(err, jc.ErrorIsNil)
 
402
        rel, err := s.State.AddRelation(eps...)
 
403
        c.Assert(err, jc.ErrorIsNil)
 
404
        wordpress_0 := s.Factory.MakeUnit(c, &factory.UnitParams{Service: wordpress})
 
405
 
 
406
        ru, err := rel.Unit(wordpress_0)
 
407
        c.Assert(err, jc.ErrorIsNil)
 
408
        relSettings := map[string]interface{}{
 
409
                "name": "wordpress/0",
 
410
        }
 
411
        err = ru.EnterScope(relSettings)
 
412
        c.Assert(err, jc.ErrorIsNil)
 
413
 
 
414
        _, newSt := s.importModel(c)
 
415
        defer newSt.Close()
 
416
 
 
417
        newWordpress, err := newSt.Service("wordpress")
 
418
        c.Assert(err, jc.ErrorIsNil)
 
419
        c.Assert(state.RelationCount(newWordpress), gc.Equals, 1)
 
420
        rels, err := newWordpress.Relations()
 
421
        c.Assert(err, jc.ErrorIsNil)
 
422
        c.Assert(rels, gc.HasLen, 1)
 
423
        units, err := newWordpress.AllUnits()
 
424
        c.Assert(err, jc.ErrorIsNil)
 
425
        c.Assert(units, gc.HasLen, 1)
 
426
 
 
427
        ru, err = rels[0].Unit(units[0])
 
428
        c.Assert(err, jc.ErrorIsNil)
 
429
 
 
430
        settings, err := ru.Settings()
 
431
        c.Assert(err, jc.ErrorIsNil)
 
432
        c.Assert(settings.Map(), gc.DeepEquals, relSettings)
 
433
}
 
434
 
 
435
func (s *MigrationImportSuite) TestUnitsOpenPorts(c *gc.C) {
 
436
        unit := s.Factory.MakeUnit(c, nil)
 
437
        err := unit.OpenPorts("tcp", 1234, 2345)
 
438
        c.Assert(err, jc.ErrorIsNil)
 
439
 
 
440
        _, newSt := s.importModel(c)
 
441
        defer newSt.Close()
 
442
 
 
443
        // Even though the opened ports document is stored with the
 
444
        // machine, the only way to easily access it is through the units.
 
445
        imported, err := newSt.Unit(unit.Name())
 
446
        c.Assert(err, jc.ErrorIsNil)
 
447
 
 
448
        ports, err := imported.OpenedPorts()
 
449
        c.Assert(err, jc.ErrorIsNil)
 
450
        c.Assert(ports, gc.HasLen, 1)
 
451
        c.Assert(ports[0], gc.Equals, network.PortRange{
 
452
                FromPort: 1234,
 
453
                ToPort:   2345,
 
454
                Protocol: "tcp",
 
455
        })
 
456
}
 
457
 
 
458
// newModel replaces the uuid and name of the config attributes so we
 
459
// can use all the other data to validate imports. An owner and name of the
 
460
// model are unique together in a controller.
 
461
func newModel(m description.Model, uuid, name string) description.Model {
 
462
        return &mockModel{m, uuid, name}
 
463
}
 
464
 
 
465
type mockModel struct {
 
466
        description.Model
 
467
        uuid string
 
468
        name string
 
469
}
 
470
 
 
471
func (m *mockModel) Tag() names.ModelTag {
 
472
        return names.NewModelTag(m.uuid)
 
473
}
 
474
 
 
475
func (m *mockModel) Config() map[string]interface{} {
 
476
        c := m.Model.Config()
 
477
        c["uuid"] = m.uuid
 
478
        c["name"] = m.name
 
479
        return c
 
480
}