~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/cmd/juju/controller/kill_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 controller_test
 
5
 
 
6
import (
 
7
        "bytes"
 
8
        "time"
 
9
 
 
10
        "github.com/juju/cmd"
 
11
        "github.com/juju/errors"
 
12
        jc "github.com/juju/testing/checkers"
 
13
        "github.com/juju/utils/clock"
 
14
        gc "gopkg.in/check.v1"
 
15
        "gopkg.in/juju/names.v2"
 
16
 
 
17
        "github.com/juju/juju/api"
 
18
        "github.com/juju/juju/api/base"
 
19
        "github.com/juju/juju/apiserver/common"
 
20
        "github.com/juju/juju/apiserver/params"
 
21
        "github.com/juju/juju/cmd/juju/controller"
 
22
        "github.com/juju/juju/cmd/modelcmd"
 
23
        cmdtesting "github.com/juju/juju/cmd/testing"
 
24
        "github.com/juju/juju/jujuclient"
 
25
        _ "github.com/juju/juju/provider/dummy"
 
26
        "github.com/juju/juju/testing"
 
27
)
 
28
 
 
29
type KillSuite struct {
 
30
        baseDestroySuite
 
31
}
 
32
 
 
33
var _ = gc.Suite(&KillSuite{})
 
34
 
 
35
func (s *KillSuite) runKillCommand(c *gc.C, args ...string) (*cmd.Context, error) {
 
36
        return testing.RunCommand(c, s.newKillCommand(), args...)
 
37
}
 
38
 
 
39
func (s *KillSuite) newKillCommand() cmd.Command {
 
40
        return controller.NewKillCommandForTest(
 
41
                s.api, s.clientapi, s.store, s.apierror, &mockClock{}, nil)
 
42
}
 
43
 
 
44
func (s *KillSuite) TestKillNoControllerNameError(c *gc.C) {
 
45
        _, err := s.runKillCommand(c)
 
46
        c.Assert(err, gc.ErrorMatches, "no controller specified")
 
47
}
 
48
 
 
49
func (s *KillSuite) TestKillBadFlags(c *gc.C) {
 
50
        _, err := s.runKillCommand(c, "-n")
 
51
        c.Assert(err, gc.ErrorMatches, "flag provided but not defined: -n")
 
52
}
 
53
 
 
54
func (s *KillSuite) TestKillUnknownArgument(c *gc.C) {
 
55
        _, err := s.runKillCommand(c, "model", "whoops")
 
56
        c.Assert(err, gc.ErrorMatches, `unrecognized args: \["whoops"\]`)
 
57
}
 
58
 
 
59
func (s *KillSuite) TestKillUnknownController(c *gc.C) {
 
60
        _, err := s.runKillCommand(c, "foo")
 
61
        c.Assert(err, gc.ErrorMatches, `controller foo not found`)
 
62
}
 
63
 
 
64
func (s *KillSuite) TestKillCannotConnectToAPISucceeds(c *gc.C) {
 
65
        s.apierror = errors.New("connection refused")
 
66
        ctx, err := s.runKillCommand(c, "test1", "-y")
 
67
        c.Assert(err, jc.ErrorIsNil)
 
68
        c.Check(testing.Stderr(ctx), jc.Contains, "Unable to open API: connection refused")
 
69
        checkControllerRemovedFromStore(c, "test1", s.store)
 
70
}
 
71
 
 
72
func (s *KillSuite) TestKillWithAPIConnection(c *gc.C) {
 
73
        _, err := s.runKillCommand(c, "test1", "-y")
 
74
        c.Assert(err, jc.ErrorIsNil)
 
75
        c.Assert(s.api.destroyAll, jc.IsTrue)
 
76
        c.Assert(s.clientapi.destroycalled, jc.IsFalse)
 
77
        checkControllerRemovedFromStore(c, "test1", s.store)
 
78
}
 
79
 
 
80
func (s *KillSuite) TestKillEnvironmentGetFailsWithoutAPIConnection(c *gc.C) {
 
81
        s.apierror = errors.New("connection refused")
 
82
        s.api.SetErrors(errors.NotFoundf(`controller "test3"`))
 
83
        _, err := s.runKillCommand(c, "test3", "-y")
 
84
        c.Assert(err, gc.ErrorMatches,
 
85
                "getting controller environ: unable to get bootstrap information from client store or API",
 
86
        )
 
87
        checkControllerExistsInStore(c, "test3", s.store)
 
88
}
 
