github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/state/modelconfig_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"strings"
     8  
     9  	"github.com/juju/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	"github.com/juju/utils"
    12  	"github.com/juju/utils/set"
    13  	gc "gopkg.in/check.v1"
    14  	"gopkg.in/juju/names.v2"
    15  
    16  	"github.com/juju/juju/cloud"
    17  	"github.com/juju/juju/constraints"
    18  	"github.com/juju/juju/environs"
    19  	"github.com/juju/juju/environs/config"
    20  	"github.com/juju/juju/mongo/mongotest"
    21  	"github.com/juju/juju/state"
    22  	statetesting "github.com/juju/juju/state/testing"
    23  	"github.com/juju/juju/storage"
    24  	"github.com/juju/juju/testing"
    25  )
    26  
    27  type ModelConfigSuite struct {
    28  	ConnSuite
    29  }
    30  
    31  var _ = gc.Suite(&ModelConfigSuite{})
    32  
    33  func (s *ModelConfigSuite) SetUpTest(c *gc.C) {
    34  	s.ControllerInheritedConfig = map[string]interface{}{
    35  		"apt-mirror": "http://cloud-mirror",
    36  	}
    37  	s.RegionConfig = cloud.RegionConfig{
    38  		"nether-region": cloud.Attrs{
    39  			"apt-mirror": "http://nether-region-mirror",
    40  			"no-proxy":   "nether-proxy",
    41  		},
    42  		"dummy-region": cloud.Attrs{
    43  			"no-proxy":     "dummy-proxy",
    44  			"image-stream": "dummy-image-stream",
    45  			"whimsy-key":   "whimsy-value",
    46  		},
    47  	}
    48  	s.ConnSuite.SetUpTest(c)
    49  	s.policy.GetConstraintsValidator = func() (constraints.Validator, error) {
    50  		validator := constraints.NewValidator()
    51  		validator.RegisterConflicts([]string{constraints.InstanceType}, []string{constraints.Mem})
    52  		validator.RegisterUnsupported([]string{constraints.CpuPower})
    53  		return validator, nil
    54  	}
    55  	s.policy.GetProviderConfigSchemaSource = func() (config.ConfigSchemaSource, error) {
    56  		return &statetesting.MockConfigSchemaSource{}, nil
    57  	}
    58  }
    59  
    60  func (s *ModelConfigSuite) TestAdditionalValidation(c *gc.C) {
    61  	updateAttrs := map[string]interface{}{"logging-config": "juju=ERROR"}
    62  	configValidator1 := func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error {
    63  		c.Assert(updateAttrs, jc.DeepEquals, map[string]interface{}{"logging-config": "juju=ERROR"})
    64  		if lc, found := updateAttrs["logging-config"]; found && lc != "" {
    65  			return errors.New("cannot change logging-config")
    66  		}
    67  		return nil
    68  	}
    69  	removeAttrs := []string{"some-attr"}
    70  	configValidator2 := func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error {
    71  		c.Assert(removeAttrs, jc.DeepEquals, []string{"some-attr"})
    72  		for _, i := range removeAttrs {
    73  			if i == "some-attr" {
    74  				return errors.New("cannot remove some-attr")
    75  			}
    76  		}
    77  		return nil
    78  	}
    79  	configValidator3 := func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error {
    80  		return nil
    81  	}
    82  
    83  	err := s.State.UpdateModelConfig(updateAttrs, nil, configValidator1)
    84  	c.Assert(err, gc.ErrorMatches, "cannot change logging-config")
    85  	err = s.State.UpdateModelConfig(nil, removeAttrs, configValidator2)
    86  	c.Assert(err, gc.ErrorMatches, "cannot remove some-attr")
    87  	err = s.State.UpdateModelConfig(updateAttrs, nil, configValidator3)
    88  	c.Assert(err, jc.ErrorIsNil)
    89  }
    90  
    91  func (s *ModelConfigSuite) TestModelConfig(c *gc.C) {
    92  	attrs := map[string]interface{}{
    93  		"authorized-keys": "different-keys",
    94  		"arbitrary-key":   "shazam!",
    95  	}
    96  	cfg, err := s.State.ModelConfig()
    97  	c.Assert(err, jc.ErrorIsNil)
    98  	err = s.State.UpdateModelConfig(attrs, nil, nil)
    99  	c.Assert(err, jc.ErrorIsNil)
   100  	cfg, err = cfg.Apply(attrs)
   101  	c.Assert(err, jc.ErrorIsNil)
   102  	oldCfg, err := s.State.ModelConfig()
   103  	c.Assert(err, jc.ErrorIsNil)
   104  
   105  	c.Assert(oldCfg, jc.DeepEquals, cfg)
   106  }
   107  
   108  func (s *ModelConfigSuite) TestComposeNewModelConfig(c *gc.C) {
   109  	attrs := map[string]interface{}{
   110  		"authorized-keys": "different-keys",
   111  		"arbitrary-key":   "shazam!",
   112  		"uuid":            testing.ModelTag.Id(),
   113  		"type":            "dummy",
   114  		"name":            "test",
   115  		"resource-tags":   map[string]string{"a": "b", "c": "d"},
   116  	}
   117  
   118  	cfgAttrs, err := s.State.ComposeNewModelConfig(
   119  		attrs, &environs.RegionSpec{
   120  			Cloud:  "dummy",
   121  			Region: "dummy-region"})
   122  	c.Assert(err, jc.ErrorIsNil)
   123  	expectedCfg, err := config.New(config.UseDefaults, attrs)
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	expected := expectedCfg.AllAttrs()
   126  	expected["apt-mirror"] = "http://cloud-mirror"
   127  	expected["providerAttr"] = "vulch"
   128  	expected["whimsy-key"] = "whimsy-value"
   129  	expected["image-stream"] = "dummy-image-stream"
   130  	expected["no-proxy"] = "dummy-proxy"
   131  	// config.New() adds logging-config so remove it.
   132  	expected["logging-config"] = ""
   133  	c.Assert(cfgAttrs, jc.DeepEquals, expected)
   134  }
   135  
   136  func (s *ModelConfigSuite) TestComposeNewModelConfigRegionMisses(c *gc.C) {
   137  	attrs := map[string]interface{}{
   138  		"authorized-keys": "different-keys",
   139  		"arbitrary-key":   "shazam!",
   140  		"uuid":            testing.ModelTag.Id(),
   141  		"type":            "dummy",
   142  		"name":            "test",
   143  		"resource-tags":   map[string]string{"a": "b", "c": "d"},
   144  	}
   145  	rspec := &environs.RegionSpec{Cloud: "dummy", Region: "dummy-region"}
   146  	cfgAttrs, err := s.State.ComposeNewModelConfig(attrs, rspec)
   147  	c.Assert(err, jc.ErrorIsNil)
   148  	expectedCfg, err := config.New(config.UseDefaults, attrs)
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	expected := expectedCfg.AllAttrs()
   151  	expected["apt-mirror"] = "http://cloud-mirror"
   152  	expected["providerAttr"] = "vulch"
   153  	expected["whimsy-key"] = "whimsy-value"
   154  	expected["no-proxy"] = "dummy-proxy"
   155  	expected["image-stream"] = "dummy-image-stream"
   156  	// config.New() adds logging-config so remove it.
   157  	expected["logging-config"] = ""
   158  	c.Assert(cfgAttrs, jc.DeepEquals, expected)
   159  }
   160  
   161  func (s *ModelConfigSuite) TestComposeNewModelConfigRegionInherits(c *gc.C) {
   162  	attrs := map[string]interface{}{
   163  		"authorized-keys": "different-keys",
   164  		"arbitrary-key":   "shazam!",
   165  		"uuid":            testing.ModelTag.Id(),
   166  		"type":            "dummy",
   167  		"name":            "test",
   168  		"resource-tags":   map[string]string{"a": "b", "c": "d"},
   169  	}
   170  	rspec := &environs.RegionSpec{Cloud: "dummy", Region: "nether-region"}
   171  	cfgAttrs, err := s.State.ComposeNewModelConfig(attrs, rspec)
   172  	c.Assert(err, jc.ErrorIsNil)
   173  	expectedCfg, err := config.New(config.UseDefaults, attrs)
   174  	c.Assert(err, jc.ErrorIsNil)
   175  	expected := expectedCfg.AllAttrs()
   176  	expected["no-proxy"] = "nether-proxy"
   177  	expected["apt-mirror"] = "http://nether-region-mirror"
   178  	expected["providerAttr"] = "vulch"
   179  	// config.New() adds logging-config so remove it.
   180  	expected["logging-config"] = ""
   181  	c.Assert(cfgAttrs, jc.DeepEquals, expected)
   182  }
   183  
   184  func (s *ModelConfigSuite) TestUpdateModelConfigRejectsControllerConfig(c *gc.C) {
   185  	updateAttrs := map[string]interface{}{"api-port": 1234}
   186  	err := s.State.UpdateModelConfig(updateAttrs, nil, nil)
   187  	c.Assert(err, gc.ErrorMatches, `cannot set controller attribute "api-port" on a model`)
   188  }
   189  
   190  func (s *ModelConfigSuite) TestUpdateModelConfigRemoveInherited(c *gc.C) {
   191  	attrs := map[string]interface{}{
   192  		"apt-mirror":    "http://different-mirror", // controller
   193  		"arbitrary-key": "shazam!",
   194  		"providerAttr":  "beef", // provider
   195  		"whimsy-key":    "eggs", // region
   196  	}
   197  	err := s.State.UpdateModelConfig(attrs, nil, nil)
   198  	c.Assert(err, jc.ErrorIsNil)
   199  
   200  	err = s.State.UpdateModelConfig(nil, []string{"apt-mirror", "arbitrary-key", "providerAttr", "whimsy-key"}, nil)
   201  	c.Assert(err, jc.ErrorIsNil)
   202  	cfg, err := s.State.ModelConfig()
   203  	c.Assert(err, jc.ErrorIsNil)
   204  	allAttrs := cfg.AllAttrs()
   205  	c.Assert(allAttrs["apt-mirror"], gc.Equals, "http://cloud-mirror")
   206  	c.Assert(allAttrs["providerAttr"], gc.Equals, "vulch")
   207  	c.Assert(allAttrs["whimsy-key"], gc.Equals, "whimsy-value")
   208  	_, ok := allAttrs["arbitrary-key"]
   209  	c.Assert(ok, jc.IsFalse)
   210  }
   211  
   212  func (s *ModelConfigSuite) TestUpdateModelConfigCoerce(c *gc.C) {
   213  	attrs := map[string]interface{}{
   214  		"resource-tags": map[string]string{"a": "b", "c": "d"},
   215  	}
   216  	err := s.State.UpdateModelConfig(attrs, nil, nil)
   217  	c.Assert(err, jc.ErrorIsNil)
   218  
   219  	modelSettings, err := s.State.ReadSettings(state.SettingsC, state.ModelGlobalKey)
   220  	c.Assert(err, jc.ErrorIsNil)
   221  	expectedTags := map[string]string{"a": "b", "c": "d"}
   222  	tagsStr := config.CoerceForStorage(modelSettings.Map())["resource-tags"].(string)
   223  	tagItems := strings.Split(tagsStr, " ")
   224  	tagsMap := make(map[string]string)
   225  	for _, kv := range tagItems {
   226  		parts := strings.Split(kv, "=")
   227  		tagsMap[parts[0]] = parts[1]
   228  	}
   229  	c.Assert(tagsMap, gc.DeepEquals, expectedTags)
   230  
   231  	cfg, err := s.State.ModelConfig()
   232  	c.Assert(err, jc.ErrorIsNil)
   233  	c.Assert(cfg.AllAttrs()["resource-tags"], gc.DeepEquals, expectedTags)
   234  }
   235  
   236  func (s *ModelConfigSuite) TestUpdateModelConfigPreferredOverRemove(c *gc.C) {
   237  	attrs := map[string]interface{}{
   238  		"apt-mirror":    "http://different-mirror", // controller
   239  		"arbitrary-key": "shazam!",
   240  		"providerAttr":  "beef", // provider
   241  	}
   242  	err := s.State.UpdateModelConfig(attrs, nil, nil)
   243  	c.Assert(err, jc.ErrorIsNil)
   244  
   245  	err = s.State.UpdateModelConfig(map[string]interface{}{
   246  		"apt-mirror":   "http://another-mirror",
   247  		"providerAttr": "pork",
   248  	}, []string{"apt-mirror", "arbitrary-key"}, nil)
   249  	c.Assert(err, jc.ErrorIsNil)
   250  	cfg, err := s.State.ModelConfig()
   251  	c.Assert(err, jc.ErrorIsNil)
   252  	allAttrs := cfg.AllAttrs()
   253  	c.Assert(allAttrs["apt-mirror"], gc.Equals, "http://another-mirror")
   254  	c.Assert(allAttrs["providerAttr"], gc.Equals, "pork")
   255  	_, ok := allAttrs["arbitrary-key"]
   256  	c.Assert(ok, jc.IsFalse)
   257  }
   258  
   259  type ModelConfigSourceSuite struct {
   260  	ConnSuite
   261  }
   262  
   263  var _ = gc.Suite(&ModelConfigSourceSuite{})
   264  
   265  func (s *ModelConfigSourceSuite) SetUpTest(c *gc.C) {
   266  	s.ControllerInheritedConfig = map[string]interface{}{
   267  		"apt-mirror": "http://cloud-mirror",
   268  		"http-proxy": "http://proxy",
   269  	}
   270  	s.RegionConfig = cloud.RegionConfig{
   271  		"dummy-region": cloud.Attrs{
   272  			"apt-mirror": "http://dummy-mirror",
   273  			"no-proxy":   "dummy-proxy",
   274  		},
   275  	}
   276  	s.ConnSuite.SetUpTest(c)
   277  
   278  	localControllerSettings, err := s.State.ReadSettings(state.GlobalSettingsC, state.ControllerInheritedSettingsGlobalKey)
   279  	c.Assert(err, jc.ErrorIsNil)
   280  	localControllerSettings.Set("apt-mirror", "http://mirror")
   281  	_, err = localControllerSettings.Write()
   282  	c.Assert(err, jc.ErrorIsNil)
   283  }
   284  
   285  func (s *ModelConfigSourceSuite) TestModelConfigWhenSetOverridesControllerValue(c *gc.C) {
   286  	attrs := map[string]interface{}{
   287  		"authorized-keys": "different-keys",
   288  		"apt-mirror":      "http://anothermirror",
   289  	}
   290  	err := s.State.UpdateModelConfig(attrs, nil, nil)
   291  	c.Assert(err, jc.ErrorIsNil)
   292  
   293  	cfg, err := s.State.ModelConfig()
   294  	c.Assert(err, jc.ErrorIsNil)
   295  	c.Assert(cfg.AllAttrs()["apt-mirror"], gc.Equals, "http://anothermirror")
   296  }
   297  
   298  func (s *ModelConfigSourceSuite) TestControllerModelConfigForksControllerValue(c *gc.C) {
   299  	modelCfg, err := s.State.ModelConfig()
   300  	c.Assert(err, jc.ErrorIsNil)
   301  	c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://cloud-mirror")
   302  
   303  	// Change the local controller settings and ensure the model setting stays the same.
   304  	localControllerSettings, err := s.State.ReadSettings(state.GlobalSettingsC, state.ControllerInheritedSettingsGlobalKey)
   305  	c.Assert(err, jc.ErrorIsNil)
   306  	localControllerSettings.Set("apt-mirror", "http://anothermirror")
   307  	_, err = localControllerSettings.Write()
   308  	c.Assert(err, jc.ErrorIsNil)
   309  
   310  	modelCfg, err = s.State.ModelConfig()
   311  	c.Assert(err, jc.ErrorIsNil)
   312  	c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://cloud-mirror")
   313  }
   314  
   315  func (s *ModelConfigSourceSuite) TestNewModelConfigForksControllerValue(c *gc.C) {
   316  	uuid, err := utils.NewUUID()
   317  	c.Assert(err, jc.ErrorIsNil)
   318  	cfg := testing.CustomModelConfig(c, testing.Attrs{
   319  		"name": "another",
   320  		"uuid": uuid.String(),
   321  	})
   322  	owner := names.NewUserTag("test@remote")
   323  	_, st, err := s.State.NewModel(state.ModelArgs{
   324  		Config: cfg, Owner: owner, CloudName: "dummy", CloudRegion: "nether-region",
   325  		StorageProviderRegistry: storage.StaticProviderRegistry{},
   326  	})
   327  	c.Assert(err, jc.ErrorIsNil)
   328  	defer st.Close()
   329  
   330  	modelCfg, err := st.ModelConfig()
   331  	c.Assert(err, jc.ErrorIsNil)
   332  	c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://mirror")
   333  
   334  	// Change the local controller settings and ensure the model setting stays the same.
   335  	localCloudSettings, err := s.State.ReadSettings(state.GlobalSettingsC, state.ControllerInheritedSettingsGlobalKey)
   336  	c.Assert(err, jc.ErrorIsNil)
   337  	localCloudSettings.Set("apt-mirror", "http://anothermirror")
   338  	_, err = localCloudSettings.Write()
   339  	c.Assert(err, jc.ErrorIsNil)
   340  
   341  	modelCfg, err = st.ModelConfig()
   342  	c.Assert(err, jc.ErrorIsNil)
   343  	c.Assert(modelCfg.AllAttrs()["apt-mirror"], gc.Equals, "http://mirror")
   344  }
   345  
   346  func (s *ModelConfigSourceSuite) assertModelConfigValues(c *gc.C, modelCfg *config.Config, modelAttributes, controllerAttributes set.Strings) {
   347  	expectedValues := make(config.ConfigValues)
   348  	defaultAttributes := set.NewStrings()
   349  	for defaultAttr := range config.ConfigDefaults() {
   350  		defaultAttributes.Add(defaultAttr)
   351  	}
   352  	for attr, val := range modelCfg.AllAttrs() {
   353  		source := "model"
   354  		if defaultAttributes.Contains(attr) {
   355  			source = "default"
   356  		}
   357  		if modelAttributes.Contains(attr) {
   358  			source = "model"
   359  		}
   360  		if controllerAttributes.Contains(attr) {
   361  			source = "controller"
   362  		}
   363  		expectedValues[attr] = config.ConfigValue{
   364  			Value:  val,
   365  			Source: source,
   366  		}
   367  	}
   368  	sources, err := s.State.ModelConfigValues()
   369  	c.Assert(err, jc.ErrorIsNil)
   370  	c.Assert(sources, jc.DeepEquals, expectedValues)
   371  }
   372  
   373  func (s *ModelConfigSourceSuite) TestModelConfigValues(c *gc.C) {
   374  	modelCfg, err := s.State.ModelConfig()
   375  	c.Assert(err, jc.ErrorIsNil)
   376  	modelAttributes := set.NewStrings("name", "apt-mirror", "logging-config", "authorized-keys", "resource-tags")
   377  	s.assertModelConfigValues(c, modelCfg, modelAttributes, set.NewStrings("http-proxy"))
   378  }
   379  
   380  func (s *ModelConfigSourceSuite) TestModelConfigUpdateSource(c *gc.C) {
   381  	attrs := map[string]interface{}{
   382  		"http-proxy": "http://anotherproxy",
   383  		"apt-mirror": "http://mirror",
   384  	}
   385  	err := s.State.UpdateModelConfig(attrs, nil, nil)
   386  	c.Assert(err, jc.ErrorIsNil)
   387  	modelCfg, err := s.State.ModelConfig()
   388  	c.Assert(err, jc.ErrorIsNil)
   389  	modelAttributes := set.NewStrings("name", "http-proxy", "logging-config", "authorized-keys", "resource-tags")
   390  	s.assertModelConfigValues(c, modelCfg, modelAttributes, set.NewStrings("apt-mirror"))
   391  }
   392  
   393  func (s *ModelConfigSourceSuite) TestModelConfigDefaults(c *gc.C) {
   394  	expectedValues := make(config.ModelDefaultAttributes)
   395  	for attr, val := range config.ConfigDefaults() {
   396  		expectedValues[attr] = config.AttributeDefaultValues{
   397  			Default: val,
   398  		}
   399  	}
   400  	ds := expectedValues["http-proxy"]
   401  	ds.Controller = "http://proxy"
   402  	expectedValues["http-proxy"] = ds
   403  
   404  	ds = expectedValues["apt-mirror"]
   405  	ds.Controller = "http://mirror"
   406  	ds.Regions = []config.RegionDefaultValue{{
   407  		Name:  "dummy-region",
   408  		Value: "http://dummy-mirror",
   409  	}}
   410  	expectedValues["apt-mirror"] = ds
   411  
   412  	ds = expectedValues["no-proxy"]
   413  	ds.Regions = []config.RegionDefaultValue{{
   414  		Name:  "dummy-region",
   415  		Value: "dummy-proxy"}}
   416  	expectedValues["no-proxy"] = ds
   417  
   418  	sources, err := s.State.ModelConfigDefaultValues()
   419  	c.Assert(err, jc.ErrorIsNil)
   420  	c.Assert(sources, jc.DeepEquals, expectedValues)
   421  }
   422  
   423  func (s *ModelConfigSourceSuite) TestUpdateModelConfigDefaults(c *gc.C) {
   424  	// Set up values that will be removed.
   425  	attrs := map[string]interface{}{
   426  		"http-proxy":  "http://http-proxy",
   427  		"https-proxy": "https://https-proxy",
   428  	}
   429  	err := s.State.UpdateModelConfigDefaultValues(attrs, nil, nil)
   430  	c.Assert(err, jc.ErrorIsNil)
   431  
   432  	attrs = map[string]interface{}{
   433  		"apt-mirror": "http://different-mirror",
   434  	}
   435  	err = s.State.UpdateModelConfigDefaultValues(attrs, []string{"http-proxy", "https-proxy"}, nil)
   436  	c.Assert(err, jc.ErrorIsNil)
   437  
   438  	info := statetesting.NewMongoInfo()
   439  	anotherState, err := state.Open(s.modelTag, s.State.ControllerTag(), info, mongotest.DialOpts(), state.NewPolicyFunc(nil))
   440  	c.Assert(err, jc.ErrorIsNil)
   441  	defer anotherState.Close()
   442  
   443  	cfg, err := anotherState.ModelConfigDefaultValues()
   444  	c.Assert(err, jc.ErrorIsNil)
   445  	expectedValues := make(config.ModelDefaultAttributes)
   446  	for attr, val := range config.ConfigDefaults() {
   447  		expectedValues[attr] = config.AttributeDefaultValues{
   448  			Default: val,
   449  		}
   450  	}
   451  	delete(expectedValues, "http-mirror")
   452  	delete(expectedValues, "https-mirror")
   453  	expectedValues["apt-mirror"] = config.AttributeDefaultValues{
   454  		Controller: "http://different-mirror",
   455  		Default:    "",
   456  		Regions: []config.RegionDefaultValue{{
   457  			Name:  "dummy-region",
   458  			Value: "http://dummy-mirror",
   459  		}}}
   460  	expectedValues["no-proxy"] = config.AttributeDefaultValues{
   461  		Default: "",
   462  		Regions: []config.RegionDefaultValue{{
   463  			Name:  "dummy-region",
   464  			Value: "dummy-proxy",
   465  		}}}
   466  	c.Assert(cfg, jc.DeepEquals, expectedValues)
   467  }
   468  
   469  func (s *ModelConfigSourceSuite) TestUpdateModelConfigRegionDefaults(c *gc.C) {
   470  	// The test env is setup with dummy/dummy-region having a no-proxy
   471  	// dummy-proxy value and nether-region with a nether-proxy value.
   472  	//
   473  	// First we change the no-proxy setting in dummy-region
   474  	attrs := map[string]interface{}{
   475  		"no-proxy": "changed-proxy",
   476  	}
   477  
   478  	rspec, err := environs.NewRegionSpec("dummy", "dummy-region")
   479  	c.Assert(err, jc.ErrorIsNil)
   480  
   481  	err = s.State.UpdateModelConfigDefaultValues(attrs, nil, rspec)
   482  	c.Assert(err, jc.ErrorIsNil)
   483  
   484  	// Then check in another state.
   485  	info := statetesting.NewMongoInfo()
   486  	anotherState, err := state.Open(s.modelTag, s.State.ControllerTag(), info, mongotest.DialOpts(), state.NewPolicyFunc(nil))
   487  	c.Assert(err, jc.ErrorIsNil)
   488  	defer anotherState.Close()
   489  
   490  	cfg, err := anotherState.ModelConfigDefaultValues()
   491  	c.Assert(err, jc.ErrorIsNil)
   492  	expectedValues := make(config.ModelDefaultAttributes)
   493  	for attr, val := range config.ConfigDefaults() {
   494  		expectedValues[attr] = config.AttributeDefaultValues{
   495  			Default: val,
   496  		}
   497  	}
   498  	expectedValues["http-proxy"] = config.AttributeDefaultValues{
   499  		Controller: "http://proxy",
   500  		Default:    "",
   501  	}
   502  	expectedValues["apt-mirror"] = config.AttributeDefaultValues{
   503  		Controller: "http://mirror",
   504  		Default:    "",
   505  		Regions: []config.RegionDefaultValue{{
   506  			Name:  "dummy-region",
   507  			Value: "http://dummy-mirror",
   508  		}}}
   509  	expectedValues["no-proxy"] = config.AttributeDefaultValues{
   510  		Default: "",
   511  		Regions: []config.RegionDefaultValue{{
   512  			Name:  "dummy-region",
   513  			Value: "changed-proxy",
   514  		}}}
   515  	c.Assert(cfg, jc.DeepEquals, expectedValues)
   516  
   517  	// remove the dummy-region setting
   518  	err = s.State.UpdateModelConfigDefaultValues(nil, []string{"no-proxy"}, rspec)
   519  
   520  	// and check again
   521  	cfg, err = anotherState.ModelConfigDefaultValues()
   522  	c.Assert(err, jc.ErrorIsNil)
   523  	cfg, err = anotherState.ModelConfigDefaultValues()
   524  	c.Assert(err, jc.ErrorIsNil)
   525  	expectedValues = make(config.ModelDefaultAttributes)
   526  	for attr, val := range config.ConfigDefaults() {
   527  		expectedValues[attr] = config.AttributeDefaultValues{
   528  			Default: val,
   529  		}
   530  	}
   531  	expectedValues["http-proxy"] = config.AttributeDefaultValues{
   532  		Controller: "http://proxy",
   533  		Default:    "",
   534  	}
   535  	expectedValues["apt-mirror"] = config.AttributeDefaultValues{
   536  		Controller: "http://mirror",
   537  		Default:    "",
   538  		Regions: []config.RegionDefaultValue{{
   539  			Name:  "dummy-region",
   540  			Value: "http://dummy-mirror",
   541  		}}}
   542  	c.Assert(cfg, jc.DeepEquals, expectedValues)
   543  }