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

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package controller_test
     5  
     6  import (
     7  	"io/ioutil"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/cmd/cmdtesting"
    13  	"github.com/juju/errors"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	"github.com/juju/juju/cmd/juju/controller"
    18  	jujucontroller "github.com/juju/juju/controller"
    19  )
    20  
    21  type ConfigSuite struct {
    22  	baseControllerSuite
    23  }
    24  
    25  var _ = gc.Suite(&ConfigSuite{})
    26  
    27  func (s *ConfigSuite) SetUpTest(c *gc.C) {
    28  	s.baseControllerSuite.SetUpTest(c)
    29  	s.createTestClientStore(c)
    30  }
    31  
    32  func (s *ConfigSuite) run(c *gc.C, args ...string) (*cmd.Context, error) {
    33  	return s.runWithAPI(c, &fakeControllerAPI{}, args...)
    34  }
    35  
    36  func (s *ConfigSuite) runWithAPI(c *gc.C, api *fakeControllerAPI, args ...string) (*cmd.Context, error) {
    37  	command := controller.NewConfigCommandForTest(api, s.store)
    38  	return cmdtesting.RunCommand(c, command, args...)
    39  }
    40  
    41  func (s *ConfigSuite) TestInit(c *gc.C) {
    42  	path := writeFile(c, "yamlfile", "")
    43  
    44  	tests := []struct {
    45  		desc string
    46  		args []string
    47  		err  string
    48  	}{{
    49  		desc: "no args",
    50  	}, {
    51  		desc: "get one key",
    52  		args: []string{"one"},
    53  	}, {
    54  		desc: "can't get two keys",
    55  		args: []string{"one", "two"},
    56  		err:  "can only retrieve a single value, or all values",
    57  	}, {
    58  		desc: "set one key",
    59  		args: []string{"key=value"},
    60  	}, {
    61  		desc: "set two keys",
    62  		args: []string{"key1=value", "key2=value"},
    63  	}, {
    64  		desc: "can't mix setting and getting",
    65  		args: []string{"key1=value", "hey2"},
    66  		err:  "can only retrieve a single value, or all values",
    67  	}, {
    68  		desc: "can mix setting with files",
    69  		args: []string{"key1=value", path},
    70  	}}
    71  	for i, test := range tests {
    72  		c.Logf("%d - %s", i, test.desc)
    73  		err := cmdtesting.InitCommand(controller.NewConfigCommandForTest(&fakeControllerAPI{}, s.store), test.args)
    74  		if test.err == "" {
    75  			c.Check(err, jc.ErrorIsNil)
    76  		} else {
    77  			c.Check(err, gc.ErrorMatches, test.err)
    78  		}
    79  	}
    80  }
    81  
    82  func (s *ConfigSuite) TestSingleValue(c *gc.C) {
    83  	context, err := s.run(c, "ca-cert")
    84  	c.Assert(err, jc.ErrorIsNil)
    85  
    86  	output := strings.TrimSpace(cmdtesting.Stdout(context))
    87  	c.Assert(output, gc.Equals, "multi\nline")
    88  }
    89  
    90  func (s *ConfigSuite) TestSingleValueJSON(c *gc.C) {
    91  	context, err := s.run(c, "--format=json", "controller-uuid")
    92  	c.Assert(err, jc.ErrorIsNil)
    93  
    94  	output := strings.TrimSpace(cmdtesting.Stdout(context))
    95  	c.Assert(output, gc.Equals, `"uuid"`)
    96  }
    97  
    98  func (s *ConfigSuite) TestAllValues(c *gc.C) {
    99  	context, err := s.run(c)
   100  	c.Assert(err, jc.ErrorIsNil)
   101  
   102  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   103  	expected := `
   104  Attribute                  Value
   105  api-port                   1234
   106  audit-log-exclude-methods  
   107  - Thing1
   108  - Thing2
   109  ca-cert  |-
   110    multi
   111    line
   112  controller-uuid  uuid`[1:]
   113  	c.Assert(output, gc.Equals, expected)
   114  }
   115  
   116  func (s *ConfigSuite) TestOneLineExcludeMethods(c *gc.C) {
   117  	var api fakeControllerAPI
   118  	api.config = map[string]interface{}{
   119  		"audit-log-exclude-methods": []string{"Actual.Size"},
   120  	}
   121  	context, err := s.runWithAPI(c, &api)
   122  	c.Assert(err, jc.ErrorIsNil)
   123  
   124  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   125  	expected := `
   126  Attribute                  Value
   127  audit-log-exclude-methods  Actual.Size`[1:]
   128  	c.Assert(output, gc.Equals, expected)
   129  }
   130  
   131  func (s *ConfigSuite) TestAllValuesJSON(c *gc.C) {
   132  	context, err := s.run(c, "--format=json")
   133  	c.Assert(err, jc.ErrorIsNil)
   134  
   135  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   136  	expected := `{"api-port":1234,"audit-log-exclude-methods":["Thing1","Thing2"],"ca-cert":"multi\nline","controller-uuid":"uuid"}`
   137  	c.Assert(output, gc.Equals, expected)
   138  }
   139  
   140  func (s *ConfigSuite) TestNonexistentValue(c *gc.C) {
   141  	context, err := s.run(c, "courtney-barnett")
   142  	c.Assert(err, gc.ErrorMatches, `key "courtney-barnett" not found in "mallards" controller`)
   143  
   144  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   145  	c.Assert(output, gc.Equals, "")
   146  }
   147  
   148  func (s *ConfigSuite) TestError(c *gc.C) {
   149  	command := controller.NewConfigCommandForTest(&fakeControllerAPI{err: errors.New("error")}, s.store)
   150  	_, err := cmdtesting.RunCommand(c, command)
   151  	c.Assert(err, gc.ErrorMatches, "error")
   152  }
   153  
   154  func (s *ConfigSuite) TestSettingKey(c *gc.C) {
   155  	var api fakeControllerAPI
   156  	context, err := s.runWithAPI(c, &api, "key1=value")
   157  	c.Assert(err, jc.ErrorIsNil)
   158  
   159  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   160  	c.Assert(output, gc.Equals, "")
   161  
   162  	c.Assert(api.values, gc.DeepEquals, map[string]interface{}{"key1": "value"})
   163  }
   164  
   165  func (s *ConfigSuite) TestSettingComplexKey(c *gc.C) {
   166  	var api fakeControllerAPI
   167  	context, err := s.runWithAPI(c, &api, "key1=[value1,value2]")
   168  	c.Assert(err, jc.ErrorIsNil)
   169  
   170  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   171  	c.Assert(output, gc.Equals, "")
   172  
   173  	c.Assert(api.values, gc.DeepEquals, map[string]interface{}{
   174  		"key1": []interface{}{"value1", "value2"},
   175  	})
   176  }
   177  
   178  func (s *ConfigSuite) TestSettingFromFile(c *gc.C) {
   179  	path := writeFile(c, "yaml", "key1: value\n")
   180  	var api fakeControllerAPI
   181  	context, err := s.runWithAPI(c, &api, path)
   182  	c.Assert(err, jc.ErrorIsNil)
   183  
   184  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   185  	c.Assert(output, gc.Equals, "")
   186  
   187  	c.Assert(api.values, gc.DeepEquals, map[string]interface{}{"key1": "value"})
   188  }
   189  
   190  func (s *ConfigSuite) TestSettingFromBothNoOverlap(c *gc.C) {
   191  	path := writeFile(c, "yaml", "key1: value\n")
   192  	var api fakeControllerAPI
   193  	context, err := s.runWithAPI(c, &api, path, "key2=123")
   194  	c.Assert(err, jc.ErrorIsNil)
   195  
   196  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   197  	c.Assert(output, gc.Equals, "")
   198  
   199  	c.Assert(api.values, gc.DeepEquals, map[string]interface{}{
   200  		"key1": "value",
   201  		"key2": 123,
   202  	})
   203  }
   204  
   205  func (s *ConfigSuite) TestSettingFromBothArgFirst(c *gc.C) {
   206  	path := writeFile(c, "yaml", "key1: value\n")
   207  	var api fakeControllerAPI
   208  	context, err := s.runWithAPI(c, &api, "key1=123", path)
   209  	c.Assert(err, jc.ErrorIsNil)
   210  
   211  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   212  	c.Assert(output, gc.Equals, "")
   213  
   214  	// This is a consequence of ConfigFlag reading input files first
   215  	// and then overlaying with values from args. It's surprising but
   216  	// probably not worth fixing - I don't think people will try to
   217  	// set an option from a file and then override it from an arg.
   218  	c.Assert(api.values, gc.DeepEquals, map[string]interface{}{
   219  		"key1": 123,
   220  	})
   221  }
   222  
   223  func (s *ConfigSuite) TestSettingFromBothFileFirst(c *gc.C) {
   224  	path := writeFile(c, "yaml", "key1: value\n")
   225  	var api fakeControllerAPI
   226  	context, err := s.runWithAPI(c, &api, path, "key1=123")
   227  	c.Assert(err, jc.ErrorIsNil)
   228  
   229  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   230  	c.Assert(output, gc.Equals, "")
   231  
   232  	c.Assert(api.values, gc.DeepEquals, map[string]interface{}{
   233  		"key1": 123,
   234  	})
   235  }
   236  
   237  func (s *ConfigSuite) TestSettingMultipleFiles(c *gc.C) {
   238  	path1 := writeFile(c, "yaml1", "key1: value\n")
   239  	path2 := writeFile(c, "yaml2", "key1: 123\n")
   240  
   241  	var api fakeControllerAPI
   242  	context, err := s.runWithAPI(c, &api, path1, path2)
   243  	c.Assert(err, jc.ErrorIsNil)
   244  
   245  	output := strings.TrimSpace(cmdtesting.Stdout(context))
   246  	c.Assert(output, gc.Equals, "")
   247  
   248  	c.Assert(api.values, gc.DeepEquals, map[string]interface{}{
   249  		"key1": 123,
   250  	})
   251  }
   252  
   253  func (s *ConfigSuite) TestErrorOnSetting(c *gc.C) {
   254  	api := fakeControllerAPI{err: errors.Errorf("kablooie")}
   255  	context, err := s.runWithAPI(c, &api, "key=value")
   256  	c.Assert(err, gc.ErrorMatches, "kablooie")
   257  
   258  	c.Assert(strings.TrimSpace(cmdtesting.Stdout(context)), gc.Equals, "")
   259  	c.Assert(api.values, gc.DeepEquals, map[string]interface{}{"key": "value"})
   260  }
   261  
   262  func writeFile(c *gc.C, name, content string) string {
   263  	path := filepath.Join(c.MkDir(), name)
   264  	err := ioutil.WriteFile(path, []byte(content), 0777)
   265  	c.Assert(err, jc.ErrorIsNil)
   266  	return path
   267  }
   268  
   269  type fakeControllerAPI struct {
   270  	err    error
   271  	config map[string]interface{}
   272  	values map[string]interface{}
   273  }
   274  
   275  func (f *fakeControllerAPI) Close() error {
   276  	return nil
   277  }
   278  
   279  func (f *fakeControllerAPI) ControllerConfig() (jujucontroller.Config, error) {
   280  	if f.err != nil {
   281  		return nil, f.err
   282  	}
   283  	var result map[string]interface{}
   284  	if f.config != nil {
   285  		result = f.config
   286  	} else {
   287  		result = map[string]interface{}{
   288  			"controller-uuid":           "uuid",
   289  			"api-port":                  1234,
   290  			"ca-cert":                   "multi\nline",
   291  			"audit-log-exclude-methods": []interface{}{"Thing1", "Thing2"},
   292  		}
   293  	}
   294  	return result, nil
   295  }
   296  
   297  func (f *fakeControllerAPI) ConfigSet(values map[string]interface{}) error {
   298  	f.values = values
   299  	return f.err
   300  }