89
 
 
90
func (s *KillSuite) TestKillEnvironmentGetFailsWithAPIConnection(c *gc.C) {
 
91
        s.api.SetErrors(errors.NotFoundf(`controller "test3"`))
 
92
        _, err := s.runKillCommand(c, "test3", "-y")
 
93
        c.Assert(err, gc.ErrorMatches,
 
94
                "getting controller environ: getting model config from API: controller \"test3\" not found",
 
95
        )
 
96
        checkControllerExistsInStore(c, "test3", s.store)
 
97
}
 
98
 
 
99
func (s *KillSuite) TestKillDestroysControllerWithAPIError(c *gc.C) {
 
100
        s.api.SetErrors(errors.New("some destroy error"))
 
101
        ctx, err := s.runKillCommand(c, "test1", "-y")
 
102
        c.Assert(err, jc.ErrorIsNil)
 
103
        c.Check(testing.Stderr(ctx), jc.Contains, "Unable to destroy controller through the API: some destroy error.  Destroying through provider.")
 
104
        c.Assert(s.api.destroyAll, jc.IsTrue)
 
105
        checkControllerRemovedFromStore(c, "test1", s.store)
 
106
}
 
107
 
 
108
func (s *KillSuite) TestKillCommandConfirmation(c *gc.C) {
 
109
        var stdin, stdout bytes.Buffer
 
110
        ctx, err := cmd.DefaultContext()
 
111
        c.Assert(err, jc.ErrorIsNil)
 
112
        ctx.Stdout = &stdout
 
113
        ctx.Stdin = &stdin
 
114
 
 
115
        // Ensure confirmation is requested if "-y" is not specified.
 
116
        stdin.WriteString("n")
 
117
        _, errc := cmdtesting.RunCommand(ctx, s.newKillCommand(), "test1")
 
118
        select {
 
119
        case err := <-errc:
 
120
                c.Check(err, gc.ErrorMatches, "controller destruction aborted")
 
121
        case <-time.After(testing.LongWait):
 
122
                c.Fatalf("command took too long")
 
123
        }
 
124
        c.Check(testing.Stdout(ctx), gc.Matches, "WARNING!.*test1(.|\n)*")
 
125
        checkControllerExistsInStore(c, "test1", s.store)
 
126
}
 
127
 
 
128
func (s *KillSuite) TestKillCommandControllerAlias(c *gc.C) {
 
129
        _, err := testing.RunCommand(c, s.newKillCommand(), "test1", "-y")
 
130
        c.Assert(err, jc.ErrorIsNil)
 
131
        checkControllerRemovedFromStore(c, "test1:test1", s.store)
 
132
}
 
133
 
 
134
func (s *KillSuite) TestKillAPIPermErrFails(c *gc.C) {
 
135
        testDialer := func(_ jujuclient.ClientStore, controllerName, modelName string) (api.Connection, error) {
 
136
                return nil, common.ErrPerm
 
137
        }
 
138
        cmd := controller.NewKillCommandForTest(nil, nil, s.store, nil, clock.WallClock, modelcmd.OpenFunc(testDialer))
 
139
        _, err := testing.RunCommand(c, cmd, "test1", "-y")
 
140
        c.Assert(err, gc.ErrorMatches, "cannot destroy controller: permission denied")
 
141
        checkControllerExistsInStore(c, "test1", s.store)
 
142
}
 
143
 
 
144
func (s *KillSuite) TestKillEarlyAPIConnectionTimeout(c *gc.C) {
 
145
        clock := &mockClock{}
 
146
 
 
147
        stop := make(chan struct{})
 
148
        defer close(stop)
 
149
        testDialer := func(_ jujuclient.ClientStore, controllerName, modelName string) (api.Connection, error) {
 
150
                <-stop
 
151
                return nil, errors.New("kill command waited too long")
 
152
        }
 
153
 
 
154
        cmd := controller.NewKillCommandForTest(nil, nil, s.store, nil, clock, modelcmd.OpenFunc(testDialer))
 
155
        ctx, err := testing.RunCommand(c, cmd, "test1", "-y")
 
156
        c.Check(err, jc.ErrorIsNil)
 
157
        c.Check(testing.Stderr(ctx), jc.Contains, "Unable to open API: open connection timed out")
 
158
        checkControllerRemovedFromStore(c, "test1", s.store)
 
159
        // Check that we were actually told to wait for 10s.
 
160
        c.Assert(clock.wait, gc.Equals, 10*time.Second)
 
161
}
 
