~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/cmd/juju/status/status_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2015 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package status
 
5
 
 
6
import (
 
7
        "bufio"
 
8
        "bytes"
 
9
        "encoding/json"
 
10
        "fmt"
 
11
        "os"
 
12
        "regexp"
 
13
        "strings"
 
14
        "time"
 
15
 
 
16
        "github.com/juju/cmd"
 
17
        jc "github.com/juju/testing/checkers"
 
18
        "github.com/juju/utils"
 
19
        "github.com/juju/version"
 
20
        gc "gopkg.in/check.v1"
 
21
        "gopkg.in/juju/charm.v6-unstable"
 
22
        "gopkg.in/juju/names.v2"
 
23
        goyaml "gopkg.in/yaml.v2"
 
24
 
 
25
        "github.com/juju/juju/apiserver/params"
 
26
        "github.com/juju/juju/cmd/modelcmd"
 
27
        "github.com/juju/juju/constraints"
 
28
        "github.com/juju/juju/core/migration"
 
29
        "github.com/juju/juju/environs"
 
30
        "github.com/juju/juju/instance"
 
31
        "github.com/juju/juju/juju/osenv"
 
32
        "github.com/juju/juju/juju/testing"
 
33
        "github.com/juju/juju/network"
 
34
        "github.com/juju/juju/state"
 
35
        "github.com/juju/juju/state/multiwatcher"
 
36
        "github.com/juju/juju/state/presence"
 
37
        "github.com/juju/juju/status"
 
38
        "github.com/juju/juju/testcharms"
 
39
        coretesting "github.com/juju/juju/testing"
 
40
        "github.com/juju/juju/testing/factory"
 
41
        coreversion "github.com/juju/juju/version"
 
42
)
 
43
 
 
44
var (
 
45
        currentVersion = version.Number{Major: 1, Minor: 2, Patch: 3}
 
46
        nextVersion    = version.Number{Major: 1, Minor: 2, Patch: 4}
 
47
)
 
48
 
 
49
func runStatus(c *gc.C, args ...string) (code int, stdout, stderr []byte) {
 
50
        ctx := coretesting.Context(c)
 
51
        code = cmd.Main(NewStatusCommand(), ctx, args)
 
52
        stdout = ctx.Stdout.(*bytes.Buffer).Bytes()
 
53
        stderr = ctx.Stderr.(*bytes.Buffer).Bytes()
 
54
        return
 
55
}
 
56
 
 
57
type StatusSuite struct {
 
58
        testing.JujuConnSuite
 
59
}
 
60
 
 
61
var _ = gc.Suite(&StatusSuite{})
 
62
 
 
63
func (s *StatusSuite) SetUpSuite(c *gc.C) {
 
64
        s.JujuConnSuite.SetUpSuite(c)
 
65
        s.PatchValue(&coreversion.Current, currentVersion)
 
66
}
 
67
 
 
68
func (s *StatusSuite) SetUpTest(c *gc.C) {
 
69
        s.ConfigAttrs = map[string]interface{}{
 
70
                "agent-version": currentVersion.String(),
 
71
        }
 
72
        s.JujuConnSuite.SetUpTest(c)
 
73
}
 
74
 
 
75
type M map[string]interface{}
 
76
 
 
77
type L []interface{}
 
78
 
 
79
type testCase struct {
 
80
        summary string
 
81
        steps   []stepper
 
82
}
 
83
 
 
84
func test(summary string, steps ...stepper) testCase {
 
85
        return testCase{summary, steps}
 
86
}
 
87
 
 
88
type stepper interface {
 
89
        step(c *gc.C, ctx *context)
 
90
}
 
91
 
 
92
//
 
93
// context
 
94
//
 
95
 
 
96
func newContext(st *state.State, env environs.Environ, adminUserTag string) *context {
 
97
        // We make changes in the API server's state so that
 
98
        // our changes to presence are immediately noticed
 
99
        // in the status.
 
100
        return &context{
 
101
                st:           st,
 
102
                env:          env,
 
103
                charms:       make(map[string]*state.Charm),
 
104
                pingers:      make(map[string]*presence.Pinger),
 
105
                adminUserTag: adminUserTag,
 
106
        }
 
107
}
 
108
 
 
109
type context struct {
 
110
        st            *state.State
 
111
        env           environs.Environ
 
112
        charms        map[string]*state.Charm
 
113
        pingers       map[string]*presence.Pinger
 
114
        adminUserTag  string // A string repr of the tag.
 
115
        expectIsoTime bool
 
116
}
 
117
 
 
118
func (ctx *context) reset(c *gc.C) {
 
119
        for _, up := range ctx.pingers {
 
120
                err := up.KillForTesting()
 
121
                c.Check(err, jc.ErrorIsNil)
 
122
        }
 
123
}
 
124
 
 
125
func (ctx *context) run(c *gc.C, steps []stepper) {
 
126
        for i, s := range steps {
 
127
                c.Logf("step %d", i)
 
128
                c.Logf("%#v", s)
 
129
                s.step(c, ctx)
 
130
        }
 
131
}
 
132
 
 
133
func (ctx *context) setAgentPresence(c *gc.C, p presence.Agent) *presence.Pinger {
 
134
        pinger, err := p.SetAgentPresence()
 
135
        c.Assert(err, jc.ErrorIsNil)
 
136
        ctx.st.StartSync()
 
137
        err = p.WaitAgentPresence(coretesting.LongWait)
 
138
        c.Assert(err, jc.ErrorIsNil)
 
139
        agentPresence, err := p.AgentPresence()
 
140
        c.Assert(err, jc.ErrorIsNil)
 
141
        c.Assert(agentPresence, jc.IsTrue)
 
142
        return pinger
 
143
}
 
144
 
 
145
func (s *StatusSuite) newContext(c *gc.C) *context {
 
146
        st := s.Environ.(testing.GetStater).GetStateInAPIServer()
 
147
 
 
148
        // We make changes in the API server's state so that
 
149
        // our changes to presence are immediately noticed
 
150
        // in the status.
 
151
        return newContext(st, s.Environ, s.AdminUserTag(c).String())
 
152
}
 
153
 
 
154
func (s *StatusSuite) resetContext(c *gc.C, ctx *context) {
 
155
        ctx.reset(c)
 
156
        s.JujuConnSuite.Reset(c)
 
157
}
 
158
 
 
159
// shortcuts for expected output.
 
160
var (
 
161
        model = M{
 
162
                "name":       "controller",
 
163
                "controller": "kontroll",
 
164
                "cloud":      "dummy",
 
165
                "version":    "1.2.3",
 
166
        }
 
167
 
 
168
        machine0 = M{
 
169
                "juju-status": M{
 
170
                        "current": "started",
 
171
                        "since":   "01 Apr 15 01:23+10:00",
 
172
                },
 
173
                "dns-name":    "controller-0.dns",
 
174
                "instance-id": "controller-0",
 
175
                "machine-status": M{
 
176
                        "current": "pending",
 
177
                        "since":   "01 Apr 15 01:23+10:00",
 
178
                },
 
179
                "series":                   "quantal",
 
180
                "hardware":                 "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
181
                "controller-member-status": "adding-vote",
 
182
        }
 
183
        machine1 = M{
 
184
                "juju-status": M{
 
185
                        "current": "started",
 
186
                        "since":   "01 Apr 15 01:23+10:00",
 
187
                },
 
188
                "dns-name":    "controller-1.dns",
 
189
                "instance-id": "controller-1",
 
190
                "machine-status": M{
 
191
                        "current": "pending",
 
192
                        "since":   "01 Apr 15 01:23+10:00",
 
193
                },
 
194
                "series":   "quantal",
 
195
                "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
196
        }
 
197
        machine2 = M{
 
198
                "juju-status": M{
 
199
                        "current": "started",
 
200
                        "since":   "01 Apr 15 01:23+10:00",
 
201
                },
 
202
                "dns-name":    "controller-2.dns",
 
203
                "instance-id": "controller-2",
 
204
                "machine-status": M{
 
205
                        "current": "pending",
 
206
                        "since":   "01 Apr 15 01:23+10:00",
 
207
                },
 
208
                "series":   "quantal",
 
209
                "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
210
        }
 
211
        machine3 = M{
 
212
                "juju-status": M{
 
213
                        "current": "started",
 
214
                        "since":   "01 Apr 15 01:23+10:00",
 
215
                },
 
216
                "dns-name":    "controller-3.dns",
 
217
                "instance-id": "controller-3",
 
218
                "machine-status": M{
 
219
                        "current": "pending",
 
220
                        "since":   "01 Apr 15 01:23+10:00",
 
221
                },
 
222
                "series":   "quantal",
 
223
                "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
224
        }
 
225
        machine4 = M{
 
226
                "juju-status": M{
 
227
                        "current": "started",
 
228
                        "since":   "01 Apr 15 01:23+10:00",
 
229
                },
 
230
                "dns-name":    "controller-4.dns",
 
231
                "instance-id": "controller-4",
 
232
                "machine-status": M{
 
233
                        "current": "pending",
 
234
                        "since":   "01 Apr 15 01:23+10:00",
 
235
                },
 
236
                "series":   "quantal",
 
237
                "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
238
        }
 
239
        machine1WithContainers = M{
 
240
                "juju-status": M{
 
241
                        "current": "started",
 
242
                        "since":   "01 Apr 15 01:23+10:00",
 
243
                },
 
244
                "containers": M{
 
245
                        "1/lxd/0": M{
 
246
                                "juju-status": M{
 
247
                                        "current": "started",
 
248
                                        "since":   "01 Apr 15 01:23+10:00",
 
249
                                },
 
250
                                "containers": M{
 
251
                                        "1/lxd/0/lxd/0": M{
 
252
                                                "juju-status": M{
 
253
                                                        "current": "started",
 
254
                                                        "since":   "01 Apr 15 01:23+10:00",
 
255
                                                },
 
256
                                                "dns-name":    "controller-3.dns",
 
257
                                                "instance-id": "controller-3",
 
258
                                                "machine-status": M{
 
259
                                                        "current": "pending",
 
260
                                                        "since":   "01 Apr 15 01:23+10:00",
 
261
                                                },
 
262
                                                "series": "quantal",
 
263
                                        },
 
264
                                },
 
265
                                "dns-name":    "controller-2.dns",
 
266
                                "instance-id": "controller-2",
 
267
                                "machine-status": M{
 
268
                                        "current": "pending",
 
269
                                        "since":   "01 Apr 15 01:23+10:00",
 
270
                                },
 
271
                                "series": "quantal",
 
272
                        },
 
273
                        "1/lxd/1": M{
 
274
                                "juju-status": M{
 
275
                                        "current": "pending",
 
276
                                        "since":   "01 Apr 15 01:23+10:00",
 
277
                                },
 
278
                                "instance-id": "pending",
 
279
                                "machine-status": M{
 
280
                                        "current": "pending",
 
281
                                        "since":   "01 Apr 15 01:23+10:00",
 
282
                                },
 
283
                                "series": "quantal",
 
284
                        },
 
285
                },
 
286
                "dns-name":    "controller-1.dns",
 
287
                "instance-id": "controller-1",
 
288
                "machine-status": M{
 
289
                        "current": "pending",
 
290
                        "since":   "01 Apr 15 01:23+10:00",
 
291
                },
 
292
 
 
293
                "series":   "quantal",
 
294
                "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
295
        }
 
296
        unexposedService = dummyCharm(M{
 
297
                "application-status": M{
 
298
                        "current": "unknown",
 
299
                        "message": "Waiting for agent initialization to finish",
 
300
                        "since":   "01 Apr 15 01:23+10:00",
 
301
                },
 
302
        })
 
303
        exposedService = dummyCharm(M{
 
304
                "application-status": M{
 
305
                        "current": "unknown",
 
306
                        "message": "Waiting for agent initialization to finish",
 
307
                        "since":   "01 Apr 15 01:23+10:00",
 
308
                },
 
309
                "exposed": true,
 
310
        })
 
311
        loggingCharm = M{
 
312
                "charm":              "cs:quantal/logging-1",
 
313
                "charm-origin":       "jujucharms",
 
314
                "charm-name":         "logging",
 
315
                "charm-rev":          1,
 
316
                "series":             "quantal",
 
317
                "os":                 "ubuntu",
 
318
                "exposed":            true,
 
319
                "application-status": M{},
 
320
                "relations": M{
 
321
                        "logging-directory": L{"wordpress"},
 
322
                        "info":              L{"mysql"},
 
323
                },
 
324
                "subordinate-to": L{"mysql", "wordpress"},
 
325
        }
 
326
)
 
327
 
 
328
type outputFormat struct {
 
329
        name      string
 
330
        marshal   func(v interface{}) ([]byte, error)
 
331
        unmarshal func(data []byte, v interface{}) error
 
332
}
 
333
 
 
334
// statusFormats list all output formats that can be marshalled as structured data,
 
335
// supported by status command.
 
336
var statusFormats = []outputFormat{
 
337
        {"yaml", goyaml.Marshal, goyaml.Unmarshal},
 
338
        {"json", json.Marshal, json.Unmarshal},
 
339
}
 
340
 
 
341
var machineCons = constraints.MustParse("cpu-cores=2 mem=8G root-disk=8G")
 
