~rogpeppe/juju-core/438-local-instance-Addresses

« back to all changes in this revision

Viewing changes to mstate/state_test.go

mstate: refactor tests like in state.

Tests are refactored into multiple suites to be compatible with
state. See issue 6348053. After mstate replaces state I plan to reverse
the dependencies between suites. Right now each suite embeds an UtilSuite
and has to call UtilSuite.SetUpTest resulting in error prone duplicate
code. Keeping the multiple suites as containers for data and embedding
all suites into a StateSuite shared by all tests is a better design. We
will keep tests in separate files.

R=niemeyer
CC=
https://codereview.appspot.com/6381045

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 
3
3
import (
4
4
        "fmt"
5
 
        "labix.org/v2/mgo"
6
5
        "labix.org/v2/mgo/bson"
7
6
        . "launchpad.net/gocheck"
8
7
        "launchpad.net/juju-core/charm"
9
8
        state "launchpad.net/juju-core/mstate"
10
 
        "launchpad.net/juju-core/testing"
 
9
        coretesting "launchpad.net/juju-core/testing"
11
10
        "net/url"
12
 
        "sort"
13
11
        stdtesting "testing"
14
12
)
15
13
 
16
14
func Test(t *stdtesting.T) { TestingT(t) }
17
15
 
 
16
type StateSuite struct {
 
17
        UtilSuite
 
18
}
 
19
 
18
20
var _ = Suite(&StateSuite{})
19
21
 
20
 
type StateSuite struct {
21
 
        MgoSuite
22
 
        session  *mgo.Session
23
 
        charms   *mgo.Collection
24
 
        machines *mgo.Collection
25
 
        services *mgo.Collection
26
 
        units    *mgo.Collection
27
 
        st       *state.State
28
 
        ch       charm.Charm
29
 
        curl     *charm.URL
30
 
}
31
 
 
32
 
func (s *StateSuite) SetUpTest(c *C) {
33
 
        s.MgoSuite.SetUpTest(c)
34
 
        session, err := mgo.Dial(mgoaddr)
35
 
        c.Assert(err, IsNil)
36
 
        s.session = session
37
 
 
38
 
        st, err := state.Dial(mgoaddr)
39
 
        c.Assert(err, IsNil)
40
 
        s.st = st
41
 
 
42
 
        s.charms = session.DB("juju").C("charms")
43
 
        s.machines = session.DB("juju").C("machines")
44
 
        s.services = session.DB("juju").C("services")
45
 
        s.units = session.DB("juju").C("units")
46
 
 
47
 
        s.ch = testing.Charms.Dir("dummy")
48
 
        url := fmt.Sprintf("local:series/%s-%d", s.ch.Meta().Name, s.ch.Revision())
49
 
        s.curl = charm.MustParseURL(url)
50
 
}
51
 
 
52
 
func (s *StateSuite) TearDownTest(c *C) {
53
 
        s.st.Close()
54
 
        s.session.Close()
55
 
        s.MgoSuite.TearDownTest(c)
56
 
}
57
 
 
58
22
func (s *StateSuite) TestAddCharm(c *C) {
59
 
        // Check that adding charms works correctly.
60
 
        bundleURL, err := url.Parse("http://bundle.url")
61
 
        c.Assert(err, IsNil)
62
 
        dummy, err := s.st.AddCharm(s.ch, s.curl, bundleURL, "dummy-sha256")
63
 
        c.Assert(err, IsNil)
64
 
        c.Assert(dummy.URL().String(), Equals, s.curl.String())
65
 
 
66
 
        mdoc := &struct {
67
 
                URL *charm.URL `bson:"_id"`
68
 
        }{}
69
 
        err = s.charms.Find(bson.D{{"_id", s.curl}}).One(mdoc)
70
 
        c.Assert(err, IsNil)
71
 
        c.Assert(mdoc.URL, DeepEquals, s.curl)
72
 
}
73
 
 
74
 
// addDummyCharm adds the 'dummy' charm state to st.
75
 