162
 
 
163
// mockClock will panic if anything but After is called
 
164
type mockClock struct {
 
165
        clock.Clock
 
166
        wait time.Duration
 
167
}
 
168
 
 
169
func (m *mockClock) After(duration time.Duration) <-chan time.Time {
 
170
        m.wait = duration
 
171
        return time.After(time.Millisecond)
 
172
}
 
173
 
 
174
func (s *KillSuite) TestControllerStatus(c *gc.C) {
 
175
        s.api.allEnvs = []base.UserModel{
 
176
                {Name: "admin",
 
177
                        UUID:  "123",
 
178
                        Owner: names.NewUserTag("admin").String(),
 
179
                }, {Name: "env1",
 
180
                        UUID:  "456",
 
181
                        Owner: names.NewUserTag("bob").String(),
 
182
                }, {Name: "env2",
 
183
                        UUID:  "789",
 
184
                        Owner: names.NewUserTag("jo").String(),
 
185
                },
 
186
        }
 
187
 
 
188
        s.api.envStatus = make(map[string]base.ModelStatus)
 
189
        for _, env := range s.api.allEnvs {
 
190
                owner, err := names.ParseUserTag(env.Owner)
 
191
                c.Assert(err, jc.ErrorIsNil)
 
192
                s.api.envStatus[env.UUID] = base.ModelStatus{
 
193
                        UUID:               env.UUID,
 
194
                        Life:               params.Dying,
 
195
                        HostedMachineCount: 2,
 
196
                        ServiceCount:       1,
 
197
                        Owner:              owner.Canonical(),
 
198
                }
 
199
        }
 
200
 
 
201
        ctrStatus, envsStatus, err := controller.NewData(s.api, "123")
 
202
        c.Assert(err, jc.ErrorIsNil)
 
203
        c.Assert(ctrStatus.HostedModelCount, gc.Equals, 2)
 
204
        c.Assert(ctrStatus.HostedMachineCount, gc.Equals, 6)
 
205
        c.Assert(ctrStatus.ServiceCount, gc.Equals, 3)
 
206
        c.Assert(envsStatus, gc.HasLen, 2)
 
207
 
 
208
        for i, expected := range []struct {
 
209
                Owner              string
 
210
                Name               string
 
211
                Life               params.Life
 
212
                HostedMachineCount int
 
213
                ServiceCount       int
 
214
        }{
 
215
                {
 
216
                        Owner:              "bob@local",
 
217
                        Name:               "env1",
 
218
                        Life:               params.Dying,
 
219
                        HostedMachineCount: 2,
 
220
                        ServiceCount:       1,
 
221
                }, {
 
222
                        Owner:              "jo@local",
 
223
                        Name:               "env2",
 
224
                        Life:               params.Dying,
 
225
                        HostedMachineCount: 2,
 
226
                        ServiceCount:       1,
 
227
                },
 
228
        } {
 
229
                c.Assert(envsStatus[i].Owner, gc.Equals, expected.Owner)
 
230
                c.Assert(envsStatus[i].Name, gc.Equals, expected.Name)
 
231
                c.Assert(envsStatus[i].Life, gc.Equals, expected.Life)
 
232
                c.Assert(envsStatus[i].HostedMachineCount, gc.Equals, expected.HostedMachineCount)
 
233
                c.Assert(envsStatus[i].ServiceCount, gc.Equals, expected.ServiceCount)
 
234
        }
 
235
 
 
236
}
 
237
 
 
238
func (s *KillSuite) TestFmtControllerStatus(c *gc.C) {
 
239
        data := controller.CtrData{
 
240
                "uuid",
 
241
                params.Alive,
 
242
                3,
 
243
                20,
 
244
                8,
 
245
        }
 
246
        out := controller.FmtCtrStatus(data)
 
247
        c.Assert(out, gc.Equals, "Waiting on 3 models, 20 machines, 8 applications")
 
248
}
 
249
 
 
250
func (s *KillSuite) TestFmtEnvironStatus(c *gc.C) {
 
251
        data := controller.ModelData{
 
252
                "uuid",
 
253
                "owner@local",
 
254
                "envname",
 
255
                params.Dying,
 
256
                8,
 
257
                1,
 
258
        }
 
259
 
 
260
        out := controller.FmtModelStatus(data)
 
261
        c.Assert(out, gc.Equals, "\towner@local/envname (dying), 8 machines, 1 application")
 
262
}