342
 
 
343
var statusTests = []testCase{
 
344
        // Status tests
 
345
        test( // 0
 
346
                "bootstrap and starting a single instance",
 
347
 
 
348
                addMachine{machineId: "0", job: state.JobManageModel},
 
349
                expect{
 
350
                        "simulate juju bootstrap by adding machine/0 to the state",
 
351
                        M{
 
352
                                "model": model,
 
353
                                "machines": M{
 
354
                                        "0": M{
 
355
                                                "juju-status": M{
 
356
                                                        "current": "pending",
 
357
                                                        "since":   "01 Apr 15 01:23+10:00",
 
358
                                                },
 
359
                                                "instance-id": "pending",
 
360
                                                "machine-status": M{
 
361
                                                        "current": "pending",
 
362
                                                        "since":   "01 Apr 15 01:23+10:00",
 
363
                                                },
 
364
                                                "series":                   "quantal",
 
365
                                                "controller-member-status": "adding-vote",
 
366
                                        },
 
367
                                },
 
368
                                "applications": M{},
 
369
                        },
 
370
                },
 
371
 
 
372
                startAliveMachine{"0"},
 
373
                setAddresses{"0", []network.Address{
 
374
                        network.NewAddress("10.0.0.1"),
 
375
                        network.NewScopedAddress("controller-0.dns", network.ScopePublic),
 
376
                }},
 
377
                expect{
 
378
                        "simulate the PA starting an instance in response to the state change",
 
379
                        M{
 
380
                                "model": model,
 
381
                                "machines": M{
 
382
                                        "0": M{
 
383
                                                "juju-status": M{
 
384
                                                        "current": "pending",
 
385
                                                        "since":   "01 Apr 15 01:23+10:00",
 
386
                                                },
 
387
                                                "dns-name":    "controller-0.dns",
 
388
                                                "instance-id": "controller-0",
 
389
                                                "machine-status": M{
 
390
                                                        "current": "pending",
 
391
                                                        "since":   "01 Apr 15 01:23+10:00",
 
392
                                                },
 
393
                                                "series":                   "quantal",
 
394
                                                "hardware":                 "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
395
                                                "controller-member-status": "adding-vote",
 
396
                                        },
 
397
                                },
 
398
                                "applications": M{},
 
399
                        },
 
400
                },
 
401
 
 
402
                setMachineStatus{"0", status.StatusStarted, ""},
 
403
                expect{
 
404
                        "simulate the MA started and set the machine status",
 
405
                        M{
 
406
                                "model": model,
 
407
                                "machines": M{
 
408
                                        "0": machine0,
 
409
                                },
 
410
                                "applications": M{},
 
411
                        },
 
412
                },
 
413
 
 
414
                setTools{"0", version.MustParseBinary("1.2.3-trusty-ppc")},
 
415
                expect{
 
416
                        "simulate the MA setting the version",
 
417
                        M{
 
418
                                "model": model,
 
419
                                "machines": M{
 
420
                                        "0": M{
 
421
                                                "dns-name":    "controller-0.dns",
 
422
                                                "instance-id": "controller-0",
 
423
                                                "machine-status": M{
 
424
                                                        "current": "pending",
 
425
                                                        "since":   "01 Apr 15 01:23+10:00",
 
426
                                                },
 
427
                                                "juju-status": M{
 
428
                                                        "current": "started",
 
429
                                                        "since":   "01 Apr 15 01:23+10:00",
 
430
                                                        "version": "1.2.3",
 
431
                                                },
 
432
                                                "series":                   "quantal",
 
433
                                                "hardware":                 "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
434
                                                "controller-member-status": "adding-vote",
 
435
                                        },
 
436
                                },
 
437
                                "applications": M{},
 
438
                        },
 
439
                },
 
440
        ),
 
441
        test( // 1
 
442
                "instance with different hardware characteristics",
 
443
                addMachine{machineId: "0", cons: machineCons, job: state.JobManageModel},
 
444
                setAddresses{"0", []network.Address{
 
445
                        network.NewAddress("10.0.0.1"),
 
446
                        network.NewScopedAddress("controller-0.dns", network.ScopePublic),
 
447
                }},
 
448
                startAliveMachine{"0"},
 
449
                setMachineStatus{"0", status.StatusStarted, ""},
 
450
                expect{
 
451
                        "machine 0 has specific hardware characteristics",
 
452
                        M{
 
453
                                "model": model,
 
454
                                "machines": M{
 
455
                                        "0": M{
 
456
                                                "juju-status": M{
 
457
                                                        "current": "started",
 
458
                                                        "since":   "01 Apr 15 01:23+10:00",
 
459
                                                },
 
460
                                                "dns-name":    "controller-0.dns",
 
461
                                                "instance-id": "controller-0",
 
462
                                                "machine-status": M{
 
463
                                                        "current": "pending",
 
464
                                                        "since":   "01 Apr 15 01:23+10:00",
 
465
                                                },
 
466
                                                "series":                   "quantal",
 
467
                                                "hardware":                 "arch=amd64 cpu-cores=2 mem=8192M root-disk=8192M",
 
468
                                                "controller-member-status": "adding-vote",
 
469
                                        },
 
470
                                },
 
471
                                "applications": M{},
 
472
                        },
 
473
                },
 
474
        ),
 
475
        test( // 2
 
476
                "instance without addresses",
 
477
                addMachine{machineId: "0", cons: machineCons, job: state.JobManageModel},
 
478
                startAliveMachine{"0"},
 
479
                setMachineStatus{"0", status.StatusStarted, ""},
 
480
                expect{
 
481
                        "machine 0 has no dns-name",
 
482
                        M{
 
483
                                "model": model,
 
484
                                "machines": M{
 
485
                                        "0": M{
 
486
                                                "juju-status": M{
 
487
                                                        "current": "started",
 
488
                                                        "since":   "01 Apr 15 01:23+10:00",
 
489
                                                },
 
490
                                                "instance-id": "controller-0",
 
491
                                                "machine-status": M{
 
492
                                                        "current": "pending",
 
493
                                                        "since":   "01 Apr 15 01:23+10:00",
 
494
                                                },
 
495
                                                "series":                   "quantal",
 
496
                                                "hardware":                 "arch=amd64 cpu-cores=2 mem=8192M root-disk=8192M",
 
497
                                                "controller-member-status": "adding-vote",
 
498
                                        },
 
499
                                },
 
500
                                "applications": M{},
 
501
                        },
 
502
                },
 
503
        ),
 
504
        test( // 3
 
505
                "test pending and missing machines",
 
506
                addMachine{machineId: "0", job: state.JobManageModel},
 
507
                expect{
 
508
                        "machine 0 reports pending",
 
509
                        M{
 
510
                                "model": model,
 
511
                                "machines": M{
 
512
                                        "0": M{
 
513
                                                "juju-status": M{
 
514
                                                        "current": "pending",
 
515
                                                        "since":   "01 Apr 15 01:23+10:00",
 
516
                                                },
 
517
                                                "instance-id": "pending",
 
518
                                                "machine-status": M{
 
519
                                                        "current": "pending",
 
520
                                                        "since":   "01 Apr 15 01:23+10:00",
 
521
                                                },
 
522
                                                "series":                   "quantal",
 
523
                                                "controller-member-status": "adding-vote",
 
524
                                        },
 
525
                                },
 
526
                                "applications": M{},
 
527
                        },
 
528
                },
 
529
 
 
530
                startMissingMachine{"0"},
 
531
                expect{
 
532
                        "machine 0 reports missing",
 
533
                        M{
 
534
                                "model": model,
 
535
                                "machines": M{
 
536
                                        "0": M{
 
537
                                                "instance-id": "i-missing",
 
538
                                                "juju-status": M{
 
539
                                                        "current": "pending",
 
540
                                                        "since":   "01 Apr 15 01:23+10:00",
 
541
                                                },
 
542
                                                "machine-status": M{
 
543
                                                        "current": "unknown",
 
544
                                                        "message": "missing",
 
545
                                                        "since":   "01 Apr 15 01:23+10:00",
 
546
                                                },
 
547
                                                "series":                   "quantal",
 
548
                                                "hardware":                 "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
549
                                                "controller-member-status": "adding-vote",
 
550
                                        },
 
551
                                },
 
552
                                "applications": M{},
 
553
                        },
 
554
                },
 
555
        ),
 
556
        test( // 4
 
557
                "add two services and expose one, then add 2 more machines and some units",
 
558
                // step 0
 
559
                addMachine{machineId: "0", job: state.JobManageModel},
 
560
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
561
                startAliveMachine{"0"},
 
562
                setMachineStatus{"0", status.StatusStarted, ""},
 
563
                addCharm{"dummy"},
 
564
                addService{name: "dummy-application", charm: "dummy"},
 
565
                addService{name: "exposed-application", charm: "dummy"},
 
566
                expect{
 
567
                        "no applications exposed yet",
 
568
                        M{
 
569
                                "model": model,
 
570
                                "machines": M{
 
571
                                        "0": machine0,
 
572
                                },
 
573
                                "applications": M{
 
574
                                        "dummy-application":   unexposedService,
 
575
                                        "exposed-application": unexposedService,
 
576
                                },
 
577
                        },
 
578
                },
 
579
 
 
580
                // step 8
 
581
                setServiceExposed{"exposed-application", true},
 
582
                expect{
 
583
                        "one exposed application",
 
584
                        M{
 
585
                                "model": model,
 
586
                                "machines": M{
 
587
                                        "0": machine0,
 
588
                                },
 
589
                                "applications": M{
 
590
                                        "dummy-application":   unexposedService,
 
591
                                        "exposed-application": exposedService,
 
592
                                },
 
593
                        },
 
594
                },
 
595
 
 
596
                // step 10
 
597
                addMachine{machineId: "1", job: state.JobHostUnits},
 
598
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
599
                startAliveMachine{"1"},
 
600
                setMachineStatus{"1", status.StatusStarted, ""},
 
601
                addMachine{machineId: "2", job: state.JobHostUnits},
 
602
                setAddresses{"2", network.NewAddresses("controller-2.dns")},
 
603
                startAliveMachine{"2"},
 
604
                setMachineStatus{"2", status.StatusStarted, ""},
 
605
                expect{
 
606
                        "two more machines added",
 
607
                        M{
 
608
                                "model": model,
 
609
                                "machines": M{
 
610
                                        "0": machine0,
 
611
                                        "1": machine1,
 
612
                                        "2": machine2,
 
613
                                },
 
614
                                "applications": M{
 
615
                                        "dummy-application":   unexposedService,
 
616
                                        "exposed-application": exposedService,
 
617
                                },
 
618
                        },
 
619
                },
 
620
 
 
621
                // step 19
 
622
                addAliveUnit{"dummy-application", "1"},
 
623
                addAliveUnit{"exposed-application", "2"},
 
624
                setAgentStatus{"exposed-application/0", status.StatusError, "You Require More Vespene Gas", nil},
 
625
                // Open multiple ports with different protocols,
 
626
                // ensure they're sorted on protocol, then number.
 
627
                openUnitPort{"exposed-application/0", "udp", 10},
 
628
                openUnitPort{"exposed-application/0", "udp", 2},
 
629
                openUnitPort{"exposed-application/0", "tcp", 3},
 
630
                openUnitPort{"exposed-application/0", "tcp", 2},
 
631
                // Simulate some status with no info, while the agent is down.
 
632
                // Status used to be down, we no longer support said state.
 
633
                // now is one of: pending, started, error.
 
634
                setUnitStatus{"dummy-application/0", status.StatusTerminated, "", nil},
 
635
                setAgentStatus{"dummy-application/0", status.StatusIdle, "", nil},
 
636
 
 
637
                expect{
 
638
                        "add two units, one alive (in error state), one started",
 
639
                        M{
 
640
                                "model": model,
 
641
                                "machines": M{
 
642
                                        "0": machine0,
 
643
                                        "1": machine1,
 
644
                                        "2": machine2,
 
645
                                },
 
646
                                "applications": M{
 
647
                                        "exposed-application": dummyCharm(M{
 
648
                                                "exposed": true,
 
649
                                                "application-status": M{
 
650
                                                        "current": "error",
 
651
                                                        "message": "You Require More Vespene Gas",
 
652
                                                        "since":   "01 Apr 15 01:23+10:00",
 
653
                                                },
 
654
                                                "units": M{
 
655
                                                        "exposed-application/0": M{
 
656
                                                                "machine": "2",
 
657
                                                                "workload-status": M{
 
658
                                                                        "current": "error",
 
659
                                                                        "message": "You Require More Vespene Gas",
 
660
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
661
                                                                },
 
662
                                                                "juju-status": M{
 
663
                                                                        "current": "idle",
 
664
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
665
                                                                },
 
666
                                                                "open-ports": L{
 
667
                                                                        "2/tcp", "3/tcp", "2/udp", "10/udp",
 
668
                                                                },
 
669
                                                                "public-address": "controller-2.dns",
 
670
                                                        },
 
671
                                                },
 
672
                                        }),
 
673
                                        "dummy-application": dummyCharm(M{
 
674
                                                "application-status": M{
 
675
                                                        "current": "terminated",
 
676
                                                        "since":   "01 Apr 15 01:23+10:00",
 
677
                                                },
 
678
                                                "units": M{
 
679
                                                        "dummy-application/0": M{
 
680
                                                                "machine": "1",
 
681
                                                                "workload-status": M{
 
682
                                                                        "current": "terminated",
 
683
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
684
                                                                },
 
685
                                                                "juju-status": M{
 
686
                                                                        "current": "idle",
 
687
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
688
                                                                },
 
689
                                                                "public-address": "controller-1.dns",
 
690
                                                        },
 
691
                                                },
 
692
                                        }),
 
693
                                },
 
694
                        },
 
695
                },
 
696
 
 
697
                // step 29
 
698
                addMachine{machineId: "3", job: state.JobHostUnits},
 
699
                startMachine{"3"},
 
700
                // Simulate some status with info, while the agent is down.
 
701
                setAddresses{"3", network.NewAddresses("controller-3.dns")},
 
702
                setMachineStatus{"3", status.StatusStopped, "Really?"},
 
703
                addMachine{machineId: "4", job: state.JobHostUnits},
 
704
                setAddresses{"4", network.NewAddresses("controller-4.dns")},
 
705
                startAliveMachine{"4"},
 
706
                setMachineStatus{"4", status.StatusError, "Beware the red toys"},
 
707
                ensureDyingUnit{"dummy-application/0"},
 
708
                addMachine{machineId: "5", job: state.JobHostUnits},
 
709
                ensureDeadMachine{"5"},
 
710
                expect{
 
711
                        "add three more machine, one with a dead agent, one in error state and one dead itself; also one dying unit",
 
712
                        M{
 
713
                                "model": model,
 
714
                                "machines": M{
 
715
                                        "0": machine0,
 
716
                                        "1": machine1,
 
717
                                        "2": machine2,
 
718
                                        "3": M{
 
719
                                                "dns-name":    "controller-3.dns",
 
720
                                                "instance-id": "controller-3",
 
721
                                                "machine-status": M{
 
722
                                                        "current": "pending",
 
723
                                                        "since":   "01 Apr 15 01:23+10:00",
 
724
                                                },
 
725
                                                "juju-status": M{
 
726
                                                        "current": "stopped",
 
727
                                                        "message": "Really?",
 
728
                                                        "since":   "01 Apr 15 01:23+10:00",
 
729
                                                },
 
730
                                                "series":   "quantal",
 
731
                                                "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
732
                                        },
 
733
                                        "4": M{
 
734
                                                "dns-name":    "controller-4.dns",
 
735
                                                "instance-id": "controller-4",
 
736
                                                "machine-status": M{
 
737
                                                        "current": "pending",
 
738
                                                        "since":   "01 Apr 15 01:23+10:00",
 
739
                                                },
 
740
                                                "juju-status": M{
 
741
                                                        "current": "error",
 
742
                                                        "message": "Beware the red toys",
 
743
                                                        "since":   "01 Apr 15 01:23+10:00",
 
744
                                                },
 
745
                                                "series":   "quantal",
 
746
                                                "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
747
                                        },
 
748
                                        "5": M{
 
749
                                                "juju-status": M{
 
750
                                                        "current": "pending",
 
751
                                                        "since":   "01 Apr 15 01:23+10:00",
 
752
                                                        "life":    "dead",
 
753
                                                },
 
754
                                                "instance-id": "pending",
 
755
                                                "machine-status": M{
 
756
                                                        "current": "pending",
 
757
                                                        "since":   "01 Apr 15 01:23+10:00",
 
758
                                                },
 
759
                                                "series": "quantal",
 
760
                                        },
 
761
                                },
 
762
                                "applications": M{
 
763
                                        "exposed-application": dummyCharm(M{
 
764
                                                "exposed": true,
 
765
                                                "application-status": M{
 
766
                                                        "current": "error",
 
767
                                                        "message": "You Require More Vespene Gas",
 
768
                                                        "since":   "01 Apr 15 01:23+10:00",
 
769
                                                },
 
770
                                                "units": M{
 
771
                                                        "exposed-application/0": M{
 
772
                                                                "machine": "2",
 
773
                                                                "workload-status": M{
 
774
                                                                        "current": "error",
 
775
                                                                        "message": "You Require More Vespene Gas",
 
776
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
777
                                                                },
 
778
                                                                "juju-status": M{
 
779
                                                                        "current": "idle",
 
780
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
781
                                                                },
 
782
                                                                "open-ports": L{
 
783
                                                                        "2/tcp", "3/tcp", "2/udp", "10/udp",
 
784
                                                                },
 
785
                                                                "public-address": "controller-2.dns",
 
786
                                                        },
 
787
                                                },
 
788
                                        }),
 
789
                                        "dummy-application": dummyCharm(M{
 
790
                                                "application-status": M{
 
791
                                                        "current": "terminated",
 
792
                                                        "since":   "01 Apr 15 01:23+10:00",
 
793
                                                },
 
794
                                                "units": M{
 
795
                                                        "dummy-application/0": M{
 
796
                                                                "machine": "1",
 
797
                                                                "workload-status": M{
 
798
                                                                        "current": "terminated",
 
799
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
800
                                                                },
 
801
                                                                "juju-status": M{
 
802
                                                                        "current": "idle",
 
803
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
804
                                                                },
 
805
                                                                "public-address": "controller-1.dns",
 
806
                                                        },
 
807
                                                },
 
808
                                        }),
 
809
                                },
 
810
                        },
 
811
                },
 
812
 
 
813
                // step 41
 
814
                scopedExpect{
 
815
                        "scope status on dummy-application/0 unit",
 
816
                        []string{"dummy-application/0"},
 
817
                        M{
 
818
                                "model": model,
 
819
                                "machines": M{
 
820
                                        "1": machine1,
 
821
                                },
 
822
                                "applications": M{
 
823
                                        "dummy-application": dummyCharm(M{
 
824
                                                "application-status": M{
 
825
                                                        "current": "terminated",
 
826
                                                        "since":   "01 Apr 15 01:23+10:00",
 
827
                                                },
 
828
                                                "units": M{
 
829
                                                        "dummy-application/0": M{
 
830
                                                                "machine": "1",
 
831
                                                                "workload-status": M{
 
832
                                                                        "current": "terminated",
 
833
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
834
                                                                },
 
835
                                                                "juju-status": M{
 
836
                                                                        "current": "idle",
 
837
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
838
                                                                },
 
839
                                                                "public-address": "controller-1.dns",
 
840
                                                        },
 
841
                                                },
 
842
                                        }),
 
843
                                },
 
844
                        },
 
845
                },
 
846
                scopedExpect{
 
847
                        "scope status on exposed-application application",
 
848
                        []string{"exposed-application"},
 
849
                        M{
 
850
                                "model": model,
 
851
                                "machines": M{
 
852
                                        "2": machine2,
 
853
                                },
 
854
                                "applications": M{
 
855
                                        "exposed-application": dummyCharm(M{
 
856
                                                "exposed": true,
 
857
                                                "application-status": M{
 
858
                                                        "current": "error",
 
859
                                                        "message": "You Require More Vespene Gas",
 
860
                                                        "since":   "01 Apr 15 01:23+10:00",
 
861
                                                },
 
862
                                                "units": M{
 
863
                                                        "exposed-application/0": M{
 
864
                                                                "machine": "2",
 
865
                                                                "workload-status": M{
 
866
                                                                        "current": "error",
 
867
                                                                        "message": "You Require More Vespene Gas",
 
868
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
869
                                                                },
 
870
                                                                "juju-status": M{
 
871
                                                                        "current": "idle",
 
872
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
873
                                                                },
 
874
                                                                "open-ports": L{
 
875
                                                                        "2/tcp", "3/tcp", "2/udp", "10/udp",
 
876
                                                                },
 
877
                                                                "public-address": "controller-2.dns",
 
878
                                                        },
 
879
                                                },
 
880
                                        }),
 
881
                                },
 
882
                        },
 
883
                },
 
884
                scopedExpect{
 
885
                        "scope status on application pattern",
 
886
                        []string{"d*-application"},
 
887
                        M{
 
888
                                "model": model,
 
889
                                "machines": M{
 
890
                                        "1": machine1,
 
891
                                },
 
892
                                "applications": M{
 
893
                                        "dummy-application": dummyCharm(M{
 
894
                                                "application-status": M{
 
895
                                                        "current": "terminated",
 
896
                                                        "since":   "01 Apr 15 01:23+10:00",
 
897
                                                },
 
898
                                                "units": M{
 
899
                                                        "dummy-application/0": M{
 
900
                                                                "machine": "1",
 
901
                                                                "workload-status": M{
 
902
                                                                        "current": "terminated",
 
903
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
904
                                                                },
 
905
                                                                "juju-status": M{
 
906
                                                                        "current": "idle",
 
907
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
908
                                                                },
 
909
                                                                "public-address": "controller-1.dns",
 
910
                                                        },
 
911
                                                },
 
912
                                        }),
 
913
                                },
 
914
                        },
 
915
                },
 
916
                scopedExpect{
 
917
                        "scope status on unit pattern",
 
918
                        []string{"e*posed-application/*"},
 
919
                        M{
 
920
                                "model": model,
 
921
                                "machines": M{
 
922
                                        "2": machine2,
 
923
                                },
 
924
                                "applications": M{
 
925
                                        "exposed-application": dummyCharm(M{
 
926
                                                "exposed": true,
 
927
                                                "application-status": M{
 
928
                                                        "current": "error",
 
929
                                                        "message": "You Require More Vespene Gas",
 
930
                                                        "since":   "01 Apr 15 01:23+10:00",
 
931
                                                },
 
932
                                                "units": M{
 
933
                                                        "exposed-application/0": M{
 
934
                                                                "machine": "2",
 
935
                                                                "workload-status": M{
 
936
                                                                        "current": "error",
 
937
                                                                        "message": "You Require More Vespene Gas",
 
938
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
939
                                                                },
 
940
                                                                "juju-status": M{
 
941
                                                                        "current": "idle",
 
942
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
943
                                                                },
 
944
                                                                "open-ports": L{
 
945
                                                                        "2/tcp", "3/tcp", "2/udp", "10/udp",
 
946
                                                                },
 
947
                                                                "public-address": "controller-2.dns",
 
948
                                                        },
 
949
                                                },
 
950
                                        }),
 
951
                                },
 
952
                        },
 
953
                },
 
954
                scopedExpect{
 
955
                        "scope status on combination of application and unit patterns",
 
956
                        []string{"exposed-application", "dummy-application", "e*posed-application/*", "dummy-application/*"},
 
957
                        M{
 
958
                                "model": model,
 
959
                                "machines": M{
 
960
                                        "1": machine1,
 
961
                                        "2": machine2,
 
962
                                },
 
963
                                "applications": M{
 
964
                                        "dummy-application": dummyCharm(M{
 
965
                                                "application-status": M{
 
966
                                                        "current": "terminated",
 
967
                                                        "since":   "01 Apr 15 01:23+10:00",
 
968
                                                },
 
969
                                                "units": M{
 
970
                                                        "dummy-application/0": M{
 
971
                                                                "machine": "1",
 
972
                                                                "workload-status": M{
 
973
                                                                        "current": "terminated",
 
974
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
975
                                                                },
 
976
                                                                "juju-status": M{
 
977
                                                                        "current": "idle",
 
978
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
979
                                                                },
 
980
                                                                "public-address": "controller-1.dns",
 
981
                                                        },
 
982
                                                },
 
983
                                        }),
 
984
                                        "exposed-application": dummyCharm(M{
 
985
                                                "exposed": true,
 
986
                                                "application-status": M{
 
987
                                                        "current": "error",
 
988
                                                        "message": "You Require More Vespene Gas",
 
989
                                                        "since":   "01 Apr 15 01:23+10:00",
 
990
                                                },
 
991
                                                "units": M{
 
992
                                                        "exposed-application/0": M{
 
993
                                                                "machine": "2",
 
994
                                                                "workload-status": M{
 
995
                                                                        "current": "error",
 
996
                                                                        "message": "You Require More Vespene Gas",
 
997
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
998
                                                                },
 
999
                                                                "juju-status": M{
 
1000
                                                                        "current": "idle",
 
1001
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1002
                                                                },
 
1003
                                                                "open-ports": L{
 
1004
                                                                        "2/tcp", "3/tcp", "2/udp", "10/udp",
 
1005
                                                                },
 
1006
                                                                "public-address": "controller-2.dns",
 
1007
                                                        },
 
1008
                                                },
 
1009
                                        }),
 
1010
                                },
 
1011
                        },
 
1012
                },
 
1013
        ),
 
1014
        test( // 5
 
1015
                "a unit with a hook relation error",
 
1016
                addMachine{machineId: "0", job: state.JobManageModel},
 
1017
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
1018
                startAliveMachine{"0"},
 
1019
                setMachineStatus{"0", status.StatusStarted, ""},
 
1020
 
 
1021
                addMachine{machineId: "1", job: state.JobHostUnits},
 
1022
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
1023
                startAliveMachine{"1"},
 
1024
                setMachineStatus{"1", status.StatusStarted, ""},
 
1025
 
 
1026
                addCharm{"wordpress"},
 
1027
                addService{name: "wordpress", charm: "wordpress"},
 
1028
                addAliveUnit{"wordpress", "1"},
 
1029
 
 
1030
                addCharm{"mysql"},
 
1031
                addService{name: "mysql", charm: "mysql"},
 
1032
                addAliveUnit{"mysql", "1"},
 
1033
 
 
1034
                relateServices{"wordpress", "mysql"},
 
1035
 
 
1036
                setAgentStatus{"wordpress/0", status.StatusError,
 
1037
                        "hook failed: some-relation-changed",
 
1038
                        map[string]interface{}{"relation-id": 0}},
 
1039
 
 
1040
                expect{
 
1041
                        "a unit with a hook relation error",
 
1042
                        M{
 
1043
                                "model": model,
 
1044
                                "machines": M{
 
1045
                                        "0": machine0,
 
1046
                                        "1": machine1,
 
1047
                                },
 
1048
                                "applications": M{
 
1049
                                        "wordpress": wordpressCharm(M{
 
1050
                                                "relations": M{
 
1051
                                                        "db": L{"mysql"},
 
1052
                                                },
 
1053
                                                "application-status": M{
 
1054
                                                        "current": "error",
 
1055
                                                        "message": "hook failed: some-relation-changed",
 
1056
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1057
                                                },
 
1058
                                                "units": M{
 
1059
                                                        "wordpress/0": M{
 
1060
                                                                "machine": "1",
 
1061
                                                                "workload-status": M{
 
1062
                                                                        "current": "error",
 
1063
                                                                        "message": "hook failed: some-relation-changed for mysql:server",
 
1064
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1065
                                                                },
 
1066
                                                                "juju-status": M{
 
1067
                                                                        "current": "idle",
 
1068
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1069
                                                                },
 
1070
                                                                "public-address": "controller-1.dns",
 
1071
                                                        },
 
1072
                                                },
 
1073
                                        }),
 
1074
                                        "mysql": mysqlCharm(M{
 
1075
                                                "relations": M{
 
1076
                                                        "server": L{"wordpress"},
 
1077
                                                },
 
1078
                                                "application-status": M{
 
1079
                                                        "current": "unknown",
 
1080
                                                        "message": "Waiting for agent initialization to finish",
 
1081
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1082
                                                },
 
1083
                                                "units": M{
 
1084
                                                        "mysql/0": M{
 
1085
                                                                "machine": "1",
 
1086
                                                                "workload-status": M{
 
1087
                                                                        "current": "unknown",
 
1088
                                                                        "message": "Waiting for agent initialization to finish",
 
1089
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1090
                                                                },
 
1091
                                                                "juju-status": M{
 
1092
                                                                        "current": "allocating",
 
1093
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1094
                                                                },
 
1095
                                                                "public-address": "controller-1.dns",
 
1096
                                                        },
 
1097
                                                },
 
1098
                                        }),
 
1099
                                },
 
1100
                        },
 
1101
                },
 
1102
        ),
 
1103
        test( // 6
 
1104
                "a unit with a hook relation error when the agent is down",
 
1105
                addMachine{machineId: "0", job: state.JobManageModel},
 
1106
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
1107
                startAliveMachine{"0"},
 
1108
                setMachineStatus{"0", status.StatusStarted, ""},
 
1109
 
 
1110
                addMachine{machineId: "1", job: state.JobHostUnits},
 
1111
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
1112
                startAliveMachine{"1"},
 
1113
                setMachineStatus{"1", status.StatusStarted, ""},
 
1114
 
 
1115
                addCharm{"wordpress"},
 
1116
                addService{name: "wordpress", charm: "wordpress"},
 
1117
                addAliveUnit{"wordpress", "1"},
 
1118
 
 
1119
                addCharm{"mysql"},
 
1120
                addService{name: "mysql", charm: "mysql"},
 
1121
                addAliveUnit{"mysql", "1"},
 
1122
 
 
1123
                relateServices{"wordpress", "mysql"},
 
1124
 
 
1125
                setAgentStatus{"wordpress/0", status.StatusError,
 
1126
                        "hook failed: some-relation-changed",
 
1127
                        map[string]interface{}{"relation-id": 0}},
 
1128
 
 
1129
                expect{
 
1130
                        "a unit with a hook relation error when the agent is down",
 
1131
                        M{
 
1132
                                "model": model,
 
1133
                                "machines": M{
 
1134
                                        "0": machine0,
 
1135
                                        "1": machine1,
 
1136
                                },
 
1137
                                "applications": M{
 
1138
                                        "wordpress": wordpressCharm(M{
 
1139
                                                "relations": M{
 
1140
                                                        "db": L{"mysql"},
 
1141
                                                },
 
1142
                                                "application-status": M{
 
1143
                                                        "current": "error",
 
1144
                                                        "message": "hook failed: some-relation-changed",
 
1145
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1146
                                                },
 
1147
                                                "units": M{
 
1148
                                                        "wordpress/0": M{
 
1149
                                                                "machine": "1",
 
1150
                                                                "workload-status": M{
 
1151
                                                                        "current": "error",
 
1152
                                                                        "message": "hook failed: some-relation-changed for mysql:server",
 
1153
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1154
                                                                },
 
1155
                                                                "juju-status": M{
 
1156
                                                                        "current": "idle",
 
1157
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1158
                                                                },
 
1159
                                                                "public-address": "controller-1.dns",
 
1160
                                                        },
 
1161
                                                },
 
1162
                                        }),
 
1163
                                        "mysql": mysqlCharm(M{
 
1164
                                                "relations": M{
 
1165
                                                        "server": L{"wordpress"},
 
1166
                                                },
 
1167
                                                "application-status": M{
 
1168
                                                        "current": "unknown",
 
1169
                                                        "message": "Waiting for agent initialization to finish",
 
1170
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1171
                                                },
 
1172
                                                "units": M{
 
1173
                                                        "mysql/0": M{
 
1174
                                                                "machine": "1",
 
1175
                                                                "workload-status": M{
 
1176
                                                                        "current": "unknown",
 
1177
                                                                        "message": "Waiting for agent initialization to finish",
 
1178
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1179
                                                                },
 
1180
                                                                "juju-status": M{
 
1181
                                                                        "current": "allocating",
 
1182
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1183
                                                                },
 
1184
                                                                "public-address": "controller-1.dns",
 
1185
                                                        },
 
1186
                                                },
 
1187
                                        }),
 
1188
                                },
 
1189
                        },
 
1190
                },
 
1191
        ),
 
1192
        test( // 7
 
1193
                "add a dying application",
 
1194
                addCharm{"dummy"},
 
1195
                addService{name: "dummy-application", charm: "dummy"},
 
1196
                addMachine{machineId: "0", job: state.JobHostUnits},
 
1197
                addAliveUnit{"dummy-application", "0"},
 
1198
                ensureDyingService{"dummy-application"},
 
1199
                expect{
 
1200
                        "application shows life==dying",
 
1201
                        M{
 
1202
                                "model": model,
 
1203
                                "machines": M{
 
1204
                                        "0": M{
 
1205
                                                "juju-status": M{
 
1206
                                                        "current": "pending",
 
1207
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1208
                                                },
 
1209
                                                "instance-id": "pending",
 
1210
                                                "machine-status": M{
 
1211
                                                        "current": "pending",
 
1212
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1213
                                                },
 
1214
 
 
1215
                                                "series": "quantal",
 
1216
                                        },
 
1217
                                },
 
1218
                                "applications": M{
 
1219
                                        "dummy-application": dummyCharm(M{
 
1220
                                                "life": "dying",
 
1221
                                                "application-status": M{
 
1222
                                                        "current": "unknown",
 
1223
                                                        "message": "Waiting for agent initialization to finish",
 
1224
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1225
                                                },
 
1226
                                                "units": M{
 
1227
                                                        "dummy-application/0": M{
 
1228
                                                                "machine": "0",
 
1229
                                                                "workload-status": M{
 
1230
                                                                        "current": "unknown",
 
1231
                                                                        "message": "Waiting for agent initialization to finish",
 
1232
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1233
                                                                },
 
1234
                                                                "juju-status": M{
 
1235
                                                                        "current": "allocating",
 
1236
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1237
                                                                },
 
1238
                                                        },
 
1239
                                                },
 
1240
                                        }),
 
1241
                                },
 
1242
                        },
 
1243
                },
 
1244
        ),
 
1245
        test( // 8
 
1246
                "a unit where the agent is down shows as lost",
 
1247
                addCharm{"dummy"},
 
1248
                addService{name: "dummy-application", charm: "dummy"},
 
1249
                addMachine{machineId: "0", job: state.JobHostUnits},
 
1250
                startAliveMachine{"0"},
 
1251
                setMachineStatus{"0", status.StatusStarted, ""},
 
1252
                addUnit{"dummy-application", "0"},
 
1253
                setAgentStatus{"dummy-application/0", status.StatusIdle, "", nil},
 
1254
                setUnitStatus{"dummy-application/0", status.StatusActive, "", nil},
 
1255
                expect{
 
1256
                        "unit shows that agent is lost",
 
1257
                        M{
 
1258
                                "model": model,
 
1259
                                "machines": M{
 
1260
                                        "0": M{
 
1261
                                                "juju-status": M{
 
1262
                                                        "current": "started",
 
1263
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1264
                                                },
 
1265
                                                "instance-id": "controller-0",
 
1266
                                                "machine-status": M{
 
1267
                                                        "current": "pending",
 
1268
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1269
                                                },
 
1270
 
 
1271
                                                "series":   "quantal",
 
1272
                                                "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
1273
                                        },
 
1274
                                },
 
1275
                                "applications": M{
 
1276
                                        "dummy-application": dummyCharm(M{
 
1277
                                                "application-status": M{
 
1278
                                                        "current": "active",
 
1279
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1280
                                                },
 
1281
                                                "units": M{
 
1282
                                                        "dummy-application/0": M{
 
1283
                                                                "machine": "0",
 
1284
                                                                "workload-status": M{
 
1285
                                                                        "current": "unknown",
 
1286
                                                                        "message": "agent is lost, sorry! See 'juju status-history dummy-application/0'",
 
1287
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1288
                                                                },
 
1289
                                                                "juju-status": M{
 
1290
                                                                        "current": "lost",
 
1291
                                                                        "message": "agent is not communicating with the server",
 
1292
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1293
                                                                },
 
1294
                                                        },
 
1295
                                                },
 
1296
                                        }),
 
1297
                                },
 
1298
                        },
 
1299
                },
 
1300
        ),
 
1301
 
 
1302
        // Relation tests
 
1303
        test( // 9
 
1304
                "complex scenario with multiple related services",
 
1305
                addMachine{machineId: "0", job: state.JobManageModel},
 
1306
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
1307
                startAliveMachine{"0"},
 
1308
                setMachineStatus{"0", status.StatusStarted, ""},
 
1309
                addCharm{"wordpress"},
 
1310
                addCharm{"mysql"},
 
1311
                addCharm{"varnish"},
 
1312
 
 
1313
                addService{name: "project", charm: "wordpress"},
 
1314
                setServiceExposed{"project", true},
 
1315
                addMachine{machineId: "1", job: state.JobHostUnits},
 
1316
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
1317
                startAliveMachine{"1"},
 
1318
                setMachineStatus{"1", status.StatusStarted, ""},
 
1319
                addAliveUnit{"project", "1"},
 
1320
                setAgentStatus{"project/0", status.StatusIdle, "", nil},
 
1321
                setUnitStatus{"project/0", status.StatusActive, "", nil},
 
1322
 
 
1323
                addService{name: "mysql", charm: "mysql"},
 
1324
                setServiceExposed{"mysql", true},
 
1325
                addMachine{machineId: "2", job: state.JobHostUnits},
 
1326
                setAddresses{"2", network.NewAddresses("controller-2.dns")},
 
1327
                startAliveMachine{"2"},
 
1328
                setMachineStatus{"2", status.StatusStarted, ""},
 
1329
                addAliveUnit{"mysql", "2"},
 
1330
                setAgentStatus{"mysql/0", status.StatusIdle, "", nil},
 
1331
                setUnitStatus{"mysql/0", status.StatusActive, "", nil},
 
1332
 
 
1333
                addService{name: "varnish", charm: "varnish"},
 
1334
                setServiceExposed{"varnish", true},
 
1335
                addMachine{machineId: "3", job: state.JobHostUnits},
 
1336
                setAddresses{"3", network.NewAddresses("controller-3.dns")},
 
1337
                startAliveMachine{"3"},
 
1338
                setMachineStatus{"3", status.StatusStarted, ""},
 
1339
                addAliveUnit{"varnish", "3"},
 
1340
 
 
1341
                addService{name: "private", charm: "wordpress"},
 
1342
                setServiceExposed{"private", true},
 
1343
                addMachine{machineId: "4", job: state.JobHostUnits},
 
1344
                setAddresses{"4", network.NewAddresses("controller-4.dns")},
 
1345
                startAliveMachine{"4"},
 
1346
                setMachineStatus{"4", status.StatusStarted, ""},
 
1347
                addAliveUnit{"private", "4"},
 
1348
 
 
1349
                relateServices{"project", "mysql"},
 
1350
                relateServices{"project", "varnish"},
 
1351
                relateServices{"private", "mysql"},
 
1352
 
 
1353
                expect{
 
1354
                        "multiples services with relations between some of them",
 
1355
                        M{
 
1356
                                "model": model,
 
1357
                                "machines": M{
 
1358
                                        "0": machine0,
 
1359
                                        "1": machine1,
 
1360
                                        "2": machine2,
 
1361
                                        "3": machine3,
 
1362
                                        "4": machine4,
 
1363
                                },
 
1364
                                "applications": M{
 
1365
                                        "project": wordpressCharm(M{
 
1366
                                                "exposed": true,
 
1367
                                                "application-status": M{
 
1368
                                                        "current": "active",
 
1369
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1370
                                                },
 
1371
                                                "units": M{
 
1372
                                                        "project/0": M{
 
1373
                                                                "machine": "1",
 
1374
                                                                "workload-status": M{
 
1375
                                                                        "current": "active",
 
1376
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1377
                                                                },
 
1378
                                                                "juju-status": M{
 
1379
                                                                        "current": "idle",
 
1380
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1381
                                                                },
 
1382
                                                                "public-address": "controller-1.dns",
 
1383
                                                        },
 
1384
                                                },
 
1385
                                                "relations": M{
 
1386
                                                        "db":    L{"mysql"},
 
1387
                                                        "cache": L{"varnish"},
 
1388
                                                },
 
1389
                                        }),
 
1390
                                        "mysql": mysqlCharm(M{
 
1391
                                                "exposed": true,
 
1392
                                                "application-status": M{
 
1393
                                                        "current": "active",
 
1394
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1395
                                                },
 
1396
                                                "units": M{
 
1397
                                                        "mysql/0": M{
 
1398
                                                                "machine": "2",
 
1399
                                                                "workload-status": M{
 
1400
                                                                        "current": "active",
 
1401
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1402
                                                                },
 
1403
                                                                "juju-status": M{
 
1404
                                                                        "current": "idle",
 
1405
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1406
                                                                },
 
1407
                                                                "public-address": "controller-2.dns",
 
1408
                                                        },
 
1409
                                                },
 
1410
                                                "relations": M{
 
1411
                                                        "server": L{"private", "project"},
 
1412
                                                },
 
1413
                                        }),
 
1414
                                        "varnish": M{
 
1415
                                                "charm":        "cs:quantal/varnish-1",
 
1416
                                                "charm-origin": "jujucharms",
 
1417
                                                "charm-name":   "varnish",
 
1418
                                                "charm-rev":    1,
 
1419
                                                "series":       "quantal",
 
1420
                                                "os":           "ubuntu",
 
1421
                                                "exposed":      true,
 
1422
                                                "application-status": M{
 
1423
                                                        "current": "unknown",
 
1424
                                                        "message": "Waiting for agent initialization to finish",
 
1425
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1426
                                                },
 
1427
                                                "units": M{
 
1428
                                                        "varnish/0": M{
 
1429
                                                                "machine": "3",
 
1430
                                                                "workload-status": M{
 
1431
                                                                        "current": "unknown",
 
1432
                                                                        "message": "Waiting for agent initialization to finish",
 
1433
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1434
                                                                },
 
1435
                                                                "juju-status": M{
 
1436
                                                                        "current": "allocating",
 
1437
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1438
                                                                },
 
1439
                                                                "public-address": "controller-3.dns",
 
1440
                                                        },
 
1441
                                                },
 
1442
                                                "relations": M{
 
1443
                                                        "webcache": L{"project"},
 
1444
                                                },
 
1445
                                        },
 
1446
                                        "private": wordpressCharm(M{
 
1447
                                                "exposed": true,
 
1448
                                                "application-status": M{
 
1449
                                                        "current": "unknown",
 
1450
                                                        "message": "Waiting for agent initialization to finish",
 
1451
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1452
                                                },
 
1453
                                                "units": M{
 
1454
                                                        "private/0": M{
 
1455
                                                                "machine": "4",
 
1456
                                                                "workload-status": M{
 
1457
                                                                        "current": "unknown",
 
1458
                                                                        "message": "Waiting for agent initialization to finish",
 
1459
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1460
                                                                },
 
1461
                                                                "juju-status": M{
 
1462
                                                                        "current": "allocating",
 
1463
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1464
                                                                },
 
1465
                                                                "public-address": "controller-4.dns",
 
1466
                                                        },
 
1467
                                                },
 
1468
                                                "relations": M{
 
1469
                                                        "db": L{"mysql"},
 
1470
                                                },
 
1471
                                        }),
 
1472
                                },
 
1473
                        },
 
1474
                },
 
1475
        ),
 
1476
        test( // 10
 
1477
                "simple peer scenario",
 
1478
                addMachine{machineId: "0", job: state.JobManageModel},
 
1479
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
1480
                startAliveMachine{"0"},
 
1481
                setMachineStatus{"0", status.StatusStarted, ""},
 
1482
                addCharm{"riak"},
 
1483
                addCharm{"wordpress"},
 
1484
 
 
1485
                addService{name: "riak", charm: "riak"},
 
1486
                setServiceExposed{"riak", true},
 
1487
                addMachine{machineId: "1", job: state.JobHostUnits},
 
1488
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
1489
                startAliveMachine{"1"},
 
1490
                setMachineStatus{"1", status.StatusStarted, ""},
 
1491
                addAliveUnit{"riak", "1"},
 
1492
                setAgentStatus{"riak/0", status.StatusIdle, "", nil},
 
1493
                setUnitStatus{"riak/0", status.StatusActive, "", nil},
 
1494
                addMachine{machineId: "2", job: state.JobHostUnits},
 
1495
                setAddresses{"2", network.NewAddresses("controller-2.dns")},
 
1496
                startAliveMachine{"2"},
 
1497
                setMachineStatus{"2", status.StatusStarted, ""},
 
1498
                addAliveUnit{"riak", "2"},
 
1499
                setAgentStatus{"riak/1", status.StatusIdle, "", nil},
 
1500
                setUnitStatus{"riak/1", status.StatusActive, "", nil},
 
1501
                addMachine{machineId: "3", job: state.JobHostUnits},
 
1502
                setAddresses{"3", network.NewAddresses("controller-3.dns")},
 
1503
                startAliveMachine{"3"},
 
1504
                setMachineStatus{"3", status.StatusStarted, ""},
 
1505
                addAliveUnit{"riak", "3"},
 
1506
                setAgentStatus{"riak/2", status.StatusIdle, "", nil},
 
1507
                setUnitStatus{"riak/2", status.StatusActive, "", nil},
 
1508
 
 
1509
                expect{
 
1510
                        "multiples related peer units",
 
1511
                        M{
 
1512
                                "model": model,
 
1513
                                "machines": M{
 
1514
                                        "0": machine0,
 
1515
                                        "1": machine1,
 
1516
                                        "2": machine2,
 
1517
                                        "3": machine3,
 
1518
                                },
 
1519
                                "applications": M{
 
1520
                                        "riak": M{
 
1521
                                                "charm":        "cs:quantal/riak-7",
 
1522
                                                "charm-origin": "jujucharms",
 
1523
                                                "charm-name":   "riak",
 
1524
                                                "charm-rev":    7,
 
1525
                                                "series":       "quantal",
 
1526
                                                "os":           "ubuntu",
 
1527
                                                "exposed":      true,
 
1528
                                                "application-status": M{
 
1529
                                                        "current": "active",
 
1530
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1531
                                                },
 
1532
                                                "units": M{
 
1533
                                                        "riak/0": M{
 
1534
                                                                "machine": "1",
 
1535
                                                                "workload-status": M{
 
1536
                                                                        "current": "active",
 
1537
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1538
                                                                },
 
1539
                                                                "juju-status": M{
 
1540
                                                                        "current": "idle",
 
1541
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1542
                                                                },
 
1543
                                                                "public-address": "controller-1.dns",
 
1544
                                                        },
 
1545
                                                        "riak/1": M{
 
1546
                                                                "machine": "2",
 
1547
                                                                "workload-status": M{
 
1548
                                                                        "current": "active",
 
1549
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1550
                                                                },
 
1551
                                                                "juju-status": M{
 
1552
                                                                        "current": "idle",
 
1553
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1554
                                                                },
 
1555
                                                                "public-address": "controller-2.dns",
 
1556
                                                        },
 
1557
                                                        "riak/2": M{
 
1558
                                                                "machine": "3",
 
1559
                                                                "workload-status": M{
 
1560
                                                                        "current": "active",
 
1561
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1562
                                                                },
 
1563
                                                                "juju-status": M{
 
1564
                                                                        "current": "idle",
 
1565
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1566
                                                                },
 
1567
                                                                "public-address": "controller-3.dns",
 
1568
                                                        },
 
1569
                                                },
 
1570
                                                "relations": M{
 
1571
                                                        "ring": L{"riak"},
 
1572
                                                },
 
1573
                                        },
 
1574
                                },
 
1575
                        },
 
1576
                },
 
1577
        ),
 
1578
 
 
1579
        // Subordinate tests
 
1580
        test( // 11
 
1581
                "one application with one subordinate application",
 
1582
                addMachine{machineId: "0", job: state.JobManageModel},
 
1583
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
1584
                startAliveMachine{"0"},
 
1585
                setMachineStatus{"0", status.StatusStarted, ""},
 
1586
                addCharm{"wordpress"},
 
1587
                addCharm{"mysql"},
 
1588
                addCharm{"logging"},
 
1589
 
 
1590
                addService{name: "wordpress", charm: "wordpress"},
 
1591
                setServiceExposed{"wordpress", true},
 
1592
                addMachine{machineId: "1", job: state.JobHostUnits},
 
1593
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
1594
                startAliveMachine{"1"},
 
1595
                setMachineStatus{"1", status.StatusStarted, ""},
 
1596
                addAliveUnit{"wordpress", "1"},
 
1597
                setAgentStatus{"wordpress/0", status.StatusIdle, "", nil},
 
1598
                setUnitStatus{"wordpress/0", status.StatusActive, "", nil},
 
1599
 
 
1600
                addService{name: "mysql", charm: "mysql"},
 
1601
                setServiceExposed{"mysql", true},
 
1602
                addMachine{machineId: "2", job: state.JobHostUnits},
 
1603
                setAddresses{"2", network.NewAddresses("controller-2.dns")},
 
1604
                startAliveMachine{"2"},
 
1605
                setMachineStatus{"2", status.StatusStarted, ""},
 
1606
                addAliveUnit{"mysql", "2"},
 
1607
                setAgentStatus{"mysql/0", status.StatusIdle, "", nil},
 
1608
                setUnitStatus{"mysql/0", status.StatusActive, "", nil},
 
1609
 
 
1610
                addService{name: "logging", charm: "logging"},
 
1611
                setServiceExposed{"logging", true},
 
1612
 
 
1613
                relateServices{"wordpress", "mysql"},
 
1614
                relateServices{"wordpress", "logging"},
 
1615
                relateServices{"mysql", "logging"},
 
1616
 
 
1617
                addSubordinate{"wordpress/0", "logging"},
 
1618
                addSubordinate{"mysql/0", "logging"},
 
1619
 
 
1620
                setUnitsAlive{"logging"},
 
1621
                setAgentStatus{"logging/0", status.StatusIdle, "", nil},
 
1622
                setUnitStatus{"logging/0", status.StatusActive, "", nil},
 
1623
                setAgentStatus{"logging/1", status.StatusError, "somehow lost in all those logs", nil},
 
1624
 
 
1625
                expect{
 
1626
                        "multiples related peer units",
 
1627
                        M{
 
1628
                                "model": model,
 
1629
                                "machines": M{
 
1630
                                        "0": machine0,
 
1631
                                        "1": machine1,
 
1632
                                        "2": machine2,
 
1633
                                },
 
1634
                                "applications": M{
 
1635
                                        "wordpress": wordpressCharm(M{
 
1636
                                                "exposed": true,
 
1637
                                                "application-status": M{
 
1638
                                                        "current": "active",
 
1639
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1640
                                                },
 
1641
                                                "units": M{
 
1642
                                                        "wordpress/0": M{
 
1643
                                                                "machine": "1",
 
1644
                                                                "workload-status": M{
 
1645
                                                                        "current": "active",
 
1646
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1647
                                                                },
 
1648
                                                                "juju-status": M{
 
1649
                                                                        "current": "idle",
 
1650
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1651
                                                                },
 
1652
                                                                "subordinates": M{
 
1653
                                                                        "logging/0": M{
 
1654
                                                                                "workload-status": M{
 
1655
                                                                                        "current": "active",
 
1656
                                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1657
                                                                                },
 
1658
                                                                                "juju-status": M{
 
1659
                                                                                        "current": "idle",
 
1660
                                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1661
                                                                                },
 
1662
                                                                                "public-address": "controller-1.dns",
 
1663
                                                                        },
 
1664
                                                                },
 
1665
                                                                "public-address": "controller-1.dns",
 
1666
                                                        },
 
1667
                                                },
 
1668
                                                "relations": M{
 
1669
                                                        "db":          L{"mysql"},
 
1670
                                                        "logging-dir": L{"logging"},
 
1671
                                                },
 
1672
                                        }),
 
1673
                                        "mysql": mysqlCharm(M{
 
1674
                                                "exposed": true,
 
1675
                                                "application-status": M{
 
1676
                                                        "current": "active",
 
1677
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1678
                                                },
 
1679
                                                "units": M{
 
1680
                                                        "mysql/0": M{
 
1681
                                                                "machine": "2",
 
1682
                                                                "workload-status": M{
 
1683
                                                                        "current": "active",
 
1684
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1685
                                                                },
 
1686
                                                                "juju-status": M{
 
1687
                                                                        "current": "idle",
 
1688
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1689
                                                                },
 
1690
                                                                "subordinates": M{
 
1691
                                                                        "logging/1": M{
 
1692
                                                                                "workload-status": M{
 
1693
                                                                                        "current": "error",
 
1694
                                                                                        "message": "somehow lost in all those logs",
 
1695
                                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1696
                                                                                },
 
1697
                                                                                "juju-status": M{
 
1698
                                                                                        "current": "idle",
 
1699
                                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1700
                                                                                },
 
1701
                                                                                "public-address": "controller-2.dns",
 
1702
                                                                        },
 
1703
                                                                },
 
1704
                                                                "public-address": "controller-2.dns",
 
1705
                                                        },
 
1706
                                                },
 
1707
                                                "relations": M{
 
1708
                                                        "server":    L{"wordpress"},
 
1709
                                                        "juju-info": L{"logging"},
 
1710
                                                },
 
1711
                                        }),
 
1712
                                        "logging": loggingCharm,
 
1713
                                },
 
1714
                        },
 
1715
                },
 
1716
 
 
1717
                // scoped on 'logging'
 
1718
                scopedExpect{
 
1719
                        "subordinates scoped on logging",
 
1720
                        []string{"logging"},
 
1721
                        M{
 
1722
                                "model": model,
 
1723
                                "machines": M{
 
1724
                                        "1": machine1,
 
1725
                                        "2": machine2,
 
1726
                                },
 
1727
                                "applications": M{
 
1728
                                        "wordpress": wordpressCharm(M{
 
1729
                                                "exposed": true,
 
1730
                                                "application-status": M{
 
1731
                                                        "current": "active",
 
1732
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1733
                                                },
 
1734
                                                "units": M{
 
1735
                                                        "wordpress/0": M{
 
1736
                                                                "machine": "1",
 
1737
                                                                "workload-status": M{
 
1738
                                                                        "current": "active",
 
1739
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1740
                                                                },
 
1741
                                                                "juju-status": M{
 
1742
                                                                        "current": "idle",
 
1743
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1744
                                                                },
 
1745
                                                                "subordinates": M{
 
1746
                                                                        "logging/0": M{
 
1747
                                                                                "workload-status": M{
 
1748
                                                                                        "current": "active",
 
1749
                                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1750
                                                                                },
 
1751
                                                                                "juju-status": M{
 
1752
                                                                                        "current": "idle",
 
1753
                                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1754
                                                                                },
 
1755
                                                                                "public-address": "controller-1.dns",
 
1756
                                                                        },
 
1757
                                                                },
 
1758
                                                                "public-address": "controller-1.dns",
 
1759
                                                        },
 
1760
                                                },
 
1761
                                                "relations": M{
 
1762
                                                        "db":          L{"mysql"},
 
1763
                                                        "logging-dir": L{"logging"},
 
1764
                                                },
 
1765
                                        }),
 
1766
                                        "mysql": mysqlCharm(M{
 
1767
                                                "exposed": true,
 
1768
                                                "application-status": M{
 
1769
                                                        "current": "active",
 
1770
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1771
                                                },
 
1772
                                                "units": M{
 
1773
                                                        "mysql/0": M{
 
1774
                                                                "machine": "2",
 
1775
                                                                "workload-status": M{
 
1776
                                                                        "current": "active",
 
1777
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1778
                                                                },
 
1779
                                                                "juju-status": M{
 
1780
                                                                        "current": "idle",
 
1781
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1782
                                                                },
 
1783
                                                                "subordinates": M{
 
1784
                                                                        "logging/1": M{
 
1785
                                                                                "workload-status": M{
 
1786
                                                                                        "current": "error",
 
1787
                                                                                        "message": "somehow lost in all those logs",
 
1788
                                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1789
                                                                                },
 
1790
                                                                                "juju-status": M{
 
1791
                                                                                        "current": "idle",
 
1792
                                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1793
                                                                                },
 
1794
                                                                                "public-address": "controller-2.dns",
 
1795
                                                                        },
 
1796
                                                                },
 
1797
                                                                "public-address": "controller-2.dns",
 
1798
                                                        },
 
1799
                                                },
 
1800
                                                "relations": M{
 
1801
                                                        "server":    L{"wordpress"},
 
1802
                                                        "juju-info": L{"logging"},
 
1803
                                                },
 
1804
                                        }),
 
1805
                                        "logging": loggingCharm,
 
1806
                                },
 
1807
                        },
 
1808
                },
 
1809
 
 
1810
                // scoped on wordpress/0
 
1811
                scopedExpect{
 
1812
                        "subordinates scoped on logging",
 
1813
                        []string{"wordpress/0"},
 
1814
                        M{
 
1815
                                "model": model,
 
1816
                                "machines": M{
 
1817
                                        "1": machine1,
 
1818
                                },
 
1819
                                "applications": M{
 
1820
                                        "wordpress": wordpressCharm(M{
 
1821
                                                "exposed": true,
 
1822
                                                "application-status": M{
 
1823
                                                        "current": "active",
 
1824
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1825
                                                },
 
1826
                                                "units": M{
 
1827
                                                        "wordpress/0": M{
 
1828
                                                                "machine": "1",
 
1829
                                                                "workload-status": M{
 
1830
                                                                        "current": "active",
 
1831
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1832
                                                                },
 
1833
                                                                "juju-status": M{
 
1834
                                                                        "current": "idle",
 
1835
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1836
                                                                },
 
1837
                                                                "subordinates": M{
 
1838
                                                                        "logging/0": M{
 
1839
                                                                                "workload-status": M{
 
1840
                                                                                        "current": "active",
 
1841
                                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1842
                                                                                },
 
1843
                                                                                "juju-status": M{
 
1844
                                                                                        "current": "idle",
 
1845
                                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1846
                                                                                },
 
1847
                                                                                "public-address": "controller-1.dns",
 
1848
                                                                        },
 
1849
                                                                },
 
1850
                                                                "public-address": "controller-1.dns",
 
1851
                                                        },
 
1852
                                                },
 
1853
                                                "relations": M{
 
1854
                                                        "db":          L{"mysql"},
 
1855
                                                        "logging-dir": L{"logging"},
 
1856
                                                },
 
1857
                                        }),
 
1858
                                        "logging": loggingCharm,
 
1859
                                },
 
1860
                        },
 
1861
                },
 
1862
        ),
 
1863
        test( // 12
 
1864
                "machines with containers",
 
1865
                // step 0
 
1866
                addMachine{machineId: "0", job: state.JobManageModel},
 
1867
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
1868
                startAliveMachine{"0"},
 
1869
                setMachineStatus{"0", status.StatusStarted, ""},
 
1870
                addCharm{"mysql"},
 
1871
                addService{name: "mysql", charm: "mysql"},
 
1872
                setServiceExposed{"mysql", true},
 
1873
 
 
1874
                // step 7
 
1875
                addMachine{machineId: "1", job: state.JobHostUnits},
 
1876
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
1877
                startAliveMachine{"1"},
 
1878
                setMachineStatus{"1", status.StatusStarted, ""},
 
1879
                addAliveUnit{"mysql", "1"},
 
1880
                setAgentStatus{"mysql/0", status.StatusIdle, "", nil},
 
1881
                setUnitStatus{"mysql/0", status.StatusActive, "", nil},
 
1882
 
 
1883
                // step 14: A container on machine 1.
 
1884
                addContainer{"1", "1/lxd/0", state.JobHostUnits},
 
1885
                setAddresses{"1/lxd/0", network.NewAddresses("controller-2.dns")},
 
1886
                startAliveMachine{"1/lxd/0"},
 
1887
                setMachineStatus{"1/lxd/0", status.StatusStarted, ""},
 
1888
                addAliveUnit{"mysql", "1/lxd/0"},
 
1889
                setAgentStatus{"mysql/1", status.StatusIdle, "", nil},
 
1890
                setUnitStatus{"mysql/1", status.StatusActive, "", nil},
 
1891
                addContainer{"1", "1/lxd/1", state.JobHostUnits},
 
1892
 
 
1893
                // step 22: A nested container.
 
1894
                addContainer{"1/lxd/0", "1/lxd/0/lxd/0", state.JobHostUnits},
 
1895
                setAddresses{"1/lxd/0/lxd/0", network.NewAddresses("controller-3.dns")},
 
1896
                startAliveMachine{"1/lxd/0/lxd/0"},
 
1897
                setMachineStatus{"1/lxd/0/lxd/0", status.StatusStarted, ""},
 
1898
 
 
1899
                expect{
 
1900
                        "machines with nested containers",
 
1901
                        M{
 
1902
                                "model": model,
 
1903
                                "machines": M{
 
1904
                                        "0": machine0,
 
1905
                                        "1": machine1WithContainers,
 
1906
                                },
 
1907
                                "applications": M{
 
1908
                                        "mysql": mysqlCharm(M{
 
1909
                                                "exposed": true,
 
1910
                                                "application-status": M{
 
1911
                                                        "current": "active",
 
1912
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1913
                                                },
 
1914
                                                "units": M{
 
1915
                                                        "mysql/0": M{
 
1916
                                                                "machine": "1",
 
1917
                                                                "workload-status": M{
 
1918
                                                                        "current": "active",
 
1919
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1920
                                                                },
 
1921
                                                                "juju-status": M{
 
1922
                                                                        "current": "idle",
 
1923
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1924
                                                                },
 
1925
                                                                "public-address": "controller-1.dns",
 
1926
                                                        },
 
1927
                                                        "mysql/1": M{
 
1928
                                                                "machine": "1/lxd/0",
 
1929
                                                                "workload-status": M{
 
1930
                                                                        "current": "active",
 
1931
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1932
                                                                },
 
1933
                                                                "juju-status": M{
 
1934
                                                                        "current": "idle",
 
1935
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1936
                                                                },
 
1937
                                                                "public-address": "controller-2.dns",
 
1938
                                                        },
 
1939
                                                },
 
1940
                                        }),
 
1941
                                },
 
1942
                        },
 
1943
                },
 
1944
 
 
1945
                // step 27: once again, with a scope on mysql/1
 
1946
                scopedExpect{
 
1947
                        "machines with nested containers 2",
 
1948
                        []string{"mysql/1"},
 
1949
                        M{
 
1950
                                "model": model,
 
1951
                                "machines": M{
 
1952
                                        "1": M{
 
1953
                                                "juju-status": M{
 
1954
                                                        "current": "started",
 
1955
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1956
                                                },
 
1957
                                                "containers": M{
 
1958
                                                        "1/lxd/0": M{
 
1959
                                                                "juju-status": M{
 
1960
                                                                        "current": "started",
 
1961
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1962
                                                                },
 
1963
                                                                "dns-name":    "controller-2.dns",
 
1964
                                                                "instance-id": "controller-2",
 
1965
                                                                "machine-status": M{
 
1966
                                                                        "current": "pending",
 
1967
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1968
                                                                },
 
1969
 
 
1970
                                                                "series": "quantal",
 
1971
                                                        },
 
1972
                                                },
 
1973
                                                "dns-name":    "controller-1.dns",
 
1974
                                                "instance-id": "controller-1",
 
1975
                                                "machine-status": M{
 
1976
                                                        "current": "pending",
 
1977
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1978
                                                },
 
1979
 
 
1980
                                                "series":   "quantal",
 
1981
                                                "hardware": "arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M",
 
1982
                                        },
 
1983
                                },
 
1984
                                "applications": M{
 
1985
                                        "mysql": mysqlCharm(M{
 
1986
                                                "exposed": true,
 
1987
                                                "application-status": M{
 
1988
                                                        "current": "active",
 
1989
                                                        "since":   "01 Apr 15 01:23+10:00",
 
1990
                                                },
 
1991
                                                "units": M{
 
1992
                                                        "mysql/1": M{
 
1993
                                                                "machine": "1/lxd/0",
 
1994
                                                                "workload-status": M{
 
1995
                                                                        "current": "active",
 
1996
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
1997
                                                                },
 
1998
                                                                "juju-status": M{
 
1999
                                                                        "current": "idle",
 
2000
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2001
                                                                },
 
2002
                                                                "public-address": "controller-2.dns",
 
2003
                                                        },
 
2004
                                                },
 
2005
                                        }),
 
2006
                                },
 
2007
                        },
 
2008
                },
 
2009
        ),
 
2010
        test( // 13
 
2011
                "application with out of date charm",
 
2012
                addMachine{machineId: "0", job: state.JobManageModel},
 
2013
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
2014
                startAliveMachine{"0"},
 
2015
                setMachineStatus{"0", status.StatusStarted, ""},
 
2016
                addMachine{machineId: "1", job: state.JobHostUnits},
 
2017
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
2018
                startAliveMachine{"1"},
 
2019
                setMachineStatus{"1", status.StatusStarted, ""},
 
2020
                addCharm{"mysql"},
 
2021
                addService{name: "mysql", charm: "mysql"},
 
2022
                setServiceExposed{"mysql", true},
 
2023
                addCharmPlaceholder{"mysql", 23},
 
2024
                addAliveUnit{"mysql", "1"},
 
2025
 
 
2026
                expect{
 
2027
                        "services and units with correct charm status",
 
2028
                        M{
 
2029
                                "model": model,
 
2030
                                "machines": M{
 
2031
                                        "0": machine0,
 
2032
                                        "1": machine1,
 
2033
                                },
 
2034
                                "applications": M{
 
2035
                                        "mysql": mysqlCharm(M{
 
2036
                                                "can-upgrade-to": "cs:quantal/mysql-23",
 
2037
                                                "exposed":        true,
 
2038
                                                "application-status": M{
 
2039
                                                        "current": "unknown",
 
2040
                                                        "message": "Waiting for agent initialization to finish",
 
2041
                                                        "since":   "01 Apr 15 01:23+10:00",
 
2042
                                                },
 
2043
                                                "units": M{
 
2044
                                                        "mysql/0": M{
 
2045
                                                                "machine": "1",
 
2046
                                                                "workload-status": M{
 
2047
                                                                        "current": "unknown",
 
2048
                                                                        "message": "Waiting for agent initialization to finish",
 
2049
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2050
                                                                },
 
2051
                                                                "juju-status": M{
 
2052
                                                                        "current": "allocating",
 
2053
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2054
                                                                },
 
2055
                                                                "public-address": "controller-1.dns",
 
2056
                                                        },
 
2057
                                                },
 
2058
                                        }),
 
2059
                                },
 
2060
                        },
 
2061
                },
 
2062
        ),
 
2063
        test( // 14
 
2064
                "unit with out of date charm",
 
2065
                addMachine{machineId: "0", job: state.JobManageModel},
 
2066
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
2067
                startAliveMachine{"0"},
 
2068
                setMachineStatus{"0", status.StatusStarted, ""},
 
2069
                addMachine{machineId: "1", job: state.JobHostUnits},
 
2070
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
2071
                startAliveMachine{"1"},
 
2072
                setMachineStatus{"1", status.StatusStarted, ""},
 
2073
                addCharm{"mysql"},
 
2074
                addService{name: "mysql", charm: "mysql"},
 
2075
                setServiceExposed{"mysql", true},
 
2076
                addAliveUnit{"mysql", "1"},
 
2077
                setUnitCharmURL{"mysql/0", "cs:quantal/mysql-1"},
 
2078
                addCharmWithRevision{addCharm{"mysql"}, "local", 1},
 
2079
                setServiceCharm{"mysql", "local:quantal/mysql-1"},
 
2080
 
 
2081
                expect{
 
2082
                        "services and units with correct charm status",
 
2083
                        M{
 
2084
                                "model": model,
 
2085
                                "machines": M{
 
2086
                                        "0": machine0,
 
2087
                                        "1": machine1,
 
2088
                                },
 
2089
                                "applications": M{
 
2090
                                        "mysql": mysqlCharm(M{
 
2091
                                                "charm":        "local:quantal/mysql-1",
 
2092
                                                "charm-origin": "local",
 
2093
                                                "exposed":      true,
 
2094
                                                "application-status": M{
 
2095
                                                        "current": "active",
 
2096
                                                        "since":   "01 Apr 15 01:23+10:00",
 
2097
                                                },
 
2098
                                                "units": M{
 
2099
                                                        "mysql/0": M{
 
2100
                                                                "machine": "1",
 
2101
                                                                "workload-status": M{
 
2102
                                                                        "current": "active",
 
2103
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2104
                                                                },
 
2105
                                                                "juju-status": M{
 
2106
                                                                        "current": "idle",
 
2107
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2108
                                                                },
 
2109
                                                                "upgrading-from": "cs:quantal/mysql-1",
 
2110
                                                                "public-address": "controller-1.dns",
 
2111
                                                        },
 
2112
                                                },
 
2113
                                        }),
 
2114
                                },
 
2115
                        },
 
2116
                },
 
2117
        ),
 
2118
        test( // 15
 
2119
                "application and unit with out of date charms",
 
2120
                addMachine{machineId: "0", job: state.JobManageModel},
 
2121
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
2122
                startAliveMachine{"0"},
 
2123
                setMachineStatus{"0", status.StatusStarted, ""},
 
2124
                addMachine{machineId: "1", job: state.JobHostUnits},
 
2125
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
2126
                startAliveMachine{"1"},
 
2127
                setMachineStatus{"1", status.StatusStarted, ""},
 
2128
                addCharm{"mysql"},
 
2129
                addService{name: "mysql", charm: "mysql"},
 
2130
                setServiceExposed{"mysql", true},
 
2131
                addAliveUnit{"mysql", "1"},
 
2132
                setUnitCharmURL{"mysql/0", "cs:quantal/mysql-1"},
 
2133
                addCharmWithRevision{addCharm{"mysql"}, "cs", 2},
 
2134
                setServiceCharm{"mysql", "cs:quantal/mysql-2"},
 
2135
                addCharmPlaceholder{"mysql", 23},
 
2136
 
 
2137
                expect{
 
2138
                        "services and units with correct charm status",
 
2139
                        M{
 
2140
                                "model": model,
 
2141
                                "machines": M{
 
2142
                                        "0": machine0,
 
2143
                                        "1": machine1,
 
2144
                                },
 
2145
                                "applications": M{
 
2146
                                        "mysql": mysqlCharm(M{
 
2147
                                                "charm":          "cs:quantal/mysql-2",
 
2148
                                                "charm-rev":      2,
 
2149
                                                "can-upgrade-to": "cs:quantal/mysql-23",
 
2150
                                                "exposed":        true,
 
2151
                                                "application-status": M{
 
2152
                                                        "current": "active",
 
2153
                                                        "since":   "01 Apr 15 01:23+10:00",
 
2154
                                                },
 
2155
                                                "units": M{
 
2156
                                                        "mysql/0": M{
 
2157
                                                                "machine": "1",
 
2158
                                                                "workload-status": M{
 
2159
                                                                        "current": "active",
 
2160
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2161
                                                                },
 
2162
                                                                "juju-status": M{
 
2163
                                                                        "current": "idle",
 
2164
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2165
                                                                },
 
2166
                                                                "upgrading-from": "cs:quantal/mysql-1",
 
2167
                                                                "public-address": "controller-1.dns",
 
2168
                                                        },
 
2169
                                                },
 
2170
                                        }),
 
2171
                                },
 
2172
                        },
 
2173
                },
 
2174
        ),
 
2175
        test( // 16
 
2176
                "application with local charm not shown as out of date",
 
2177
                addMachine{machineId: "0", job: state.JobManageModel},
 
2178
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
2179
                startAliveMachine{"0"},
 
2180
                setMachineStatus{"0", status.StatusStarted, ""},
 
2181
                addMachine{machineId: "1", job: state.JobHostUnits},
 
2182
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
2183
                startAliveMachine{"1"},
 
2184
                setMachineStatus{"1", status.StatusStarted, ""},
 
2185
                addCharm{"mysql"},
 
2186
                addService{name: "mysql", charm: "mysql"},
 
2187
                setServiceExposed{"mysql", true},
 
2188
                addAliveUnit{"mysql", "1"},
 
2189
                setUnitCharmURL{"mysql/0", "cs:quantal/mysql-1"},
 
2190
                addCharmWithRevision{addCharm{"mysql"}, "local", 1},
 
2191
                setServiceCharm{"mysql", "local:quantal/mysql-1"},
 
2192
                addCharmPlaceholder{"mysql", 23},
 
2193
 
 
2194
                expect{
 
2195
                        "services and units with correct charm status",
 
2196
                        M{
 
2197
                                "model": model,
 
2198
                                "machines": M{
 
2199
                                        "0": machine0,
 
2200
                                        "1": machine1,
 
2201
                                },
 
2202
                                "applications": M{
 
2203
                                        "mysql": mysqlCharm(M{
 
2204
                                                "charm":        "local:quantal/mysql-1",
 
2205
                                                "charm-origin": "local",
 
2206
                                                "exposed":      true,
 
2207
                                                "application-status": M{
 
2208
                                                        "current": "active",
 
2209
                                                        "since":   "01 Apr 15 01:23+10:00",
 
2210
                                                },
 
2211
                                                "units": M{
 
2212
                                                        "mysql/0": M{
 
2213
                                                                "machine": "1",
 
2214
                                                                "workload-status": M{
 
2215
                                                                        "current": "active",
 
2216
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2217
                                                                },
 
2218
                                                                "juju-status": M{
 
2219
                                                                        "current": "idle",
 
2220
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2221
                                                                },
 
2222
                                                                "upgrading-from": "cs:quantal/mysql-1",
 
2223
                                                                "public-address": "controller-1.dns",
 
2224
                                                        },
 
2225
                                                },
 
2226
                                        }),
 
2227
                                },
 
2228
                        },
 
2229
                },
 
2230
        ),
 
2231
        test( // 17
 
2232
                "deploy two services; set meter statuses on one",
 
2233
                addMachine{machineId: "0", job: state.JobManageModel},
 
2234
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
2235
                startAliveMachine{"0"},
 
2236
                setMachineStatus{"0", status.StatusStarted, ""},
 
2237
 
 
2238
                addMachine{machineId: "1", job: state.JobHostUnits},
 
2239
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
2240
                startAliveMachine{"1"},
 
2241
                setMachineStatus{"1", status.StatusStarted, ""},
 
2242
 
 
2243
                addMachine{machineId: "2", job: state.JobHostUnits},
 
2244
                setAddresses{"2", network.NewAddresses("controller-2.dns")},
 
2245
                startAliveMachine{"2"},
 
2246
                setMachineStatus{"2", status.StatusStarted, ""},
 
2247
 
 
2248
                addMachine{machineId: "3", job: state.JobHostUnits},
 
2249
                setAddresses{"3", network.NewAddresses("controller-3.dns")},
 
2250
                startAliveMachine{"3"},
 
2251
                setMachineStatus{"3", status.StatusStarted, ""},
 
2252
 
 
2253
                addMachine{machineId: "4", job: state.JobHostUnits},
 
2254
                setAddresses{"4", network.NewAddresses("controller-4.dns")},
 
2255
                startAliveMachine{"4"},
 
2256
                setMachineStatus{"4", status.StatusStarted, ""},
 
2257
 
 
2258
                addCharm{"mysql"},
 
2259
                addService{name: "mysql", charm: "mysql"},
 
2260
                setServiceExposed{"mysql", true},
 
2261
 
 
2262
                addService{name: "servicewithmeterstatus", charm: "mysql"},
 
2263
 
 
2264
                addAliveUnit{"mysql", "1"},
 
2265
                addAliveUnit{"servicewithmeterstatus", "2"},
 
2266
                addAliveUnit{"servicewithmeterstatus", "3"},
 
2267
                addAliveUnit{"servicewithmeterstatus", "4"},
 
2268
 
 
2269
                setServiceExposed{"mysql", true},
 
2270
 
 
2271
                setAgentStatus{"mysql/0", status.StatusIdle, "", nil},
 
2272
                setUnitStatus{"mysql/0", status.StatusActive, "", nil},
 
2273
                setAgentStatus{"servicewithmeterstatus/0", status.StatusIdle, "", nil},
 
2274
                setUnitStatus{"servicewithmeterstatus/0", status.StatusActive, "", nil},
 
2275
                setAgentStatus{"servicewithmeterstatus/1", status.StatusIdle, "", nil},
 
2276
                setUnitStatus{"servicewithmeterstatus/1", status.StatusActive, "", nil},
 
2277
                setAgentStatus{"servicewithmeterstatus/2", status.StatusIdle, "", nil},
 
2278
                setUnitStatus{"servicewithmeterstatus/2", status.StatusActive, "", nil},
 
2279
 
 
2280
                setUnitMeterStatus{"servicewithmeterstatus/1", "GREEN", "test green status"},
 
2281
                setUnitMeterStatus{"servicewithmeterstatus/2", "RED", "test red status"},
 
2282
 
 
2283
                expect{
 
2284
                        "simulate just the two services and a bootstrap node",
 
2285
                        M{
 
2286
                                "model": model,
 
2287
                                "machines": M{
 
2288
                                        "0": machine0,
 
2289
                                        "1": machine1,
 
2290
                                        "2": machine2,
 
2291
                                        "3": machine3,
 
2292
                                        "4": machine4,
 
2293
                                },
 
2294
                                "applications": M{
 
2295
                                        "mysql": mysqlCharm(M{
 
2296
                                                "exposed": true,
 
2297
                                                "application-status": M{
 
2298
                                                        "current": "active",
 
2299
                                                        "since":   "01 Apr 15 01:23+10:00",
 
2300
                                                },
 
2301
                                                "units": M{
 
2302
                                                        "mysql/0": M{
 
2303
                                                                "machine": "1",
 
2304
                                                                "workload-status": M{
 
2305
                                                                        "current": "active",
 
2306
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2307
                                                                },
 
2308
                                                                "juju-status": M{
 
2309
                                                                        "current": "idle",
 
2310
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2311
                                                                },
 
2312
                                                                "public-address": "controller-1.dns",
 
2313
                                                        },
 
2314
                                                },
 
2315
                                        }),
 
2316
 
 
2317
                                        "servicewithmeterstatus": mysqlCharm(M{
 
2318
                                                "application-status": M{
 
2319
                                                        "current": "active",
 
2320
                                                        "since":   "01 Apr 15 01:23+10:00",
 
2321
                                                },
 
2322
                                                "units": M{
 
2323
                                                        "servicewithmeterstatus/0": M{
 
2324
                                                                "machine": "2",
 
2325
                                                                "workload-status": M{
 
2326
                                                                        "current": "active",
 
2327
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2328
                                                                },
 
2329
                                                                "juju-status": M{
 
2330
                                                                        "current": "idle",
 
2331
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2332
                                                                },
 
2333
                                                                "public-address": "controller-2.dns",
 
2334
                                                        },
 
2335
                                                        "servicewithmeterstatus/1": M{
 
2336
                                                                "machine": "3",
 
2337
                                                                "workload-status": M{
 
2338
                                                                        "current": "active",
 
2339
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2340
                                                                },
 
2341
                                                                "juju-status": M{
 
2342
                                                                        "current": "idle",
 
2343
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2344
                                                                },
 
2345
                                                                "meter-status": M{
 
2346
                                                                        "color":   "green",
 
2347
                                                                        "message": "test green status",
 
2348
                                                                },
 
2349
                                                                "public-address": "controller-3.dns",
 
2350
                                                        },
 
2351
                                                        "servicewithmeterstatus/2": M{
 
2352
                                                                "machine": "4",
 
2353
                                                                "workload-status": M{
 
2354
                                                                        "current": "active",
 
2355
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2356
                                                                },
 
2357
                                                                "juju-status": M{
 
2358
                                                                        "current": "idle",
 
2359
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2360
                                                                },
 
2361
                                                                "meter-status": M{
 
2362
                                                                        "color":   "red",
 
2363
                                                                        "message": "test red status",
 
2364
                                                                },
 
2365
                                                                "public-address": "controller-4.dns",
 
2366
                                                        },
 
2367
                                                },
 
2368
                                        }),
 
2369
                                },
 
2370
                        },
 
2371
                },
 
2372
        ),
 
2373
        test( // 18
 
2374
                "upgrade available",
 
2375
                setToolsUpgradeAvailable{},
 
2376
                expect{
 
2377
                        "upgrade availability should be shown in model-status",
 
2378
                        M{
 
2379
                                "model": M{
 
2380
                                        "name":              "controller",
 
2381
                                        "controller":        "kontroll",
 
2382
                                        "cloud":             "dummy",
 
2383
                                        "version":           "1.2.3",
 
2384
                                        "upgrade-available": "1.2.4",
 
2385
                                },
 
2386
                                "machines":     M{},
 
2387
                                "applications": M{},
 
2388
                        },
 
2389
                },
 
2390
        ),
 
2391
        test( // 19
 
2392
                "consistent workload version",
 
2393
                addMachine{machineId: "0", job: state.JobManageModel},
 
2394
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
2395
                startAliveMachine{"0"},
 
2396
                setMachineStatus{"0", status.StatusStarted, ""},
 
2397
 
 
2398
                addCharm{"mysql"},
 
2399
                addService{name: "mysql", charm: "mysql"},
 
2400
 
 
2401
                addMachine{machineId: "1", job: state.JobHostUnits},
 
2402
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
2403
                startAliveMachine{"1"},
 
2404
                setMachineStatus{"1", status.StatusStarted, ""},
 
2405
                addAliveUnit{"mysql", "1"},
 
2406
                setUnitWorkloadVersion{"mysql/0", "the best!"},
 
2407
 
 
2408
                expect{
 
2409
                        "application and unit with correct workload version",
 
2410
                        M{
 
2411
                                "model": model,
 
2412
                                "machines": M{
 
2413
                                        "0": machine0,
 
2414
                                        "1": machine1,
 
2415
                                },
 
2416
                                "applications": M{
 
2417
                                        "mysql": mysqlCharm(M{
 
2418
                                                "version": "the best!",
 
2419
                                                "application-status": M{
 
2420
                                                        "current": "unknown",
 
2421
                                                        "message": "Waiting for agent initialization to finish",
 
2422
                                                        "since":   "01 Apr 15 01:23+10:00",
 
2423
                                                },
 
2424
                                                "units": M{
 
2425
                                                        "mysql/0": M{
 
2426
                                                                "machine": "1",
 
2427
                                                                "workload-status": M{
 
2428
                                                                        "current": "unknown",
 
2429
                                                                        "message": "Waiting for agent initialization to finish",
 
2430
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2431
                                                                },
 
2432
                                                                "juju-status": M{
 
2433
                                                                        "current": "allocating",
 
2434
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2435
                                                                },
 
2436
                                                                "public-address": "controller-1.dns",
 
2437
                                                        },
 
2438
                                                },
 
2439
                                        }),
 
2440
                                },
 
2441
                        },
 
2442
                },
 
2443
        ),
 
2444
        test( // 20
 
2445
                "mixed workload version",
 
2446
                addMachine{machineId: "0", job: state.JobManageModel},
 
2447
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
2448
                startAliveMachine{"0"},
 
2449
                setMachineStatus{"0", status.StatusStarted, ""},
 
2450
 
 
2451
                addCharm{"mysql"},
 
2452
                addService{name: "mysql", charm: "mysql"},
 
2453
 
 
2454
                addMachine{machineId: "1", job: state.JobHostUnits},
 
2455
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
2456
                startAliveMachine{"1"},
 
2457
                setMachineStatus{"1", status.StatusStarted, ""},
 
2458
                addAliveUnit{"mysql", "1"},
 
2459
                setUnitWorkloadVersion{"mysql/0", "the best!"},
 
2460
 
 
2461
                addMachine{machineId: "2", job: state.JobHostUnits},
 
2462
                setAddresses{"2", network.NewAddresses("controller-2.dns")},
 
2463
                startAliveMachine{"2"},
 
2464
                setMachineStatus{"2", status.StatusStarted, ""},
 
2465
                addAliveUnit{"mysql", "2"},
 
2466
                setUnitWorkloadVersion{"mysql/1", "not as good"},
 
2467
 
 
2468
                expect{
 
2469
                        "application and unit with correct workload version",
 
2470
                        M{
 
2471
                                "model": model,
 
2472
                                "machines": M{
 
2473
                                        "0": machine0,
 
2474
                                        "1": machine1,
 
2475
                                        "2": machine2,
 
2476
                                },
 
2477
                                "applications": M{
 
2478
                                        "mysql": mysqlCharm(M{
 
2479
                                                "version": "not as good",
 
2480
                                                "application-status": M{
 
2481
                                                        "current": "unknown",
 
2482
                                                        "message": "Waiting for agent initialization to finish",
 
2483
                                                        "since":   "01 Apr 15 01:23+10:00",
 
2484
                                                },
 
2485
                                                "units": M{
 
2486
                                                        "mysql/0": M{
 
2487
                                                                "machine": "1",
 
2488
                                                                "workload-status": M{
 
2489
                                                                        "current": "unknown",
 
2490
                                                                        "message": "Waiting for agent initialization to finish",
 
2491
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2492
                                                                },
 
2493
                                                                "juju-status": M{
 
2494
                                                                        "current": "allocating",
 
2495
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2496
                                                                },
 
2497
                                                                "public-address": "controller-1.dns",
 
2498
                                                        },
 
2499
                                                        "mysql/1": M{
 
2500
                                                                "machine": "2",
 
2501
                                                                "workload-status": M{
 
2502
                                                                        "current": "unknown",
 
2503
                                                                        "message": "Waiting for agent initialization to finish",
 
2504
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2505
                                                                },
 
2506
                                                                "juju-status": M{
 
2507
                                                                        "current": "allocating",
 
2508
                                                                        "since":   "01 Apr 15 01:23+10:00",
 
2509
                                                                },
 
2510
                                                                "public-address": "controller-2.dns",
 
2511
                                                        },
 
2512
                                                },
 
2513
                                        }),
 
2514
                                },
 
2515
                        },
 
2516
                },
 
2517
        ),
 
2518
}
 
