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  }