github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/model/defaultscommand_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 package model_test 4 5 import ( 6 "io/ioutil" 7 "path/filepath" 8 "strings" 9 10 "github.com/juju/cmd" 11 "github.com/juju/cmd/cmdtesting" 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/apiserver/common" 16 "github.com/juju/juju/cmd/juju/model" 17 "github.com/juju/juju/environs/config" 18 "github.com/juju/juju/jujuclient" 19 "github.com/juju/juju/testing" 20 ) 21 22 type DefaultsCommandSuite struct { 23 fakeModelDefaultEnvSuite 24 store *jujuclient.MemStore 25 } 26 27 var _ = gc.Suite(&DefaultsCommandSuite{}) 28 29 func (s *DefaultsCommandSuite) SetUpTest(c *gc.C) { 30 s.fakeModelDefaultEnvSuite.SetUpTest(c) 31 s.store = jujuclient.NewMemStore() 32 s.store.CurrentControllerName = "controller" 33 s.store.Controllers["controller"] = jujuclient.ControllerDetails{} 34 } 35 36 func (s *DefaultsCommandSuite) run(c *gc.C, args ...string) (*cmd.Context, error) { 37 command := model.NewDefaultsCommandForTest(s.fakeAPIRoot, s.fakeDefaultsAPI, s.fakeCloudAPI, s.store) 38 return cmdtesting.RunCommand(c, command, args...) 39 } 40 41 func (s *DefaultsCommandSuite) TestDefaultsInit(c *gc.C) { 42 for i, test := range []struct { 43 description string 44 args []string 45 errorMatch string 46 nilErr bool 47 }{{ 48 // Test set 49 description: "test cannot set agent-version", 50 args: []string{"agent-version=2.0.0"}, 51 errorMatch: `"agent-version" must be set via "upgrade-model"`, 52 }, { 53 description: "test set multiple keys", 54 args: []string{"foo=bar", "baz=eggs"}, 55 nilErr: true, 56 }, { 57 // Test reset 58 description: "test empty args with reset fails", 59 args: []string{"--reset"}, 60 errorMatch: "option needs an argument: --reset", 61 }, { 62 description: "test reset with positional arg interpereted as invalid region", 63 args: []string{"--reset", "something", "weird"}, 64 errorMatch: `invalid region specified: "weird"`, 65 }, { 66 description: "test reset with valid region and duplicate key set", 67 args: []string{"--reset", "something", "dummy-region", "something=weird"}, 68 errorMatch: `key "something" cannot be both set and unset in the same command`, 69 }, { 70 description: "test reset with valid region and extra positional arg", 71 args: []string{"--reset", "something", "dummy-region", "weird"}, 72 errorMatch: "cannot retrieve defaults for a region and reset attributes at the same time", 73 }, { 74 description: "test reset with valid region only", 75 args: []string{"--reset", "foo", "dummy-region"}, 76 nilErr: true, 77 }, { 78 description: "test cannot reset agent version", 79 args: []string{"--reset", "agent-version"}, 80 errorMatch: `"agent-version" cannot be reset`, 81 }, { 82 description: "test reset inits", 83 args: []string{"--reset", "foo"}, 84 nilErr: true, 85 }, { 86 description: "test trailing reset fails", 87 args: []string{"foo=bar", "--reset"}, 88 errorMatch: "option needs an argument: --reset", 89 }, { 90 description: "test reset and get init", 91 args: []string{"--reset", "agent-version,b", "foo=bar"}, 92 errorMatch: `"agent-version" cannot be reset`, 93 }, { 94 description: "test reset with key=val fails", 95 args: []string{"--reset", "foo=bar"}, 96 errorMatch: `--reset accepts a comma delimited set of keys "a,b,c", received: "foo=bar"`, 97 }, { 98 description: "test reset multiple with key=val fails", 99 args: []string{"--reset", "a,foo=bar,b"}, 100 errorMatch: `--reset accepts a comma delimited set of keys "a,b,c", received: "foo=bar"`, 101 }, { 102 description: "test reset with two positional args fails expecting a region", 103 args: []string{"--reset", "a", "b", "c"}, 104 errorMatch: `invalid region specified: "b"`, 105 }, { 106 description: "test reset with two positional args fails expecting a region reordered", 107 args: []string{"a", "--reset", "b", "c"}, 108 errorMatch: `invalid region specified: "a"`, 109 }, { 110 description: "test multiple reset inits", 111 args: []string{"--reset", "a", "--reset", "b"}, 112 nilErr: true, 113 }, { 114 description: "test multiple reset and set inits", 115 args: []string{"--reset", "a", "b=c", "--reset", "d"}, 116 nilErr: true, 117 }, { 118 description: "test multiple reset with valid region inits", 119 args: []string{"dummy-region", "--reset", "a", "--reset", "b"}, 120 nilErr: true, 121 }, { 122 description: "test multiple reset with two positional args fails expecting a region reordered", 123 args: []string{"a", "--reset", "b", "--reset", "c", "d"}, 124 errorMatch: `invalid region specified: "a"`, 125 }, { 126 description: "test reset multiple with key=val fails", 127 args: []string{"--reset", "a", "--reset", "b,foo=bar,c"}, 128 errorMatch: `--reset accepts a comma delimited set of keys "a,b,c", received: "foo=bar"`, 129 }, { 130 // test get 131 description: "test no args inits", 132 args: nil, 133 nilErr: true, 134 }, { 135 description: "one key arg inits", 136 args: []string{"attr"}, 137 nilErr: true, 138 }, { 139 description: "test two key args fails", 140 args: []string{"one", "two"}, 141 errorMatch: "can only retrieve defaults for one key or all", 142 }, { 143 description: "test multiple key args fails", 144 args: []string{"one", "two", "three"}, 145 errorMatch: "can only retrieve defaults for one key or all", 146 }, { 147 description: "test valid region and one arg", 148 args: []string{"dummy-region", "attr2"}, 149 nilErr: true, 150 }, { 151 description: "test valid region and no args", 152 args: []string{"dummy-region"}, 153 nilErr: true, 154 }, { 155 // test cloud/region 156 description: "test invalid cloud fails", 157 args: []string{"invalidCloud/invalidRegion", "one=two"}, 158 errorMatch: "Unknown cloud", 159 }, { 160 description: "test valid cloud with invalid region fails", 161 args: []string{"dummy/invalidRegion", "one=two"}, 162 errorMatch: `invalid region specified: "dummy/invalidRegion"`, 163 }, { 164 description: "test no cloud with invalid region fails", 165 args: []string{"invalidRegion", "one=two"}, 166 errorMatch: `invalid region specified: "invalidRegion"`, 167 }, { 168 description: "test valid region with set arg succeeds", 169 args: []string{"dummy-region", "one=two"}, 170 nilErr: true, 171 }, { 172 description: "test valid region with set and reset succeeds", 173 args: []string{"dummy-region", "one=two", "--reset", "three"}, 174 nilErr: true, 175 }, { 176 description: "test reset and set with extra key is interpereted as invalid region", 177 args: []string{"--reset", "something,else", "invalidRegion", "is=weird"}, 178 errorMatch: `invalid region specified: "invalidRegion"`, 179 }, { 180 description: "test reset and set with valid region and extra key fails", 181 args: []string{"--reset", "something,else", "dummy-region", "invalidkey", "is=weird"}, 182 errorMatch: "cannot set and retrieve default values simultaneously", 183 }, { 184 // test various invalid 185 description: "test too many positional args with reset", 186 args: []string{"--reset", "a", "b", "c", "d"}, 187 errorMatch: "invalid input", 188 }, { 189 description: "test too many positional args with invalid region set", 190 args: []string{"a", "a=b", "b", "c=d"}, 191 errorMatch: `invalid region specified: "a"`, 192 }, { 193 description: "test invalid positional args with set", 194 args: []string{"a=b", "b", "c=d"}, 195 errorMatch: `.*(no such file or directory|cannot find the file specified).*`, 196 }, { 197 description: "test invalid positional args with set and trailing key", 198 args: []string{"a=b", "c=d", "e"}, 199 errorMatch: "cannot set and retrieve default values simultaneously", 200 }, { 201 description: "test invalid positional args with valid region, set, reset", 202 args: []string{"dummy-region", "a=b", "--reset", "c,d,", "e=f", "g"}, 203 errorMatch: "cannot set and retrieve default values simultaneously", 204 }, { 205 // Test some random orderings 206 description: "test invalid positional args with set, reset with trailing comman and split key=values", 207 args: []string{"dummy-region", "a=b", "--reset", "c,d,", "e=f"}, 208 nilErr: true, 209 }, { 210 description: "test leading comma with reset", 211 args: []string{"--reset", ",a,b"}, 212 nilErr: true, 213 }} { 214 c.Logf("test %d: %s", i, test.description) 215 _, err := s.run(c, test.args...) 216 if test.nilErr { 217 c.Check(err, jc.ErrorIsNil) 218 continue 219 } 220 c.Check(err, gc.ErrorMatches, test.errorMatch) 221 } 222 } 223 224 func (s *DefaultsCommandSuite) TestResetUnknownValueLogs(c *gc.C) { 225 ctx, err := s.run(c, "--reset", "attr,weird") 226 c.Assert(err, jc.ErrorIsNil) 227 expected := `key "weird" is not defined in the known model configuration: possible misspelling` 228 c.Check(c.GetTestLog(), jc.Contains, expected) 229 c.Check(cmdtesting.Stdout(ctx), jc.DeepEquals, "") 230 } 231 232 func (s *DefaultsCommandSuite) TestResetAttr(c *gc.C) { 233 ctx, err := s.run(c, "--reset", "attr,unknown") 234 c.Check(err, jc.ErrorIsNil) 235 c.Check(s.fakeDefaultsAPI.defaults, jc.DeepEquals, config.ModelDefaultAttributes{ 236 "attr2": {Controller: "bar", Default: nil, Regions: []config.RegionDefaultValue{{ 237 Name: "dummy-region", 238 Value: "dummy-value", 239 }, { 240 Name: "another-region", 241 Value: "another-value", 242 }}}, 243 }) 244 c.Check(cmdtesting.Stdout(ctx), jc.DeepEquals, "") 245 } 246 247 func (s *DefaultsCommandSuite) TestResetRegionAttr(c *gc.C) { 248 ctx, err := s.run(c, "--reset", "attr,unknown", "dummy-region") 249 c.Check(err, jc.ErrorIsNil) 250 c.Check(s.fakeDefaultsAPI.defaults, jc.DeepEquals, config.ModelDefaultAttributes{ 251 "attr2": {Controller: "bar", Default: nil, Regions: []config.RegionDefaultValue{{ 252 Name: "dummy-region", 253 Value: "dummy-value", 254 }, { 255 Name: "another-region", 256 Value: "another-value", 257 }}}, 258 }) 259 c.Check(cmdtesting.Stdout(ctx), jc.DeepEquals, "") 260 } 261 262 func (s *DefaultsCommandSuite) TestResetBlockedError(c *gc.C) { 263 s.fakeDefaultsAPI.err = common.OperationBlockedError("TestBlockedError") 264 _, err := s.run(c, "--reset", "attr") 265 testing.AssertOperationWasBlocked(c, err, ".*TestBlockedError.*") 266 } 267 268 func (s *DefaultsCommandSuite) TestSetUnknownValueLogs(c *gc.C) { 269 _, err := s.run(c, "weird=foo") 270 c.Assert(err, jc.ErrorIsNil) 271 expected := `key "weird" is not defined in the known model configuration: possible misspelling` 272 c.Check(c.GetTestLog(), jc.Contains, expected) 273 } 274 275 func (s *DefaultsCommandSuite) TestSet(c *gc.C) { 276 _, err := s.run(c, "special=extra", "attr=baz") 277 c.Assert(err, jc.ErrorIsNil) 278 c.Assert(s.fakeDefaultsAPI.defaults, jc.DeepEquals, config.ModelDefaultAttributes{ 279 "attr": {Controller: "baz", Default: nil, Regions: nil}, 280 "attr2": {Controller: "bar", Default: nil, Regions: []config.RegionDefaultValue{{ 281 Name: "dummy-region", 282 Value: "dummy-value", 283 }, { 284 Name: "another-region", 285 Value: "another-value", 286 }}}, 287 "special": {Controller: "extra", Default: nil, Regions: nil}, 288 }) 289 } 290 291 func (s *DefaultsCommandSuite) TestSetFromFile(c *gc.C) { 292 tmpdir := c.MkDir() 293 configFile := filepath.Join(tmpdir, "config.yaml") 294 err := ioutil.WriteFile(configFile, []byte("special: extra\n"), 0644) 295 c.Assert(err, jc.ErrorIsNil) 296 297 _, err = s.run(c, configFile) 298 c.Assert(err, jc.ErrorIsNil) 299 c.Assert(s.fakeDefaultsAPI.defaults, jc.DeepEquals, config.ModelDefaultAttributes{ 300 "attr": {Controller: nil, Default: "foo", Regions: nil}, 301 "attr2": {Controller: "bar", Default: nil, Regions: []config.RegionDefaultValue{{ 302 Name: "dummy-region", 303 Value: "dummy-value", 304 }, { 305 Name: "another-region", 306 Value: "another-value", 307 }}}, 308 "special": {Controller: "extra", Default: nil, Regions: nil}, 309 }) 310 } 311 312 func (s *DefaultsCommandSuite) TestSetFromFileCombined(c *gc.C) { 313 tmpdir := c.MkDir() 314 configFile := filepath.Join(tmpdir, "config.yaml") 315 err := ioutil.WriteFile(configFile, []byte("special: extra\n"), 0644) 316 c.Assert(err, jc.ErrorIsNil) 317 318 _, err = s.run(c, configFile, "attr=baz") 319 c.Assert(err, jc.ErrorIsNil) 320 c.Assert(s.fakeDefaultsAPI.defaults, jc.DeepEquals, config.ModelDefaultAttributes{ 321 "attr": {Controller: "baz", Default: nil, Regions: nil}, 322 "attr2": {Controller: "bar", Default: nil, Regions: []config.RegionDefaultValue{{ 323 Name: "dummy-region", 324 Value: "dummy-value", 325 }, { 326 Name: "another-region", 327 Value: "another-value", 328 }}}, 329 "special": {Controller: "extra", Default: nil, Regions: nil}, 330 }) 331 } 332 333 func (s *DefaultsCommandSuite) TestSetConveysCloudRegion(c *gc.C) { 334 table := []struct { 335 input, cloud, region string 336 }{ 337 {"", "", ""}, 338 {"dummy-region", "dummy", "dummy-region"}, 339 {"dummy/dummy-region", "dummy", "dummy-region"}, 340 {"another-region", "dummy", "another-region"}, 341 } 342 for i, test := range table { 343 c.Logf("test %d", i) 344 var err error 345 if test.input == "" { 346 _, err = s.run(c, "special=extra", "--reset", "attr") 347 } else { 348 _, err = s.run(c, test.input, "special=extra", "--reset", "attr") 349 } 350 c.Assert(err, jc.ErrorIsNil) 351 c.Assert(s.fakeDefaultsAPI.region, jc.DeepEquals, test.region) 352 c.Assert(s.fakeDefaultsAPI.cloud, jc.DeepEquals, test.cloud) 353 } 354 } 355 356 func (s *DefaultsCommandSuite) TestBlockedErrorOnSet(c *gc.C) { 357 s.fakeDefaultsAPI.err = common.OperationBlockedError("TestBlockedError") 358 _, err := s.run(c, "special=extra") 359 testing.AssertOperationWasBlocked(c, err, ".*TestBlockedError.*") 360 } 361 362 func (s *DefaultsCommandSuite) TestGetSingleValue(c *gc.C) { 363 context, err := s.run(c, "attr2") 364 c.Assert(err, jc.ErrorIsNil) 365 366 output := strings.TrimSpace(cmdtesting.Stdout(context)) 367 expected := "" + 368 "Attribute Default Controller\n" + 369 "attr2 - bar\n" + 370 " dummy-region dummy-value -\n" + 371 " another-region another-value -" 372 c.Assert(output, gc.Equals, expected) 373 } 374 375 func (s *DefaultsCommandSuite) TestGetSingleValueJSON(c *gc.C) { 376 context, err := s.run(c, "--format=json", "attr2") 377 c.Assert(err, jc.ErrorIsNil) 378 379 output := strings.TrimSpace(cmdtesting.Stdout(context)) 380 c.Assert(output, gc.Equals, 381 `{"attr2":{"controller":"bar","regions":[{"name":"dummy-region","value":"dummy-value"},{"name":"another-region","value":"another-value"}]}}`) 382 } 383 384 func (s *DefaultsCommandSuite) TestGetAllValuesYAML(c *gc.C) { 385 context, err := s.run(c, "--format=yaml") 386 c.Assert(err, jc.ErrorIsNil) 387 388 output := strings.TrimSpace(cmdtesting.Stdout(context)) 389 expected := "" + 390 "attr:\n" + 391 " default: foo\n" + 392 "attr2:\n" + 393 " controller: bar\n" + 394 " regions:\n" + 395 " - name: dummy-region\n" + 396 " value: dummy-value\n" + 397 " - name: another-region\n" + 398 " value: another-value" 399 c.Assert(output, gc.Equals, expected) 400 } 401 402 func (s *DefaultsCommandSuite) TestGetAllValuesJSON(c *gc.C) { 403 context, err := s.run(c, "--format=json") 404 c.Assert(err, jc.ErrorIsNil) 405 406 output := strings.TrimSpace(cmdtesting.Stdout(context)) 407 expected := `{"attr":{"default":"foo"},"attr2":{"controller":"bar","regions":[{"name":"dummy-region","value":"dummy-value"},{"name":"another-region","value":"another-value"}]}}` 408 c.Assert(output, gc.Equals, expected) 409 } 410 411 func (s *DefaultsCommandSuite) TestGetAllValuesTabular(c *gc.C) { 412 context, err := s.run(c) 413 c.Assert(err, jc.ErrorIsNil) 414 415 output := strings.TrimSpace(cmdtesting.Stdout(context)) 416 expected := "" + 417 "Attribute Default Controller\n" + 418 "attr foo -\n" + 419 "attr2 - bar\n" + 420 " dummy-region dummy-value -\n" + 421 " another-region another-value -" 422 c.Assert(output, gc.Equals, expected) 423 } 424 425 func (s *DefaultsCommandSuite) TestGetRegionValuesTabular(c *gc.C) { 426 context, err := s.run(c, "dummy-region") 427 c.Assert(err, jc.ErrorIsNil) 428 429 output := strings.TrimSpace(cmdtesting.Stdout(context)) 430 expected := "" + 431 "Attribute Default Controller\n" + 432 "attr2 - bar\n" + 433 " dummy-region dummy-value -" 434 c.Assert(output, gc.Equals, expected) 435 } 436 437 func (s *DefaultsCommandSuite) TestGetRegionNoValuesTabular(c *gc.C) { 438 _, err := s.run(c, "--reset", "attr2") 439 c.Assert(err, jc.ErrorIsNil) 440 ctx, err := s.run(c, "dummy-region") 441 c.Assert(err, gc.ErrorMatches, `there are no default model values in region "dummy-region"`) 442 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "") 443 } 444 445 func (s *DefaultsCommandSuite) TestGetRegionOneArgNoValuesTabular(c *gc.C) { 446 ctx, err := s.run(c, "dummy-region", "attr") 447 c.Assert(err, gc.ErrorMatches, `there are no default model values for "attr" in region "dummy-region"`) 448 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "") 449 }