2519
 
 
2520
func mysqlCharm(extras M) M {
 
2521
        charm := M{
 
2522
                "charm":        "cs:quantal/mysql-1",
 
2523
                "charm-origin": "jujucharms",
 
2524
                "charm-name":   "mysql",
 
2525
                "charm-rev":    1,
 
2526
                "series":       "quantal",
 
2527
                "os":           "ubuntu",
 
2528
                "exposed":      false,
 
2529
        }
 
2530
        for key, value := range extras {
 
2531
                charm[key] = value
 
2532
        }
 
2533
        return charm
 
2534
}
 
2535
 
 
2536
func dummyCharm(extras M) M {
 
2537
        charm := M{
 
2538
                "charm":        "cs:quantal/dummy-1",
 
2539
                "charm-origin": "jujucharms",
 
2540
                "charm-name":   "dummy",
 
2541
                "charm-rev":    1,
 
2542
                "series":       "quantal",
 
2543
                "os":           "ubuntu",
 
2544
                "exposed":      false,
 
2545
        }
 
2546
        for key, value := range extras {
 
2547
                charm[key] = value
 
2548
        }
 
2549
        return charm
 
2550
}
 
2551
 
 
2552
func wordpressCharm(extras M) M {
 
2553
        charm := M{
 
2554
                "charm":        "cs:quantal/wordpress-3",
 
2555
                "charm-origin": "jujucharms",
 
2556
                "charm-name":   "wordpress",
 
2557
                "charm-rev":    3,
 
2558
                "series":       "quantal",
 
2559
                "os":           "ubuntu",
 
2560
                "exposed":      false,
 
2561
        }
 
2562
        for key, value := range extras {
 
2563
                charm[key] = value
 
2564
        }
 
2565
        return charm
 
2566
}
 
