~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/provider/lxd/config_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2015 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
// +build go1.3
 
5
 
 
6
package lxd_test
 
7
 
 
8
import (
 
9
        "fmt"
 
10
 
 
11
        jc "github.com/juju/testing/checkers"
 
12
        gc "gopkg.in/check.v1"
 
13
        "gopkg.in/juju/environschema.v1"
 
14
 
 
15
        "github.com/juju/juju/environs"
 
16
        "github.com/juju/juju/environs/config"
 
17
        "github.com/juju/juju/provider/lxd"
 
18
        "github.com/juju/juju/testing"
 
19
        "github.com/juju/juju/tools/lxdclient"
 
20
)
 
21
 
 
22
type configSuite struct {
 
23
        lxd.BaseSuite
 
24
 
 
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
        cfg, err := testing.ModelConfig(c).Apply(lxd.ConfigAttrs)
 
34
        c.Assert(err, jc.ErrorIsNil)
 
35
        s.config = cfg
 
36
}
 
37
 
 
38
func (s *configSuite) TestDefaults(c *gc.C) {
 
39
        cfg := lxd.NewBaseConfig(c)
 
40
        ecfg := lxd.NewConfig(cfg)
 
41
 
 
42
        values, extras := ecfg.Values(c)
 
43
        c.Assert(extras, gc.HasLen, 0)
 
44
 
 
45
        c.Check(values, jc.DeepEquals, lxd.ConfigValues{
 
46
                RemoteURL:  "",
 
47
                ClientCert: "",
 
48
                ClientKey:  "",
 
49
                ServerCert: "",
 
50
        })
 
51
}
 
52
 
 
53
func (s *configSuite) TestClientConfigLocal(c *gc.C) {
 
54
        cfg := lxd.NewBaseConfig(c)
 
55
        ecfg := lxd.NewConfig(cfg)
 
56
        values, _ := ecfg.Values(c)
 
57
        c.Assert(values.RemoteURL, gc.Equals, "")
 
58
 
 
59
        clientCfg, err := ecfg.ClientConfig()
 
60
        c.Assert(err, jc.ErrorIsNil)
 
61
 
 
62
        c.Check(clientCfg, jc.DeepEquals, lxdclient.Config{
 
63
                Remote: lxdclient.Remote{
 
64
                        Name:          "juju-remote",
 
65
                        Host:          "",
 
66
                        Protocol:      lxdclient.LXDProtocol,
 
67
                        Cert:          nil,
 
68
                        ServerPEMCert: "",
 
69
                },
 
70
        })
 
71
}
 
72
 
 
73
func (s *configSuite) TestClientConfigNonLocal(c *gc.C) {
 
74
        cfg := lxd.NewBaseConfig(c)
 
75
        ecfg := lxd.NewConfig(cfg)
 
76
        ecfg = ecfg.Apply(c, map[string]interface{}{
 
77
                "remote-url":  "10.0.0.1",
 
78
                "client-cert": "<a valid x.509 cert>",
 
79
                "client-key":  "<a valid x.509 key>",
 
80
                "server-cert": "<a valid x.509 server cert>",
 
81
        })
 
82
 
 
83
        clientCfg, err := ecfg.ClientConfig()
 
84
        c.Assert(err, jc.ErrorIsNil)
 
85
 
 
86
        c.Check(clientCfg, jc.DeepEquals, lxdclient.Config{
 
87
                Remote: lxdclient.Remote{
 
88
                        Name:     "juju-remote",
 
89
                        Host:     "10.0.0.1",
 
90
                        Protocol: lxdclient.LXDProtocol,
 
91
                        Cert: &lxdclient.Cert{
 
92
                                Name:    fmt.Sprintf("juju cert for env %q", s.config.Name()),
 
93
                                CertPEM: []byte("<a valid x.509 cert>"),
 
94
                                KeyPEM:  []byte("<a valid x.509 key>"),
 
95
                        },
 
96
                        ServerPEMCert: "<a valid x.509 server cert>",
 
97
                },
 
98
        })
 
99
}
 