func (s *StateSuite) addDummyCharm(c *C) *state.Charm {
76
 
        bundleURL, err := url.Parse("http://bundle.url")
77
 
        c.Assert(err, IsNil)
78
 
        dummy, err := s.st.AddCharm(s.ch, s.curl, bundleURL, "dummy-sha256")
79
 
        c.Assert(err, IsNil)
80
 
        return dummy
81
 
}
82
 
 
83
 
func (s *StateSuite) TestCharmAttributes(c *C) {
84
 
        // Check that the basic (invariant) fields of the charm
85
 
        // are correctly in place.
86
 
        s.addDummyCharm(c)
87
 
 
88
 
        dummy, err := s.st.Charm(s.curl)
89
 
        c.Assert(err, IsNil)
90
 
        c.Assert(dummy.URL().String(), Equals, s.curl.String())
91
 
        c.Assert(dummy.Revision(), Equals, 1)
92
 
        bundleURL, err := url.Parse("http://bundle.url")
93
 
        c.Assert(err, IsNil)
94
 
        c.Assert(dummy.BundleURL(), DeepEquals, bundleURL)
95
 
        c.Assert(dummy.BundleSha256(), Equals, "dummy-sha256")
96
 
        meta := dummy.Meta()
97
 
        c.Assert(meta.Name, Equals, "dummy")
98
 
        config := dummy.Config()
99
 
        c.Assert(config.Options["title"], Equals,
100
 
                charm.Option{
101
 
                        Default:     "My Title",
102
 
                        Description: "A descriptive title used for the service.",
103
 
                        Type:        "string",
104
 
                },
 
23
        // Check that adding charms from scratch works correctly.
 
24
        ch := coretesting.Charms.Dir("dummy")
 
25
        curl := charm.MustParseURL(
 
26
                fmt.Sprintf("local:series/%s-%d", ch.Meta().Name, ch.Revision()),
105
27
        )
106
 
}
107
 
 
108
 
func (s *StateSuite) TestNonExistentCharmPriorToInitialization(c *C) {
109
 
        // Check that getting a charm before any other charm has been added fails nicely.
110
 
        _, err := s.st.Charm(s.curl)
111
 
        c.Assert(err, ErrorMatches, `can't get charm "local:series/dummy-1": .*`)
112
 
}
113
 
 
114
 
func (s *StateSuite) TestGetNonExistentCharm(c *C) {
115
 
        // Check that getting a non-existent charm fails nicely.
116
 
        s.addDummyCharm(c)
117
 
 
118
 
        curl := charm.MustParseURL("local:anotherseries/dummy-1")
119
 
        _, err := s.st.Charm(curl)
120
 
        c.Assert(err, ErrorMatches, `can't get charm "local:anotherseries/dummy-1": .*`)
121
 
}
122
 
 
123
 
func (s *StateSuite) assertMachineCount(c *C, expect int) {
124
 
        ms, err := s.st.AllMachines()
 
28
        bundleURL, err := url.Parse("http://bundles.example.com/dummy-1")
 
29
        c.Assert(err, IsNil)
 
30
        dummy, err := s.State.AddCharm(ch, curl, bundleURL, "dummy-1-sha256")
 
31
        c.Assert(err, IsNil)
 
32
        c.Assert(dummy.URL().String(), Equals, curl.String())
 
33
 
 
34
        doc := state.CharmDoc{}
 
35
        err = s.charms.FindId(curl).One(&doc)
 
36
        c.Assert(err, IsNil)
 
37
        c.Logf("%#v", doc)
 
38
        c.Assert(doc.URL, DeepEquals, curl)
 
39
}
 
40
 
 
41
func (s *StateSuite) AssertMachineCount(c *C, expect int) {
 
42
        ms, err := s.State.AllMachines()
125
43
        c.Assert(err, IsNil)
126
44
        c.Assert(len(ms), Equals, expect)
127
45
}
128
46
 
129
 
func (s *StateSuite) TestAllMachines(c *C) {
130
 
        numInserts := 42
131
 
        for i := 0; i < numInserts; i++ {
132
 
                err := s.machines.Insert(bson.D{{"_id", i}, {"life", state.Alive}})
133
 
                c.Assert(err, IsNil)
134
 
        }
135
 
        s.assertMachineCount(c, numInserts)
136
 
        ms, _ := s.st.AllMachines()
137
 
        for k, v := range ms {
138
 
                c.Assert(v.Id(), Equals, k)
139
 
        }
140
 
}
141
 
 
142
47
func (s *StateSuite) TestAddMachine(c *C) {
143
 
        numInserts := 42
144
 
        for i := 0; i < numInserts; i++ {
145
 
                m, err := s.st.AddMachine()
146
 
                c.Assert(err, IsNil)
147
 
                c.Assert(m.Id(), Equals, i)
148
 
        }
149
 
        s.assertMachineCount(c, numInserts)
 
48
        machine0, err := s.State.AddMachine()
 
49
        c.Assert(err, IsNil)
 
50
        c.Assert(machine0.Id(), Equals, 0)
 
51
        machine1, err := s.State.AddMachine()
 
52
        c.Assert(err, IsNil)
 
53
        c.Assert(machine1.Id(), Equals, 1)
 
54
 
 
55
        machines := s.AllMachines(c)
 
56
        c.Assert(machines, DeepEquals, []int{0, 1})
150
57
}
151
58
 
152
59
func (s *StateSuite) TestRemoveMachine(c *C) {
153
 
        m0, err := s.st.AddMachine()
154
 
        c.Assert(err, IsNil)
155
 
        m1, err := s.st.AddMachine()
156
 
        c.Assert(err, IsNil)
157
 
        err = s.st.RemoveMachine(m0.Id())
158
 
        c.Assert(err, IsNil)
159
 
        s.assertMachineCount(c, 1)
160
 
        ms, err := s.st.AllMachines()
161
 
        c.Assert(ms[0].Id(), Equals, m1.Id())
 
60
        machine, err := s.State.AddMachine()
 
61
        c.Assert(err, IsNil)
 
62
        _, err = s.State.AddMachine()
 
63
        c.Assert(err, IsNil)
 
64
        err = s.State.RemoveMachine(machine.Id())
 
65
        c.Assert(err, IsNil)
 
66
 
 
67
        machines := s.AllMachines(c)
 
68
        c.Assert(machines, DeepEquals, []int{1})
162
69
 
163
70
        // Removing a non-existing machine has to fail.
164
 
        err = s.st.RemoveMachine(m0.Id())
165
 
        c.Assert(err, ErrorMatches, "can't remove machine 0")
166
 
}
167
 
 
168
 
func (s *StateSuite) TestMachineInstanceId(c *C) {
169
 
        machine, err := s.st.AddMachine()
170
 
        c.Assert(err, IsNil)
171
 
        err = s.machines.Update(
172
 
                bson.D{{"_id", machine.Id()}},
173
 
                bson.D{{"$set", bson.D{{"instanceid", "spaceship/0"}}}},
174
 
        )
175
 
        c.Assert(err, IsNil)
176
 
 
177
 
        iid, err := machine.InstanceId()
178
 
        c.Assert(err, IsNil)
179
 
        c.Assert(iid, Equals, "spaceship/0")
180
 
}
181
 
 
182
 
func (s *StateSuite) TestMachineSetInstanceId(c *C) {
183
 
        machine, err := s.st.AddMachine()
184
 
        c.Assert(err, IsNil)
185
 
        err = machine.SetInstanceId("umbrella/0")
186
 
        c.Assert(err, IsNil)
187
 
 
188
 
        n, err := s.machines.Find(bson.D{{"instanceid", "umbrella/0"}}).Count()
189
 
        c.Assert(err, IsNil)
190
 
        c.Assert(n, Equals, 1)
 
71
        // BUG: use error strings from state.
 
72
        err = s.State.RemoveMachine(machine.Id())
 
73
        c.Assert(err, ErrorMatches, "can't remove machine 0: .*")
191
74
}
192
75
 
193
76
func (s *StateSuite) TestReadMachine(c *C) {
194
 
        machine, err := s.st.AddMachine()
 
77
        machine, err := s.State.AddMachine()
195
78
        c.Assert(err, IsNil)
196
79
        expectedId := machine.Id()
197
 
        machine, err = s.st.Machine(expectedId)
 
80
        machine, err = s.State.Machine(expectedId)
198
81
        c.Assert(err, IsNil)
199
82
        c.Assert(machine.Id(), Equals, expectedId)
200
83
}
201
84
 
202
 
func (s *StateSuite) TestMachineUnits(c *C) {
203
 
        // Check that Machine.Units works correctly.
204
 
 
205
 
        // Make three machines, three services and three units for each service;
206
 
        // variously assign units to machines and check that Machine.Units
207
 
        // tells us the right thing.
208
 
 
209
 
        m0, err := s.st.AddMachine()
210
 
        c.Assert(err, IsNil)
211
 
        m1, err := s.st.AddMachine()
212
 
        c.Assert(err, IsNil)
213
 
        m2, err := s.st.AddMachine()
214
 
        c.Assert(err, IsNil)
215
 
 
216
 
        dummy := s.addDummyCharm(c)
217
 
        logging := addLoggingCharm(c, s.st)
218
 
        s0, err := s.st.AddService("s0", dummy)
219
 
        c.Assert(err, IsNil)
220
 
        s1, err := s.st.AddService("s1", dummy)
221
 
        c.Assert(err, IsNil)
222
 
        s2, err := s.st.AddService("s2", dummy)
223
 
        c.Assert(err, IsNil)
224
 
        s3, err := s.st.AddService("s3", logging)
225
 
        c.Assert(err, IsNil)
226
 
 
227
 
        units := make([][]*state.Unit, 4)
228
 
        for i, svc := range []*state.Service{s0, s1, s2} {
229
 
                units[i] = make([]*state.Unit, 3)
230
 
                for j := range units[i] {
231
 
                        units[i][j], err = svc.AddUnit()
232
 
                        c.Assert(err, IsNil)
233
 
                }
234
 
        }
235
 
        // Add the logging units subordinate to the s2 units.
236
 
        units[3] = make([]*state.Unit, 3)
237
 
        for i := range units[3] {
238
 
                units[3][i], err = s3.AddUnitSubordinateTo(units[2][i])
239
 
        }
240
 
 
241
 
        assignments := []struct {
242
 
                machine      *state.Machine
243
 
                units        []*state.Unit
244
 
                subordinates []*state.Unit
245
 
        }{
246
 
                {m0, []*state.Unit{units[0][0]}, nil},
247
 
                {m1, []*state.Unit{units[0][1], units[1][0], units[1][1], units[2][0]}, []*state.Unit{units[3][0]}},
248
 
                {m2, []*state.Unit{units[2][2]}, []*state.Unit{units[3][2]}},
249
 
        }
250
 
 
251
 
        for _, a := range assignments {
252
 
                for _, u := range a.units {
253
 
                        err := u.AssignToMachine(a.machine)
254
 
                        c.Assert(err, IsNil)
255
 
                }
256
 
        }
257
 
 
258
 
        for i, a := range assignments {
259
 
                c.Logf("test %d", i)
260
 
                got, err := a.machine.Units()
 
85
func (s *StateSuite) TestAllMachines(c *C) {
 
86
        numInserts := 42
 
87
        for i := 0; i < numInserts; i++ {
 
88
                err := s.machines.Insert(bson.D{{"_id", i}, {"life", state.Alive}})
261
89
                c.Assert(err, IsNil)
262
 
                expect := sortedUnitNames(append(a.units, a.subordinates...))
263
 
                c.Assert(sortedUnitNames(got), DeepEquals, expect)
264
 
        }
265
 
}
266
 
 
267
 
func sortedUnitNames(units []*state.Unit) []string {
268
 
        names := make([]string, len(units))
269
 
        for i, u := range units {
270
 
                names[i] = u.Name()
271
 
        }
272
 
        sort.Strings(names)
273
 
        return names
 
90
        }
 
91
        s.AssertMachineCount(c, numInserts)
 
92
        ms, _ := s.State.AllMachines()
 
93
        for k, v := range ms {
 
94
                c.Assert(v.Id(), Equals, k)
 
95
        }
274
96
}
275
97
 
276
98
func (s *StateSuite) TestAddService(c *C) {
277
 
        dummy := s.addDummyCharm(c)
278
 
        wordpress, err := s.st.AddService("wordpress", dummy)
 
99
        charm := s.AddTestingCharm(c, "dummy")
 
100
        wordpress, err := s.State.AddService("wordpress", charm)
279
101
        c.Assert(err, IsNil)
280
102
        c.Assert(wordpress.Name(), Equals, "wordpress")
281
 
        mysql, err := s.st.AddService("mysql", dummy)
 
103
        mysql, err := s.State.AddService("mysql", charm)
282
104
        c.Assert(err, IsNil)
283
105
        c.Assert(mysql.Name(), Equals, "mysql")
284
106
 
285
107
        // Check that retrieving the new created services works correctly.
286
 
        wordpress, err = s.st.Service("wordpress")
 
108
        wordpress, err = s.State.Service("wordpress")
287
109
        c.Assert(err, IsNil)
288
110
        c.Assert(wordpress.Name(), Equals, "wordpress")
289
111
        url, err := wordpress.CharmURL()
290
112
        c.Assert(err, IsNil)
291
 
        c.Assert(url.String(), Equals, s.curl.String())
292
 
        mysql, err = s.st.Service("mysql")
 
113
        c.Assert(url.String(), Equals, charm.URL().String())
 
114
        mysql, err = s.State.Service("mysql")
293
115
        c.Assert(err, IsNil)
294
116
        c.Assert(mysql.Name(), Equals, "mysql")
295
117
        url, err = mysql.CharmURL()
296
118
        c.Assert(err, IsNil)
297
 
        c.Assert(url.String(), Equals, s.curl.String())
298
 
}
299
 
 
300
 
func (s *StateSuite) TestReadNonExistentService(c *C) {
301
 
        _, err := s.st.Service("pressword")
302
 
        c.Assert(err, ErrorMatches, `can't get service "pressword": .*`)
 
119
        c.Assert(url.String(), Equals, charm.URL().String())
303
120
}
304
121
 
305
122
func (s *StateSuite) TestRemoveService(c *C) {
306
 
        dummy := s.addDummyCharm(c)
307
 
        service, err := s.st.AddService("wordpress", dummy)
 
123
        charm := s.AddTestingCharm(c, "dummy")
 
124
        service, err := s.State.AddService("wordpress", charm)
308
125
        c.Assert(err, IsNil)
309
126
 
310
127
        // Remove of existing service.
311
 
        err = s.st.RemoveService(service)
 
128
        err = s.State.RemoveService(service)
312
129
        c.Assert(err, IsNil)
313
 
        _, err = s.st.Service("wordpress")
 
130
        _, err = s.State.Service("wordpress")
314
131
        c.Assert(err, ErrorMatches, `can't get service "wordpress": .*`)
 
132
 
 
133
        // Remove of an illegal service, it has already been removed.
 
134
        // BUG: use error strings from state.
 
135
        err = s.State.RemoveService(service)
 
136
        c.Assert(err, ErrorMatches, `can't remove service "wordpress": .*`)
 
137
}
 
138
 
 
139
func (s *StateSuite) TestReadNonExistentService(c *C) {
 
140
        // BUG: use error strings from state.
 
141
        _, err := s.State.Service("pressword")
 
142
        c.Assert(err, ErrorMatches, `can't get service "pressword": .*`)
315
143
}
316
144
 
317
145
func (s *StateSuite) TestAllServices(c *C) {
318
 
        services, err := s.st.AllServices()
 
146
        charm := s.AddTestingCharm(c, "dummy")
 
147
        services, err := s.State.AllServices()
319
148
        c.Assert(err, IsNil)
320
149
        c.Assert(len(services), Equals, 0)
321
150
 
322
151
        // Check that after adding services the result is ok.
323
 
        dummy := s.addDummyCharm(c)
324
 
        _, err = s.st.AddService("wordpress", dummy)
 
152
        _, err = s.State.AddService("wordpress", charm)
325
153
        c.Assert(err, IsNil)
326
 
        services, err = s.st.AllServices()
 
154
        services, err = s.State.AllServices()
327
155
        c.Assert(err, IsNil)
328
156
        c.Assert(len(services), Equals, 1)
329
157
 
330
 
        _, err = s.st.AddService("mysql", dummy)
 
158
        _, err = s.State.AddService("mysql", charm)
331
159
        c.Assert(err, IsNil)
332
 
        services, err = s.st.AllServices()
 
160
        services, err = s.State.AllServices()
333
161
        c.Assert(err, IsNil)
334
162
        c.Assert(len(services), Equals, 2)
335
163
 
337
165
        c.Assert(services[0].Name(), Equals, "wordpress")
338
166
        c.Assert(services[1].Name(), Equals, "mysql")
339
167
}
340
 
 
341
 
func (s *StateSuite) TestAddUnit(c *C) {
342
 
        dummy := s.addDummyCharm(c)
343
 
        wordpress, err := s.st.AddService("wordpress", dummy)
344
 
        c.Assert(err, IsNil)
345
 
 
346
 
        // Check that principal units can be added on their own.
347
 
        unitZero, err := wordpress.AddUnit()
348
 
        c.Assert(err, IsNil)
349
 
        c.Assert(unitZero.Name(), Equals, "wordpress/0")
350
 
        principal := unitZero.IsPrincipal()
351
 
        c.Assert(principal, Equals, true)
352
 
        unitOne, err := wordpress.AddUnit()
353
 
        c.Assert(err, IsNil)
354
 
        c.Assert(unitOne.Name(), Equals, "wordpress/1")
355
 
        principal = unitOne.IsPrincipal()
356
 
        c.Assert(principal, Equals, true)
357
 
 
358
 
        // Check that principal units cannot be added to principal units.
359
 
        _, err = wordpress.AddUnitSubordinateTo(unitZero)
360
 
        c.Assert(err, ErrorMatches, `can't add unit of principal service "wordpress" as a subordinate of "wordpress/0"`)
361
 
 
362
 
        // Assign the principal unit to a machine.
363
 
        m, err := s.st.AddMachine()
364
 
        c.Assert(err, IsNil)
365
 
        err = unitZero.AssignToMachine(m)
366
 
        c.Assert(err, IsNil)
367
 
 
368
 
        // Add a subordinate service.
369
 
        subCh := addLoggingCharm(c, s.st)
370
 
        logging, err := s.st.AddService("logging", subCh)
371
 
        c.Assert(err, IsNil)
372
 
 
373
 
        // Check that subordinate units can be added to principal units
374
 
        subZero, err := logging.AddUnitSubordinateTo(unitZero)
375
 
        c.Assert(err, IsNil)
376
 
        c.Assert(subZero.Name(), Equals, "logging/0")
377
 
        principal = subZero.IsPrincipal()
378
 
        c.Assert(principal, Equals, false)
379
 
 
380
 
        // Check the subordinate unit has been assigned its principal's machine.
381
 
        id, err := subZero.AssignedMachineId()
382
 
        c.Assert(err, IsNil)
383
 
        c.Assert(id, Equals, m.Id())
384
 
 
385
 
        // Check that subordinate units must be added to other units.
386
 
        _, err = logging.AddUnit()
387
 
        c.Assert(err, ErrorMatches, `cannot directly add units to subordinate service "logging"`)
388
 
 
389
 
        // Check that subordinate units cannnot be added to subordinate units.
390
 
        _, err = logging.AddUnitSubordinateTo(subZero)
391
 
        c.Assert(err, ErrorMatches, "a subordinate unit must be added to a principal unit")
392
 
}
393
 
 
394
 
func (s *StateSuite) TestReadUnit(c *C) {
395
 
        dummy := s.addDummyCharm(c)
396
 
        wordpress, err := s.st.AddService("wordpress", dummy)
397
 
        c.Assert(err, IsNil)
398
 
        _, err = wordpress.AddUnit()
399
 
        c.Assert(err, IsNil)
400
 
        _, err = wordpress.AddUnit()
401
 
        c.Assert(err, IsNil)
402
 
        mysql, err := s.st.AddService("mysql", dummy)
403
 
        c.Assert(err, IsNil)
404
 
        _, err = mysql.AddUnit()
405
 
        c.Assert(err, IsNil)
406
 
 
407
 
        // Check that retrieving a unit works correctly.
408
 
        unit, err := wordpress.Unit("wordpress/0")
409
 
        c.Assert(err, IsNil)
410
 
        c.Assert(unit.Name(), Equals, "wordpress/0")
411
 
 
412
 
        // Check that retrieving a non-existent or an invalidly
413
 
        // named unit fail nicely.
414
 
        unit, err = wordpress.Unit("wordpress")
415
 
        c.Assert(err, ErrorMatches, `can't get unit "wordpress" from service "wordpress": .*`)
416
 
        unit, err = wordpress.Unit("wordpress/0/0")
417
 
        c.Assert(err, ErrorMatches, `can't get unit "wordpress/0/0" from service "wordpress": .*`)
418
 
        unit, err = wordpress.Unit("pressword/0")
419
 
        c.Assert(err, ErrorMatches, `can't get unit "pressword/0" from service "wordpress": .*`)
420
 
        unit, err = wordpress.Unit("mysql/0")
421
 
        c.Assert(err, ErrorMatches, `can't get unit "mysql/0" from service "wordpress": .*`)
422
 
 
423
 
        // Check that retrieving all units works.
424
 
        units, err := wordpress.AllUnits()
425
 
        c.Assert(err, IsNil)
426
 
        c.Assert(len(units), Equals, 2)
427
 
        c.Assert(units[0].Name(), Equals, "wordpress/0")
428
 
        c.Assert(units[1].Name(), Equals, "wordpress/1")
429
 
}
430
 
 
431
 
func (s *StateSuite) TestServiceCharm(c *C) {
432
 
        dummy := s.addDummyCharm(c)
433
 
        wordpress, err := s.st.AddService("wordpress", dummy)
434
 
        c.Assert(err, IsNil)
435
 
 
436
 
        // Check that getting and setting the service charm URL works correctly.
437
 
        testcurl, err := wordpress.CharmURL()
438
 
        c.Assert(err, IsNil)
439
 
        c.Assert(testcurl.String(), Equals, s.curl.String())
440
 
        testcurl, err = charm.ParseURL("local:myseries/mydummy-1")
441
 
        c.Assert(err, IsNil)
442
 
        err = wordpress.SetCharmURL(testcurl)
443
 
        c.Assert(err, IsNil)
444
 
        testcurl, err = wordpress.CharmURL()
445
 
        c.Assert(err, IsNil)
446
 
        c.Assert(testcurl.String(), Equals, "local:myseries/mydummy-1")
447
 
}
448
 
 
449
 
func (s *StateSuite) TestRemoveUnit(c *C) {
450
 
        dummy := s.addDummyCharm(c)
451
 
        wordpress, err := s.st.AddService("wordpress", dummy)
452
 
        c.Assert(err, IsNil)
453
 
        _, err = wordpress.AddUnit()
454
 
        c.Assert(err, IsNil)
455
 
        _, err = wordpress.AddUnit()
456
 
        c.Assert(err, IsNil)
457
 
 
458
 
        // Check that removing a unit works.
459
 
        unit, err := wordpress.Unit("wordpress/0")
460
 
        c.Assert(err, IsNil)
461
 
        err = wordpress.RemoveUnit(unit)
462
 
        c.Assert(err, IsNil)
463
 
 
464
 
        units, err := wordpress.AllUnits()
465
 
        c.Assert(err, IsNil)
466
 
        c.Assert(units, HasLen, 1)
467
 
        c.Assert(units[0].Name(), Equals, "wordpress/1")
468
 
 
469
 
        // Check that removing a non-existent unit fails nicely.
470
 
        err = wordpress.RemoveUnit(unit)
471
 
        // TODO use error string from state_test.TestRemoveUnit()
472
 
        c.Assert(err, ErrorMatches, `can't remove unit "wordpress/0": .*`)
473
 
}
474
 
 
475
 
// addLoggingCharm adds a "logging" (subordinate) charm
476
 
// to the state.
477
 
func addLoggingCharm(c *C, st *state.State) *state.Charm {
478
 
        bundle := testing.Charms.Bundle(c.MkDir(), "logging")
479
 
        curl := charm.MustParseURL("cs:series/logging-99")
480
 
        bundleURL, err := url.Parse("http://subordinate.url")
481
 
        c.Assert(err, IsNil)
482
 
        ch, err := st.AddCharm(bundle, curl, bundleURL, "dummy-sha256")
483
 
        c.Assert(err, IsNil)
484
 
        return ch
485
 
}
486
 
 
487
 
func (s *StateSuite) TestUnassignUnitFromMachineWithoutBeingAssigned(c *C) {
488
 
        // When unassigning a machine from a unit, it is possible that
489
 
        // the machine has not been previously assigned, or that it
490
 
        // was assigned but the state changed beneath us.  In either
491
 
        // case, the end state is the intended state, so we simply
492
 
        // move forward without any errors here, to avoid having to
493
 
        // handle the extra complexity of dealing with the concurrency
494
 
        // problems.
495
 
        dummy := s.addDummyCharm(c)
496
 
        wordpress, err := s.st.AddService("wordpress", dummy)
497
 
        c.Assert(err, IsNil)
498
 
        unit, err := wordpress.AddUnit()
499
 
        c.Assert(err, IsNil)
500
 
 
501
 
        err = unit.UnassignFromMachine()
502
 
        c.Assert(err, IsNil)
503
 
 
504
 
        // Check that the unit has no machine assigned.
505
 
        wordpress, err = s.st.Service("wordpress")
506
 
        c.Assert(err, IsNil)
507
 
        units, err := wordpress.AllUnits()
508
 
        c.Assert(err, IsNil)
509
 
        unit = units[0]
510
 
        _, err = unit.AssignedMachineId()
511
 
        c.Assert(err, ErrorMatches, `can't get machine id of unit "wordpress/0": unit not assigned to machine`)
512
 
}
513
 
 
514
 
func (s *StateSuite) TestAssignUnitToMachineAgainFails(c *C) {
515
 
        // Check that assigning an already assigned unit to
516
 
        // a machine fails if it isn't precisely the same
517
 
        // machine. 
518
 
        dummy := s.addDummyCharm(c)
519
 
        wordpress, err := s.st.AddService("wordpress", dummy)
520
 
        c.Assert(err, IsNil)
521
 
        unit, err := wordpress.AddUnit()
522
 
        c.Assert(err, IsNil)
523
 
        machineOne, err := s.st.AddMachine()
524
 
        c.Assert(err, IsNil)
525
 
        machineTwo, err := s.st.AddMachine()
526
 
        c.Assert(err, IsNil)
527
 
 
528
 
        err = unit.AssignToMachine(machineOne)
529
 
        c.Assert(err, IsNil)
530
 
 
531
 
        // Assigning the unit to the same machine should return no error.
532
 
        err = unit.AssignToMachine(machineOne)
533
 
        c.Assert(err, IsNil)
534
 
 
535
 
        // Assigning the unit to a different machine should fail.
536
 
        err = unit.AssignToMachine(machineTwo)
537
 
        c.Assert(err, ErrorMatches, `can't assign unit "wordpress/0" to machine 1: .*`)
538
 
        // TODO use error string from state_test.TestAssignUnitToMachineAgainFails
539
 
 
540
 
        machineId, err := unit.AssignedMachineId()
541
 
        c.Assert(err, IsNil)
542
 
        c.Assert(machineId, Equals, 0)
543
 
}