2567
 
 
2568
// TODO(dfc) test failing components by destructively mutating the state under the hood
 
2569
 
 
2570
type addMachine struct {
 
2571
        machineId string
 
2572
        cons      constraints.Value
 
2573
        job       state.MachineJob
 
2574
}
 
2575
 
 
2576
func (am addMachine) step(c *gc.C, ctx *context) {
 
2577
        m, err := ctx.st.AddOneMachine(state.MachineTemplate{
 
2578
                Series:      "quantal",
 
2579
                Constraints: am.cons,
 
2580
                Jobs:        []state.MachineJob{am.job},
 
2581
        })
 
2582
        c.Assert(err, jc.ErrorIsNil)
 
2583
        c.Assert(m.Id(), gc.Equals, am.machineId)
 
2584
}
 
2585
 
 
2586
type addContainer struct {
 
2587
        parentId  string
 
2588
        machineId string
 
2589
        job       state.MachineJob
 
2590
}
 
2591
 
 
2592
func (ac addContainer) step(c *gc.C, ctx *context) {
 
2593
        template := state.MachineTemplate{
 
2594
                Series: "quantal",
 
2595
                Jobs:   []state.MachineJob{ac.job},
 
2596
        }
 
2597
        m, err := ctx.st.AddMachineInsideMachine(template, ac.parentId, instance.LXD)
 
2598
        c.Assert(err, jc.ErrorIsNil)
 
2599
        c.Assert(m.Id(), gc.Equals, ac.machineId)
 
2600
}
 
