~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/cmd/juju/subnet/list_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 subnet_test
 
5
 
 
6
import (
 
7
        "io/ioutil"
 
8
        "os"
 
9
        "path/filepath"
 
10
 
 
11
        "github.com/juju/errors"
 
12
        jc "github.com/juju/testing/checkers"
 
13
        gc "gopkg.in/check.v1"
 
14
        "gopkg.in/juju/names.v2"
 
15
 
 
16
        "github.com/juju/juju/cmd/juju/subnet"
 
17
        coretesting "github.com/juju/juju/testing"
 
18
)
 
19
 
 
20
type ListSuite struct {
 
21
        BaseSubnetSuite
 
22
}
 
23
 
 
24
var _ = gc.Suite(&ListSuite{})
 
25
 
 
26
func (s *ListSuite) SetUpTest(c *gc.C) {
 
27
        s.BaseSubnetSuite.SetUpTest(c)
 
28
        s.command, _ = subnet.NewListCommandForTest(s.api)
 
29
        c.Assert(s.command, gc.NotNil)
 
30
}
 
31
 
 
32
func (s *ListSuite) TestInit(c *gc.C) {
 
33
        for i, test := range []struct {
 
34
                about        string
 
35
                args         []string
 
36
                expectSpace  string
 
37
                expectZone   string
 
38
                expectFormat string
 
39
                expectErr    string
 
40
        }{{
 
41
                about:        "too many arguments",
 
42
                args:         s.Strings("foo", "bar"),
 
43
                expectErr:    `unrecognized args: \["foo" "bar"\]`,
 
44
                expectFormat: "yaml",
 
45
        }, {
 
46
                about:        "invalid space name",
 
47
                args:         s.Strings("--space", "%inv$alid"),
 
48
                expectErr:    `"%inv\$alid" is not a valid space name`,
 
49
                expectFormat: "yaml",
 
50
        }, {
 
51
                about:        "valid space name",
 
52
                args:         s.Strings("--space", "my-space"),
 
53
                expectSpace:  "my-space",
 
54
                expectFormat: "yaml",
 
55
        }, {
 
56
                about:        "both space and zone given",
 
57
                args:         s.Strings("--zone", "zone1", "--space", "my-space"),
 
58
                expectSpace:  "my-space",
 
59
                expectZone:   "zone1",
 
60
                expectFormat: "yaml",
 
61
        }, {
 
62
                about:        "invalid format",
 
63
                args:         s.Strings("--format", "foo"),
 
64
                expectErr:    `invalid value "foo" for flag --format: unknown format "foo"`,
 
65
                expectFormat: "yaml",
 
66
        }, {
 
67
                about:        "invalid format (value is case-sensitive)",
 
68
                args:         s.Strings("--format", "JSON"),
 
69
                expectErr:    `invalid value "JSON" for flag --format: unknown format "JSON"`,
 
70
                expectFormat: "yaml",
 
71
        }, {
 
72
                about:        "json format",
 
73
                args:         s.Strings("--format", "json"),
 
74
                expectFormat: "json",
 
75
        }, {
 
76
                about:        "yaml format",
 
77
                args:         s.Strings("--format", "yaml"),
 
78
                expectFormat: "yaml",
 
79
        }, {
 
80
                // --output and -o are tested separately in TestOutputFormats.
 
81
                about:        "both --output and -o specified (latter overrides former)",
 
82
                args:         s.Strings("--output", "foo", "-o", "bar"),
 
83
                expectFormat: "yaml",
 
84
        }} {
 
85
                c.Logf("test #%d: %s", i, test.about)
 
86
                // Create a new instance of the subcommand for each test, but
 
87
                // since we're not running the command no need to use
 
88
                // modelcmd.Wrap().
 
89
                wrappedCommand, command := subnet.NewListCommandForTest(s.api)
 
90
                err := coretesting.InitCommand(wrappedCommand, test.args)
 
91
                if test.expectErr != "" {
 
92
                        c.Check(err, gc.ErrorMatches, test.expectErr)
 
93
                } else {
 
94
                        c.Check(err, jc.ErrorIsNil)
 
95
                }
 
96
                c.Check(command.SpaceName, gc.Equals, test.expectSpace)
 
97
                c.Check(command.ZoneName, gc.Equals, test.expectZone)
 
98
                c.Check(command.Out.Name(), gc.Equals, test.expectFormat)
 
99
 
 
100
                // No API calls should be recorded at this stage.
 
101
                s.api.CheckCallNames(c)
 
102
        }
 
103
}
 