100
 
 
101
func (s *configSuite) TestUpdateForClientConfigLocal(c *gc.C) {
 
102
        cfg := lxd.NewBaseConfig(c)
 
103
        ecfg := lxd.NewConfig(cfg)
 
104
 
 
105
        clientCfg, err := ecfg.ClientConfig()
 
106
        c.Assert(err, jc.ErrorIsNil)
 
107
        updated, err := ecfg.UpdateForClientConfig(clientCfg)
 
108
        c.Assert(err, jc.ErrorIsNil)
 
109
 
 
110
        values, extras := updated.Values(c)
 
111
        c.Assert(extras, gc.HasLen, 0)
 
112
 
 
113
        c.Check(values, jc.DeepEquals, lxd.ConfigValues{
 
114
                RemoteURL:  "",
 
115
                ClientCert: "",
 
116
                ClientKey:  "",
 
117
                ServerCert: "",
 
118
        })
 
119
}
 
120
 
 
121
func (s *configSuite) TestUpdateForClientConfigNonLocal(c *gc.C) {
 
122
        cfg := lxd.NewBaseConfig(c)
 
123
        ecfg := lxd.NewConfig(cfg)
 
124
        ecfg = ecfg.Apply(c, map[string]interface{}{
 
125
                "remote-url":  "10.0.0.1",
 
126
                "client-cert": "<a valid x.509 cert>",
 
127
                "client-key":  "<a valid x.509 key>",
 
128
                "server-cert": "<a valid x.509 server cert>",
 
129
        })
 
130
 
 
131
        before, extras := ecfg.Values(c)
 
132
        c.Assert(extras, gc.HasLen, 0)
 
133
 
 
134
        clientCfg, err := ecfg.ClientConfig()
 
135
        c.Assert(err, jc.ErrorIsNil)
 
136
        updated, err := ecfg.UpdateForClientConfig(clientCfg)
 
137
        c.Assert(err, jc.ErrorIsNil)
 
138
 
 
139
        after, extras := updated.Values(c)
 
140
        c.Assert(extras, gc.HasLen, 0)
 
141
 
 
142
        c.Check(before, jc.DeepEquals, lxd.ConfigValues{
 
143
                RemoteURL:  "10.0.0.1",
 
144
                ClientCert: "<a valid x.509 cert>",
 
145
                ClientKey:  "<a valid x.509 key>",
 
146
                ServerCert: "<a valid x.509 server cert>",
 
147
        })
 
148
        c.Check(after, jc.DeepEquals, lxd.ConfigValues{
 
149
                RemoteURL:  "10.0.0.1",
 
150
                ClientCert: "<a valid x.509 cert>",
 
151
                ClientKey:  "<a valid x.509 key>",
 
152
                ServerCert: "<a valid x.509 server cert>",
 
153
        })
 
154
}
 
155
 
 
156
func (s *configSuite) TestUpdateForClientConfigGeneratedCert(c *gc.C) {
 
157
        cfg := lxd.NewBaseConfig(c)
 
158
        ecfg := lxd.NewConfig(cfg)
 
159
        ecfg = ecfg.Apply(c, map[string]interface{}{
 
160
                "remote-url":  "10.0.0.1",
 
161
                "client-cert": "",
 
162
                "client-key":  "",
 
163
                "server-cert": "",
 
164
        })
 
165
 
 
166
        before, extras := ecfg.Values(c)
 
167
        c.Assert(extras, gc.HasLen, 0)
 
168
 
 
169
        clientCfg, err := ecfg.ClientConfig()
 
170
        c.Assert(err, jc.ErrorIsNil)
 
171
        updated, err := ecfg.UpdateForClientConfig(clientCfg)
 
172
        c.Assert(err, jc.ErrorIsNil)
 
173
 
 
174
        after, extras := updated.Values(c)
 
175
        c.Assert(extras, gc.HasLen, 0)
 
176
 
 
177
        c.Check(before, jc.DeepEquals, lxd.ConfigValues{
 
178
                RemoteURL:  "10.0.0.1",
 
179
                ClientCert: "",
 
180
                ClientKey:  "",
 
181
                ServerCert: "",
 
182
        })
 
183
        after.CheckCert(c)
 
184
        after.ClientCert = ""
 
185
        after.ClientKey = ""
 
186
        after.ServerCert = ""
 
187
        c.Check(after, jc.DeepEquals, lxd.ConfigValues{
 
188
                RemoteURL:  "10.0.0.1",
 
189
                ClientCert: "",
 
190
                ClientKey:  "",
 
191
                ServerCert: "",
 
192
        })
 
193
}
 