2601
 
 
2602
type startMachine struct {
 
2603
        machineId string
 
2604
}
 
2605
 
 
2606
func (sm startMachine) step(c *gc.C, ctx *context) {
 
2607
        m, err := ctx.st.Machine(sm.machineId)
 
2608
        c.Assert(err, jc.ErrorIsNil)
 
2609
        cons, err := m.Constraints()
 
2610
        c.Assert(err, jc.ErrorIsNil)
 
2611
        cfg, err := ctx.st.ControllerConfig()
 
2612
        c.Assert(err, jc.ErrorIsNil)
 
2613
        inst, hc := testing.AssertStartInstanceWithConstraints(c, ctx.env, cfg.ControllerUUID(), m.Id(), cons)
 
2614
        err = m.SetProvisioned(inst.Id(), "fake_nonce", hc)
 
2615
        c.Assert(err, jc.ErrorIsNil)
 
2616
}
 
2617
 
 
2618
type startMissingMachine struct {
 
2619
        machineId string
 
2620
}
 
2621
 
 
2622
func (sm startMissingMachine) step(c *gc.C, ctx *context) {
 
2623
        m, err := ctx.st.Machine(sm.machineId)
 
2624
        c.Assert(err, jc.ErrorIsNil)
 
2625
        cons, err := m.Constraints()
 
2626
        c.Assert(err, jc.ErrorIsNil)
 
2627
        cfg, err := ctx.st.ControllerConfig()
 
2628
        c.Assert(err, jc.ErrorIsNil)
 
2629
        _, hc := testing.AssertStartInstanceWithConstraints(c, ctx.env, cfg.ControllerUUID(), m.Id(), cons)
 
2630
        err = m.SetProvisioned("i-missing", "fake_nonce", hc)
 
2631
        c.Assert(err, jc.ErrorIsNil)
 
2632
        // lp:1558657
 
2633
        now := time.Now()
 
2634
        s := status.StatusInfo{
 
2635
                Status:  status.StatusUnknown,
 
2636
                Message: "missing",
 
2637
                Since:   &now,
 
2638
        }
 
2639
        err = m.SetInstanceStatus(s)
 
2640
        c.Assert(err, jc.ErrorIsNil)
 
2641
}
 
2642
 
 
2643
type startAliveMachine struct {
 
2644
        machineId string
 
2645
}
 
2646
 
 
2647
func (sam startAliveMachine) step(c *gc.C, ctx *context) {
 
2648
        m, err := ctx.st.Machine(sam.machineId)
 
2649
        c.Assert(err, jc.ErrorIsNil)
 
2650
        pinger := ctx.setAgentPresence(c, m)
 
2651
        cons, err := m.Constraints()
 
2652
        c.Assert(err, jc.ErrorIsNil)
 
2653
        cfg, err := ctx.st.ControllerConfig()
 
2654
        c.Assert(err, jc.ErrorIsNil)
 
2655
        inst, hc := testing.AssertStartInstanceWithConstraints(c, ctx.env, cfg.ControllerUUID(), m.Id(), cons)
 
2656
        err = m.SetProvisioned(inst.Id(), "fake_nonce", hc)
 
2657
        c.Assert(err, jc.ErrorIsNil)
 
2658
        ctx.pingers[m.Id()] = pinger
 
2659
}
 
2660
 
 
2661
type startMachineWithHardware struct {
 
2662
        machineId string
 
2663
        hc        instance.HardwareCharacteristics
 
2664
}
 
2665
 
 
2666
func (sm startMachineWithHardware) step(c *gc.C, ctx *context) {
 
2667
        m, err := ctx.st.Machine(sm.machineId)
 
2668
        c.Assert(err, jc.ErrorIsNil)
 
2669
        pinger := ctx.setAgentPresence(c, m)
 
2670
        cons, err := m.Constraints()
 
2671
        c.Assert(err, jc.ErrorIsNil)
 
2672
        cfg, err := ctx.st.ControllerConfig()
 
2673
        c.Assert(err, jc.ErrorIsNil)
 
2674
        inst, _ := testing.AssertStartInstanceWithConstraints(c, ctx.env, cfg.ControllerUUID(), m.Id(), cons)
 
2675
        err = m.SetProvisioned(inst.Id(), "fake_nonce", &sm.hc)
 
2676
        c.Assert(err, jc.ErrorIsNil)
 
2677
        ctx.pingers[m.Id()] = pinger
 
2678
}
 
2679
 
 
2680
type setAddresses struct {
 
2681
        machineId string
 
2682
        addresses []network.Address
 
2683
}
 
2684
 
 
2685
func (sa setAddresses) step(c *gc.C, ctx *context) {
 
2686
        m, err := ctx.st.Machine(sa.machineId)
 
2687
        c.Assert(err, jc.ErrorIsNil)
 
2688
        err = m.SetProviderAddresses(sa.addresses...)
 
2689
        c.Assert(err, jc.ErrorIsNil)
 
2690
}
 
2691
 
 
2692
type setTools struct {
 
2693
        machineId string
 
2694
        version   version.Binary
 
2695
}
 
2696
 
 
2697
func (st setTools) step(c *gc.C, ctx *context) {
 
2698
        m, err := ctx.st.Machine(st.machineId)
 
2699
        c.Assert(err, jc.ErrorIsNil)
 
2700
        err = m.SetAgentVersion(st.version)
 
2701
        c.Assert(err, jc.ErrorIsNil)
 
2702
}
 
2703
 
 
2704
type setUnitTools struct {
 
2705
        unitName string
 
2706
        version  version.Binary
 
2707
}
 
2708
 
 
2709
func (st setUnitTools) step(c *gc.C, ctx *context) {
 
2710
        m, err := ctx.st.Unit(st.unitName)
 
2711
        c.Assert(err, jc.ErrorIsNil)
 
2712
        err = m.SetAgentVersion(st.version)
 
2713
        c.Assert(err, jc.ErrorIsNil)
 
2714
}
 
2715
 
 
2716
type addCharm struct {
 
2717
        name string
 
2718
}
 
2719
 
 
2720
func (ac addCharm) addCharmStep(c *gc.C, ctx *context, scheme string, rev int) {
 
2721
        ch := testcharms.Repo.CharmDir(ac.name)
 
2722
        name := ch.Meta().Name
 
2723
        curl := charm.MustParseURL(fmt.Sprintf("%s:quantal/%s-%d", scheme, name, rev))
 
2724
        info := state.CharmInfo{
 
2725
                Charm:       ch,
 
2726
                ID:          curl,
 
2727
                StoragePath: "dummy-path",
 
2728
                SHA256:      fmt.Sprintf("%s-%d-sha256", name, rev),
 
2729
        }
 
2730
        dummy, err := ctx.st.AddCharm(info)
 
2731
        c.Assert(err, jc.ErrorIsNil)
 
2732
        ctx.charms[ac.name] = dummy
 
2733
}
 
2734
 
 
2735
func (ac addCharm) step(c *gc.C, ctx *context) {
 
2736
        ch := testcharms.Repo.CharmDir(ac.name)
 
2737
        ac.addCharmStep(c, ctx, "cs", ch.Revision())
 
2738
}
 
2739
 
 
2740
type addCharmWithRevision struct {
 
2741
        addCharm
 
2742
        scheme string
 
2743
        rev    int
 
2744
}
 
2745
 
 
2746
func (ac addCharmWithRevision) step(c *gc.C, ctx *context) {
 
2747
        ac.addCharmStep(c, ctx, ac.scheme, ac.rev)
 
2748
}
 
2749
 
 
2750
type addService struct {
 
2751
        name  string
 
2752
        charm string
 
2753
        cons  constraints.Value
 
2754
}
 
2755
 
 
2756
func (as addService) step(c *gc.C, ctx *context) {
 
2757
        ch, ok := ctx.charms[as.charm]
 
2758
        c.Assert(ok, jc.IsTrue)
 
2759
        svc, err := ctx.st.AddApplication(state.AddApplicationArgs{Name: as.name, Charm: ch})
 
2760
        c.Assert(err, jc.ErrorIsNil)
 
2761
        if svc.IsPrincipal() {
 
2762
                err = svc.SetConstraints(as.cons)
 
2763
                c.Assert(err, jc.ErrorIsNil)
 
2764
        }
 
2765
}
 
2766
 
 
2767
type setServiceExposed struct {
 
2768
        name    string
 
2769
        exposed bool
 
2770
}
 
2771
 
 
2772
func (sse setServiceExposed) step(c *gc.C, ctx *context) {
 
2773
        s, err := ctx.st.Application(sse.name)
 
2774
        c.Assert(err, jc.ErrorIsNil)
 
2775
        err = s.ClearExposed()
 
2776
        c.Assert(err, jc.ErrorIsNil)
 
2777
        if sse.exposed {
 
2778
                err = s.SetExposed()
 
2779
                c.Assert(err, jc.ErrorIsNil)
 
2780
        }
 
2781
}
 