104
 
 
105
func (s *ListSuite) TestOutputFormats(c *gc.C) {
 
106
        outDir := c.MkDir()
 
107
        expectedYAML := `
 
108
subnets:
 
109
  10.10.0.0/16:
 
110
    type: ipv4
 
111
    status: terminating
 
112
    space: vlan-42
 
113
    zones:
 
114
    - zone1
 
115
  10.20.0.0/24:
 
116
    type: ipv4
 
117
    provider-id: subnet-foo
 
118
    status: in-use
 
119
    space: public
 
120
    zones:
 
121
    - zone1
 
122
    - zone2
 
123
  2001:db8::/32:
 
124
    type: ipv6
 
125
    provider-id: subnet-bar
 
126
    status: terminating
 
127
    space: dmz
 
128
    zones:
 
129
    - zone2
 
130
`[1:]
 
131
        expectedJSON := `{"subnets":{` +
 
132
                `"10.10.0.0/16":{` +
 
133
                `"type":"ipv4",` +
 
134
                `"status":"terminating",` +
 
135
                `"space":"vlan-42",` +
 
136
                `"zones":["zone1"]},` +
 
137
 
 
138
                `"10.20.0.0/24":{` +
 
139
                `"type":"ipv4",` +
 
140
                `"provider-id":"subnet-foo",` +
 
141
                `"status":"in-use",` +
 
142
                `"space":"public",` +
 
143
                `"zones":["zone1","zone2"]},` +
 
144
 
 
145
                `"2001:db8::/32":{` +
 
146
                `"type":"ipv6",` +
 
147
                `"provider-id":"subnet-bar",` +
 
148
                `"status":"terminating",` +
 
149
                `"space":"dmz",` +
 
150
                `"zones":["zone2"]}}}
 
151
`
 
152
 
 
153
        assertAPICalls := func() {
 
154
                // Verify the API calls and reset the recorded calls.
 
155
                s.api.CheckCallNames(c, "ListSubnets", "Close")
 
156
                s.api.ResetCalls()
 
157
        }
 
158
        makeArgs := func(format string, extraArgs ...string) []string {
 
159
                args := s.Strings(extraArgs...)
 
160
                if format != "" {
 
161
                        args = append(args, "--format", format)
 
162
                }
 
163
                return args
 
164
        }
 
165
        assertOutput := func(format, expected string) {
 
166
                outFile := filepath.Join(outDir, "output")
 
167
                c.Assert(outFile, jc.DoesNotExist)
 
168
                defer os.Remove(outFile)
 
169
                // Check -o works.
 
170
                args := makeArgs(format, "-o", outFile)
 
171
                s.AssertRunSucceeds(c, "", "", args...)
 
172
                assertAPICalls()
 
173
 
 
174
                data, err := ioutil.ReadFile(outFile)
 
175
                c.Assert(err, jc.ErrorIsNil)
 
176
                c.Assert(string(data), gc.Equals, expected)
 
177
 
 
178
                // Check the last output argument takes precedence when both
 
179
                // -o and --output are given (and also that --output works the
 
180
                // same as -o).
 
181
                outFile1 := filepath.Join(outDir, "output1")
 
182
                c.Assert(outFile1, jc.DoesNotExist)
 
183
                defer os.Remove(outFile1)
 
184
                outFile2 := filepath.Join(outDir, "output2")
 
185
                c.Assert(outFile2, jc.DoesNotExist)
 
186
                defer os.Remove(outFile2)
 
187
                // Write something in outFile2 to verify its contents are
 
188
                // overwritten.
 
189
                err = ioutil.WriteFile(outFile2, []byte("some contents"), 0644)
 
190
                c.Assert(err, jc.ErrorIsNil)
 
191
 
 
192
                args = makeArgs(format, "-o", outFile1, "--output", outFile2)
 
193
                s.AssertRunSucceeds(c, "", "", args...)
 
194
                // Check only the last output file was used, and the output
 
195
                // file was overwritten.
 
196
                c.Assert(outFile1, jc.DoesNotExist)
 
197
                data, err = ioutil.ReadFile(outFile2)
 
198
                c.Assert(err, jc.ErrorIsNil)
 
199
                c.Assert(string(data), gc.Equals, expected)
 
200
                assertAPICalls()
 
201
 
 
202
                // Finally, check without --output.
 
203
                args = makeArgs(format)
 
204
                s.AssertRunSucceeds(c, "", expected, args...)
 
205
                assertAPICalls()
 
206
        }
 
207
 
 
208
        for i, test := range []struct {
 
209
                format   string
 
210
                expected string
 
211
        }{
 
212
                {"", expectedYAML}, // default format is YAML
 
213
                {"yaml", expectedYAML},
 
214
                {"json", expectedJSON},
 
215
        } {
 
216
                c.Logf("test #%d: format %q", i, test.format)
 
217
                assertOutput(test.format, test.expected)
 
218
        }
 
219
}
 
220
 
 
221
func (s *ListSuite) TestRunWhenNoneMatchSucceeds(c *gc.C) {
 
222
        // Simulate no subnets are using the "default" space.
 
223
        s.api.Subnets = s.api.Subnets[0:0]
 
224
 
 
225
        s.AssertRunSucceeds(c,
 
226
                `no subnets found matching requested criteria\n`,
 
227
                "", // empty stdout.
 
228
                "--space", "default",
 
229
        )
 
230
 
 
231
        s.api.CheckCallNames(c, "ListSubnets", "Close")
 
232
        tag := names.NewSpaceTag("default")
 
233
        s.api.CheckCall(c, 0, "ListSubnets", &tag, "")
 
234
}
 
