github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/space/list_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package space_test 5 6 import ( 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "strings" 11 12 "regexp" 13 14 "github.com/juju/errors" 15 jc "github.com/juju/testing/checkers" 16 gc "gopkg.in/check.v1" 17 18 "github.com/juju/juju/cmd/juju/space" 19 coretesting "github.com/juju/juju/testing" 20 ) 21 22 type ListSuite struct { 23 BaseSpaceSuite 24 } 25 26 var _ = gc.Suite(&ListSuite{}) 27 28 func (s *ListSuite) SetUpTest(c *gc.C) { 29 s.BaseSpaceSuite.SetUpTest(c) 30 s.command, _ = space.NewListCommandForTest(s.api) 31 c.Assert(s.command, gc.NotNil) 32 } 33 34 func (s *ListSuite) TestInit(c *gc.C) { 35 for i, test := range []struct { 36 about string 37 args []string 38 expectShort bool 39 expectFormat string 40 expectErr string 41 }{{ 42 about: "unrecognized arguments", 43 args: s.Strings("foo"), 44 expectErr: `unrecognized args: \["foo"\]`, 45 expectFormat: "tabular", 46 }, { 47 about: "invalid format", 48 args: s.Strings("--format", "foo"), 49 expectErr: `invalid value "foo" for flag --format: unknown format "foo"`, 50 expectFormat: "tabular", 51 }, { 52 about: "invalid format (value is case-sensitive)", 53 args: s.Strings("--format", "JSON"), 54 expectErr: `invalid value "JSON" for flag --format: unknown format "JSON"`, 55 expectFormat: "tabular", 56 }, { 57 about: "json format", 58 args: s.Strings("--format", "json"), 59 expectFormat: "json", 60 }, { 61 about: "yaml format", 62 args: s.Strings("--format", "yaml"), 63 expectFormat: "yaml", 64 }, { 65 about: "tabular format", 66 args: s.Strings("--format", "tabular"), 67 expectFormat: "tabular", 68 }, { 69 // --output and -o are tested separately in TestOutputFormats. 70 about: "both --output and -o specified (latter overrides former)", 71 args: s.Strings("--output", "foo", "-o", "bar"), 72 expectFormat: "tabular", 73 }} { 74 c.Logf("test #%d: %s", i, test.about) 75 // Create a new instance of the subcommand for each test, but 76 // since we're not running the command no need to use 77 // modelcmd.Wrap(). 78 wrappedCommand, command := space.NewListCommandForTest(s.api) 79 err := coretesting.InitCommand(wrappedCommand, test.args) 80 if test.expectErr != "" { 81 c.Check(err, gc.ErrorMatches, test.expectErr) 82 } else { 83 c.Check(err, jc.ErrorIsNil) 84 } 85 c.Check(command.ListFormat(), gc.Equals, test.expectFormat) 86 c.Check(command.Short, gc.Equals, test.expectShort) 87 88 // No API calls should be recorded at this stage. 89 s.api.CheckCallNames(c) 90 } 91 } 92 93 func (s *ListSuite) TestOutputFormats(c *gc.C) { 94 outDir := c.MkDir() 95 expectedYAML := ` 96 spaces: 97 space1: 98 2001:db8::/32: 99 type: ipv6 100 provider-id: subnet-public 101 status: terminating 102 zones: 103 - zone2 104 invalid: 105 type: unknown 106 provider-id: no-such 107 status: 'error: invalid subnet CIDR: invalid' 108 zones: 109 - zone1 110 space2: 111 4.3.2.0/28: 112 type: ipv4 113 provider-id: vlan-42 114 status: terminating 115 zones: 116 - zone1 117 10.1.2.0/24: 118 type: ipv4 119 provider-id: subnet-private 120 status: in-use 121 zones: 122 - zone1 123 - zone2 124 `[1:] 125 unwrap := regexp.MustCompile(`[\s+\n]`) 126 expectedJSON := unwrap.ReplaceAllLiteralString(` 127 { 128 "spaces": { 129 "space1": { 130 "2001:db8::/32": { 131 "type": "ipv6", 132 "provider-id": "subnet-public", 133 "status": "terminating", 134 "zones": ["zone2"] 135 }, 136 "invalid": { 137 "type": "unknown", 138 "provider-id": "no-such", 139 "status": "error: invalid subnet CIDR: invalid", 140 "zones": ["zone1"] 141 } 142 }, 143 "space2": { 144 "10.1.2.0/24": { 145 "type": "ipv4", 146 "provider-id": "subnet-private", 147 "status": "in-use", 148 "zones": ["zone1","zone2"] 149 }, 150 "4.3.2.0/28": { 151 "type": "ipv4", 152 "provider-id": "vlan-42", 153 "status": "terminating", 154 "zones": ["zone1"] 155 } 156 } 157 } 158 } 159 `, "") + "\n" 160 // Work around the big unwrap hammer above. 161 expectedJSON = strings.Replace( 162 expectedJSON, 163 "error:invalidsubnetCIDR:invalid", 164 "error: invalid subnet CIDR: invalid", 165 1, 166 ) 167 expectedShortYAML := ` 168 spaces: 169 - space1 170 - space2 171 `[1:] 172 173 expectedShortJSON := unwrap.ReplaceAllLiteralString(` 174 { 175 "spaces": [ 176 "space1", 177 "space2" 178 ] 179 } 180 `, "") + "\n" 181 182 expectedTabular := `SPACE SUBNETS 183 space1 2001:db8::/32 184 invalid 185 space2 10.1.2.0/24 186 4.3.2.0/28 187 188 ` 189 expectedShortTabular := `SPACE 190 space1 191 space2 192 193 ` 194 195 assertAPICalls := func() { 196 // Verify the API calls and reset the recorded calls. 197 s.api.CheckCallNames(c, "ListSpaces", "Close") 198 s.api.ResetCalls() 199 } 200 makeArgs := func(format string, short bool, extraArgs ...string) []string { 201 args := s.Strings(extraArgs...) 202 if format != "" { 203 args = append(args, "--format", format) 204 } 205 if short == true { 206 args = append(args, "--short") 207 } 208 return args 209 } 210 assertOutput := func(format, expected string, short bool) { 211 outFile := filepath.Join(outDir, "output") 212 c.Assert(outFile, jc.DoesNotExist) 213 defer os.Remove(outFile) 214 // Check -o works. 215 var args []string 216 args = makeArgs(format, short, "-o", outFile) 217 s.AssertRunSucceeds(c, "", "", args...) 218 assertAPICalls() 219 220 data, err := ioutil.ReadFile(outFile) 221 c.Assert(err, jc.ErrorIsNil) 222 c.Assert(string(data), gc.Equals, expected) 223 224 // Check the last output argument takes precedence when both 225 // -o and --output are given (and also that --output works the 226 // same as -o). 227 outFile1 := filepath.Join(outDir, "output1") 228 c.Assert(outFile1, jc.DoesNotExist) 229 defer os.Remove(outFile1) 230 outFile2 := filepath.Join(outDir, "output2") 231 c.Assert(outFile2, jc.DoesNotExist) 232 defer os.Remove(outFile2) 233 // Write something in outFile2 to verify its contents are 234 // overwritten. 235 err = ioutil.WriteFile(outFile2, []byte("some contents"), 0644) 236 c.Assert(err, jc.ErrorIsNil) 237 238 args = makeArgs(format, short, "-o", outFile1, "--output", outFile2) 239 s.AssertRunSucceeds(c, "", "", args...) 240 // Check only the last output file was used, and the output 241 // file was overwritten. 242 c.Assert(outFile1, jc.DoesNotExist) 243 data, err = ioutil.ReadFile(outFile2) 244 c.Assert(err, jc.ErrorIsNil) 245 c.Assert(string(data), gc.Equals, expected) 246 assertAPICalls() 247 248 // Finally, check without --output. 249 args = makeArgs(format, short) 250 s.AssertRunSucceeds(c, "", expected, args...) 251 assertAPICalls() 252 } 253 254 for i, test := range []struct { 255 format string 256 expected string 257 short bool 258 }{ 259 {"", expectedTabular, false}, // default format is tabular 260 {"tabular", expectedTabular, false}, 261 {"yaml", expectedYAML, false}, 262 {"json", expectedJSON, false}, 263 {"", expectedShortTabular, true}, // default format is tabular 264 {"tabular", expectedShortTabular, true}, 265 {"yaml", expectedShortYAML, true}, 266 {"json", expectedShortJSON, true}, 267 } { 268 c.Logf("test #%d: format %q, short %v", i, test.format, test.short) 269 assertOutput(test.format, test.expected, test.short) 270 } 271 } 272 273 func (s *ListSuite) TestRunWhenNoSpacesExistSucceeds(c *gc.C) { 274 s.api.Spaces = s.api.Spaces[0:0] 275 276 s.AssertRunSucceeds(c, 277 `no spaces to display\n`, 278 "", // empty stdout. 279 ) 280 281 s.api.CheckCallNames(c, "ListSpaces", "Close") 282 s.api.CheckCall(c, 0, "ListSpaces") 283 } 284 285 func (s *ListSuite) TestRunWhenSpacesNotSupported(c *gc.C) { 286 s.api.SetErrors(errors.NewNotSupported(nil, "spaces not supported")) 287 288 err := s.AssertRunSpacesNotSupported(c, "cannot list spaces: spaces not supported") 289 c.Assert(err, jc.Satisfies, errors.IsNotSupported) 290 291 s.api.CheckCallNames(c, "ListSpaces", "Close") 292 s.api.CheckCall(c, 0, "ListSpaces") 293 } 294 295 func (s *ListSuite) TestRunWhenSpacesAPIFails(c *gc.C) { 296 s.api.SetErrors(errors.New("boom")) 297 298 s.AssertRunFails(c, "cannot list spaces: boom") 299 300 s.api.CheckCallNames(c, "ListSpaces", "Close") 301 s.api.CheckCall(c, 0, "ListSpaces") 302 }