2782
 
 
2783
type setServiceCharm struct {
 
2784
        name  string
 
2785
        charm string
 
2786
}
 
2787
 
 
2788
func (ssc setServiceCharm) step(c *gc.C, ctx *context) {
 
2789
        ch, err := ctx.st.Charm(charm.MustParseURL(ssc.charm))
 
2790
        c.Assert(err, jc.ErrorIsNil)
 
2791
        s, err := ctx.st.Application(ssc.name)
 
2792
        c.Assert(err, jc.ErrorIsNil)
 
2793
        cfg := state.SetCharmConfig{Charm: ch}
 
2794
        err = s.SetCharm(cfg)
 
2795
        c.Assert(err, jc.ErrorIsNil)
 
2796
}
 
2797
 
 
2798
type addCharmPlaceholder struct {
 
2799
        name string
 
2800
        rev  int
 
2801
}
 
2802
 
 
2803
func (ac addCharmPlaceholder) step(c *gc.C, ctx *context) {
 
2804
        ch := testcharms.Repo.CharmDir(ac.name)
 
2805
        name := ch.Meta().Name
 
2806
        curl := charm.MustParseURL(fmt.Sprintf("cs:quantal/%s-%d", name, ac.rev))
 
2807
        err := ctx.st.AddStoreCharmPlaceholder(curl)
 
2808
        c.Assert(err, jc.ErrorIsNil)
 
2809
}
 
2810
 
 
2811
type addUnit struct {
 
2812
        serviceName string
 
2813
        machineId   string
 
2814
}
 
2815
 
 
2816
func (au addUnit) step(c *gc.C, ctx *context) {
 
2817
        s, err := ctx.st.Application(au.serviceName)
 
2818
        c.Assert(err, jc.ErrorIsNil)
 
2819
        u, err := s.AddUnit()
 
2820
        c.Assert(err, jc.ErrorIsNil)
 
2821
        m, err := ctx.st.Machine(au.machineId)
 
2822
        c.Assert(err, jc.ErrorIsNil)
 
2823
        err = u.AssignToMachine(m)
 
2824
        c.Assert(err, jc.ErrorIsNil)
 
2825
}
 
2826
 
 
2827
type addAliveUnit struct {
 
2828
        serviceName string
 
2829
        machineId   string
 
2830
}
 
2831
 
 
2832
func (aau addAliveUnit) step(c *gc.C, ctx *context) {
 
2833
        s, err := ctx.st.Application(aau.serviceName)
 
2834
        c.Assert(err, jc.ErrorIsNil)
 
2835
        u, err := s.AddUnit()
 
2836
        c.Assert(err, jc.ErrorIsNil)
 
2837
        pinger := ctx.setAgentPresence(c, u)
 
2838
        m, err := ctx.st.Machine(aau.machineId)
 
2839
        c.Assert(err, jc.ErrorIsNil)
 
2840
        err = u.AssignToMachine(m)
 
2841
        c.Assert(err, jc.ErrorIsNil)
 
2842
        ctx.pingers[u.Name()] = pinger
 
2843
}
 
2844
 
 
2845
type setUnitsAlive struct {
 
2846
        serviceName string
 
2847
}
 
2848
 
 
2849
func (sua setUnitsAlive) step(c *gc.C, ctx *context) {
 
2850
        s, err := ctx.st.Application(sua.serviceName)
 
2851
        c.Assert(err, jc.ErrorIsNil)
 
2852
        us, err := s.AllUnits()
 
2853
        c.Assert(err, jc.ErrorIsNil)
 
2854
        for _, u := range us {
 
2855
                ctx.pingers[u.Name()] = ctx.setAgentPresence(c, u)
 
2856
        }
 
2857
}
 
2858
 
 
2859
type setUnitMeterStatus struct {
 
2860
        unitName string
 
2861
        color    string
 
2862
        message  string
 
2863
}
 
2864
 
 
2865
func (s setUnitMeterStatus) step(c *gc.C, ctx *context) {
 
2866
        u, err := ctx.st.Unit(s.unitName)
 
2867
        c.Assert(err, jc.ErrorIsNil)
 
2868
        err = u.SetMeterStatus(s.color, s.message)
 
2869
        c.Assert(err, jc.ErrorIsNil)
 
2870
}
 
2871
 
 
2872
type setUnitStatus struct {
 
2873
        unitName   string
 
2874
        status     status.Status
 
2875
        statusInfo string
 
2876
        statusData map[string]interface{}
 
2877
}
 
2878
 
 
2879
func (sus setUnitStatus) step(c *gc.C, ctx *context) {
 
2880
        u, err := ctx.st.Unit(sus.unitName)
 
2881
        c.Assert(err, jc.ErrorIsNil)
 
2882
        // lp:1558657
 
2883
        now := time.Now()
 
2884
        s := status.StatusInfo{
 
2885
                Status:  sus.status,
 
2886
                Message: sus.statusInfo,
 
2887
                Data:    sus.statusData,
 
2888
                Since:   &now,
 
2889
        }
 
2890
        err = u.SetStatus(s)
 
2891
        c.Assert(err, jc.ErrorIsNil)
 
2892
}
 
2893
 
 
2894
type setAgentStatus struct {
 
2895
        unitName   string
 
2896
        status     status.Status
 
2897
        statusInfo string
 
2898
        statusData map[string]interface{}
 
2899
}
 
2900
 
 
2901
func (sus setAgentStatus) step(c *gc.C, ctx *context) {
 
2902
        u, err := ctx.st.Unit(sus.unitName)
 
2903
        c.Assert(err, jc.ErrorIsNil)
 
2904
        // lp:1558657
 
2905
        now := time.Now()
 
2906
        sInfo := status.StatusInfo{
 
2907
                Status:  sus.status,
 
2908
                Message: sus.statusInfo,
 
2909
                Data:    sus.statusData,
 
2910
                Since:   &now,
 
2911
        }
 
2912
        err = u.SetAgentStatus(sInfo)
 
2913
        c.Assert(err, jc.ErrorIsNil)
 
2914
}
 
2915
 
 
2916
type setUnitCharmURL struct {
 
2917
        unitName string
 
2918
        charm    string
 
2919
}
 
2920
 
 
2921
func (uc setUnitCharmURL) step(c *gc.C, ctx *context) {
 
2922
        u, err := ctx.st.Unit(uc.unitName)
 
2923
        c.Assert(err, jc.ErrorIsNil)
 
2924
        curl := charm.MustParseURL(uc.charm)
 
2925
        err = u.SetCharmURL(curl)
 
2926
        c.Assert(err, jc.ErrorIsNil)
 
2927
        // lp:1558657
 
2928
        now := time.Now()
 
2929
        s := status.StatusInfo{
 
2930
                Status:  status.StatusActive,
 
2931
                Message: "",
 
2932
                Since:   &now,
 
2933
        }
 
2934
        err = u.SetStatus(s)
 
2935
        c.Assert(err, jc.ErrorIsNil)
 
2936
        sInfo := status.StatusInfo{
 
2937
                Status:  status.StatusIdle,
 
2938
                Message: "",
 
2939
                Since:   &now,
 
2940
        }
 
2941
        err = u.SetAgentStatus(sInfo)
 
2942
        c.Assert(err, jc.ErrorIsNil)
 
2943
 
 
2944
}
 
2945
 
 
2946
type setUnitWorkloadVersion struct {
 
2947
        unitName string
 
2948
        version  string
 
2949
}
 
2950
 
 
2951
func (wv setUnitWorkloadVersion) step(c *gc.C, ctx *context) {
 
2952
        u, err := ctx.st.Unit(wv.unitName)
 
2953
        c.Assert(err, jc.ErrorIsNil)
 
2954
        err = u.SetWorkloadVersion(wv.version)
 
2955
        c.Assert(err, jc.ErrorIsNil)
 
2956
}
 
2957
 
 
2958
type openUnitPort struct {
 
2959
        unitName string
 
2960
        protocol string
 
2961
        number   int
 
2962
}
 
2963
 
 
2964
func (oup openUnitPort) step(c *gc.C, ctx *context) {
 
2965
        u, err := ctx.st.Unit(oup.unitName)
 
2966
        c.Assert(err, jc.ErrorIsNil)
 
2967
        err = u.OpenPort(oup.protocol, oup.number)
 
2968
        c.Assert(err, jc.ErrorIsNil)
 
2969
}
 
2970
 
 
2971
type ensureDyingUnit struct {
 
2972
        unitName string
 
2973
}
 
2974
 
 
2975
func (e ensureDyingUnit) step(c *gc.C, ctx *context) {
 
2976
        u, err := ctx.st.Unit(e.unitName)
 
2977
        c.Assert(err, jc.ErrorIsNil)
 
2978
        err = u.Destroy()
 
2979
        c.Assert(err, jc.ErrorIsNil)
 
2980
        c.Assert(u.Life(), gc.Equals, state.Dying)
 
2981
}
 
2982
 
 
2983
type ensureDyingService struct {
 
2984
        serviceName string
 
2985
}
 
2986
 
 
2987
func (e ensureDyingService) step(c *gc.C, ctx *context) {
 
2988
        svc, err := ctx.st.Application(e.serviceName)
 
2989
        c.Assert(err, jc.ErrorIsNil)
 
2990
        err = svc.Destroy()
 
2991
        c.Assert(err, jc.ErrorIsNil)
 
2992
        err = svc.Refresh()
 
2993
        c.Assert(err, jc.ErrorIsNil)
 
2994
        c.Assert(svc.Life(), gc.Equals, state.Dying)
 
2995
}
 
2996
 
 
2997
type ensureDeadMachine struct {
 
2998
        machineId string
 
2999
}
 
3000
 
 
3001
func (e ensureDeadMachine) step(c *gc.C, ctx *context) {
 
3002
        m, err := ctx.st.Machine(e.machineId)
 
3003
        c.Assert(err, jc.ErrorIsNil)
 
3004
        err = m.EnsureDead()
 
3005
        c.Assert(err, jc.ErrorIsNil)
 
3006
        c.Assert(m.Life(), gc.Equals, state.Dead)
 
3007
}
 
3008
 
 
3009
type setMachineStatus struct {
 
3010
        machineId  string
 
3011
        status     status.Status
 
3012
        statusInfo string
 
3013
}
 
3014
 
 
3015
func (sms setMachineStatus) step(c *gc.C, ctx *context) {
 
3016
        // lp:1558657
 
3017
        now := time.Now()
 
3018
        m, err := ctx.st.Machine(sms.machineId)
 
3019
        c.Assert(err, jc.ErrorIsNil)
 
3020
        sInfo := status.StatusInfo{
 
3021
                Status:  sms.status,
 
3022
                Message: sms.statusInfo,
 
3023
                Since:   &now,
 
3024
        }
 
3025
        err = m.SetStatus(sInfo)
 
3026
        c.Assert(err, jc.ErrorIsNil)
 
3027
}
 
3028
 
 
3029
type relateServices struct {
 
3030
        ep1, ep2 string
 
3031
}
 
3032
 
 
3033
func (rs relateServices) step(c *gc.C, ctx *context) {
 
3034
        eps, err := ctx.st.InferEndpoints(rs.ep1, rs.ep2)
 
3035
        c.Assert(err, jc.ErrorIsNil)
 
3036
        _, err = ctx.st.AddRelation(eps...)
 
3037
        c.Assert(err, jc.ErrorIsNil)
 
3038
}
 
3039
 
 
3040
type addSubordinate struct {
 
3041
        prinUnit   string
 
3042
        subService string
 
3043
}
 
3044
 
 
3045
func (as addSubordinate) step(c *gc.C, ctx *context) {
 
3046
        u, err := ctx.st.Unit(as.prinUnit)
 
3047
        c.Assert(err, jc.ErrorIsNil)
 
3048
        eps, err := ctx.st.InferEndpoints(u.ApplicationName(), as.subService)
 
3049
        c.Assert(err, jc.ErrorIsNil)
 
3050
        rel, err := ctx.st.EndpointsRelation(eps...)
 
3051
        c.Assert(err, jc.ErrorIsNil)
 
3052
        ru, err := rel.Unit(u)
 
3053
        c.Assert(err, jc.ErrorIsNil)
 
3054
        err = ru.EnterScope(nil)
 
3055
        c.Assert(err, jc.ErrorIsNil)
 
3056
}
 
3057
 
 
3058
type scopedExpect struct {
 
3059
        what   string
 
3060
        scope  []string
 
3061
        output M
 
3062
}
 
3063
 
 
3064
type expect struct {
 
3065
        what   string
 
3066
        output M
 
3067
}
 
3068
 
 
3069
// substituteFakeTime replaces all "since" values
 
3070
// in actual status output with a known fake value.
 
3071
func substituteFakeSinceTime(c *gc.C, in []byte, expectIsoTime bool) []byte {
 
3072
        // This regexp will work for yaml and json.
 
3073
        exp := regexp.MustCompile(`(?P<since>"?since"?:\ ?)(?P<quote>"?)(?P<timestamp>[^("|\n)]*)*"?`)
 
3074
        // Before the substritution is done, check that the timestamp produced
 
3075
        // by status is in the correct format.
 
3076
        if matches := exp.FindStringSubmatch(string(in)); matches != nil {
 
3077
                for i, name := range exp.SubexpNames() {
 
3078
                        if name != "timestamp" {
 
3079
                                continue
 
3080
                        }
 
3081
                        timeFormat := "02 Jan 2006 15:04:05Z07:00"
 
3082
                        if expectIsoTime {
 
3083
                                timeFormat = "2006-01-02 15:04:05Z"
 
3084
                        }
 
3085
                        _, err := time.Parse(timeFormat, matches[i])
 
3086
                        c.Assert(err, jc.ErrorIsNil)
 
3087
                }
 
3088
        }
 
3089
 
 
3090
        out := exp.ReplaceAllString(string(in), `$since$quote<timestamp>$quote`)
 
3091
        // Substitute a made up time used in our expected output.
 
3092
        out = strings.Replace(out, "<timestamp>", "01 Apr 15 01:23+10:00", -1)
 
3093
        return []byte(out)
 
3094
}
 
3095
 
 
3096
func (e scopedExpect) step(c *gc.C, ctx *context) {
 
3097
        c.Logf("\nexpect: %s %s\n", e.what, strings.Join(e.scope, " "))
 
3098
 
 
3099
        // Now execute the command for each format.
 
3100
        for _, format := range statusFormats {
 
3101
                c.Logf("format %q", format.name)
 
3102
                // Run command with the required format.
 
3103
                args := []string{"--format", format.name}
 
3104
                if ctx.expectIsoTime {
 
3105
                        args = append(args, "--utc")
 
3106
                }
 
3107
                args = append(args, e.scope...)
 
3108
                c.Logf("running status %s", strings.Join(args, " "))
 
3109
                code, stdout, stderr := runStatus(c, args...)
 
3110
                c.Assert(code, gc.Equals, 0)
 
3111
                if !c.Check(stderr, gc.HasLen, 0) {
 
3112
                        c.Fatalf("status failed: %s", string(stderr))
 
3113
                }
 
3114
 
 
3115
                // Prepare the output in the same format.
 
3116
                buf, err := format.marshal(e.output)
 
3117
                c.Assert(err, jc.ErrorIsNil)
 
3118
                expected := make(M)
 
3119
                err = format.unmarshal(buf, &expected)
 
3120
                c.Assert(err, jc.ErrorIsNil)
 
3121
 
 
3122
                // Check the output is as expected.
 
3123
                actual := make(M)
 
3124
                out := substituteFakeSinceTime(c, stdout, ctx.expectIsoTime)
 
3125
                err = format.unmarshal(out, &actual)
 
3126
                c.Assert(err, jc.ErrorIsNil)
 
3127
                c.Assert(actual, jc.DeepEquals, expected)
 
3128
        }
 
3129
}
 
3130
 
 
3131
func (e expect) step(c *gc.C, ctx *context) {
 
3132
        scopedExpect{e.what, nil, e.output}.step(c, ctx)
 
3133
}
 
3134
 
 
3135
type setToolsUpgradeAvailable struct{}
 
3136
 
 
3137
func (ua setToolsUpgradeAvailable) step(c *gc.C, ctx *context) {
 
3138
        env, err := ctx.st.Model()
 
3139
        c.Assert(err, jc.ErrorIsNil)
 
3140
        err = env.UpdateLatestToolsVersion(nextVersion)
 
3141
        c.Assert(err, jc.ErrorIsNil)
 
3142
}
 
3143
 
 
3144
func (s *StatusSuite) TestStatusAllFormats(c *gc.C) {
 
3145
        for i, t := range statusTests {
 
3146
                c.Logf("test %d: %s", i, t.summary)
 
3147
                func(t testCase) {
 
3148
                        // Prepare context and run all steps to setup.
 
3149
                        ctx := s.newContext(c)
 
3150
                        defer s.resetContext(c, ctx)
 
3151
                        ctx.run(c, t.steps)
 
3152
                }(t)
 
3153
        }
 
3154
}
 
3155
 
 
3156
func (s *StatusSuite) TestMigrationInProgress(c *gc.C) {
 
3157
        // This test isn't part of statusTests because migrations can't be
 
3158
        // run on controller models.
 
3159
 
 
3160
        const hostedModelName = "hosted"
 
3161
        const statusText = "foo bar"
 
3162
 
 
3163
        f := factory.NewFactory(s.BackingState)
 
3164
        hostedSt := f.MakeModel(c, &factory.ModelParams{
 
3165
                Name: hostedModelName,
 
3166
        })
 
3167
        defer hostedSt.Close()
 
3168
 
 
3169
        mig, err := hostedSt.CreateModelMigration(state.ModelMigrationSpec{
 
3170
                InitiatedBy: names.NewUserTag("admin"),
 
3171
                TargetInfo: migration.TargetInfo{
 
3172
                        ControllerTag: names.NewModelTag(utils.MustNewUUID().String()),
 
3173
                        Addrs:         []string{"1.2.3.4:5555", "4.3.2.1:6666"},
 
3174
                        CACert:        "cert",
 
3175
                        AuthTag:       names.NewUserTag("user"),
 
3176
                        Password:      "password",
 
3177
                },
 
3178
        })
 
3179
        c.Assert(err, jc.ErrorIsNil)
 
3180
        err = mig.SetStatusMessage(statusText)
 
3181
        c.Assert(err, jc.ErrorIsNil)
 
3182
 
 
3183
        expected := M{
 
3184
                "model": M{
 
3185
                        "name":       hostedModelName,
 
3186
                        "controller": "kontroll",
 
3187
                        "cloud":      "dummy",
 
3188
                        "version":    "1.2.3",
 
3189
                        "migration":  statusText,
 
3190
                },
 
3191
                "machines":     M{},
 
3192
                "applications": M{},
 
3193
        }
 
3194
 
 
3195
        for _, format := range statusFormats {
 
3196
                code, stdout, stderr := runStatus(c, "-m", hostedModelName, "--format", format.name)
 
3197
                c.Check(code, gc.Equals, 0)
 
3198
                c.Assert(stderr, gc.HasLen, 0, gc.Commentf("status failed: %s", stderr))
 
3199
 
 
3200
                // Roundtrip expected through format so that types will match.
 
3201
                buf, err := format.marshal(expected)
 
3202
                c.Assert(err, jc.ErrorIsNil)
 
3203
                var expectedForFormat M
 
3204
                err = format.unmarshal(buf, &expectedForFormat)
 
3205
                c.Assert(err, jc.ErrorIsNil)
 
3206
 
 
3207
                var actual M
 
3208
                c.Assert(format.unmarshal(stdout, &actual), jc.ErrorIsNil)
 
3209
                c.Check(actual, jc.DeepEquals, expectedForFormat)
 
3210
        }
 
3211
}
 
3212
 
 
3213
type fakeApiClient struct {
 
3214
        statusReturn *params.FullStatus
 
3215
        patternsUsed []string
 
3216
        closeCalled  bool
 
3217
}
 
3218
 
 
3219
func (a *fakeApiClient) Status(patterns []string) (*params.FullStatus, error) {
 
3220
        a.patternsUsed = patterns
 
3221
        return a.statusReturn, nil
 
3222
}
 
3223
 
 
3224
func (a *fakeApiClient) Close() error {
 
3225
        a.closeCalled = true
 
3226
        return nil
 
3227
}
 
3228
 
 
3229
func (s *StatusSuite) TestStatusWithFormatSummary(c *gc.C) {
 
3230
        ctx := s.newContext(c)
 
3231
        defer s.resetContext(c, ctx)
 
3232
        steps := []stepper{
 
3233
                addMachine{machineId: "0", job: state.JobManageModel},
 
3234
                setAddresses{"0", network.NewAddresses("localhost")},
 
3235
                startAliveMachine{"0"},
 
3236
                setMachineStatus{"0", status.StatusStarted, ""},
 
3237
                addCharm{"wordpress"},
 
3238
                addCharm{"mysql"},
 
3239
                addCharm{"logging"},
 
3240
                addService{name: "wordpress", charm: "wordpress"},
 
3241
                setServiceExposed{"wordpress", true},
 
3242
                addMachine{machineId: "1", job: state.JobHostUnits},
 
3243
                setAddresses{"1", network.NewAddresses("localhost")},
 
3244
                startAliveMachine{"1"},
 
3245
                setMachineStatus{"1", status.StatusStarted, ""},
 
3246
                addAliveUnit{"wordpress", "1"},
 
3247
                setAgentStatus{"wordpress/0", status.StatusIdle, "", nil},
 
3248
                setUnitStatus{"wordpress/0", status.StatusActive, "", nil},
 
3249
                addService{name: "mysql", charm: "mysql"},
 
3250
                setServiceExposed{"mysql", true},
 
3251
                addMachine{machineId: "2", job: state.JobHostUnits},
 
3252
                setAddresses{"2", network.NewAddresses("10.0.0.1")},
 
3253
                startAliveMachine{"2"},
 
3254
                setMachineStatus{"2", status.StatusStarted, ""},
 
3255
                addAliveUnit{"mysql", "2"},
 
3256
                setAgentStatus{"mysql/0", status.StatusIdle, "", nil},
 
3257
                setUnitStatus{"mysql/0", status.StatusActive, "", nil},
 
3258
                addService{name: "logging", charm: "logging"},
 
3259
                setServiceExposed{"logging", true},
 
3260
                relateServices{"wordpress", "mysql"},
 
3261
                relateServices{"wordpress", "logging"},
 
3262
                relateServices{"mysql", "logging"},
 
3263
                addSubordinate{"wordpress/0", "logging"},
 
3264
                addSubordinate{"mysql/0", "logging"},
 
3265
                setUnitsAlive{"logging"},
 
3266
                setAgentStatus{"logging/0", status.StatusIdle, "", nil},
 
3267
                setUnitStatus{"logging/0", status.StatusActive, "", nil},
 
3268
                setAgentStatus{"logging/1", status.StatusError, "somehow lost in all those logs", nil},
 
3269
        }
 
3270
        for _, s := range steps {
 
3271
                s.step(c, ctx)
 
3272
        }
 
3273
        code, stdout, stderr := runStatus(c, "--format", "summary")
 
3274
        c.Check(code, gc.Equals, 0)
 
3275
        c.Check(string(stderr), gc.Equals, "")
 
3276
        c.Assert(string(stdout), gc.Equals, `
 
3277
Running on subnets: 127.0.0.1/8, 10.0.0.1/8 
 
3278
Utilizing ports:                            
 
3279
     # MACHINES: (3)
 
3280
        started:  3 
 
3281
                
 
3282
        # UNITS: (4)
 
3283
         active:  3 
 
3284
          error:  1 
 
3285
                
 
3286
 # APPLICATIONS:  (3)
 
3287
         logging  1/1 exposed
 
3288
           mysql  1/1 exposed
 
3289
       wordpress  1/1 exposed
 
3290
 
 
3291
`[1:])
 
3292
}
 
