~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/cmd/juju/commands/enableha_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 commands
 
5
 
 
6
import (
 
7
        "bytes"
 
8
        "encoding/json"
 
9
        "fmt"
 
10
        "strings"
 
11
 
 
12
        "github.com/juju/cmd"
 
13
        jc "github.com/juju/testing/checkers"
 
14
        gc "gopkg.in/check.v1"
 
15
        goyaml "gopkg.in/yaml.v2"
 
16
 
 
17
        "github.com/juju/juju/apiserver/common"
 
18
        "github.com/juju/juju/apiserver/params"
 
19
        "github.com/juju/juju/cmd/modelcmd"
 
20
        "github.com/juju/juju/constraints"
 
21
        "github.com/juju/juju/instance"
 
22
        "github.com/juju/juju/juju/testing"
 
23
        "github.com/juju/juju/state"
 
24
        coretesting "github.com/juju/juju/testing"
 
25
        "github.com/juju/juju/testing/factory"
 
26
)
 
27
 
 
28
type EnableHASuite struct {
 
29
        // TODO (cherylj) change this back to a FakeJujuXDGDataHomeSuite to
 
30
        // remove the mongo dependency once ensure-availability is
 
31
        // moved under a supercommand again.
 
32
        testing.JujuConnSuite
 
33
        fake *fakeHAClient
 
34
}
 
35
 
 
36
// invalidNumServers is a number of controllers that would
 
37
// never be generated by the enable-ha command.
 
38
const invalidNumServers = -2
 
39
 
 
40
func (s *EnableHASuite) SetUpTest(c *gc.C) {
 
41
        s.JujuConnSuite.SetUpTest(c)
 
42
 
 
43
        // Initialize numControllers to an invalid number to validate
 
44
        // that enable-ha doesn't call into the API when its
 
45
        // pre-checks fail
 
46
        s.fake = &fakeHAClient{numControllers: invalidNumServers}
 
47
}
 
48
 
 
49
type fakeHAClient struct {
 
50
        numControllers int
 
51
        cons           constraints.Value
 
52
        err            error
 
53
        placement      []string
 
54
        result         params.ControllersChanges
 
55
}
 
56
 
 
57
func (f *fakeHAClient) Close() error {
 
58
        return nil
 
59
}
 
60
 
 
61
func (f *fakeHAClient) EnableHA(numControllers int, cons constraints.Value, placement []string) (params.ControllersChanges, error) {
 
62
 
 
63
        f.numControllers = numControllers
 
64
        f.cons = cons
 
65
        f.placement = placement
 
66
 
 
67
        if f.err != nil {
 
68
                return f.result, f.err
 
69
        }
 
70
 
 
71
        if numControllers == 1 {
 
72
                return f.result, nil
 
73
        }
 
74
 
 
75
        // In the real HAClient, specifying a numControllers value of 0
 
76
        // indicates that the default value (3) should be used
 
77
        if numControllers == 0 {
 
78
                numControllers = 3
 
79
        }
 
80
 
 
81
        f.result.Maintained = append(f.result.Maintained, "machine-0")
 
82
 
 
83
        for _, p := range placement {
 
84
                m, err := instance.ParsePlacement(p)
 
85
                if err == nil && m.Scope == instance.MachineScope {
 
86
                        f.result.Converted = append(f.result.Converted, "machine-"+m.Directive)
 
87
                }
 
88
        }
 
89
 
 
90
        // We may need to pretend that we added some machines.
 
91
        for i := len(f.result.Converted) + 1; i < numControllers; i++ {
 
92
                f.result.Added = append(f.result.Added, fmt.Sprintf("machine-%d", i))
 
93
        }
 
94
 
 
95
        return f.result, nil
 
96
}
 
97
 
 
98
var _ = gc.Suite(&EnableHASuite{})
 
99
 
 
100
func (s *EnableHASuite) runEnableHA(c *gc.C, args ...string) (*cmd.Context, error) {
 
101
        command := &enableHACommand{newHAClientFunc: func() (MakeHAClient, error) { return s.fake, nil }}
 
102
        return coretesting.RunCommand(c, modelcmd.Wrap(command), args...)
 
103
}
 
104
 
 
105
func (s *EnableHASuite) TestEnableHA(c *gc.C) {
 
106
        ctx, err := s.runEnableHA(c, "-n", "1")
 
107
        c.Assert(err, jc.ErrorIsNil)
 
108
        c.Assert(coretesting.Stdout(ctx), gc.Equals, "")
 
109
 
 
110
        c.Assert(s.fake.numControllers, gc.Equals, 1)
 
111
        c.Assert(&s.fake.cons, jc.Satisfies, constraints.IsEmpty)
 
112
        c.Assert(len(s.fake.placement), gc.Equals, 0)
 
113
}
 