194
 
 
195
// TODO(ericsnow) Each test only deals with a single field, so having
 
196
// multiple values in insert and remove (in configTestSpec) is a little
 
197
// misleading and unecessary.
 
198
 
 
199
// configTestSpec defines a subtest to run in a table driven test.
 
200
type configTestSpec struct {
 
201
        // info describes the subtest.
 
202
        info string
 
203
        // insert holds attrs that should be merged into the config.
 
204
        insert testing.Attrs
 
205
        // remove has the names of attrs that should be removed.
 
206
        remove []string
 
207
        // expect defines the expected attributes in a success case.
 
208
        expect testing.Attrs
 
209
        // err is the error message to expect in a failure case.
 
210
        err string
 
211
}
 
212
 
 
213
func (ts configTestSpec) checkSuccess(c *gc.C, value interface{}, err error) {
 
214
        if !c.Check(err, jc.ErrorIsNil) {
 
215
                return
 
216
        }
 
217
 
 
218
        var cfg *config.Config
 
219
        switch typed := value.(type) {
 
220
        case *config.Config:
 
221
                cfg = typed
 
222
        case environs.Environ:
 
223
                cfg = typed.Config()
 
224
        }
 
225
 
 
226
        attrs := cfg.AllAttrs()
 
227
        for field, value := range ts.expect {
 
228
                c.Check(attrs[field], gc.Equals, value)
 
229
        }
 
230
}
 
231
 
 
232
func (ts configTestSpec) checkFailure(c *gc.C, err error, msg string) {
 
233
        c.Check(err, gc.ErrorMatches, msg+": "+ts.err)
 
234
}
 
235
 
 
236
func (ts configTestSpec) checkAttrs(c *gc.C, attrs map[string]interface{}, cfg *config.Config) {
 
237
        for field, expected := range cfg.UnknownAttrs() {
 
238
                value := attrs[field]
 
239
                c.Check(value, gc.Equals, expected)
 
240
        }
 
241
}
 
242
 
 
243
func (ts configTestSpec) attrs() testing.Attrs {
 
244
        attrs := lxd.ConfigAttrs
 
245
        return attrs.Merge(ts.insert).Delete(ts.remove...)
 
246
}
 
247
 
 
248
func (ts configTestSpec) newConfig(c *gc.C) *config.Config {
 
249
        attrs := ts.attrs()
 
250
        cfg, err := testing.ModelConfig(c).Apply(attrs)
 
251
        c.Assert(err, jc.ErrorIsNil)
 
252
        return cfg
 
253
}
 
254
 
 
255
func (ts configTestSpec) fixCfg(c *gc.C, cfg *config.Config) *config.Config {
 
256
        fixes := make(map[string]interface{})
 
257
 
 
258
        // Set changed values.
 
259
        fixes = updateAttrs(fixes, ts.insert)
 
260
 
 
261
        newCfg, err := cfg.Apply(fixes)
 
262
        c.Assert(err, jc.ErrorIsNil)
 
263
        return newCfg
 
264
}
 
265
 
 
266
func updateAttrs(attrs, updates testing.Attrs) testing.Attrs {
 
267
        updated := make(testing.Attrs, len(attrs))
 
268
        for k, v := range attrs {
 
269
                updated[k] = v
 
270
        }
 
271
        for k, v := range updates {
 
272
                updated[k] = v
 
273
        }
 
274
        return updated
 
275
}
 