3293
func (s *StatusSuite) TestStatusWithFormatOneline(c *gc.C) {
 
3294
        ctx := s.newContext(c)
 
3295
        defer s.resetContext(c, ctx)
 
3296
        steps := []stepper{
 
3297
                addMachine{machineId: "0", job: state.JobManageModel},
 
3298
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
3299
                startAliveMachine{"0"},
 
3300
                setMachineStatus{"0", status.StatusStarted, ""},
 
3301
                addCharm{"wordpress"},
 
3302
                addCharm{"mysql"},
 
3303
                addCharm{"logging"},
 
3304
 
 
3305
                addService{name: "wordpress", charm: "wordpress"},
 
3306
                setServiceExposed{"wordpress", true},
 
3307
                addMachine{machineId: "1", job: state.JobHostUnits},
 
3308
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
3309
                startAliveMachine{"1"},
 
3310
                setMachineStatus{"1", status.StatusStarted, ""},
 
3311
                addAliveUnit{"wordpress", "1"},
 
3312
                setAgentStatus{"wordpress/0", status.StatusIdle, "", nil},
 
3313
                setUnitStatus{"wordpress/0", status.StatusActive, "", nil},
 
3314
 
 
3315
                addService{name: "mysql", charm: "mysql"},
 
3316
                setServiceExposed{"mysql", true},
 
3317
                addMachine{machineId: "2", job: state.JobHostUnits},
 
3318
                setAddresses{"2", network.NewAddresses("controller-2.dns")},
 
3319
                startAliveMachine{"2"},
 
3320
                setMachineStatus{"2", status.StatusStarted, ""},
 
3321
                addAliveUnit{"mysql", "2"},
 
3322
                setAgentStatus{"mysql/0", status.StatusIdle, "", nil},
 
3323
                setUnitStatus{"mysql/0", status.StatusActive, "", nil},
 
3324
 
 
3325
                addService{name: "logging", charm: "logging"},
 
3326
                setServiceExposed{"logging", true},
 
3327
 
 
3328
                relateServices{"wordpress", "mysql"},
 
3329
                relateServices{"wordpress", "logging"},
 
3330
                relateServices{"mysql", "logging"},
 
3331
 
 
3332
                addSubordinate{"wordpress/0", "logging"},
 
3333
                addSubordinate{"mysql/0", "logging"},
 
3334
 
 
3335
                setUnitsAlive{"logging"},
 
3336
                setAgentStatus{"logging/0", status.StatusIdle, "", nil},
 
3337
                setUnitStatus{"logging/0", status.StatusActive, "", nil},
 
3338
                setAgentStatus{"logging/1", status.StatusError, "somehow lost in all those logs", nil},
 
3339
        }
 
3340
 
 
3341
        ctx.run(c, steps)
 
3342
 
 
3343
        const expected = `
 
3344
- mysql/0: controller-2.dns (agent:idle, workload:active)
 
3345
  - logging/1: controller-2.dns (agent:idle, workload:error)
 
3346
- wordpress/0: controller-1.dns (agent:idle, workload:active)
 
3347
  - logging/0: controller-1.dns (agent:idle, workload:active)
 
3348
`
 
3349
        assertOneLineStatus(c, expected)
 
3350
}
 
3351
 
 
3352
func assertOneLineStatus(c *gc.C, expected string) {
 
3353
        code, stdout, stderr := runStatus(c, "--format", "oneline")
 
3354
        c.Check(code, gc.Equals, 0)
 
3355
        c.Check(string(stderr), gc.Equals, "")
 
3356
        c.Assert(string(stdout), gc.Equals, expected)
 
3357
 
 
3358
        c.Log(`Check that "short" is an alias for oneline.`)
 
3359
        code, stdout, stderr = runStatus(c, "--format", "short")
 
3360
        c.Check(code, gc.Equals, 0)
 
3361
        c.Check(string(stderr), gc.Equals, "")
 
3362
        c.Assert(string(stdout), gc.Equals, expected)
 
3363
 
 
3364
        c.Log(`Check that "line" is an alias for oneline.`)
 
3365
        code, stdout, stderr = runStatus(c, "--format", "line")
 
3366
        c.Check(code, gc.Equals, 0)
 
3367
        c.Check(string(stderr), gc.Equals, "")
 
3368
        c.Assert(string(stdout), gc.Equals, expected)
 
3369
}
 
3370
 
 
3371
func (s *StatusSuite) prepareTabularData(c *gc.C) *context {
 
3372
        ctx := s.newContext(c)
 
3373
        steps := []stepper{
 
3374
                setToolsUpgradeAvailable{},
 
3375
                addMachine{machineId: "0", job: state.JobManageModel},
 
3376
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
3377
                startMachineWithHardware{"0", instance.MustParseHardware("availability-zone=us-east-1a")},
 
3378
                setMachineStatus{"0", status.StatusStarted, ""},
 
3379
                addCharm{"wordpress"},
 
3380
                addCharm{"mysql"},
 
3381
                addCharm{"logging"},
 
3382
                addService{name: "wordpress", charm: "wordpress"},
 
3383
                setServiceExposed{"wordpress", true},
 
3384
                addMachine{machineId: "1", job: state.JobHostUnits},
 
3385
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
3386
                startAliveMachine{"1"},
 
3387
                setMachineStatus{"1", status.StatusStarted, ""},
 
3388
                addAliveUnit{"wordpress", "1"},
 
3389
                setAgentStatus{"wordpress/0", status.StatusIdle, "", nil},
 
3390
                setUnitStatus{"wordpress/0", status.StatusActive, "", nil},
 
3391
                setUnitTools{"wordpress/0", version.MustParseBinary("1.2.3-trusty-ppc")},
 
3392
                addService{name: "mysql", charm: "mysql"},
 
3393
                setServiceExposed{"mysql", true},
 
3394
                addMachine{machineId: "2", job: state.JobHostUnits},
 
3395
                setAddresses{"2", network.NewAddresses("controller-2.dns")},
 
3396
                startAliveMachine{"2"},
 
3397
                setMachineStatus{"2", status.StatusStarted, ""},
 
3398
                addAliveUnit{"mysql", "2"},
 
3399
                setAgentStatus{"mysql/0", status.StatusIdle, "", nil},
 
3400
                setUnitStatus{
 
3401
                        "mysql/0",
 
3402
                        status.StatusMaintenance,
 
3403
                        "installing all the things", nil},
 
3404
                setUnitTools{"mysql/0", version.MustParseBinary("1.2.3-trusty-ppc")},
 
3405
                addService{name: "logging", charm: "logging"},
 
3406
                setServiceExposed{"logging", true},
 
3407
                relateServices{"wordpress", "mysql"},
 
3408
                relateServices{"wordpress", "logging"},
 
3409
                relateServices{"mysql", "logging"},
 
3410
                addSubordinate{"wordpress/0", "logging"},
 
3411
                addSubordinate{"mysql/0", "logging"},
 
3412
                setUnitsAlive{"logging"},
 
3413
                setAgentStatus{"logging/0", status.StatusIdle, "", nil},
 
3414
                setUnitStatus{"logging/0", status.StatusActive, "", nil},
 
3415
                setAgentStatus{"logging/1", status.StatusError, "somehow lost in all those logs", nil},
 
3416
                setUnitWorkloadVersion{"logging/1", "a bit too long, really"},
 
3417
                setUnitWorkloadVersion{"wordpress/0", "4.5.3"},
 
3418
                setUnitWorkloadVersion{"mysql/0", "5.7.13"},
 
3419
        }
 
3420
        for _, s := range steps {
 
3421
                s.step(c, ctx)
 
3422
        }
 
3423
        return ctx
 
3424
}
 
3425
 
 
3426
func (s *StatusSuite) testStatusWithFormatTabular(c *gc.C, useFeatureFlag bool) {
 
3427
        ctx := s.prepareTabularData(c)
 
3428
        defer s.resetContext(c, ctx)
 
3429
        var args []string
 
3430
        if !useFeatureFlag {
 
3431
                args = []string{"--format", "tabular"}
 
3432
        }
 
3433
        code, stdout, stderr := runStatus(c, args...)
 
3434
        c.Check(code, gc.Equals, 0)
 
3435
        c.Check(string(stderr), gc.Equals, "")
 
3436
        expected := `
 
3437
MODEL       CONTROLLER  CLOUD/REGION  VERSION  UPGRADE-AVAILABLE
 
3438
controller  kontroll    dummy         1.2.3    1.2.4
 
3439
 
 
3440
APP        VERSION  STATUS       EXPOSED  ORIGIN      CHARM      REV  OS
 
3441
logging    a bi...               true     jujucharms  logging    1    ubuntu
 
3442
mysql      5.7.13   maintenance  true     jujucharms  mysql      1    ubuntu
 
3443
wordpress  4.5.3    active       true     jujucharms  wordpress  3    ubuntu
 
3444
 
 
3445
RELATION           PROVIDES   CONSUMES   TYPE
 
3446
juju-info          logging    mysql      regular
 
3447
logging-dir        logging    wordpress  regular
 
3448
info               mysql      logging    subordinate
 
3449
db                 mysql      wordpress  regular
 
3450
logging-directory  wordpress  logging    subordinate
 
3451
 
 
3452
UNIT         WORKLOAD     AGENT  MACHINE  PUBLIC-ADDRESS    PORTS  MESSAGE
 
3453
mysql/0      maintenance  idle   2        controller-2.dns         installing all the things
 
3454
  logging/1  error        idle            controller-2.dns         somehow lost in all those logs
 
3455
wordpress/0  active       idle   1        controller-1.dns         
 
3456
  logging/0  active       idle            controller-1.dns         
 
3457
 
 
3458
MACHINE  STATE    DNS               INS-ID        SERIES   AZ
 
3459
0        started  controller-0.dns  controller-0  quantal  us-east-1a
 
3460
1        started  controller-1.dns  controller-1  quantal  
 
3461
2        started  controller-2.dns  controller-2  quantal  
 
3462
 
 
3463
`[1:]
 
3464
        c.Assert(string(stdout), gc.Equals, expected)
 
3465
}
 
3466
 
 
3467
func (s *StatusSuite) TestStatusWithFormatTabular(c *gc.C) {
 
3468
        s.testStatusWithFormatTabular(c, false)
 
3469
}
 
3470
 
 
3471
func (s *StatusSuite) TestFormatTabularHookActionName(c *gc.C) {
 
3472
        status := formattedStatus{
 
3473
                Applications: map[string]applicationStatus{
 
3474
                        "foo": {
 
3475
                                Units: map[string]unitStatus{
 
3476
                                        "foo/0": {
 
3477
                                                JujuStatusInfo: statusInfoContents{
 
3478
                                                        Current: status.StatusExecuting,
 
3479
                                                        Message: "running config-changed hook",
 
3480
                                                },
 
3481
                                                WorkloadStatusInfo: statusInfoContents{
 
3482
                                                        Current: status.StatusMaintenance,
 
3483
                                                        Message: "doing some work",
 
3484
                                                },
 
3485
                                        },
 
3486
                                        "foo/1": {
 
3487
                                                JujuStatusInfo: statusInfoContents{
 
3488
                                                        Current: status.StatusExecuting,
 
3489
                                                        Message: "running action backup database",
 
3490
                                                },
 
3491
                                                WorkloadStatusInfo: statusInfoContents{
 
3492
                                                        Current: status.StatusMaintenance,
 
3493
                                                        Message: "doing some work",
 
3494
                                                },
 
3495
                                        },
 
3496
                                },
 
3497
                        },
 
3498
                },
 
3499
        }
 
3500
        out, err := FormatTabular(status)
 
3501
        c.Assert(err, jc.ErrorIsNil)
 
3502
        c.Assert(string(out), gc.Equals, `
 
3503
MODEL  CONTROLLER  CLOUD/REGION  VERSION
 
3504
                                 
 
3505
 
 
3506
APP  VERSION  STATUS  EXPOSED  ORIGIN  CHARM  REV  OS
 
3507
foo                   false                   0    
 
3508
 
 
3509
UNIT   WORKLOAD     AGENT      MACHINE  PUBLIC-ADDRESS  PORTS  MESSAGE
 
3510
foo/0  maintenance  executing                                  (config-changed) doing some work
 
3511
foo/1  maintenance  executing                                  (backup database) doing some work
 
3512
 
 
3513
MACHINE  STATE  DNS  INS-ID  SERIES  AZ
 
3514
`[1:])
 
3515
}
 
3516
 
 
3517
func (s *StatusSuite) TestFormatTabularConsistentPeerRelationName(c *gc.C) {
 
3518
        status := formattedStatus{
 
3519
                Applications: map[string]applicationStatus{
 
3520
                        "foo": {
 
3521
                                Relations: map[string][]string{
 
3522
                                        "coordinator":  {"foo"},
 
3523
                                        "frobulator":   {"foo"},
 
3524
                                        "encapsulator": {"foo"},
 
3525
                                        "catchulator":  {"foo"},
 
3526
                                        "perforator":   {"foo"},
 
3527
                                        "deliverator":  {"foo"},
 
3528
                                        "replicator":   {"foo"},
 
3529
                                },
 
3530
                        },
 
3531
                },
 
3532
        }
 
3533
        out, err := FormatTabular(status)
 
3534
        c.Assert(err, jc.ErrorIsNil)
 
3535
        sections, err := splitTableSections(out)
 
3536
        c.Assert(err, jc.ErrorIsNil)
 
3537
        c.Assert(sections["RELATION"], gc.DeepEquals, []string{
 
3538
                "RELATION    PROVIDES  CONSUMES  TYPE",
 
3539
                "replicator  foo       foo       peer",
 
3540
        })
 
3541
}
 
3542
 
 
3543
func (s *StatusSuite) TestStatusWithNilStatusApi(c *gc.C) {
 
3544
        ctx := s.newContext(c)
 
3545
        defer s.resetContext(c, ctx)
 
3546
        steps := []stepper{
 
3547
                addMachine{machineId: "0", job: state.JobManageModel},
 
3548
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
3549
                startAliveMachine{"0"},
 
3550
                setMachineStatus{"0", status.StatusStarted, ""},
 
3551
        }
 
3552
 
 
3553
        for _, s := range steps {
 
3554
                s.step(c, ctx)
 
3555
        }
 
3556
 
 
3557
        client := fakeApiClient{}
 
3558
        var status = client.Status
 
3559
        s.PatchValue(&status, func(_ []string) (*params.FullStatus, error) {
 
3560
                return nil, nil
 
3561
        })
 
3562
        s.PatchValue(&newApiClientForStatus, func(_ *statusCommand) (statusAPI, error) {
 
3563
                return &client, nil
 
3564
        })
 
3565
 
 
3566
        code, _, stderr := runStatus(c, "--format", "tabular")
 
3567
        c.Check(code, gc.Equals, 1)
 
3568
        c.Check(string(stderr), gc.Equals, "error: unable to obtain the current status\n")
 
3569
}
 
3570
 
 
3571
func (s *StatusSuite) TestFormatTabularMetering(c *gc.C) {
 
3572
        status := formattedStatus{
 
3573
                Applications: map[string]applicationStatus{
 
3574
                        "foo": {
 
3575
                                Units: map[string]unitStatus{
 
3576
                                        "foo/0": {
 
3577
                                                MeterStatus: &meterStatus{
 
3578
                                                        Color:   "strange",
 
3579
                                                        Message: "warning: stable strangelets",
 
3580
                                                },
 
3581
                                        },
 
3582
                                        "foo/1": {
 
3583
                                                MeterStatus: &meterStatus{
 
3584
                                                        Color:   "up",
 
3585
                                                        Message: "things are looking up",
 
3586
                                                },
 
3587
                                        },
 
3588
                                },
 
3589
                        },
 
3590
                },
 
3591
        }
 
3592
        out, err := FormatTabular(status)
 
3593
        c.Assert(err, jc.ErrorIsNil)
 
3594
        c.Assert(string(out), gc.Equals, `
 
3595
MODEL  CONTROLLER  CLOUD/REGION  VERSION
 
3596
                                 
 
3597
 
 
3598
APP  VERSION  STATUS  EXPOSED  ORIGIN  CHARM  REV  OS
 
3599
foo                   false                   0    
 
3600
 
 
3601
UNIT   WORKLOAD  AGENT  MACHINE  PUBLIC-ADDRESS  PORTS  MESSAGE
 
3602
foo/0                                                   
 
3603
foo/1                                                   
 
3604
 
 
3605
METER  STATUS   MESSAGE
 
3606
foo/0  strange  warning: stable strangelets
 
3607
foo/1  up       things are looking up
 
3608
 
 
3609
MACHINE  STATE  DNS  INS-ID  SERIES  AZ
 
3610
`[1:])
 
3611
}
 
3612
 
 
3613
//
 
3614
// Filtering Feature
 
3615
//
 
3616
 
 
3617
func (s *StatusSuite) FilteringTestSetup(c *gc.C) *context {
 
3618
        ctx := s.newContext(c)
 
3619
 
 
3620
        steps := []stepper{
 
3621
                // Given a machine is started
 
3622
                // And the machine's ID is "0"
 
3623
                // And the machine's job is to manage the environment
 
3624
                addMachine{machineId: "0", job: state.JobManageModel},
 
3625
                startAliveMachine{"0"},
 
3626
                setMachineStatus{"0", status.StatusStarted, ""},
 
3627
                // And the machine's address is "controller-0.dns"
 
3628
                setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
3629
                // And a container is started
 
3630
                // And the container's ID is "0/lxd/0"
 
3631
                addContainer{"0", "0/lxd/0", state.JobHostUnits},
 
3632
 
 
3633
                // And the "wordpress" charm is available
 
3634
                addCharm{"wordpress"},
 
3635
                addService{name: "wordpress", charm: "wordpress"},
 
3636
                // And the "mysql" charm is available
 
3637
                addCharm{"mysql"},
 
3638
                addService{name: "mysql", charm: "mysql"},
 
3639
                // And the "logging" charm is available
 
3640
                addCharm{"logging"},
 
3641
 
 
3642
                // And a machine is started
 
3643
                // And the machine's ID is "1"
 
3644
                // And the machine's job is to host units
 
3645
                addMachine{machineId: "1", job: state.JobHostUnits},
 
3646
                startAliveMachine{"1"},
 
3647
                setMachineStatus{"1", status.StatusStarted, ""},
 
3648
                // And the machine's address is "controller-1.dns"
 
3649
                setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
3650
                // And a unit of "wordpress" is deployed to machine "1"
 
3651
                addAliveUnit{"wordpress", "1"},
 
3652
                // And the unit is started
 
3653
                setAgentStatus{"wordpress/0", status.StatusIdle, "", nil},
 
3654
                setUnitStatus{"wordpress/0", status.StatusActive, "", nil},
 
3655
                // And a machine is started
 
3656
 
 
3657
                // And the machine's ID is "2"
 
3658
                // And the machine's job is to host units
 
3659
                addMachine{machineId: "2", job: state.JobHostUnits},
 
3660
                startAliveMachine{"2"},
 
3661
                setMachineStatus{"2", status.StatusStarted, ""},
 
3662
                // And the machine's address is "controller-2.dns"
 
3663
                setAddresses{"2", network.NewAddresses("controller-2.dns")},
 
3664
                // And a unit of "mysql" is deployed to machine "2"
 
3665
                addAliveUnit{"mysql", "2"},
 
3666
                // And the unit is started
 
3667
                setAgentStatus{"mysql/0", status.StatusIdle, "", nil},
 
3668
                setUnitStatus{"mysql/0", status.StatusActive, "", nil},
 
3669
                // And the "logging" service is added
 
3670
                addService{name: "logging", charm: "logging"},
 
3671
                // And the service is exposed
 
3672
                setServiceExposed{"logging", true},
 
3673
                // And the "wordpress" service is related to the "mysql" service
 
3674
                relateServices{"wordpress", "mysql"},
 
3675
                // And the "wordpress" service is related to the "logging" service
 
3676
                relateServices{"wordpress", "logging"},
 
3677
                // And the "mysql" service is related to the "logging" service
 
3678
                relateServices{"mysql", "logging"},
 
3679
                // And the "logging" service is a subordinate to unit 0 of the "wordpress" service
 
3680
                addSubordinate{"wordpress/0", "logging"},
 
3681
                setAgentStatus{"logging/0", status.StatusIdle, "", nil},
 
3682
                setUnitStatus{"logging/0", status.StatusActive, "", nil},
 
3683
                // And the "logging" service is a subordinate to unit 0 of the "mysql" service
 
3684
                addSubordinate{"mysql/0", "logging"},
 
3685
                setAgentStatus{"logging/1", status.StatusIdle, "", nil},
 
3686
                setUnitStatus{"logging/1", status.StatusActive, "", nil},
 
3687
                setUnitsAlive{"logging"},
 
3688
        }
 
3689
 
 
3690
        ctx.run(c, steps)
 
3691
        return ctx
 
3692
}
 
3693
 
 
3694
// Scenario: One unit is in an errored state and user filters to active
 