114
 
 
115
func (s *EnableHASuite) TestBlockEnableHA(c *gc.C) {
 
116
        s.fake.err = common.OperationBlockedError("TestBlockEnableHA")
 
117
        _, err := s.runEnableHA(c, "-n", "1")
 
118
        c.Assert(err, gc.ErrorMatches, cmd.ErrSilent.Error())
 
119
 
 
120
        // msg is logged
 
121
        stripped := strings.Replace(c.GetTestLog(), "\n", "", -1)
 
122
        c.Check(stripped, gc.Matches, ".*TestBlockEnableHA.*")
 
123
}
 
124
 
 
125
func (s *EnableHASuite) TestEnableHAFormatYaml(c *gc.C) {
 
126
        expected := map[string][]string{
 
127
                "maintained": {"0"},
 
128
                "added":      {"1", "2"},
 
129
        }
 
130
 
 
131
        ctx, err := s.runEnableHA(c, "-n", "3", "--format", "yaml")
 
132
        c.Assert(err, jc.ErrorIsNil)
 
133
 
 
134
        c.Assert(s.fake.numControllers, gc.Equals, 3)
 
135
        c.Assert(&s.fake.cons, jc.Satisfies, constraints.IsEmpty)
 
136
        c.Assert(len(s.fake.placement), gc.Equals, 0)
 
137
 
 
138
        var result map[string][]string
 
139
        err = goyaml.Unmarshal(ctx.Stdout.(*bytes.Buffer).Bytes(), &result)
 
140
        c.Assert(err, jc.ErrorIsNil)
 
141
        c.Assert(result, gc.DeepEquals, expected)
 
142
}
 
143
 
 
144
func (s *EnableHASuite) TestEnableHAFormatJson(c *gc.C) {
 
145
        expected := map[string][]string{
 
146
                "maintained": {"0"},
 
147
                "added":      {"1", "2"},
 
148
        }
 
149
 
 
150
        ctx, err := s.runEnableHA(c, "-n", "3", "--format", "json")
 
151
        c.Assert(err, jc.ErrorIsNil)
 
152
 
 
153
        c.Assert(s.fake.numControllers, gc.Equals, 3)
 
154
        c.Assert(&s.fake.cons, jc.Satisfies, constraints.IsEmpty)
 
155
        c.Assert(len(s.fake.placement), gc.Equals, 0)
 
156
 
 
157
        var result map[string][]string
 
158
        err = json.Unmarshal(ctx.Stdout.(*bytes.Buffer).Bytes(), &result)
 
159
        c.Assert(err, jc.ErrorIsNil)
 
160
        c.Assert(result, gc.DeepEquals, expected)
 
161
}
 
162
 
 
163
func (s *EnableHASuite) TestEnableHAWithFive(c *gc.C) {
 
164
        // Also test with -n 5 to validate numbers other than 1 and 3
 
165
        ctx, err := s.runEnableHA(c, "-n", "5")
 
166
        c.Assert(err, jc.ErrorIsNil)
 
167
        c.Assert(coretesting.Stdout(ctx), gc.Equals,
 
168
                "maintaining machines: 0\n"+
 
169
                        "adding machines: 1, 2, 3, 4\n\n")
 
170
 
 
171
        c.Assert(s.fake.numControllers, gc.Equals, 5)
 
172
        c.Assert(&s.fake.cons, jc.Satisfies, constraints.IsEmpty)
 
173
        c.Assert(len(s.fake.placement), gc.Equals, 0)
 
174
}
 
175
 
 
176
func (s *EnableHASuite) TestEnableHAWithConstraints(c *gc.C) {
 
177
        ctx, err := s.runEnableHA(c, "--constraints", "mem=4G", "-n", "3")
 
178
        c.Assert(err, jc.ErrorIsNil)
 
179
        c.Assert(coretesting.Stdout(ctx), gc.Equals,
 
180
                "maintaining machines: 0\n"+
 
181
                        "adding machines: 1, 2\n\n")
 
182
 
 
183
        c.Assert(s.fake.numControllers, gc.Equals, 3)
 
184
        expectedCons := constraints.MustParse("mem=4G")
 
185
        c.Assert(s.fake.cons, gc.DeepEquals, expectedCons)
 
186
        c.Assert(len(s.fake.placement), gc.Equals, 0)
 
187
}
 