276
 
 
277
var newConfigTests = []configTestSpec{{
 
278
        info:   "remote-url is optional",
 
279
        remove: []string{"remote-url"},
 
280
        expect: testing.Attrs{"remote-url": ""},
 
281
}, {
 
282
        info:   "remote-url can be empty",
 
283
        insert: testing.Attrs{"remote-url": ""},
 
284
        expect: testing.Attrs{"remote-url": ""},
 
285
}, {
 
286
        info:   "client-cert is optional",
 
287
        remove: []string{"client-cert"},
 
288
        expect: testing.Attrs{"client-cert": ""},
 
289
}, {
 
290
        info:   "client-cert can be empty",
 
291
        insert: testing.Attrs{"client-cert": ""},
 
292
        expect: testing.Attrs{"client-cert": ""},
 
293
}, {
 
294
        info:   "client-key is optional",
 
295
        remove: []string{"client-key"},
 
296
        expect: testing.Attrs{"client-key": ""},
 
297
}, {
 
298
        info:   "client-key can be empty",
 
299
        insert: testing.Attrs{"client-key": ""},
 
300
        expect: testing.Attrs{"client-key": ""},
 
301
}, {
 
302
        info:   "server-cert is optional",
 
303
        remove: []string{"server-cert"},
 
304
        expect: testing.Attrs{"server-cert": ""},
 
305
}, {
 
306
        info:   "unknown field is not touched",
 
307
        insert: testing.Attrs{"unknown-field": 12345},
 
308
        expect: testing.Attrs{"unknown-field": 12345},
 
309
}}
 
310
 
 
311
func (s *configSuite) TestNewModelConfig(c *gc.C) {
 
312
        // TODO(ericsnow) Move to a functional suite.
 
313
        if !s.IsRunningLocally(c) {
 
314
                c.Skip("LXD not running locally")
 
315
        }
 
316
 
 
317
        // TODO(redir): Remove after wily or in yakkety.
 
318
        skipIfWily(c)
 
319
 
 
320
        for i, test := range newConfigTests {
 
321
                c.Logf("test %d: %s", i, test.info)
 
322
 
 
323
                testConfig := test.newConfig(c)
 
324
                environ, err := environs.New(environs.OpenParams{lxdCloudSpec(), testConfig})
 
325
 
 
326
                // Check the result
 
327
                if test.err != "" {
 
328
                        test.checkFailure(c, err, "invalid config")
 
329
                } else {
 
330
                        test.checkSuccess(c, environ, err)
 
331
                }
 
332
        }
 
333
}
 
334
 
 
335
// TODO(wwitzel3) refactor to provider_test file
 
336
func (s *configSuite) TestValidateNewConfig(c *gc.C) {
 
337
        for i, test := range newConfigTests {
 
338
                c.Logf("test %d: %s", i, test.info)
 
339
 
 
340
                testConfig := test.newConfig(c)
 
341
                validatedConfig, err := lxd.Provider.Validate(testConfig, nil)
 
342
 
 
343
                // Check the result
 
344
                if test.err != "" {
 
345
                        test.checkFailure(c, err, "invalid config")
 
346
                } else {
 
347
                        c.Check(validatedConfig, gc.NotNil)
 
348
                        test.checkSuccess(c, validatedConfig, err)
 
349
                }
 
350
        }
 
351
}
 
352
 
 
353
// TODO(wwitzel3) refactor to the provider_test file
 