3695
func (s *StatusSuite) TestFilterToActive(c *gc.C) {
 
3696
        ctx := s.FilteringTestSetup(c)
 
3697
        defer s.resetContext(c, ctx)
 
3698
 
 
3699
        // Given unit 1 of the "logging" service has an error
 
3700
        setAgentStatus{"logging/1", status.StatusError, "mock error", nil}.step(c, ctx)
 
3701
        // And unit 0 of the "mysql" service has an error
 
3702
        setAgentStatus{"mysql/0", status.StatusError, "mock error", nil}.step(c, ctx)
 
3703
        // When I run juju status --format oneline started
 
3704
        _, stdout, stderr := runStatus(c, "--format", "oneline", "active")
 
3705
        c.Assert(string(stderr), gc.Equals, "")
 
3706
        // Then I should receive output prefixed with:
 
3707
        const expected = `
 
3708
 
 
3709
- wordpress/0: controller-1.dns (agent:idle, workload:active)
 
3710
  - logging/0: controller-1.dns (agent:idle, workload:active)
 
3711
`
 
3712
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3713
}
 
3714
 
 
3715
// Scenario: user filters to a single machine
 
3716
func (s *StatusSuite) TestFilterToMachine(c *gc.C) {
 
3717
        ctx := s.FilteringTestSetup(c)
 
3718
        defer s.resetContext(c, ctx)
 
3719
 
 
3720
        // When I run juju status --format oneline 1
 
3721
        _, stdout, stderr := runStatus(c, "--format", "oneline", "1")
 
3722
        c.Assert(string(stderr), gc.Equals, "")
 
3723
        // Then I should receive output prefixed with:
 
3724
        const expected = `
 
3725
 
 
3726
- wordpress/0: controller-1.dns (agent:idle, workload:active)
 
3727
  - logging/0: controller-1.dns (agent:idle, workload:active)
 
3728
`
 
3729
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3730
}
 
3731
 
 
3732
// Scenario: user filters to a machine, shows containers
 
3733
func (s *StatusSuite) TestFilterToMachineShowsContainer(c *gc.C) {
 
3734
        ctx := s.FilteringTestSetup(c)
 
3735
        defer s.resetContext(c, ctx)
 
3736
 
 
3737
        // When I run juju status --format yaml 0
 
3738
        _, stdout, stderr := runStatus(c, "--format", "yaml", "0")
 
3739
        c.Assert(string(stderr), gc.Equals, "")
 
3740
        // Then I should receive output matching:
 
3741
        const expected = "(.|\n)*machines:(.|\n)*\"0\"(.|\n)*0/lxd/0(.|\n)*"
 
3742
        c.Assert(string(stdout), gc.Matches, expected)
 
3743
}
 
3744
 
 
3745
// Scenario: user filters to a container
 
3746
func (s *StatusSuite) TestFilterToContainer(c *gc.C) {
 
3747
        ctx := s.FilteringTestSetup(c)
 
3748
        defer s.resetContext(c, ctx)
 
3749
 
 
3750
        // When I run juju status --format yaml 0/lxd/0
 
3751
        _, stdout, stderr := runStatus(c, "--format", "yaml", "0/lxd/0")
 
3752
        c.Assert(string(stderr), gc.Equals, "")
 
3753
        out := substituteFakeSinceTime(c, stdout, ctx.expectIsoTime)
 
3754
        const expected = "" +
 
3755
                "model:\n" +
 
3756
                "  name: controller\n" +
 
3757
                "  controller: kontroll\n" +
 
3758
                "  cloud: dummy\n" +
 
3759
                "  version: 1.2.3\n" +
 
3760
                "machines:\n" +
 
3761
                "  \"0\":\n" +
 
3762
                "    juju-status:\n" +
 
3763
                "      current: started\n" +
 
3764
                "      since: 01 Apr 15 01:23+10:00\n" +
 
3765
                "    dns-name: controller-0.dns\n" +
 
3766
                "    instance-id: controller-0\n" +
 
3767
                "    machine-status:\n" +
 
3768
                "      current: pending\n" +
 
3769
                "      since: 01 Apr 15 01:23+10:00\n" +
 
3770
                "    series: quantal\n" +
 
3771
                "    containers:\n" +
 
3772
                "      0/lxd/0:\n" +
 
3773
                "        juju-status:\n" +
 
3774
                "          current: pending\n" +
 
3775
                "          since: 01 Apr 15 01:23+10:00\n" +
 
3776
                "        instance-id: pending\n" +
 
3777
                "        machine-status:\n" +
 
3778
                "          current: pending\n" +
 
3779
                "          since: 01 Apr 15 01:23+10:00\n" +
 
3780
                "        series: quantal\n" +
 
3781
                "    hardware: arch=amd64 cpu-cores=1 mem=1024M root-disk=8192M\n" +
 
3782
                "    controller-member-status: adding-vote\n" +
 
3783
                "applications: {}\n"
 
3784
 
 
3785
        c.Assert(string(out), gc.Equals, expected)
 
3786
}
 
3787
 
 
3788
// Scenario: One unit is in an errored state and user filters to errored
 
3789
func (s *StatusSuite) TestFilterToErrored(c *gc.C) {
 
3790
        ctx := s.FilteringTestSetup(c)
 
3791
        defer s.resetContext(c, ctx)
 
3792
 
 
3793
        // Given unit 1 of the "logging" service has an error
 
3794
        setAgentStatus{"logging/1", status.StatusError, "mock error", nil}.step(c, ctx)
 
3795
        // When I run juju status --format oneline error
 
3796
        _, stdout, stderr := runStatus(c, "--format", "oneline", "error")
 
3797
        c.Assert(stderr, gc.IsNil)
 
3798
        // Then I should receive output prefixed with:
 
3799
        const expected = `
 
3800
 
 
3801
- mysql/0: controller-2.dns (agent:idle, workload:active)
 
3802
  - logging/1: controller-2.dns (agent:idle, workload:error)
 
3803
`
 
3804
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3805
}
 
3806
 
 
3807
// Scenario: User filters to mysql service
 
3808
func (s *StatusSuite) TestFilterToService(c *gc.C) {
 
3809
        ctx := s.FilteringTestSetup(c)
 
3810
        defer s.resetContext(c, ctx)
 
3811
 
 
3812
        // When I run juju status --format oneline error
 
3813
        _, stdout, stderr := runStatus(c, "--format", "oneline", "mysql")
 
3814
        c.Assert(stderr, gc.IsNil)
 
3815
        // Then I should receive output prefixed with:
 
3816
        const expected = `
 
3817
 
 
3818
- mysql/0: controller-2.dns (agent:idle, workload:active)
 
3819
  - logging/1: controller-2.dns (agent:idle, workload:active)
 
3820
`
 
3821
 
 
3822
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3823
}
 
3824
 
 
3825
// Scenario: User filters to exposed services
 
3826
func (s *StatusSuite) TestFilterToExposedService(c *gc.C) {
 
3827
        ctx := s.FilteringTestSetup(c)
 
3828
        defer s.resetContext(c, ctx)
 
3829
 
 
3830
        // Given unit 1 of the "mysql" service is exposed
 
3831
        setServiceExposed{"mysql", true}.step(c, ctx)
 
3832
        // And the logging service is not exposed
 
3833
        setServiceExposed{"logging", false}.step(c, ctx)
 
3834
        // And the wordpress service is not exposed
 
3835
        setServiceExposed{"wordpress", false}.step(c, ctx)
 
3836
        // When I run juju status --format oneline exposed
 
3837
        _, stdout, stderr := runStatus(c, "--format", "oneline", "exposed")
 
3838
        c.Assert(stderr, gc.IsNil)
 
3839
        // Then I should receive output prefixed with:
 
3840
        const expected = `
 
3841
 
 
3842
- mysql/0: controller-2.dns (agent:idle, workload:active)
 
3843
  - logging/1: controller-2.dns (agent:idle, workload:active)
 
3844
`
 
3845
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3846
}
 
3847
 
 
3848
// Scenario: User filters to non-exposed services
 
3849
func (s *StatusSuite) TestFilterToNotExposedService(c *gc.C) {
 
3850
        ctx := s.FilteringTestSetup(c)
 
3851
        defer s.resetContext(c, ctx)
 
3852
 
 
3853
        setServiceExposed{"mysql", true}.step(c, ctx)
 
3854
        // When I run juju status --format oneline not exposed
 
3855
        _, stdout, stderr := runStatus(c, "--format", "oneline", "not", "exposed")
 
3856
        c.Assert(stderr, gc.IsNil)
 
3857
        // Then I should receive output prefixed with:
 
3858
        const expected = `
 
3859
 
 
3860
- wordpress/0: controller-1.dns (agent:idle, workload:active)
 
3861
  - logging/0: controller-1.dns (agent:idle, workload:active)
 
3862
`
 
3863
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3864
}
 
3865
 
 
3866
// Scenario: Filtering on Subnets
 
3867
func (s *StatusSuite) TestFilterOnSubnet(c *gc.C) {
 
3868
        ctx := s.FilteringTestSetup(c)
 
3869
        defer s.resetContext(c, ctx)
 
3870
 
 
3871
        // Given the address for machine "1" is "localhost"
 
3872
        setAddresses{"1", network.NewAddresses("localhost", "127.0.0.1")}.step(c, ctx)
 
3873
        // And the address for machine "2" is "10.0.0.1"
 
3874
        setAddresses{"2", network.NewAddresses("10.0.0.1")}.step(c, ctx)
 
3875
        // When I run juju status --format oneline 127.0.0.1
 
3876
        _, stdout, stderr := runStatus(c, "--format", "oneline", "127.0.0.1")
 
3877
        c.Assert(stderr, gc.IsNil)
 
3878
        // Then I should receive output prefixed with:
 
3879
        const expected = `
 
3880
 
 
3881
- wordpress/0: localhost (agent:idle, workload:active)
 
3882
  - logging/0: localhost (agent:idle, workload:active)
 
3883
`
 
3884
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3885
}
 
3886
 
 
3887
// Scenario: Filtering on Ports
 
3888
func (s *StatusSuite) TestFilterOnPorts(c *gc.C) {
 
3889
        ctx := s.FilteringTestSetup(c)
 
3890
        defer s.resetContext(c, ctx)
 
3891
 
 
3892
        // Given the address for machine "1" is "localhost"
 
3893
        setAddresses{"1", network.NewAddresses("localhost")}.step(c, ctx)
 
3894
        // And the address for machine "2" is "10.0.0.1"
 
3895
        setAddresses{"2", network.NewAddresses("10.0.0.1")}.step(c, ctx)
 
3896
        openUnitPort{"wordpress/0", "tcp", 80}.step(c, ctx)
 
3897
        // When I run juju status --format oneline 80/tcp
 
3898
        _, stdout, stderr := runStatus(c, "--format", "oneline", "80/tcp")
 
3899
        c.Assert(stderr, gc.IsNil)
 
3900
        // Then I should receive output prefixed with:
 
3901
        const expected = `
 
3902
 
 
3903
- wordpress/0: localhost (agent:idle, workload:active) 80/tcp
 
3904
  - logging/0: localhost (agent:idle, workload:active)
 
3905
`
 
3906
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3907
}
 
3908
 
 
3909
// Scenario: User filters out a parent, but not its subordinate
 
3910
func (s *StatusSuite) TestFilterParentButNotSubordinate(c *gc.C) {
 
3911
        ctx := s.FilteringTestSetup(c)
 
3912
        defer s.resetContext(c, ctx)
 
3913
 
 
3914
        // When I run juju status --format oneline 80/tcp
 
3915
        _, stdout, stderr := runStatus(c, "--format", "oneline", "logging")
 
3916
        c.Assert(stderr, gc.IsNil)
 
3917
        // Then I should receive output prefixed with:
 
3918
        const expected = `
 
3919
 
 
3920
- mysql/0: controller-2.dns (agent:idle, workload:active)
 
3921
  - logging/1: controller-2.dns (agent:idle, workload:active)
 
3922
- wordpress/0: controller-1.dns (agent:idle, workload:active)
 
3923
  - logging/0: controller-1.dns (agent:idle, workload:active)
 
3924
`
 
3925
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3926
}
 
3927
 
 
3928
// Scenario: User filters out a subordinate, but not its parent
 
3929
func (s *StatusSuite) TestFilterSubordinateButNotParent(c *gc.C) {
 
3930
        ctx := s.FilteringTestSetup(c)
 
3931
        defer s.resetContext(c, ctx)
 
3932
 
 
3933
        // Given the wordpress service is exposed
 
3934
        setServiceExposed{"wordpress", true}.step(c, ctx)
 
3935
        // When I run juju status --format oneline not exposed
 
3936
        _, stdout, stderr := runStatus(c, "--format", "oneline", "not", "exposed")
 
3937
        c.Assert(stderr, gc.IsNil)
 
3938
        // Then I should receive output prefixed with:
 
3939
        const expected = `
 
3940
 
 
3941
- mysql/0: controller-2.dns (agent:idle, workload:active)
 
3942
  - logging/1: controller-2.dns (agent:idle, workload:active)
 
3943
`
 
3944
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3945
}
 
3946
 
 
3947
func (s *StatusSuite) TestFilterMultipleHomogenousPatterns(c *gc.C) {
 
3948
        ctx := s.FilteringTestSetup(c)
 
3949
        defer s.resetContext(c, ctx)
 
3950
 
 
3951
        _, stdout, stderr := runStatus(c, "--format", "oneline", "wordpress/0", "mysql/0")
 
3952
        c.Assert(stderr, gc.IsNil)
 
3953
        // Then I should receive output prefixed with:
 
3954
        const expected = `
 
3955
 
 
3956
- mysql/0: controller-2.dns (agent:idle, workload:active)
 
3957
  - logging/1: controller-2.dns (agent:idle, workload:active)
 
3958
- wordpress/0: controller-1.dns (agent:idle, workload:active)
 
3959
  - logging/0: controller-1.dns (agent:idle, workload:active)
 
3960
`
 
3961
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3962
}
 
3963
 
 
3964
func (s *StatusSuite) TestFilterMultipleHeterogenousPatterns(c *gc.C) {
 
3965
        ctx := s.FilteringTestSetup(c)
 
3966
        defer s.resetContext(c, ctx)
 
3967
 
 
3968
        _, stdout, stderr := runStatus(c, "--format", "oneline", "wordpress/0", "active")
 
3969
        c.Assert(stderr, gc.IsNil)
 
3970
        // Then I should receive output prefixed with:
 
3971
        const expected = `
 
3972
 
 
3973
- mysql/0: controller-2.dns (agent:idle, workload:active)
 
3974
  - logging/1: controller-2.dns (agent:idle, workload:active)
 
3975
- wordpress/0: controller-1.dns (agent:idle, workload:active)
 
3976
  - logging/0: controller-1.dns (agent:idle, workload:active)
 
3977
`
 
3978
        c.Assert(string(stdout), gc.Equals, expected[1:])
 
3979
}
 
3980
 
 
3981
// TestSummaryStatusWithUnresolvableDns is result of bug# 1410320.
 
3982
func (s *StatusSuite) TestSummaryStatusWithUnresolvableDns(c *gc.C) {
 
3983
        formatter := &summaryFormatter{}
 
3984
        formatter.resolveAndTrackIp("invalidDns")
 
3985
        // Test should not panic.
 
3986
}
 
3987
 
 
3988
func initStatusCommand(args ...string) (*statusCommand, error) {
 
3989
        com := &statusCommand{}
 
3990
        return com, coretesting.InitCommand(modelcmd.Wrap(com), args)
 
3991
}
 
3992
 
 
3993
var statusInitTests = []struct {
 
3994
        args    []string
 
3995
        envVar  string
 
3996
        isoTime bool
 
3997
        err     string
 
3998
}{
 
3999
        {
 
4000
                isoTime: false,
 
4001
        }, {
 
4002
                args:    []string{"--utc"},
 
4003
                isoTime: true,
 
4004
        }, {
 
4005
                envVar:  "true",
 
4006
                isoTime: true,
 
4007
        }, {
 
4008
                envVar: "foo",
 
4009
                err:    "invalid JUJU_STATUS_ISO_TIME env var, expected true|false.*",
 
4010
        },
 
4011
}
 
4012
 
 
4013
func (*StatusSuite) TestStatusCommandInit(c *gc.C) {
 
4014
        defer os.Setenv(osenv.JujuStatusIsoTimeEnvKey, os.Getenv(osenv.JujuStatusIsoTimeEnvKey))
 
4015
 
 
4016
        for i, t := range statusInitTests {
 
4017
                c.Logf("test %d", i)
 
4018
                os.Setenv(osenv.JujuStatusIsoTimeEnvKey, t.envVar)
 
4019
                com, err := initStatusCommand(t.args...)
 
4020
                if t.err != "" {
 
4021
                        c.Check(err, gc.ErrorMatches, t.err)
 
4022
                } else {
 
4023
                        c.Check(err, jc.ErrorIsNil)
 
4024
                }
 
4025
                c.Check(com.isoTime, gc.DeepEquals, t.isoTime)
 
4026
        }
 
4027
}
 
4028
 
 
4029
var statusTimeTest = test(
 
4030
        "status generates timestamps as UTC in ISO format",
 
4031
        addMachine{machineId: "0", job: state.JobManageModel},
 
4032
        setAddresses{"0", network.NewAddresses("controller-0.dns")},
 
4033
        startAliveMachine{"0"},
 
4034
        setMachineStatus{"0", status.StatusStarted, ""},
 
4035
        addCharm{"dummy"},
 
4036
        addService{name: "dummy-application", charm: "dummy"},
 
4037
 
 
4038
        addMachine{machineId: "1", job: state.JobHostUnits},
 
4039
        startAliveMachine{"1"},
 
4040
        setAddresses{"1", network.NewAddresses("controller-1.dns")},
 
4041
        setMachineStatus{"1", status.StatusStarted, ""},
 
4042
 
 
4043
        addAliveUnit{"dummy-application", "1"},
 
4044
        expect{
 
4045
                "add two units, one alive (in error state), one started",
 
4046
                M{
 
4047
                        "model": M{
 
4048
                                "name":       "controller",
 
4049
                                "controller": "kontroll",
 
4050
                                "cloud":      "dummy",
 
4051
                                "version":    "1.2.3",
 
4052
                        },
 
4053
                        "machines": M{
 
4054
                                "0": machine0,
 
4055
                                "1": machine1,
 
4056
                        },
 
4057
                        "applications": M{
 
4058
                                "dummy-application": dummyCharm(M{
 
4059
                                        "application-status": M{
 
4060
                                                "current": "unknown",
 
4061
                                                "message": "Waiting for agent initialization to finish",
 
4062
                                                "since":   "01 Apr 15 01:23+10:00",
 
4063
                                        },
 
4064
                                        "units": M{
 
4065
                                                "dummy-application/0": M{
 
4066
                                                        "machine": "1",
 
4067
                                                        "workload-status": M{
 
4068
                                                                "current": "unknown",
 
4069
                                                                "message": "Waiting for agent initialization to finish",
 
4070
                                                                "since":   "01 Apr 15 01:23+10:00",
 
4071
                                                        },
 
4072
                                                        "juju-status": M{
 
4073
                                                                "current": "allocating",
 
4074
                                                                "since":   "01 Apr 15 01:23+10:00",
 
4075
                                                        },
 
4076
                                                        "public-address": "controller-1.dns",
 
4077
                                                },
 
4078
                                        },
 
4079
                                }),
 
4080
                        },
 
4081
                },
 
4082
        },
 
4083
)
 
4084
 
 
4085
func (s *StatusSuite) TestIsoTimeFormat(c *gc.C) {
 
4086
        func(t testCase) {
 
4087
                // Prepare context and run all steps to setup.
 
4088
                ctx := s.newContext(c)
 
4089
                ctx.expectIsoTime = true
 
4090
                defer s.resetContext(c, ctx)
 
4091
                ctx.run(c, t.steps)
 
4092
        }(statusTimeTest)
 
4093
}
 
4094
 
 
4095
func (s *StatusSuite) TestFormatProvisioningError(c *gc.C) {
 
4096
        status := &params.FullStatus{
 
4097
                Machines: map[string]params.MachineStatus{
 
4098
                        "1": {
 
4099
                                AgentStatus: params.DetailedStatus{
 
4100
                                        Status: "error",
 
4101
                                        Info:   "<error while provisioning>",
 
4102
                                },
 
4103
                                InstanceId:     "pending",
 
4104
                                InstanceStatus: params.DetailedStatus{},
 
4105
                                Series:         "trusty",
 
4106
                                Id:             "1",
 
4107
                                Jobs:           []multiwatcher.MachineJob{"JobHostUnits"},
 
4108
                        },
 
4109
                },
 
4110
        }
 
4111
        formatter := NewStatusFormatter(status, true)
 
4112
        formatted := formatter.format()
 
4113
 
 
4114
        c.Check(formatted, jc.DeepEquals, formattedStatus{
 
4115
                Machines: map[string]machineStatus{
 
4116
                        "1": {
 
4117
                                JujuStatus: statusInfoContents{Current: "error", Message: "<error while provisioning>"},
 
4118
                                InstanceId: "pending",
 
4119
                                Series:     "trusty",
 
4120
                                Id:         "1",
 
4121
                                Containers: map[string]machineStatus{},
 
4122
                        },
 
4123
                },
 
4124
                Applications: map[string]applicationStatus{},
 
4125
        })
 
4126
}
 
4127
 
 
4128
type tableSections map[string][]string
 
4129
 
 
4130
func sectionTitle(lines []string) string {
 
4131
        return strings.SplitN(lines[0], " ", 2)[0]
 
4132
}
 
4133
 
 
4134
func splitTableSections(tableData []byte) (tableSections, error) {
 
4135
        scanner := bufio.NewScanner(bytes.NewReader(tableData))
 
4136
        result := make(tableSections)
 
4137
        var current []string
 
4138
        for scanner.Scan() {
 
4139
                if line := scanner.Text(); line == "" && current != nil {
 
4140
                        result[sectionTitle(current)] = current
 
4141
                        current = nil
 
4142
                } else if line != "" {
 
4143
                        current = append(current, line)
 
4144
                }
 
4145
        }
 
4146
        if scanner.Err() != nil {
 
4147
                return nil, scanner.Err()
 
4148
        }
 
4149
        if current != nil {
 
4150
                result[sectionTitle(current)] = current
 
4151
        }
 
4152
        return result, nil
 
4153
}