github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/provider/lxd/config_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package lxd_test 5 6 import ( 7 stdcontext "context" 8 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 "gopkg.in/juju/environschema.v1" 12 13 "github.com/juju/juju/cloud" 14 "github.com/juju/juju/environs" 15 environscloudspec "github.com/juju/juju/environs/cloudspec" 16 "github.com/juju/juju/environs/config" 17 "github.com/juju/juju/provider/lxd" 18 "github.com/juju/juju/testing" 19 ) 20 21 type configSuite struct { 22 lxd.BaseSuite 23 24 provider environs.EnvironProvider 25 config *config.Config 26 } 27 28 var _ = gc.Suite(&configSuite{}) 29 30 func (s *configSuite) SetUpTest(c *gc.C) { 31 s.BaseSuite.SetUpTest(c) 32 33 s.provider = lxd.NewProvider() 34 35 cfg, err := testing.ModelConfig(c).Apply(lxd.ConfigAttrs) 36 c.Assert(err, jc.ErrorIsNil) 37 s.config = cfg 38 } 39 40 func (s *configSuite) TestDefaults(c *gc.C) { 41 cfg := lxd.NewBaseConfig(c) 42 ecfg := lxd.NewConfig(cfg) 43 44 values, extras := ecfg.Values(c) 45 c.Assert(extras, gc.HasLen, 0) 46 47 c.Check(values, jc.DeepEquals, lxd.ConfigValues{}) 48 } 49 50 // TODO(ericsnow) Each test only deals with a single field, so having 51 // multiple values in insert and remove (in configTestSpec) is a little 52 // misleading and unnecessary. 53 54 // configTestSpec defines a subtest to run in a table driven test. 55 type configTestSpec struct { 56 // info describes the subtest. 57 info string 58 // insert holds attrs that should be merged into the config. 59 insert testing.Attrs 60 // remove has the names of attrs that should be removed. 61 remove []string 62 // expect defines the expected attributes in a success case. 63 expect testing.Attrs 64 // err is the error message to expect in a failure case. 65 err string 66 } 67 68 func (ts configTestSpec) checkSuccess(c *gc.C, value interface{}, err error) { 69 if !c.Check(err, jc.ErrorIsNil) { 70 return 71 } 72 73 var cfg *config.Config 74 switch typed := value.(type) { 75 case *config.Config: 76 cfg = typed 77 case environs.Environ: 78 cfg = typed.Config() 79 } 80 81 attrs := cfg.AllAttrs() 82 for field, value := range ts.expect { 83 c.Check(attrs[field], gc.Equals, value) 84 } 85 } 86 87 func (ts configTestSpec) checkFailure(c *gc.C, err error, msg string) { 88 c.Check(err, gc.ErrorMatches, msg+": "+ts.err) 89 } 90 91 func (ts configTestSpec) checkAttrs(c *gc.C, attrs map[string]interface{}, cfg *config.Config) { 92 for field, expected := range cfg.UnknownAttrs() { 93 value := attrs[field] 94 c.Check(value, gc.Equals, expected) 95 } 96 } 97 98 func (ts configTestSpec) attrs() testing.Attrs { 99 attrs := lxd.ConfigAttrs 100 return attrs.Merge(ts.insert).Delete(ts.remove...) 101 } 102 103 func (ts configTestSpec) newConfig(c *gc.C) *config.Config { 104 attrs := ts.attrs() 105 cfg, err := testing.ModelConfig(c).Apply(attrs) 106 c.Assert(err, jc.ErrorIsNil) 107 return cfg 108 } 109 110 func (ts configTestSpec) fixCfg(c *gc.C, cfg *config.Config) *config.Config { 111 fixes := make(map[string]interface{}) 112 113 // Set changed values. 114 fixes = updateAttrs(fixes, ts.insert) 115 116 newCfg, err := cfg.Apply(fixes) 117 c.Assert(err, jc.ErrorIsNil) 118 return newCfg 119 } 120 121 func updateAttrs(attrs, updates testing.Attrs) testing.Attrs { 122 updated := make(testing.Attrs, len(attrs)) 123 for k, v := range attrs { 124 updated[k] = v 125 } 126 for k, v := range updates { 127 updated[k] = v 128 } 129 return updated 130 } 131 132 var newConfigTests = []configTestSpec{{ 133 info: "unknown field is not touched", 134 insert: testing.Attrs{"unknown-field": 12345}, 135 expect: testing.Attrs{"unknown-field": 12345}, 136 }} 137 138 func (s *configSuite) TestNewModelConfig(c *gc.C) { 139 for i, test := range newConfigTests { 140 c.Logf("test %d: %s", i, test.info) 141 142 testConfig := test.newConfig(c) 143 environ, err := environs.New(stdcontext.TODO(), environs.OpenParams{ 144 Cloud: lxdCloudSpec(), 145 Config: testConfig, 146 }) 147 148 // Check the result 149 if test.err != "" { 150 test.checkFailure(c, err, "invalid config") 151 } else { 152 test.checkSuccess(c, environ, err) 153 } 154 } 155 } 156 157 func (s *configSuite) TestValidateNewConfig(c *gc.C) { 158 for i, test := range newConfigTests { 159 c.Logf("test %d: %s", i, test.info) 160 161 testConfig := test.newConfig(c) 162 validatedConfig, err := s.provider.Validate(testConfig, nil) 163 164 // Check the result 165 if test.err != "" { 166 test.checkFailure(c, err, "invalid config") 167 } else { 168 c.Check(validatedConfig, gc.NotNil) 169 test.checkSuccess(c, validatedConfig, err) 170 } 171 } 172 } 173 174 func (s *configSuite) TestValidateOldConfig(c *gc.C) { 175 for i, test := range newConfigTests { 176 c.Logf("test %d: %s", i, test.info) 177 178 oldcfg := test.newConfig(c) 179 var err error 180 oldcfg, err = s.provider.Validate(oldcfg, nil) 181 c.Assert(err, jc.ErrorIsNil) 182 newcfg := test.fixCfg(c, s.config) 183 expected := updateAttrs(lxd.ConfigAttrs, test.insert) 184 185 // Validate the new config (relative to the old one) using the 186 // provider. 187 validatedConfig, err := s.provider.Validate(newcfg, oldcfg) 188 189 // Check the result. 190 if test.err != "" { 191 test.checkFailure(c, err, "invalid base config") 192 } else { 193 if !c.Check(err, jc.ErrorIsNil) { 194 continue 195 } 196 // We verify that Validate filled in the defaults 197 // appropriately. 198 c.Check(validatedConfig, gc.NotNil) 199 test.checkAttrs(c, expected, validatedConfig) 200 } 201 } 202 } 203 204 var changeConfigTests = []configTestSpec{{ 205 info: "no change, no error", 206 expect: lxd.ConfigAttrs, 207 }, { 208 info: "can insert unknown field", 209 insert: testing.Attrs{"unknown": "ignoti"}, 210 expect: testing.Attrs{"unknown": "ignoti"}, 211 }} 212 213 func (s *configSuite) TestValidateChange(c *gc.C) { 214 for i, test := range changeConfigTests { 215 c.Logf("test %d: %s", i, test.info) 216 217 testConfig := test.newConfig(c) 218 validatedConfig, err := s.provider.Validate(testConfig, s.config) 219 220 // Check the result. 221 if test.err != "" { 222 test.checkFailure(c, err, "invalid config change") 223 } else { 224 test.checkSuccess(c, validatedConfig, err) 225 } 226 } 227 } 228 229 func (s *configSuite) TestSetConfig(c *gc.C) { 230 for i, test := range changeConfigTests { 231 c.Logf("test %d: %s", i, test.info) 232 233 environ, err := environs.New(stdcontext.TODO(), environs.OpenParams{ 234 Cloud: lxdCloudSpec(), 235 Config: s.config, 236 }) 237 c.Assert(err, jc.ErrorIsNil) 238 239 testConfig := test.newConfig(c) 240 err = environ.SetConfig(testConfig) 241 242 // Check the result. 243 if test.err != "" { 244 test.checkFailure(c, err, "invalid config change") 245 expected, err := s.provider.Validate(s.config, nil) 246 c.Assert(err, jc.ErrorIsNil) 247 test.checkAttrs(c, environ.Config().AllAttrs(), expected) 248 } else { 249 test.checkSuccess(c, environ.Config(), err) 250 } 251 } 252 } 253 254 func (s *configSuite) TestSchema(c *gc.C) { 255 fields := s.provider.(interface { 256 Schema() environschema.Fields 257 }).Schema() 258 // Check that all the fields defined in environs/config 259 // are in the returned schema. 260 globalFields, err := config.Schema(nil) 261 c.Assert(err, gc.IsNil) 262 for name, field := range globalFields { 263 c.Check(fields[name], jc.DeepEquals, field) 264 } 265 } 266 267 func lxdCloudSpec() environscloudspec.CloudSpec { 268 cred := cloud.NewCredential(cloud.CertificateAuthType, map[string]string{ 269 "client-cert": "client.crt", 270 "client-key": "client.key", 271 "server-cert": "servert.crt", 272 }) 273 return environscloudspec.CloudSpec{ 274 Type: "lxd", 275 Name: "localhost", 276 Credential: &cred, 277 } 278 }