github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/controller/configcommand_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package controller_test 5 6 import ( 7 "io/ioutil" 8 "path/filepath" 9 "strings" 10 11 "github.com/juju/cmd" 12 "github.com/juju/cmd/cmdtesting" 13 "github.com/juju/errors" 14 jc "github.com/juju/testing/checkers" 15 gc "gopkg.in/check.v1" 16 17 "github.com/juju/juju/cmd/juju/controller" 18 jujucontroller "github.com/juju/juju/controller" 19 ) 20 21 type ConfigSuite struct { 22 baseControllerSuite 23 } 24 25 var _ = gc.Suite(&ConfigSuite{}) 26 27 func (s *ConfigSuite) SetUpTest(c *gc.C) { 28 s.baseControllerSuite.SetUpTest(c) 29 s.createTestClientStore(c) 30 } 31 32 func (s *ConfigSuite) run(c *gc.C, args ...string) (*cmd.Context, error) { 33 return s.runWithAPI(c, &fakeControllerAPI{}, args...) 34 } 35 36 func (s *ConfigSuite) runWithAPI(c *gc.C, api *fakeControllerAPI, args ...string) (*cmd.Context, error) { 37 command := controller.NewConfigCommandForTest(api, s.store) 38 return cmdtesting.RunCommand(c, command, args...) 39 } 40 41 func (s *ConfigSuite) TestInit(c *gc.C) { 42 path := writeFile(c, "yamlfile", "") 43 44 tests := []struct { 45 desc string 46 args []string 47 err string 48 }{{ 49 desc: "no args", 50 }, { 51 desc: "get one key", 52 args: []string{"one"}, 53 }, { 54 desc: "can't get two keys", 55 args: []string{"one", "two"}, 56 err: "can only retrieve a single value, or all values", 57 }, { 58 desc: "set one key", 59 args: []string{"key=value"}, 60 }, { 61 desc: "set two keys", 62 args: []string{"key1=value", "key2=value"}, 63 }, { 64 desc: "can't mix setting and getting", 65 args: []string{"key1=value", "hey2"}, 66 err: "can only retrieve a single value, or all values", 67 }, { 68 desc: "can mix setting with files", 69 args: []string{"key1=value", path}, 70 }} 71 for i, test := range tests { 72 c.Logf("%d - %s", i, test.desc) 73 err := cmdtesting.InitCommand(controller.NewConfigCommandForTest(&fakeControllerAPI{}, s.store), test.args) 74 if test.err == "" { 75 c.Check(err, jc.ErrorIsNil) 76 } else { 77 c.Check(err, gc.ErrorMatches, test.err) 78 } 79 } 80 } 81 82 func (s *ConfigSuite) TestSingleValue(c *gc.C) { 83 context, err := s.run(c, "ca-cert") 84 c.Assert(err, jc.ErrorIsNil) 85 86 output := strings.TrimSpace(cmdtesting.Stdout(context)) 87 c.Assert(output, gc.Equals, "multi\nline") 88 } 89 90 func (s *ConfigSuite) TestSingleValueJSON(c *gc.C) { 91 context, err := s.run(c, "--format=json", "controller-uuid") 92 c.Assert(err, jc.ErrorIsNil) 93 94 output := strings.TrimSpace(cmdtesting.Stdout(context)) 95 c.Assert(output, gc.Equals, `"uuid"`) 96 } 97 98 func (s *ConfigSuite) TestAllValues(c *gc.C) { 99 context, err := s.run(c) 100 c.Assert(err, jc.ErrorIsNil) 101 102 output := strings.TrimSpace(cmdtesting.Stdout(context)) 103 expected := ` 104 Attribute Value 105 api-port 1234 106 audit-log-exclude-methods 107 - Thing1 108 - Thing2 109 ca-cert |- 110 multi 111 line 112 controller-uuid uuid`[1:] 113 c.Assert(output, gc.Equals, expected) 114 } 115 116 func (s *ConfigSuite) TestOneLineExcludeMethods(c *gc.C) { 117 var api fakeControllerAPI 118 api.config = map[string]interface{}{ 119 "audit-log-exclude-methods": []string{"Actual.Size"}, 120 } 121 context, err := s.runWithAPI(c, &api) 122 c.Assert(err, jc.ErrorIsNil) 123 124 output := strings.TrimSpace(cmdtesting.Stdout(context)) 125 expected := ` 126 Attribute Value 127 audit-log-exclude-methods Actual.Size`[1:] 128 c.Assert(output, gc.Equals, expected) 129 } 130 131 func (s *ConfigSuite) TestAllValuesJSON(c *gc.C) { 132 context, err := s.run(c, "--format=json") 133 c.Assert(err, jc.ErrorIsNil) 134 135 output := strings.TrimSpace(cmdtesting.Stdout(context)) 136 expected := `{"api-port":1234,"audit-log-exclude-methods":["Thing1","Thing2"],"ca-cert":"multi\nline","controller-uuid":"uuid"}` 137 c.Assert(output, gc.Equals, expected) 138 } 139 140 func (s *ConfigSuite) TestNonexistentValue(c *gc.C) { 141 context, err := s.run(c, "courtney-barnett") 142 c.Assert(err, gc.ErrorMatches, `key "courtney-barnett" not found in "mallards" controller`) 143 144 output := strings.TrimSpace(cmdtesting.Stdout(context)) 145 c.Assert(output, gc.Equals, "") 146 } 147 148 func (s *ConfigSuite) TestError(c *gc.C) { 149 command := controller.NewConfigCommandForTest(&fakeControllerAPI{err: errors.New("error")}, s.store) 150 _, err := cmdtesting.RunCommand(c, command) 151 c.Assert(err, gc.ErrorMatches, "error") 152 } 153 154 func (s *ConfigSuite) TestSettingKey(c *gc.C) { 155 var api fakeControllerAPI 156 context, err := s.runWithAPI(c, &api, "key1=value") 157 c.Assert(err, jc.ErrorIsNil) 158 159 output := strings.TrimSpace(cmdtesting.Stdout(context)) 160 c.Assert(output, gc.Equals, "") 161 162 c.Assert(api.values, gc.DeepEquals, map[string]interface{}{"key1": "value"}) 163 } 164 165 func (s *ConfigSuite) TestSettingComplexKey(c *gc.C) { 166 var api fakeControllerAPI 167 context, err := s.runWithAPI(c, &api, "key1=[value1,value2]") 168 c.Assert(err, jc.ErrorIsNil) 169 170 output := strings.TrimSpace(cmdtesting.Stdout(context)) 171 c.Assert(output, gc.Equals, "") 172 173 c.Assert(api.values, gc.DeepEquals, map[string]interface{}{ 174 "key1": []interface{}{"value1", "value2"}, 175 }) 176 } 177 178 func (s *ConfigSuite) TestSettingFromFile(c *gc.C) { 179 path := writeFile(c, "yaml", "key1: value\n") 180 var api fakeControllerAPI 181 context, err := s.runWithAPI(c, &api, path) 182 c.Assert(err, jc.ErrorIsNil) 183 184 output := strings.TrimSpace(cmdtesting.Stdout(context)) 185 c.Assert(output, gc.Equals, "") 186 187 c.Assert(api.values, gc.DeepEquals, map[string]interface{}{"key1": "value"}) 188 } 189 190 func (s *ConfigSuite) TestSettingFromBothNoOverlap(c *gc.C) { 191 path := writeFile(c, "yaml", "key1: value\n") 192 var api fakeControllerAPI 193 context, err := s.runWithAPI(c, &api, path, "key2=123") 194 c.Assert(err, jc.ErrorIsNil) 195 196 output := strings.TrimSpace(cmdtesting.Stdout(context)) 197 c.Assert(output, gc.Equals, "") 198 199 c.Assert(api.values, gc.DeepEquals, map[string]interface{}{ 200 "key1": "value", 201 "key2": 123, 202 }) 203 } 204 205 func (s *ConfigSuite) TestSettingFromBothArgFirst(c *gc.C) { 206 path := writeFile(c, "yaml", "key1: value\n") 207 var api fakeControllerAPI 208 context, err := s.runWithAPI(c, &api, "key1=123", path) 209 c.Assert(err, jc.ErrorIsNil) 210 211 output := strings.TrimSpace(cmdtesting.Stdout(context)) 212 c.Assert(output, gc.Equals, "") 213 214 // This is a consequence of ConfigFlag reading input files first 215 // and then overlaying with values from args. It's surprising but 216 // probably not worth fixing - I don't think people will try to 217 // set an option from a file and then override it from an arg. 218 c.Assert(api.values, gc.DeepEquals, map[string]interface{}{ 219 "key1": 123, 220 }) 221 } 222 223 func (s *ConfigSuite) TestSettingFromBothFileFirst(c *gc.C) { 224 path := writeFile(c, "yaml", "key1: value\n") 225 var api fakeControllerAPI 226 context, err := s.runWithAPI(c, &api, path, "key1=123") 227 c.Assert(err, jc.ErrorIsNil) 228 229 output := strings.TrimSpace(cmdtesting.Stdout(context)) 230 c.Assert(output, gc.Equals, "") 231 232 c.Assert(api.values, gc.DeepEquals, map[string]interface{}{ 233 "key1": 123, 234 }) 235 } 236 237 func (s *ConfigSuite) TestSettingMultipleFiles(c *gc.C) { 238 path1 := writeFile(c, "yaml1", "key1: value\n") 239 path2 := writeFile(c, "yaml2", "key1: 123\n") 240 241 var api fakeControllerAPI 242 context, err := s.runWithAPI(c, &api, path1, path2) 243 c.Assert(err, jc.ErrorIsNil) 244 245 output := strings.TrimSpace(cmdtesting.Stdout(context)) 246 c.Assert(output, gc.Equals, "") 247 248 c.Assert(api.values, gc.DeepEquals, map[string]interface{}{ 249 "key1": 123, 250 }) 251 } 252 253 func (s *ConfigSuite) TestErrorOnSetting(c *gc.C) { 254 api := fakeControllerAPI{err: errors.Errorf("kablooie")} 255 context, err := s.runWithAPI(c, &api, "key=value") 256 c.Assert(err, gc.ErrorMatches, "kablooie") 257 258 c.Assert(strings.TrimSpace(cmdtesting.Stdout(context)), gc.Equals, "") 259 c.Assert(api.values, gc.DeepEquals, map[string]interface{}{"key": "value"}) 260 } 261 262 func writeFile(c *gc.C, name, content string) string { 263 path := filepath.Join(c.MkDir(), name) 264 err := ioutil.WriteFile(path, []byte(content), 0777) 265 c.Assert(err, jc.ErrorIsNil) 266 return path 267 } 268 269 type fakeControllerAPI struct { 270 err error 271 config map[string]interface{} 272 values map[string]interface{} 273 } 274 275 func (f *fakeControllerAPI) Close() error { 276 return nil 277 } 278 279 func (f *fakeControllerAPI) ControllerConfig() (jujucontroller.Config, error) { 280 if f.err != nil { 281 return nil, f.err 282 } 283 var result map[string]interface{} 284 if f.config != nil { 285 result = f.config 286 } else { 287 result = map[string]interface{}{ 288 "controller-uuid": "uuid", 289 "api-port": 1234, 290 "ca-cert": "multi\nline", 291 "audit-log-exclude-methods": []interface{}{"Thing1", "Thing2"}, 292 } 293 } 294 return result, nil 295 } 296 297 func (f *fakeControllerAPI) ConfigSet(values map[string]interface{}) error { 298 f.values = values 299 return f.err 300 }