github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/provider/gce/config_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package gce_test 5 6 import ( 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/environs" 15 "github.com/juju/juju/environs/config" 16 "github.com/juju/juju/provider/gce" 17 "github.com/juju/juju/testing" 18 ) 19 20 type ConfigSuite struct { 21 gce.BaseSuite 22 23 config *config.Config 24 rootDir string 25 } 26 27 var _ = gc.Suite(&ConfigSuite{}) 28 29 func (s *ConfigSuite) SetUpTest(c *gc.C) { 30 s.BaseSuite.SetUpTest(c) 31 32 cfg, err := testing.EnvironConfig(c).Apply(gce.ConfigAttrs) 33 c.Assert(err, jc.ErrorIsNil) 34 s.config = cfg 35 s.rootDir = c.MkDir() 36 } 37 38 // TODO(ericsnow) Each test only deals with a single field, so having 39 // multiple values in insert and remove (in configTestSpec) is a little 40 // misleading and unecessary. 41 42 // configTestSpec defines a subtest to run in a table driven test. 43 type configTestSpec struct { 44 // info describes the subtest. 45 info string 46 // insert holds attrs that should be merged into the config. 47 insert testing.Attrs 48 // remove has the names of attrs that should be removed. 49 remove []string 50 // expect defines the expected attributes in a success case. 51 expect testing.Attrs 52 // err is the error message to expect in a failure case. 53 err string 54 55 // rootDir is the path to the root directory for this test. 56 rootDir string 57 } 58 59 func (ts configTestSpec) checkSuccess(c *gc.C, value interface{}, err error) { 60 if !c.Check(err, jc.ErrorIsNil) { 61 return 62 } 63 64 var cfg *config.Config 65 switch typed := value.(type) { 66 case *config.Config: 67 cfg = typed 68 case environs.Environ: 69 cfg = typed.Config() 70 } 71 72 attrs := cfg.AllAttrs() 73 for field, value := range ts.expect { 74 if field == "auth-file" && value != nil && value.(string) != "" { 75 value = filepath.Join(ts.rootDir, value.(string)) 76 } 77 c.Check(attrs[field], gc.Equals, value) 78 } 79 } 80 81 func (ts configTestSpec) checkFailure(c *gc.C, err error, msg string) { 82 c.Check(err, gc.ErrorMatches, msg+": "+ts.err) 83 } 84 85 func (ts configTestSpec) checkAttrs(c *gc.C, attrs map[string]interface{}, cfg *config.Config) { 86 for field, expected := range cfg.UnknownAttrs() { 87 value := attrs[field] 88 if field == "auth-file" && value != nil { 89 filename := value.(string) 90 if filename != "" { 91 value = interface{}(filepath.Join(ts.rootDir, filename)) 92 } 93 } 94 c.Check(value, gc.Equals, expected) 95 } 96 } 97 98 func (ts configTestSpec) attrs() testing.Attrs { 99 return gce.ConfigAttrs.Merge(ts.insert).Delete(ts.remove...) 100 } 101 102 func (ts configTestSpec) newConfig(c *gc.C) *config.Config { 103 filename := ts.writeAuthFile(c) 104 105 attrs := ts.attrs() 106 if filename != "" { 107 attrs["auth-file"] = filename 108 } 109 cfg, err := testing.EnvironConfig(c).Apply(attrs) 110 c.Assert(err, jc.ErrorIsNil) 111 return cfg 112 } 113 114 func (ts configTestSpec) writeAuthFile(c *gc.C) string { 115 value, ok := ts.insert["auth-file"] 116 if !ok { 117 return "" 118 } 119 filename := value.(string) 120 if filename == "" { 121 return "" 122 } 123 filename = filepath.Join(ts.rootDir, filename) 124 err := os.MkdirAll(filepath.Dir(filename), 0755) 125 c.Assert(err, jc.ErrorIsNil) 126 err = ioutil.WriteFile(filename, []byte(gce.AuthFile), 0600) 127 c.Assert(err, jc.ErrorIsNil) 128 return filename 129 } 130 131 func (ts configTestSpec) fixCfg(c *gc.C, cfg *config.Config) *config.Config { 132 fixes := make(map[string]interface{}) 133 134 var filename string 135 if value, ok := ts.insert["auth-file"]; ok { 136 filename = value.(string) 137 if filename != "" { 138 filename = filepath.Join(ts.rootDir, filename) 139 } 140 } 141 142 // Set changed values. 143 fixes = updateAttrs(fixes, ts.insert) 144 if filename != "" { 145 fixes = updateAttrs(fixes, testing.Attrs{"auth-file": filename}) 146 } 147 148 newCfg, err := cfg.Apply(fixes) 149 c.Assert(err, jc.ErrorIsNil) 150 return newCfg 151 } 152 153 func updateAttrs(attrs, updates testing.Attrs) testing.Attrs { 154 updated := make(testing.Attrs, len(attrs)) 155 for k, v := range attrs { 156 updated[k] = v 157 } 158 for k, v := range updates { 159 updated[k] = v 160 } 161 return updated 162 } 163 164 var newConfigTests = []configTestSpec{{ 165 info: "auth-file is optional", 166 remove: []string{"auth-file"}, 167 expect: testing.Attrs{"auth-file": ""}, 168 }, { 169 info: "auth-file can be empty", 170 insert: testing.Attrs{"auth-file": ""}, 171 expect: testing.Attrs{"auth-file": ""}, 172 }, { 173 info: "auth-file ignored", 174 insert: testing.Attrs{ 175 "auth-file": "/home/someuser/gce.json", 176 "client-id": "spam.x", 177 "client-email": "spam@x", 178 "private-key": "abc", 179 }, 180 expect: testing.Attrs{ 181 "auth-file": "/home/someuser/gce.json", 182 "client-id": "spam.x", 183 "client-email": "spam@x", 184 "private-key": "abc", 185 }, 186 }, { 187 info: "auth-file parsed", 188 insert: testing.Attrs{"auth-file": "/home/someuser/gce.json"}, 189 remove: []string{"client-id", "client-email", "private-key"}, 190 expect: testing.Attrs{ 191 "auth-file": "/home/someuser/gce.json", 192 "client-id": gce.ClientID, 193 "client-email": gce.ClientEmail, 194 "private-key": gce.PrivateKey, 195 }, 196 }, { 197 info: "client-id is required", 198 remove: []string{"client-id"}, 199 err: "client-id: expected string, got nothing", 200 }, { 201 info: "client-id cannot be empty", 202 insert: testing.Attrs{"client-id": ""}, 203 err: "client-id: must not be empty", 204 }, { 205 info: "private-key is required", 206 remove: []string{"private-key"}, 207 err: "private-key: expected string, got nothing", 208 }, { 209 info: "private-key cannot be empty", 210 insert: testing.Attrs{"private-key": ""}, 211 err: "private-key: must not be empty", 212 }, { 213 info: "client-email is required", 214 remove: []string{"client-email"}, 215 err: "client-email: expected string, got nothing", 216 }, { 217 info: "client-email cannot be empty", 218 insert: testing.Attrs{"client-email": ""}, 219 err: "client-email: must not be empty", 220 }, { 221 info: "region is optional", 222 remove: []string{"region"}, 223 expect: testing.Attrs{"region": "us-central1"}, 224 }, { 225 info: "region cannot be empty", 226 insert: testing.Attrs{"region": ""}, 227 err: "region: must not be empty", 228 }, { 229 info: "project-id is required", 230 remove: []string{"project-id"}, 231 err: "project-id: expected string, got nothing", 232 }, { 233 info: "project-id cannot be empty", 234 insert: testing.Attrs{"project-id": ""}, 235 err: "project-id: must not be empty", 236 }, { 237 info: "image-endpoint is inserted if missing", 238 remove: []string{"image-endpoint"}, 239 expect: testing.Attrs{"image-endpoint": "https://www.googleapis.com"}, 240 }, { 241 info: "image-endpoint cannot be empty", 242 insert: testing.Attrs{"image-endpoint": ""}, 243 err: "image-endpoint: must not be empty", 244 }, { 245 info: "unknown field is not touched", 246 insert: testing.Attrs{"unknown-field": 12345}, 247 expect: testing.Attrs{"unknown-field": 12345}, 248 }} 249 250 func (s *ConfigSuite) TestNewEnvironConfig(c *gc.C) { 251 for i, test := range newConfigTests { 252 c.Logf("test %d: %s", i, test.info) 253 254 test.rootDir = s.rootDir 255 testConfig := test.newConfig(c) 256 environ, err := environs.New(testConfig) 257 258 // Check the result 259 if test.err != "" { 260 test.checkFailure(c, err, "invalid config") 261 } else { 262 test.checkSuccess(c, environ, err) 263 } 264 } 265 } 266 267 // TODO(wwitzel3) refactor to provider_test file 268 func (s *ConfigSuite) TestValidateNewConfig(c *gc.C) { 269 for i, test := range newConfigTests { 270 c.Logf("test %d: %s", i, test.info) 271 272 test.rootDir = s.rootDir 273 testConfig := test.newConfig(c) 274 validatedConfig, err := gce.Provider.Validate(testConfig, nil) 275 276 // Check the result 277 if test.err != "" { 278 test.checkFailure(c, err, "invalid config") 279 } else { 280 c.Check(validatedConfig, gc.NotNil) 281 test.checkSuccess(c, validatedConfig, err) 282 } 283 } 284 } 285 286 // TODO(wwitzel3) refactor to the provider_test file 287 func (s *ConfigSuite) TestValidateOldConfig(c *gc.C) { 288 for i, test := range newConfigTests { 289 c.Logf("test %d: %s", i, test.info) 290 291 test.rootDir = s.rootDir 292 oldcfg := test.newConfig(c) 293 newcfg := test.fixCfg(c, s.config) 294 expected := updateAttrs(gce.ConfigAttrs, test.insert) 295 296 // Validate the new config (relative to the old one) using the 297 // provider. 298 validatedConfig, err := gce.Provider.Validate(newcfg, oldcfg) 299 300 // Check the result. 301 if test.err != "" { 302 test.checkFailure(c, err, "invalid base config") 303 } else { 304 if test.insert == nil && test.remove != nil { 305 // No defaults are set on the old config. 306 c.Check(err, gc.ErrorMatches, "invalid base config: .*") 307 continue 308 } 309 310 if !c.Check(err, jc.ErrorIsNil) { 311 continue 312 } 313 // We verify that Validate filled in the defaults 314 // appropriately. 315 c.Check(validatedConfig, gc.NotNil) 316 test.checkAttrs(c, expected, validatedConfig) 317 } 318 } 319 } 320 321 var changeConfigTests = []configTestSpec{{ 322 info: "no change, no error", 323 expect: gce.ConfigAttrs, 324 }, { 325 info: "cannot change auth-file", 326 insert: testing.Attrs{"auth-file": "gce.json"}, 327 err: "auth-file: cannot change from to .*gce.json", 328 }, { 329 info: "cannot change private-key", 330 insert: testing.Attrs{"private-key": "okkult"}, 331 err: "private-key: cannot change from " + gce.PrivateKey + " to okkult", 332 }, { 333 info: "cannot change client-id", 334 insert: testing.Attrs{"client-id": "mutant"}, 335 err: "client-id: cannot change from " + gce.ClientID + " to mutant", 336 }, { 337 info: "cannot change client-email", 338 insert: testing.Attrs{"client-email": "spam@eggs.com"}, 339 err: "client-email: cannot change from " + gce.ClientEmail + " to spam@eggs.com", 340 }, { 341 info: "cannot change region", 342 insert: testing.Attrs{"region": "not home"}, 343 err: "region: cannot change from home to not home", 344 }, { 345 info: "cannot change project-id", 346 insert: testing.Attrs{"project-id": "your-juju"}, 347 err: "project-id: cannot change from my-juju to your-juju", 348 }, { 349 info: "can insert unknown field", 350 insert: testing.Attrs{"unknown": "ignoti"}, 351 expect: testing.Attrs{"unknown": "ignoti"}, 352 }} 353 354 // TODO(wwitzel3) refactor this to the provider_test file. 355 func (s *ConfigSuite) TestValidateChange(c *gc.C) { 356 for i, test := range changeConfigTests { 357 c.Logf("test %d: %s", i, test.info) 358 359 test.rootDir = s.rootDir 360 testConfig := test.newConfig(c) 361 validatedConfig, err := gce.Provider.Validate(testConfig, s.config) 362 363 // Check the result. 364 if test.err != "" { 365 test.checkFailure(c, err, "invalid config change") 366 } else { 367 test.checkSuccess(c, validatedConfig, err) 368 } 369 } 370 } 371 372 func (s *ConfigSuite) TestSetConfig(c *gc.C) { 373 for i, test := range changeConfigTests { 374 c.Logf("test %d: %s", i, test.info) 375 376 environ, err := environs.New(s.config) 377 c.Assert(err, jc.ErrorIsNil) 378 379 test.rootDir = s.rootDir 380 testConfig := test.newConfig(c) 381 err = environ.SetConfig(testConfig) 382 383 // Check the result. 384 if test.err != "" { 385 test.checkFailure(c, err, "invalid config change") 386 test.checkAttrs(c, environ.Config().AllAttrs(), s.config) 387 } else { 388 test.checkSuccess(c, environ.Config(), err) 389 } 390 } 391 }