354
func (s *configSuite) TestValidateOldConfig(c *gc.C) {
 
355
        for i, test := range newConfigTests {
 
356
                c.Logf("test %d: %s", i, test.info)
 
357
 
 
358
                oldcfg := test.newConfig(c)
 
359
                var err error
 
360
                oldcfg, err = lxd.Provider.Validate(oldcfg, nil)
 
361
                c.Assert(err, jc.ErrorIsNil)
 
362
                newcfg := test.fixCfg(c, s.config)
 
363
                expected := updateAttrs(lxd.ConfigAttrs, test.insert)
 
364
 
 
365
                // Validate the new config (relative to the old one) using the
 
366
                // provider.
 
367
                validatedConfig, err := lxd.Provider.Validate(newcfg, oldcfg)
 
368
 
 
369
                // Check the result.
 
370
                if test.err != "" {
 
371
                        test.checkFailure(c, err, "invalid base config")
 
372
                } else {
 
373
                        if !c.Check(err, jc.ErrorIsNil) {
 
374
                                continue
 
375
                        }
 
376
                        // We verify that Validate filled in the defaults
 
377
                        // appropriately.
 
378
                        c.Check(validatedConfig, gc.NotNil)
 
379
                        test.checkAttrs(c, expected, validatedConfig)
 
380
                }
 
381
        }
 
382
}
 
383
 
 
384
// TODO(ericsnow) Add tests for client-cert and client-key.
 
385
 
 
386
var changeConfigTests = []configTestSpec{{
 
387
        info:   "no change, no error",
 
388
        expect: lxd.ConfigAttrs,
 
389
}, {
 
390
        info:   "can insert unknown field",
 
391
        insert: testing.Attrs{"unknown": "ignoti"},
 
392
        expect: testing.Attrs{"unknown": "ignoti"},
 
393
}}
 
394
 
 
395
// TODO(wwitzel3) refactor this to the provider_test file.
 
396
func (s *configSuite) TestValidateChange(c *gc.C) {
 
397
        for i, test := range changeConfigTests {
 
398
                c.Logf("test %d: %s", i, test.info)
 
399
 
 
400
                testConfig := test.newConfig(c)
 
401
                validatedConfig, err := lxd.Provider.Validate(testConfig, s.config)
 
402
 
 
403
                // Check the result.
 
404
                if test.err != "" {
 
405
                        test.checkFailure(c, err, "invalid config change")
 
406
                } else {
 
407
                        test.checkSuccess(c, validatedConfig, err)
 
408
                }
 
409
        }
 
410
}
 
411
 
 
412
func (s *configSuite) TestSetConfig(c *gc.C) {
 
413
        // TODO(ericsnow) Move to a functional suite.
 
414
        if !s.IsRunningLocally(c) {
 
415
                c.Skip("LXD not running locally")
 
416
        }
 
417
 
 
418
        // TODO(redir): Remove after wily or in yakkety.
 
419
        skipIfWily(c)
 
420
 
 
421
        for i, test := range changeConfigTests {
 
422
                c.Logf("test %d: %s", i, test.info)
 
423
 
 
424
                environ, err := environs.New(environs.OpenParams{lxdCloudSpec(), s.config})
 
425
                c.Assert(err, jc.ErrorIsNil)
 
426
 
 
427
                testConfig := test.newConfig(c)
 
428
                err = environ.SetConfig(testConfig)
 
429
 
 
430
                // Check the result.
 
431
                if test.err != "" {
 
432
                        test.checkFailure(c, err, "invalid config change")
 
433
                        expected, err := lxd.Provider.Validate(s.config, nil)
 
434
                        c.Assert(err, jc.ErrorIsNil)
 
435
                        test.checkAttrs(c, environ.Config().AllAttrs(), expected)
 
436
                } else {
 
437
                        test.checkSuccess(c, environ.Config(), err)
 
438
                }
 
439
        }
 
440
}
 
441
 
 
442
func (*configSuite) TestSchema(c *gc.C) {
 
443
        fields := lxd.Provider.(interface {
 
444
                Schema() environschema.Fields
 
445
        }).Schema()
 
446
        // Check that all the fields defined in environs/config
 
447
        // are in the returned schema.
 
448
        globalFields, err := config.Schema(nil)
 
449
        c.Assert(err, gc.IsNil)
 
450
        for name, field := range globalFields {
 
451
                c.Check(fields[name], jc.DeepEquals, field)
 
452
        }
 
453
}
 
454
 
 
455
func lxdCloudSpec() environs.CloudSpec {
 
456
        return environs.CloudSpec{
 
457
                Type: "lxd",
 
458
                Name: "localhost",
 
459
        }
 
460
}