github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/model/defaultscommand_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  package model_test
     4  
     5  import (
     6  	"io/ioutil"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/juju/cmd"
    11  	"github.com/juju/cmd/cmdtesting"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/apiserver/common"
    16  	"github.com/juju/juju/cmd/juju/model"
    17  	"github.com/juju/juju/environs/config"
    18  	"github.com/juju/juju/jujuclient"
    19  	"github.com/juju/juju/testing"
    20  )
    21  
    22  type DefaultsCommandSuite struct {
    23  	fakeModelDefaultEnvSuite
    24  	store *jujuclient.MemStore
    25  }
    26  
    27  var _ = gc.Suite(&DefaultsCommandSuite{})
    28  
    29  func (s *DefaultsCommandSuite) SetUpTest(c *gc.C) {
    30  	s.fakeModelDefaultEnvSuite.SetUpTest(c)
    31  	s.store = jujuclient.NewMemStore()
    32  	s.store.CurrentControllerName = "controller"
    33  	s.store.Controllers["controller"] = jujuclient.ControllerDetails{}
    34  }
    35  
    36  func (s *DefaultsCommandSuite) run(c *gc.C, args ...string) (*cmd.Context, error) {
    37  	command := model.NewDefaultsCommandForTest(s.fakeAPIRoot, s.fakeDefaultsAPI, s.fakeCloudAPI, s.store)
    38  	return cmdtesting.RunCommand(c, command, args...)
    39  }
    40  
    41  func (s *DefaultsCommandSuite) TestDefaultsInit(c *gc.C) {
    42  	for i, test := range []struct {
    43  		description string
    44  		args        []string
    45  		errorMatch  string
    46  		nilErr      bool
    47  	}{{
    48  		// Test set
    49  		description: "test cannot set agent-version",
    50  		args:        []string{"agent-version=2.0.0"},
    51  		errorMatch:  `"agent-version" must be set via "upgrade-model"`,
    52  	}, {
    53  		description: "test set multiple keys",
    54  		args:        []string{"foo=bar", "baz=eggs"},
    55  		nilErr:      true,
    56  	}, {
    57  		// Test reset
    58  		description: "test empty args with reset fails",
    59  		args:        []string{"--reset"},
    60  		errorMatch:  "option needs an argument: --reset",
    61  	}, {
    62  		description: "test reset with positional arg interpereted as invalid region",
    63  		args:        []string{"--reset", "something", "weird"},
    64  		errorMatch:  `invalid region specified: "weird"`,
    65  	}, {
    66  		description: "test reset with valid region and duplicate key set",
    67  		args:        []string{"--reset", "something", "dummy-region", "something=weird"},
    68  		errorMatch:  `key "something" cannot be both set and unset in the same command`,
    69  	}, {
    70  		description: "test reset with valid region and extra positional arg",
    71  		args:        []string{"--reset", "something", "dummy-region", "weird"},
    72  		errorMatch:  "cannot retrieve defaults for a region and reset attributes at the same time",
    73  	}, {
    74  		description: "test reset with valid region only",
    75  		args:        []string{"--reset", "foo", "dummy-region"},
    76  		nilErr:      true,
    77  	}, {
    78  		description: "test cannot reset agent version",
    79  		args:        []string{"--reset", "agent-version"},
    80  		errorMatch:  `"agent-version" cannot be reset`,
    81  	}, {
    82  		description: "test reset inits",
    83  		args:        []string{"--reset", "foo"},
    84  		nilErr:      true,
    85  	}, {
    86  		description: "test trailing reset fails",
    87  		args:        []string{"foo=bar", "--reset"},
    88  		errorMatch:  "option needs an argument: --reset",
    89  	}, {
    90  		description: "test reset and get init",
    91  		args:        []string{"--reset", "agent-version,b", "foo=bar"},
    92  		errorMatch:  `"agent-version" cannot be reset`,
    93  	}, {
    94  		description: "test reset with key=val fails",
    95  		args:        []string{"--reset", "foo=bar"},
    96  		errorMatch:  `--reset accepts a comma delimited set of keys "a,b,c", received: "foo=bar"`,
    97  	}, {
    98  		description: "test reset multiple with key=val fails",
    99  		args:        []string{"--reset", "a,foo=bar,b"},
   100  		errorMatch:  `--reset accepts a comma delimited set of keys "a,b,c", received: "foo=bar"`,
   101  	}, {
   102  		description: "test reset with two positional args fails expecting a region",
   103  		args:        []string{"--reset", "a", "b", "c"},
   104  		errorMatch:  `invalid region specified: "b"`,
   105  	}, {
   106  		description: "test reset with two positional args fails expecting a region reordered",
   107  		args:        []string{"a", "--reset", "b", "c"},
   108  		errorMatch:  `invalid region specified: "a"`,
   109  	}, {
   110  		description: "test multiple reset inits",
   111  		args:        []string{"--reset", "a", "--reset", "b"},
   112  		nilErr:      true,
   113  	}, {
   114  		description: "test multiple reset and set inits",
   115  		args:        []string{"--reset", "a", "b=c", "--reset", "d"},
   116  		nilErr:      true,
   117  	}, {
   118  		description: "test multiple reset with valid region inits",
   119  		args:        []string{"dummy-region", "--reset", "a", "--reset", "b"},
   120  		nilErr:      true,
   121  	}, {
   122  		description: "test multiple reset with two positional args fails expecting a region reordered",
   123  		args:        []string{"a", "--reset", "b", "--reset", "c", "d"},
   124  		errorMatch:  `invalid region specified: "a"`,
   125  	}, {
   126  		description: "test reset multiple with key=val fails",
   127  		args:        []string{"--reset", "a", "--reset", "b,foo=bar,c"},
   128  		errorMatch:  `--reset accepts a comma delimited set of keys "a,b,c", received: "foo=bar"`,
   129  	}, {
   130  		// test get
   131  		description: "test no args inits",
   132  		args:        nil,
   133  		nilErr:      true,
   134  	}, {
   135  		description: "one key arg inits",
   136  		args:        []string{"attr"},
   137  		nilErr:      true,
   138  	}, {
   139  		description: "test two key args fails",
   140  		args:        []string{"one", "two"},
   141  		errorMatch:  "can only retrieve defaults for one key or all",
   142  	}, {
   143  		description: "test multiple key args fails",
   144  		args:        []string{"one", "two", "three"},
   145  		errorMatch:  "can only retrieve defaults for one key or all",
   146  	}, {
   147  		description: "test valid region and one arg",
   148  		args:        []string{"dummy-region", "attr2"},
   149  		nilErr:      true,
   150  	}, {
   151  		description: "test valid region and no args",
   152  		args:        []string{"dummy-region"},
   153  		nilErr:      true,
   154  	}, {
   155  		// test cloud/region
   156  		description: "test invalid cloud fails",
   157  		args:        []string{"invalidCloud/invalidRegion", "one=two"},
   158  		errorMatch:  "Unknown cloud",
   159  	}, {
   160  		description: "test valid cloud with invalid region fails",
   161  		args:        []string{"dummy/invalidRegion", "one=two"},
   162  		errorMatch:  `invalid region specified: "dummy/invalidRegion"`,
   163  	}, {
   164  		description: "test no cloud with invalid region fails",
   165  		args:        []string{"invalidRegion", "one=two"},
   166  		errorMatch:  `invalid region specified: "invalidRegion"`,
   167  	}, {
   168  		description: "test valid region with set arg succeeds",
   169  		args:        []string{"dummy-region", "one=two"},
   170  		nilErr:      true,
   171  	}, {
   172  		description: "test valid region with set and reset succeeds",
   173  		args:        []string{"dummy-region", "one=two", "--reset", "three"},
   174  		nilErr:      true,
   175  	}, {
   176  		description: "test reset and set with extra key is interpereted as invalid region",
   177  		args:        []string{"--reset", "something,else", "invalidRegion", "is=weird"},
   178  		errorMatch:  `invalid region specified: "invalidRegion"`,
   179  	}, {
   180  		description: "test reset and set with valid region and extra key fails",
   181  		args:        []string{"--reset", "something,else", "dummy-region", "invalidkey", "is=weird"},
   182  		errorMatch:  "cannot set and retrieve default values simultaneously",
   183  	}, {
   184  		// test various invalid
   185  		description: "test too many positional args with reset",
   186  		args:        []string{"--reset", "a", "b", "c", "d"},
   187  		errorMatch:  "invalid input",
   188  	}, {
   189  		description: "test too many positional args with invalid region set",
   190  		args:        []string{"a", "a=b", "b", "c=d"},
   191  		errorMatch:  `invalid region specified: "a"`,
   192  	}, {
   193  		description: "test invalid positional args with set",
   194  		args:        []string{"a=b", "b", "c=d"},
   195  		errorMatch:  `.*(no such file or directory|cannot find the file specified).*`,
   196  	}, {
   197  		description: "test invalid positional args with set and trailing key",
   198  		args:        []string{"a=b", "c=d", "e"},
   199  		errorMatch:  "cannot set and retrieve default values simultaneously",
   200  	}, {
   201  		description: "test invalid positional args with valid region, set, reset",
   202  		args:        []string{"dummy-region", "a=b", "--reset", "c,d,", "e=f", "g"},
   203  		errorMatch:  "cannot set and retrieve default values simultaneously",
   204  	}, {
   205  		// Test some random orderings
   206  		description: "test invalid positional args with set, reset with trailing comman and split key=values",
   207  		args:        []string{"dummy-region", "a=b", "--reset", "c,d,", "e=f"},
   208  		nilErr:      true,
   209  	}, {
   210  		description: "test leading comma with reset",
   211  		args:        []string{"--reset", ",a,b"},
   212  		nilErr:      true,
   213  	}} {
   214  		c.Logf("test %d: %s", i, test.description)
   215  		_, err := s.run(c, test.args...)
   216  		if test.nilErr {
   217  			c.Check(err, jc.ErrorIsNil)
   218  			continue
   219  		}
   220  		c.Check(err, gc.ErrorMatches, test.errorMatch)
   221  	}
   222  }
   223  
   224  func (s *DefaultsCommandSuite) TestResetUnknownValueLogs(c *gc.C) {
   225  	ctx, err := s.run(c, "--reset", "attr,weird")
   226  	c.Assert(err, jc.ErrorIsNil)
   227  	expected := `key "weird" is not defined in the known model configuration: possible misspelling`
   228  	c.Check(c.GetTestLog(), jc.Contains, expected)
   229  	c.Check(cmdtesting.Stdout(ctx), jc.DeepEquals, "")
   230  }
   231  
   232  func (s *DefaultsCommandSuite) TestResetAttr(c *gc.C) {
   233  	ctx, err := s.run(c, "--reset", "attr,unknown")
   234  	c.Check(err, jc.ErrorIsNil)
   235  	c.Check(s.fakeDefaultsAPI.defaults, jc.DeepEquals, config.ModelDefaultAttributes{
   236  		"attr2": {Controller: "bar", Default: nil, Regions: []config.RegionDefaultValue{{
   237  			Name:  "dummy-region",
   238  			Value: "dummy-value",
   239  		}, {
   240  			Name:  "another-region",
   241  			Value: "another-value",
   242  		}}},
   243  	})
   244  	c.Check(cmdtesting.Stdout(ctx), jc.DeepEquals, "")
   245  }
   246  
   247  func (s *DefaultsCommandSuite) TestResetRegionAttr(c *gc.C) {
   248  	ctx, err := s.run(c, "--reset", "attr,unknown", "dummy-region")
   249  	c.Check(err, jc.ErrorIsNil)
   250  	c.Check(s.fakeDefaultsAPI.defaults, jc.DeepEquals, config.ModelDefaultAttributes{
   251  		"attr2": {Controller: "bar", Default: nil, Regions: []config.RegionDefaultValue{{
   252  			Name:  "dummy-region",
   253  			Value: "dummy-value",
   254  		}, {
   255  			Name:  "another-region",
   256  			Value: "another-value",
   257  		}}},
   258  	})
   259  	c.Check(cmdtesting.Stdout(ctx), jc.DeepEquals, "")
   260  }
   261  
   262  func (s *DefaultsCommandSuite) TestResetBlockedError(c *gc.C) {
   263  	s.fakeDefaultsAPI.err = common.OperationBlockedError("TestBlockedError")
   264  	_, err := s.run(c, "--reset", "attr")
   265  	testing.AssertOperationWasBlocked(c, err, ".*TestBlockedError.*")
   266  }
   267  
   268  func (s *DefaultsCommandSuite) TestSetUnknownValueLogs(c *gc.C) {
   269  	_, err := s.run(c, "weird=foo")
   270  	c.Assert(err, jc.ErrorIsNil)
   271  	expected := `key "weird" is not defined in the known model configuration: possible misspelling`
   272  	c.Check(c.GetTestLog(), jc.Contains, expected)
   273  }
   274  
   275  func (s *DefaultsCommandSuite) TestSet(c *gc.C) {
   276  	_, err := s.run(c, "special=extra", "attr=baz")
   277  	c.Assert(err, jc.ErrorIsNil)
   278  	c.Assert(s.fakeDefaultsAPI.defaults, jc.DeepEquals, config.ModelDefaultAttributes{
   279  		"attr": {Controller: "baz", Default: nil, Regions: nil},
   280  		"attr2": {Controller: "bar", Default: nil, Regions: []config.RegionDefaultValue{{
   281  			Name:  "dummy-region",
   282  			Value: "dummy-value",
   283  		}, {
   284  			Name:  "another-region",
   285  			Value: "another-value",
   286  		}}},
   287  		"special": {Controller: "extra", Default: nil, Regions: nil},
   288  	})
   289  }
   290  
   291  func (s *DefaultsCommandSuite) TestSetFromFile(c *gc.C) {
   292  	tmpdir := c.MkDir()
   293  	configFile := filepath.Join(tmpdir, "config.yaml")
   294  	err := ioutil.WriteFile(configFile, []byte("special: extra\n"), 0644)
   295  	c.Assert(err, jc.ErrorIsNil)
   296  
   297  	_, err = s.run(c, configFile)
   298  	c.Assert(err, jc.ErrorIsNil)
   299  	c.Assert(s.fakeDefaultsAPI.defaults, jc.DeepEquals, config.ModelDefaultAttributes{
   300  		"attr": {Controller: nil, Default: "foo", Regions: nil},
   301  		"attr2": {Controller: "bar", Default: nil, Regions: []config.RegionDefaultValue{{
   302  			Name:  "dummy-region",
   303  			Value: "dummy-value",
   304  		}, {
   305  			Name:  "another-region",
   306  			Value: "another-value",
   307  		}}},
   308  		"special": {Controller: "extra", Default: nil, Regions: nil},
   309  	})
   310  }
   311  
   312  func (s *DefaultsCommandSuite) TestSetFromFileCombined(c *gc.C) {
   313  	tmpdir := c.MkDir()
   314  	configFile := filepath.Join(tmpdir, "config.yaml")
   315  	err := ioutil.WriteFile(configFile, []byte("special: extra\n"), 0644)
   316  	c.Assert(err, jc.ErrorIsNil)
   317  
   318  	_, err = s.run(c, configFile, "attr=baz")
   319  	c.Assert(err, jc.ErrorIsNil)
   320  	c.Assert(s.fakeDefaultsAPI.defaults, jc.DeepEquals, config.ModelDefaultAttributes{
   321  		"attr": {Controller: "baz", Default: nil, Regions: nil},
   322  		"attr2": {Controller: "bar", Default: nil, Regions: []config.RegionDefaultValue{{
   323  			Name:  "dummy-region",
   324  			Value: "dummy-value",
   325  		}, {
   326  			Name:  "another-region",
   327  			Value: "another-value",
   328  		}}},
   329  		"special": {Controller: "extra", Default: nil, Regions: nil},
   330  	})
   331  }
   332  
   333  func (s *DefaultsCommandSuite) TestSetConveysCloudRegion(c *gc.C) {
   334  	table := []struct {
   335  		input, cloud, region string
   336  	}{
   337  		{"", "", ""},
   338  		{"dummy-region", "dummy", "dummy-region"},
   339  		{"dummy/dummy-region", "dummy", "dummy-region"},
   340  		{"another-region", "dummy", "another-region"},
   341  	}
   342  	for i, test := range table {
   343  		c.Logf("test %d", i)
   344  		var err error
   345  		if test.input == "" {
   346  			_, err = s.run(c, "special=extra", "--reset", "attr")
   347  		} else {
   348  			_, err = s.run(c, test.input, "special=extra", "--reset", "attr")
   349  		}
   350  		c.Assert(err, jc.ErrorIsNil)
   351  		c.Assert(s.fakeDefaultsAPI.region, jc.DeepEquals, test.region)
   352  		c.Assert(s.fakeDefaultsAPI.cloud, jc.DeepEquals, test.cloud)
   353  	}
   354  }
   355  
   356  func (s *DefaultsCommandSuite) TestBlockedErrorOnSet(c *gc.C) {
   357  	s.fakeDefaultsAPI.err = common.OperationBlockedError("TestBlockedError")
   358  	_, err := s.run(c, "special=extra")
   359  	testing.AssertOperationWasBlocked(c, err, ".*TestBlockedError.*")
   360  }
   361  
   362  func (s *DefaultsCommandSuite) TestGetSingleValue(c *gc.C) {
   363  	context, err := s.run(c, "attr2")
   364  	c.Assert(err, jc.ErrorIsNil)
   365  
   366  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   367  	expected := "" +
   368  		"Attribute         Default        Controller\n" +
   369  		"attr2             -              bar\n" +
   370  		"  dummy-region    dummy-value    -\n" +
   371  		"  another-region  another-value  -"
   372  	c.Assert(output, gc.Equals, expected)
   373  }
   374  
   375  func (s *DefaultsCommandSuite) TestGetSingleValueJSON(c *gc.C) {
   376  	context, err := s.run(c, "--format=json", "attr2")
   377  	c.Assert(err, jc.ErrorIsNil)
   378  
   379  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   380  	c.Assert(output, gc.Equals,
   381  		`{"attr2":{"controller":"bar","regions":[{"name":"dummy-region","value":"dummy-value"},{"name":"another-region","value":"another-value"}]}}`)
   382  }
   383  
   384  func (s *DefaultsCommandSuite) TestGetAllValuesYAML(c *gc.C) {
   385  	context, err := s.run(c, "--format=yaml")
   386  	c.Assert(err, jc.ErrorIsNil)
   387  
   388  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   389  	expected := "" +
   390  		"attr:\n" +
   391  		"  default: foo\n" +
   392  		"attr2:\n" +
   393  		"  controller: bar\n" +
   394  		"  regions:\n" +
   395  		"  - name: dummy-region\n" +
   396  		"    value: dummy-value\n" +
   397  		"  - name: another-region\n" +
   398  		"    value: another-value"
   399  	c.Assert(output, gc.Equals, expected)
   400  }
   401  
   402  func (s *DefaultsCommandSuite) TestGetAllValuesJSON(c *gc.C) {
   403  	context, err := s.run(c, "--format=json")
   404  	c.Assert(err, jc.ErrorIsNil)
   405  
   406  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   407  	expected := `{"attr":{"default":"foo"},"attr2":{"controller":"bar","regions":[{"name":"dummy-region","value":"dummy-value"},{"name":"another-region","value":"another-value"}]}}`
   408  	c.Assert(output, gc.Equals, expected)
   409  }
   410  
   411  func (s *DefaultsCommandSuite) TestGetAllValuesTabular(c *gc.C) {
   412  	context, err := s.run(c)
   413  	c.Assert(err, jc.ErrorIsNil)
   414  
   415  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   416  	expected := "" +
   417  		"Attribute         Default        Controller\n" +
   418  		"attr              foo            -\n" +
   419  		"attr2             -              bar\n" +
   420  		"  dummy-region    dummy-value    -\n" +
   421  		"  another-region  another-value  -"
   422  	c.Assert(output, gc.Equals, expected)
   423  }
   424  
   425  func (s *DefaultsCommandSuite) TestGetRegionValuesTabular(c *gc.C) {
   426  	context, err := s.run(c, "dummy-region")
   427  	c.Assert(err, jc.ErrorIsNil)
   428  
   429  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   430  	expected := "" +
   431  		"Attribute       Default      Controller\n" +
   432  		"attr2           -            bar\n" +
   433  		"  dummy-region  dummy-value  -"
   434  	c.Assert(output, gc.Equals, expected)
   435  }
   436  
   437  func (s *DefaultsCommandSuite) TestGetRegionNoValuesTabular(c *gc.C) {
   438  	_, err := s.run(c, "--reset", "attr2")
   439  	c.Assert(err, jc.ErrorIsNil)
   440  	ctx, err := s.run(c, "dummy-region")
   441  	c.Assert(err, gc.ErrorMatches, `there are no default model values in region "dummy-region"`)
   442  	c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "")
   443  }
   444  
   445  func (s *DefaultsCommandSuite) TestGetRegionOneArgNoValuesTabular(c *gc.C) {
   446  	ctx, err := s.run(c, "dummy-region", "attr")
   447  	c.Assert(err, gc.ErrorMatches, `there are no default model values for "attr" in region "dummy-region"`)
   448  	c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "")
   449  }