235
 
 
236
func (s *ListSuite) TestRunWhenNoSubnetsExistSucceeds(c *gc.C) {
 
237
        s.api.Subnets = s.api.Subnets[0:0]
 
238
 
 
239
        s.AssertRunSucceeds(c,
 
240
                `no subnets to display\n`,
 
241
                "", // empty stdout.
 
242
        )
 
243
 
 
244
        s.api.CheckCallNames(c, "ListSubnets", "Close")
 
245
        s.api.CheckCall(c, 0, "ListSubnets", nil, "")
 
246
}
 
247
 
 
248
func (s *ListSuite) TestRunWithFilteringSucceeds(c *gc.C) {
 
249
        // Simulate one subnet is using the "public" space or "zone1".
 
250
        s.api.Subnets = s.api.Subnets[0:1]
 
251
 
 
252
        expected := `
 
253
subnets:
 
254
  10.20.0.0/24:
 
255
    type: ipv4
 
256
    provider-id: subnet-foo
 
257
    status: in-use
 
258
    space: public
 
259
    zones:
 
260
    - zone1
 
261
    - zone2
 
262
`[1:]
 
263
 
 
264
        // Filter by space name first.
 
265
        s.AssertRunSucceeds(c,
 
266
                "", // empty stderr.
 
267
                expected,
 
268
                "--space", "public",
 
269
        )
 
270
 
 
271
        s.api.CheckCallNames(c, "ListSubnets", "Close")
 
272
        tag := names.NewSpaceTag("public")
 
273
        s.api.CheckCall(c, 0, "ListSubnets", &tag, "")
 
274
        s.api.ResetCalls()
 
275
 
 
276
        // Now filter by zone.
 
277
        s.AssertRunSucceeds(c,
 
278
                "", // empty stderr.
 
279
                expected,
 
280
                "--zone", "zone1",
 
281
        )
 
282
 
 
283
        s.api.CheckCallNames(c, "ListSubnets", "Close")
 
284
        s.api.CheckCall(c, 0, "ListSubnets", nil, "zone1")
 
285
        s.api.ResetCalls()
 
286
 
 
287
        // Finally, filter by both space and zone.
 
288
        s.AssertRunSucceeds(c,
 
289
                "", // empty stderr.
 
290
                expected,
 
291
                "--zone", "zone1", "--space", "public",
 
292
        )
 
293
 
 
294
        s.api.CheckCallNames(c, "ListSubnets", "Close")
 
295
        tag = names.NewSpaceTag("public")
 
296
        s.api.CheckCall(c, 0, "ListSubnets", &tag, "zone1")
 
297
}
 
298
 
 
299
func (s *ListSuite) TestRunWhenListSubnetFails(c *gc.C) {
 
300
        s.api.SetErrors(errors.NotSupportedf("foo"))
 
301
 
 
302
        // Ensure the error cause is preserved.
 
303
        err := s.AssertRunFails(c, "cannot list subnets: foo not supported")
 
304
        c.Assert(err, jc.Satisfies, errors.IsNotSupported)
 
305
 
 
306
        s.api.CheckCallNames(c, "ListSubnets", "Close")
 
307
        s.api.CheckCall(c, 0, "ListSubnets", nil, "")
 
308
}
 
309
 
 
310
func (s *ListSuite) TestRunWhenASubnetHasInvalidCIDRFails(c *gc.C) {
 
311
        // This cannot happen in practice, as CIDRs are validated before
 
312
        // adding a subnet, but this test ensures 100% coverage.
 
313
        s.api.Subnets = s.api.Subnets[0:1]
 
314
        s.api.Subnets[0].CIDR = "invalid"
 
315
 
 
316
        s.AssertRunFails(c, `subnet "invalid" has invalid CIDR`)
 
317
 
 
318
        s.api.CheckCallNames(c, "ListSubnets", "Close")
 
319
        s.api.CheckCall(c, 0, "ListSubnets", nil, "")
 
320
}
 
321
 
 
322
func (s *ListSuite) TestRunWhenASubnetHasInvalidSpaceFails(c *gc.C) {
 
323
        // This cannot happen in practice, as space names are validated
 
324
        // before adding a subnet, but this test ensures 100% coverage.
 
325
        s.api.Subnets = s.api.Subnets[0:1]
 
326
        s.api.Subnets[0].SpaceTag = "foo"
 
327
 
 
328
        s.AssertRunFails(c, `subnet "10.20.0.0/24" has invalid space: "foo" is not a valid tag`)
 
329
 
 
330
        s.api.CheckCallNames(c, "ListSubnets", "Close")
 
331
        s.api.CheckCall(c, 0, "ListSubnets", nil, "")
 
332
}