1
// Copyright 2015 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
11
"github.com/juju/errors"
12
jc "github.com/juju/testing/checkers"
13
gc "gopkg.in/check.v1"
14
"gopkg.in/juju/names.v2"
16
"github.com/juju/juju/cmd/juju/subnet"
17
coretesting "github.com/juju/juju/testing"
20
type ListSuite struct {
24
var _ = gc.Suite(&ListSuite{})
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)
32
func (s *ListSuite) TestInit(c *gc.C) {
33
for i, test := range []struct {
41
about: "too many arguments",
42
args: s.Strings("foo", "bar"),
43
expectErr: `unrecognized args: \["foo" "bar"\]`,
46
about: "invalid space name",
47
args: s.Strings("--space", "%inv$alid"),
48
expectErr: `"%inv\$alid" is not a valid space name`,
51
about: "valid space name",
52
args: s.Strings("--space", "my-space"),
53
expectSpace: "my-space",
56
about: "both space and zone given",
57
args: s.Strings("--zone", "zone1", "--space", "my-space"),
58
expectSpace: "my-space",
62
about: "invalid format",
63
args: s.Strings("--format", "foo"),
64
expectErr: `invalid value "foo" for flag --format: unknown format "foo"`,
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"`,
73
args: s.Strings("--format", "json"),
77
args: s.Strings("--format", "yaml"),
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"),
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
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)
94
c.Check(err, jc.ErrorIsNil)
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)
100
// No API calls should be recorded at this stage.
101
s.api.CheckCallNames(c)
105
func (s *ListSuite) TestOutputFormats(c *gc.C) {
117
provider-id: subnet-foo
125
provider-id: subnet-bar
131
expectedJSON := `{"subnets":{` +
134
`"status":"terminating",` +
135
`"space":"vlan-42",` +
136
`"zones":["zone1"]},` +
140
`"provider-id":"subnet-foo",` +
141
`"status":"in-use",` +
142
`"space":"public",` +
143
`"zones":["zone1","zone2"]},` +
145
`"2001:db8::/32":{` +
147
`"provider-id":"subnet-bar",` +
148
`"status":"terminating",` +
150
`"zones":["zone2"]}}}
153
assertAPICalls := func() {
154
// Verify the API calls and reset the recorded calls.
155
s.api.CheckCallNames(c, "ListSubnets", "Close")
158
makeArgs := func(format string, extraArgs ...string) []string {
159
args := s.Strings(extraArgs...)
161
args = append(args, "--format", format)
165
assertOutput := func(format, expected string) {
166
outFile := filepath.Join(outDir, "output")
167
c.Assert(outFile, jc.DoesNotExist)
168
defer os.Remove(outFile)
170
args := makeArgs(format, "-o", outFile)
171
s.AssertRunSucceeds(c, "", "", args...)
174
data, err := ioutil.ReadFile(outFile)
175
c.Assert(err, jc.ErrorIsNil)
176
c.Assert(string(data), gc.Equals, expected)
178
// Check the last output argument takes precedence when both
179
// -o and --output are given (and also that --output works the
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
189
err = ioutil.WriteFile(outFile2, []byte("some contents"), 0644)
190
c.Assert(err, jc.ErrorIsNil)
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)
202
// Finally, check without --output.
203
args = makeArgs(format)
204
s.AssertRunSucceeds(c, "", expected, args...)
208
for i, test := range []struct {
212
{"", expectedYAML}, // default format is YAML
213
{"yaml", expectedYAML},
214
{"json", expectedJSON},
216
c.Logf("test #%d: format %q", i, test.format)
217
assertOutput(test.format, test.expected)
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]
225
s.AssertRunSucceeds(c,
226
`no subnets found matching requested criteria\n`,
228
"--space", "default",
231
s.api.CheckCallNames(c, "ListSubnets", "Close")
232
tag := names.NewSpaceTag("default")
233
s.api.CheckCall(c, 0, "ListSubnets", &tag, "")
236
func (s *ListSuite) TestRunWhenNoSubnetsExistSucceeds(c *gc.C) {
237
s.api.Subnets = s.api.Subnets[0:0]
239
s.AssertRunSucceeds(c,
240
`no subnets to display\n`,
244
s.api.CheckCallNames(c, "ListSubnets", "Close")
245
s.api.CheckCall(c, 0, "ListSubnets", nil, "")
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]
256
provider-id: subnet-foo
264
// Filter by space name first.
265
s.AssertRunSucceeds(c,
271
s.api.CheckCallNames(c, "ListSubnets", "Close")
272
tag := names.NewSpaceTag("public")
273
s.api.CheckCall(c, 0, "ListSubnets", &tag, "")
276
// Now filter by zone.
277
s.AssertRunSucceeds(c,
283
s.api.CheckCallNames(c, "ListSubnets", "Close")
284
s.api.CheckCall(c, 0, "ListSubnets", nil, "zone1")
287
// Finally, filter by both space and zone.
288
s.AssertRunSucceeds(c,
291
"--zone", "zone1", "--space", "public",
294
s.api.CheckCallNames(c, "ListSubnets", "Close")
295
tag = names.NewSpaceTag("public")
296
s.api.CheckCall(c, 0, "ListSubnets", &tag, "zone1")
299
func (s *ListSuite) TestRunWhenListSubnetFails(c *gc.C) {
300
s.api.SetErrors(errors.NotSupportedf("foo"))
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)
306
s.api.CheckCallNames(c, "ListSubnets", "Close")
307
s.api.CheckCall(c, 0, "ListSubnets", nil, "")
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"
316
s.AssertRunFails(c, `subnet "invalid" has invalid CIDR`)
318
s.api.CheckCallNames(c, "ListSubnets", "Close")
319
s.api.CheckCall(c, 0, "ListSubnets", nil, "")
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"
328
s.AssertRunFails(c, `subnet "10.20.0.0/24" has invalid space: "foo" is not a valid tag`)
330
s.api.CheckCallNames(c, "ListSubnets", "Close")
331
s.api.CheckCall(c, 0, "ListSubnets", nil, "")