188
 
 
189
func (s *EnableHASuite) TestEnableHAWithPlacement(c *gc.C) {
 
190
        ctx, err := s.runEnableHA(c, "--to", "valid", "-n", "3")
 
191
        c.Assert(err, jc.ErrorIsNil)
 
192
        c.Assert(coretesting.Stdout(ctx), gc.Equals,
 
193
                "maintaining machines: 0\n"+
 
194
                        "adding machines: 1, 2\n\n")
 
195
 
 
196
        c.Assert(s.fake.numControllers, gc.Equals, 3)
 
197
        c.Assert(&s.fake.cons, jc.Satisfies, constraints.IsEmpty)
 
198
        expectedPlacement := []string{"valid"}
 
199
        c.Assert(s.fake.placement, gc.DeepEquals, expectedPlacement)
 
200
}
 
201
 
 
202
func (s *EnableHASuite) TestEnableHAErrors(c *gc.C) {
 
203
        for _, n := range []int{-1, 2} {
 
204
                _, err := s.runEnableHA(c, "-n", fmt.Sprint(n))
 
205
                c.Assert(err, gc.ErrorMatches, "must specify a number of controllers odd and non-negative")
 
206
        }
 
207
 
 
208
        // Verify that enable-ha didn't call into the API
 
209
        c.Assert(s.fake.numControllers, gc.Equals, invalidNumServers)
 
210
}
 
211
 
 
212
func (s *EnableHASuite) TestEnableHAAllows0(c *gc.C) {
 
213
        // If the number of controllers is specified as "0", the API will
 
214
        // then use the default number of 3.
 
215
        ctx, err := s.runEnableHA(c, "-n", "0")
 
216
        c.Assert(err, jc.ErrorIsNil)
 
217
        c.Assert(coretesting.Stdout(ctx), gc.Equals,
 
218
                "maintaining machines: 0\n"+
 
219
                        "adding machines: 1, 2\n\n")
 
220
 
 
221
        c.Assert(s.fake.numControllers, gc.Equals, 0)
 
222
        c.Assert(&s.fake.cons, jc.Satisfies, constraints.IsEmpty)
 
223
        c.Assert(len(s.fake.placement), gc.Equals, 0)
 
224
}
 
225
 
 
226
func (s *EnableHASuite) TestEnableHADefaultsTo0(c *gc.C) {
 
227
        // If the number of controllers is not specified, we pass in 0 to the
 
228
        // API.  The API will then use the default number of 3.
 
229
        ctx, err := s.runEnableHA(c)
 
230
        c.Assert(err, jc.ErrorIsNil)
 
231
        c.Assert(coretesting.Stdout(ctx), gc.Equals,
 
232
                "maintaining machines: 0\n"+
 
233
                        "adding machines: 1, 2\n\n")
 
234
 
 
235
        c.Assert(s.fake.numControllers, gc.Equals, 0)
 
236
        c.Assert(&s.fake.cons, jc.Satisfies, constraints.IsEmpty)
 
237
        c.Assert(len(s.fake.placement), gc.Equals, 0)
 
238
}
 
239
 
 
240
func (s *EnableHASuite) TestEnableHAEndToEnd(c *gc.C) {
 
241
        s.Factory.MakeMachine(c, &factory.MachineParams{
 
242
                Jobs: []state.MachineJob{state.JobManageModel},
 
243
        })
 
244
        ctx, err := coretesting.RunCommand(c, newEnableHACommand(), "-n", "3")
 
245
        c.Assert(err, jc.ErrorIsNil)
 
246
 
 
247
        // Machine 0 is demoted because it hasn't reported its presence
 
248
        c.Assert(coretesting.Stdout(ctx), gc.Equals,
 
249
                "adding machines: 1, 2, 3\n"+
 
250
                        "demoting machines: 0\n\n")
 
251
}
 
252
 
 
253
func (s *EnableHASuite) TestEnableHAToExisting(c *gc.C) {
 
254
        ctx, err := s.runEnableHA(c, "--to", "1,2")
 
255
        c.Assert(err, jc.ErrorIsNil)
 
256
        c.Check(coretesting.Stdout(ctx), gc.Equals, `
 
257
maintaining machines: 0
 
258
converting machines: 1, 2
 
259
 
 
260
`[1:])
 
261
 
 
262
        c.Check(s.fake.numControllers, gc.Equals, 0)
 
263
        c.Check(&s.fake.cons, jc.Satisfies, constraints.IsEmpty)
 
264
        c.Check(len(s.fake.placement), gc.Equals, 2)
 
265
}
 
266
 
 
267
func (s *EnableHASuite) TestEnableHADisallowsSeries(c *gc.C) {
 
268
        // We don't allow --series as an argument. This test ensures it is not
 
269
        // inadvertantly added back.
 
270
        ctx, err := s.runEnableHA(c, "-n", "0", "--series", "xenian")
 
271
        c.Assert(err, gc.ErrorMatches, "flag provided but not defined: --series")
 
272
        c.Assert(coretesting.Stdout(ctx), gc.Equals, "")
 
273
}