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

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  package application_test
     4  
     5  import (
     6  	"bytes"
     7  	"io/ioutil"
     8  	"os"
     9  	"strings"
    10  	"unicode/utf8"
    11  
    12  	"github.com/juju/cmd"
    13  	"github.com/juju/cmd/cmdtesting"
    14  	"github.com/juju/errors"
    15  	jc "github.com/juju/testing/checkers"
    16  	"github.com/juju/utils"
    17  	gc "gopkg.in/check.v1"
    18  	goyaml "gopkg.in/yaml.v2"
    19  
    20  	"github.com/juju/juju/apiserver/common"
    21  	"github.com/juju/juju/cmd/juju/application"
    22  	"github.com/juju/juju/core/model"
    23  	"github.com/juju/juju/feature"
    24  	"github.com/juju/juju/jujuclient"
    25  	"github.com/juju/juju/jujuclient/jujuclienttesting"
    26  	coretesting "github.com/juju/juju/testing"
    27  )
    28  
    29  type configCommandSuite struct {
    30  	coretesting.FakeJujuXDGDataHomeSuite
    31  	dir                string
    32  	fake               *fakeApplicationAPI
    33  	store              jujuclient.ClientStore
    34  	defaultCharmValues map[string]interface{}
    35  	defaultAppValues   map[string]interface{}
    36  }
    37  
    38  var (
    39  	_ = gc.Suite(&configCommandSuite{})
    40  
    41  	validSetTestValue   = "a value with spaces\nand newline\nand UTF-8 characters: \U0001F604 / \U0001F44D"
    42  	invalidSetTestValue = "a value with an invalid UTF-8 sequence: " + string([]byte{0xFF, 0xFF})
    43  	yamlConfigValue     = "dummy-application:\n  skill-level: 9000\n  username: admin001\n\n"
    44  )
    45  
    46  var charmSettings = map[string]interface{}{
    47  	"multiline-value": map[string]interface{}{
    48  		"description": "Specifies multiline-value",
    49  		"type":        "string",
    50  		"value":       "The quick brown fox jumps over the lazy dog. \"The quick brown fox jumps over the lazy dog\" \"The quick brown fox jumps over the lazy dog\" ",
    51  	},
    52  	"title": map[string]interface{}{
    53  		"description": "Specifies title",
    54  		"type":        "string",
    55  		"value":       "Nearly There",
    56  	},
    57  	"skill-level": map[string]interface{}{
    58  		"description": "Specifies skill-level",
    59  		"value":       100,
    60  		"type":        "int",
    61  	},
    62  	"username": map[string]interface{}{
    63  		"description": "Specifies username",
    64  		"type":        "string",
    65  		"value":       "admin001",
    66  	},
    67  	"outlook": map[string]interface{}{
    68  		"description": "Specifies outlook",
    69  		"type":        "string",
    70  		"value":       "true",
    71  	},
    72  }
    73  
    74  var getTests = []struct {
    75  	application  string
    76  	useAppConfig bool
    77  	expected     map[string]interface{}
    78  }{
    79  	{
    80  		"dummy-application",
    81  		true,
    82  		map[string]interface{}{
    83  			"application": "dummy-application",
    84  			"charm":       "dummy",
    85  			"application-config": map[string]interface{}{
    86  				"juju-external-hostname": map[string]interface{}{
    87  					"description": "Specifies juju-external-hostname",
    88  					"type":        "string",
    89  					"value":       "ext-host",
    90  				},
    91  			},
    92  			"settings":                               charmSettings,
    93  			"changes will be targeted to generation": interface{}("current"),
    94  		},
    95  	}, {
    96  		"dummy-application",
    97  		false,
    98  		map[string]interface{}{
    99  			"application":                            "dummy-application",
   100  			"charm":                                  "dummy",
   101  			"settings":                               charmSettings,
   102  			"changes will be targeted to generation": interface{}("current"),
   103  		},
   104  	},
   105  }
   106  
   107  func (s *configCommandSuite) SetUpTest(c *gc.C) {
   108  	s.FakeJujuXDGDataHomeSuite.SetUpTest(c)
   109  	s.SetFeatureFlags(feature.Generations)
   110  
   111  	s.defaultCharmValues = map[string]interface{}{
   112  		"title":           "Nearly There",
   113  		"skill-level":     100,
   114  		"username":        "admin001",
   115  		"outlook":         "true",
   116  		"multiline-value": "The quick brown fox jumps over the lazy dog. \"The quick brown fox jumps over the lazy dog\" \"The quick brown fox jumps over the lazy dog\" ",
   117  	}
   118  	s.defaultAppValues = map[string]interface{}{
   119  		"juju-external-hostname": "ext-host",
   120  	}
   121  
   122  	s.fake = &fakeApplicationAPI{
   123  		generation:  model.GenerationCurrent,
   124  		name:        "dummy-application",
   125  		charmName:   "dummy",
   126  		charmValues: s.defaultCharmValues,
   127  		appValues:   s.defaultAppValues,
   128  		version:     6,
   129  	}
   130  
   131  	s.store = jujuclienttesting.MinimalStore()
   132  
   133  	s.dir = c.MkDir()
   134  	c.Assert(utf8.ValidString(validSetTestValue), jc.IsTrue)
   135  	c.Assert(utf8.ValidString(invalidSetTestValue), jc.IsFalse)
   136  	setupValueFile(c, s.dir, "valid.txt", validSetTestValue)
   137  	setupValueFile(c, s.dir, "invalid.txt", invalidSetTestValue)
   138  	setupBigFile(c, s.dir)
   139  	setupConfigFile(c, s.dir)
   140  }
   141  
   142  func (s *configCommandSuite) TestGetCommandInit(c *gc.C) {
   143  	// missing args
   144  	err := cmdtesting.InitCommand(application.NewConfigCommandForTest(s.fake, s.store), []string{})
   145  	c.Assert(err, gc.ErrorMatches, "no application name specified")
   146  }
   147  
   148  func (s *configCommandSuite) TestGetCommandInitWithApplication(c *gc.C) {
   149  	err := cmdtesting.InitCommand(application.NewConfigCommandForTest(s.fake, s.store), []string{"app"})
   150  	c.Assert(err, jc.ErrorIsNil)
   151  }
   152  
   153  func (s *configCommandSuite) TestGetCommandInitWithKey(c *gc.C) {
   154  	err := cmdtesting.InitCommand(application.NewConfigCommandForTest(s.fake, s.store), []string{"app", "key"})
   155  	c.Assert(err, jc.ErrorIsNil)
   156  }
   157  
   158  func (s *configCommandSuite) TestGetCommandInitWithGeneration(c *gc.C) {
   159  	err := cmdtesting.InitCommand(
   160  		application.NewConfigCommandForTest(s.fake, s.store), []string{"app", "key", "--generation", "current"})
   161  	c.Assert(err, jc.ErrorIsNil)
   162  }
   163  
   164  func (s *configCommandSuite) TestGetConfig(c *gc.C) {
   165  	s.SetFeatureFlags(feature.Generations)
   166  	for _, t := range getTests {
   167  		if !t.useAppConfig {
   168  			s.fake.appValues = nil
   169  		}
   170  		ctx := cmdtesting.Context(c)
   171  		code := cmd.Main(application.NewConfigCommandForTest(s.fake, s.store), ctx, []string{t.application})
   172  		c.Check(code, gc.Equals, 0)
   173  		c.Assert(ctx.Stderr.(*bytes.Buffer).String(), gc.Equals, "")
   174  		// round trip via goyaml to avoid being sucked into a quagmire of
   175  		// map[interface{}]interface{} vs map[string]interface{}. This is
   176  		// also required if we add json support to this command.
   177  		buf, err := goyaml.Marshal(t.expected)
   178  		c.Assert(err, jc.ErrorIsNil)
   179  		expected := make(map[string]interface{})
   180  		err = goyaml.Unmarshal(buf, &expected)
   181  		c.Assert(err, jc.ErrorIsNil)
   182  
   183  		actual := make(map[string]interface{})
   184  		err = goyaml.Unmarshal(ctx.Stdout.(*bytes.Buffer).Bytes(), &actual)
   185  		c.Assert(err, jc.ErrorIsNil)
   186  		c.Assert(actual, jc.DeepEquals, expected)
   187  	}
   188  }
   189  
   190  func (s *configCommandSuite) TestGetCharmConfigKey(c *gc.C) {
   191  	ctx := cmdtesting.Context(c)
   192  	code := cmd.Main(application.NewConfigCommandForTest(s.fake, s.store), ctx, []string{"dummy-application", "title"})
   193  	c.Check(code, gc.Equals, 0)
   194  	c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "")
   195  	c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "Nearly There")
   196  }
   197  
   198  func (s *configCommandSuite) TestGetCharmConfigKeyMultilineValue(c *gc.C) {
   199  	ctx := cmdtesting.Context(c)
   200  	code := cmd.Main(application.NewConfigCommandForTest(s.fake, s.store), ctx, []string{"dummy-application", "multiline-value"})
   201  	c.Check(code, gc.Equals, 0)
   202  	c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "")
   203  	c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "The quick brown fox jumps over the lazy dog. \"The quick brown fox jumps over the lazy dog\" \"The quick brown fox jumps over the lazy dog\" ")
   204  }
   205  
   206  func (s *configCommandSuite) TestGetCharmConfigKeyMultilineValueJSON(c *gc.C) {
   207  	ctx := cmdtesting.Context(c)
   208  	code := cmd.Main(application.NewConfigCommandForTest(s.fake, s.store), ctx, []string{"dummy-application", "multiline-value", "--format", "json"})
   209  	c.Check(code, gc.Equals, 0)
   210  	c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "")
   211  	c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "The quick brown fox jumps over the lazy dog. \"The quick brown fox jumps over the lazy dog\" \"The quick brown fox jumps over the lazy dog\" ")
   212  }
   213  
   214  func (s *configCommandSuite) TestGetAppConfigKey(c *gc.C) {
   215  	ctx := cmdtesting.Context(c)
   216  	code := cmd.Main(application.NewConfigCommandForTest(
   217  		s.fake, s.store), ctx, []string{"dummy-application", "juju-external-hostname"})
   218  	c.Check(code, gc.Equals, 0)
   219  	c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "")
   220  	c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "ext-host")
   221  }
   222  
   223  func (s *configCommandSuite) TestGetConfigKeyNotFound(c *gc.C) {
   224  	_, err := cmdtesting.RunCommand(c, application.NewConfigCommandForTest(s.fake, s.store), "dummy-application", "invalid")
   225  	c.Assert(err, gc.ErrorMatches, `key "invalid" not found in "dummy-application" application config or charm settings.`, gc.Commentf("details: %v", errors.Details(err)))
   226  }
   227  
   228  var setCommandInitErrorTests = []struct {
   229  	about       string
   230  	args        []string
   231  	expectError string
   232  }{{
   233  	about:       "no arguments",
   234  	expectError: "no application name specified",
   235  }, {
   236  	about:       "missing application name",
   237  	args:        []string{"name=foo"},
   238  	expectError: "no application name specified",
   239  }, {
   240  	about:       "--file path, but no application",
   241  	args:        []string{"--file", "testconfig.yaml"},
   242  	expectError: "no application name specified",
   243  }, {
   244  	about:       "--file and options specified",
   245  	args:        []string{"application", "--file", "testconfig.yaml", "bees="},
   246  	expectError: "cannot specify --file and key=value arguments simultaneously",
   247  }, {
   248  	about:       "--reset and no config name provided",
   249  	args:        []string{"application", "--reset"},
   250  	expectError: "option needs an argument: --reset",
   251  }, {
   252  	about:       "cannot set and retrieve simultaneously",
   253  	args:        []string{"application", "get", "set=value"},
   254  	expectError: "cannot set and retrieve values simultaneously",
   255  }, {
   256  	about:       "cannot reset and get simultaneously",
   257  	args:        []string{"application", "--reset", "reset", "get"},
   258  	expectError: "cannot reset and retrieve values simultaneously",
   259  }, {
   260  	about:       "invalid reset keys",
   261  	args:        []string{"application", "--reset", "reset,bad=key"},
   262  	expectError: `--reset accepts a comma delimited set of keys "a,b,c", received: "bad=key"`,
   263  }, {
   264  	about:       "init too many args fails",
   265  	args:        []string{"application", "key", "another"},
   266  	expectError: "can only retrieve a single value, or all values",
   267  }, {
   268  	about:       "--generation with no value",
   269  	args:        []string{"application", "key", "--generation"},
   270  	expectError: "option needs an argument: --generation",
   271  }, {
   272  	about:       "--generation with invalid value",
   273  	args:        []string{"application", "key", "--generation", "not-there"},
   274  	expectError: `generation option must be "current" or "next"`,
   275  }}
   276  
   277  func (s *configCommandSuite) TestSetCommandInitError(c *gc.C) {
   278  	testStore := jujuclienttesting.MinimalStore()
   279  	for i, test := range setCommandInitErrorTests {
   280  		c.Logf("test %d: %s", i, test.about)
   281  		cmd := application.NewConfigCommandForTest(s.fake, s.store)
   282  		cmd.SetClientStore(testStore)
   283  		err := cmdtesting.InitCommand(cmd, test.args)
   284  		c.Assert(err, gc.ErrorMatches, test.expectError)
   285  	}
   286  }
   287  
   288  func (s *configCommandSuite) TestSetCharmConfigSuccess(c *gc.C) {
   289  	s.assertSetSuccess(c, s.dir, []string{
   290  		"username=hello",
   291  		"outlook=hello@world.tld",
   292  	}, s.defaultAppValues, map[string]interface{}{
   293  		"username": "hello",
   294  		"outlook":  "hello@world.tld",
   295  	})
   296  	s.assertSetSuccess(c, s.dir, []string{
   297  		"username=hello=foo",
   298  	}, s.defaultAppValues, map[string]interface{}{
   299  		"username": "hello=foo",
   300  		"outlook":  "hello@world.tld",
   301  	})
   302  	s.assertSetSuccess(c, s.dir, []string{
   303  		"username=@valid.txt",
   304  	}, s.defaultAppValues, map[string]interface{}{
   305  		"username": validSetTestValue,
   306  		"outlook":  "hello@world.tld",
   307  	})
   308  	s.assertSetSuccess(c, s.dir, []string{
   309  		"username=",
   310  	}, s.defaultAppValues, map[string]interface{}{
   311  		"username": "",
   312  		"outlook":  "hello@world.tld",
   313  	})
   314  	s.assertSetSuccess(c, s.dir, []string{
   315  		"--generation",
   316  		"current",
   317  		"username=hello",
   318  		"outlook=hello@world.tld",
   319  	}, s.defaultAppValues, map[string]interface{}{
   320  		"username": "hello",
   321  		"outlook":  "hello@world.tld",
   322  	})
   323  
   324  	s.fake.generation = model.GenerationNext
   325  	s.assertSetSuccess(c, s.dir, []string{
   326  		"username=hello",
   327  		"outlook=hello@world.tld",
   328  		"--generation",
   329  		"next",
   330  	}, s.defaultAppValues, map[string]interface{}{
   331  		"username": "hello",
   332  		"outlook":  "hello@world.tld",
   333  	})
   334  }
   335  
   336  func (s *configCommandSuite) TestSetAppConfigSuccess(c *gc.C) {
   337  	s.assertSetSuccess(c, s.dir, []string{
   338  		"juju-external-hostname=hello",
   339  	}, map[string]interface{}{
   340  		"juju-external-hostname": "hello",
   341  	}, s.defaultCharmValues)
   342  	s.assertSetSuccess(c, s.dir, []string{
   343  		"juju-external-hostname=",
   344  	}, map[string]interface{}{
   345  		"juju-external-hostname": "",
   346  	}, s.defaultCharmValues)
   347  }
   348  
   349  func (s *configCommandSuite) TestSetSameValue(c *gc.C) {
   350  	s.assertSetSuccess(c, s.dir, []string{
   351  		"username=hello",
   352  		"outlook=hello@world.tld",
   353  	}, s.defaultAppValues, map[string]interface{}{
   354  		"username": "hello",
   355  		"outlook":  "hello@world.tld",
   356  	})
   357  	s.assertSetWarning(c, s.dir, []string{
   358  		"username=hello",
   359  	}, "the configuration setting \"username\" already has the value \"hello\"")
   360  	s.assertSetWarning(c, s.dir, []string{
   361  		"outlook=hello@world.tld",
   362  	}, "the configuration setting \"outlook\" already has the value \"hello@world.tld\"")
   363  
   364  }
   365  
   366  func (s *configCommandSuite) TestSetConfigFail(c *gc.C) {
   367  	s.assertSetFail(c, s.dir, []string{"foo", "bar"},
   368  		"can only retrieve a single value, or all values")
   369  	s.assertSetFail(c, s.dir, []string{"=bar"}, "expected \"key=value\", got \"=bar\"")
   370  	s.assertSetFail(c, s.dir, []string{
   371  		"username=@missing.txt",
   372  	}, "cannot read option from file \"missing.txt\": .* "+utils.NoSuchFileErrRegexp)
   373  	s.assertSetFail(c, s.dir, []string{
   374  		"username=@big.txt",
   375  	}, "size of option file is larger than 5M")
   376  	s.assertSetFail(c, s.dir, []string{
   377  		"username=@invalid.txt",
   378  	}, "value for option \"username\" contains non-UTF-8 sequences")
   379  }
   380  
   381  func (s *configCommandSuite) TestSetCharmConfigFromYAML(c *gc.C) {
   382  	s.assertSetFail(c, s.dir, []string{
   383  		"--file",
   384  		"missing.yaml",
   385  	}, ".*"+utils.NoSuchFileErrRegexp)
   386  
   387  	ctx := cmdtesting.ContextForDir(c, s.dir)
   388  	code := cmd.Main(application.NewConfigCommandForTest(s.fake, s.store), ctx, []string{
   389  		"dummy-application",
   390  		"--file",
   391  		"testconfig.yaml"})
   392  
   393  	c.Check(code, gc.Equals, 0)
   394  	c.Check(s.fake.config, gc.Equals, yamlConfigValue)
   395  }
   396  
   397  func (s *configCommandSuite) TestSetFromStdin(c *gc.C) {
   398  	s.fake = &fakeApplicationAPI{name: "dummy-application"}
   399  	ctx := cmdtesting.Context(c)
   400  	ctx.Stdin = strings.NewReader("settings:\n  username:\n  value: world\n")
   401  	code := cmd.Main(application.NewConfigCommandForTest(s.fake, s.store), ctx, []string{
   402  		"dummy-application",
   403  		"--file",
   404  		"-"})
   405  
   406  	c.Check(code, gc.Equals, 0)
   407  	c.Check(s.fake.config, jc.DeepEquals, "settings:\n  username:\n  value: world\n")
   408  }
   409  
   410  func (s *configCommandSuite) TestResetCharmConfigToDefault(c *gc.C) {
   411  	s.fake = &fakeApplicationAPI{name: "dummy-application", charmValues: map[string]interface{}{
   412  		"username": "hello",
   413  	}}
   414  	s.assertResetSuccess(c, s.dir, []string{
   415  		"--reset",
   416  		"username",
   417  	}, nil, make(map[string]interface{}))
   418  }
   419  
   420  func (s *configCommandSuite) TestResetAppConfig(c *gc.C) {
   421  	s.fake = &fakeApplicationAPI{name: "dummy-application", appValues: map[string]interface{}{
   422  		"juju-external-hostname": "app-value",
   423  	}}
   424  	s.assertResetSuccess(c, s.dir, []string{
   425  		"--reset",
   426  		"juju-external-hostname",
   427  	}, make(map[string]interface{}), nil)
   428  }
   429  
   430  func (s *configCommandSuite) TestBlockSetConfig(c *gc.C) {
   431  	// Block operation
   432  	s.fake.err = common.OperationBlockedError("TestBlockSetConfig")
   433  	cmd := application.NewConfigCommandForTest(s.fake, s.store)
   434  	cmd.SetClientStore(jujuclienttesting.MinimalStore())
   435  	_, err := cmdtesting.RunCommandInDir(c, cmd, []string{
   436  		"dummy-application",
   437  		"--file",
   438  		"testconfig.yaml",
   439  	}, s.dir)
   440  	c.Assert(err, gc.ErrorMatches, `(.|\n)*All operations that change model have been disabled(.|\n)*`)
   441  	c.Check(c.GetTestLog(), gc.Matches, "(.|\n)*TestBlockSetConfig(.|\n)*")
   442  }
   443  
   444  // assertSetSuccess sets configuration options and checks the expected settings.
   445  func (s *configCommandSuite) assertSetSuccess(
   446  	c *gc.C, dir string, args []string,
   447  	expectAppValues map[string]interface{}, expectCharmValues map[string]interface{},
   448  ) {
   449  	cmd := application.NewConfigCommandForTest(s.fake, s.store)
   450  	cmd.SetClientStore(jujuclienttesting.MinimalStore())
   451  
   452  	args = append([]string{"dummy-application"}, args...)
   453  	_, err := cmdtesting.RunCommandInDir(c, cmd, args, dir)
   454  	c.Assert(err, jc.ErrorIsNil)
   455  	appValues := make(map[string]interface{})
   456  	for k, v := range s.defaultAppValues {
   457  		appValues[k] = v
   458  	}
   459  	for k, v := range expectAppValues {
   460  		appValues[k] = v
   461  	}
   462  	c.Assert(s.fake.appValues, jc.DeepEquals, appValues)
   463  
   464  	charmValues := make(map[string]interface{})
   465  	for k, v := range s.defaultCharmValues {
   466  		charmValues[k] = v
   467  	}
   468  	for k, v := range expectCharmValues {
   469  		charmValues[k] = v
   470  	}
   471  	c.Assert(s.fake.charmValues, jc.DeepEquals, charmValues)
   472  }
   473  
   474  func (s *configCommandSuite) assertResetSuccess(
   475  	c *gc.C, dir string, args []string,
   476  	expectAppValues map[string]interface{}, expectCharmValues map[string]interface{},
   477  ) {
   478  	cmd := application.NewConfigCommandForTest(s.fake, s.store)
   479  	cmd.SetClientStore(jujuclienttesting.MinimalStore())
   480  
   481  	args = append([]string{"dummy-application"}, args...)
   482  	_, err := cmdtesting.RunCommandInDir(c, cmd, args, dir)
   483  	c.Assert(err, jc.ErrorIsNil)
   484  	c.Assert(s.fake.appValues, jc.DeepEquals, expectAppValues)
   485  	c.Assert(s.fake.charmValues, jc.DeepEquals, expectCharmValues)
   486  }
   487  
   488  // assertSetFail sets configuration options and checks the expected error.
   489  func (s *configCommandSuite) assertSetFail(c *gc.C, dir string, args []string, expectErr string) {
   490  	cmd := application.NewConfigCommandForTest(s.fake, s.store)
   491  	cmd.SetClientStore(jujuclienttesting.MinimalStore())
   492  
   493  	args = append([]string{"dummy-application"}, args...)
   494  	_, err := cmdtesting.RunCommandInDir(c, cmd, args, dir)
   495  	c.Assert(err, gc.ErrorMatches, expectErr)
   496  }
   497  
   498  func (s *configCommandSuite) assertSetWarning(c *gc.C, dir string, args []string, w string) {
   499  	cmd := application.NewConfigCommandForTest(s.fake, s.store)
   500  	cmd.SetClientStore(jujuclienttesting.MinimalStore())
   501  	_, err := cmdtesting.RunCommandInDir(c, cmd, append([]string{"dummy-application"}, args...), dir)
   502  	c.Assert(err, jc.ErrorIsNil)
   503  	c.Assert(strings.Replace(c.GetTestLog(), "\n", " ", -1), gc.Matches, ".*WARNING.*"+w+".*")
   504  }
   505  
   506  // setupValueFile creates a file containing one value for testing
   507  // set with name=@filename.
   508  func setupValueFile(c *gc.C, dir, filename, value string) string {
   509  	ctx := cmdtesting.ContextForDir(c, dir)
   510  	path := ctx.AbsPath(filename)
   511  	content := []byte(value)
   512  	err := ioutil.WriteFile(path, content, 0666)
   513  	c.Assert(err, jc.ErrorIsNil)
   514  	return path
   515  }
   516  
   517  // setupBigFile creates a too big file for testing
   518  // set with name=@filename.
   519  func setupBigFile(c *gc.C, dir string) string {
   520  	ctx := cmdtesting.ContextForDir(c, dir)
   521  	path := ctx.AbsPath("big.txt")
   522  	file, err := os.Create(path)
   523  	c.Assert(err, jc.ErrorIsNil)
   524  	defer file.Close()
   525  	chunk := make([]byte, 1024)
   526  	for i := 0; i < cap(chunk); i++ {
   527  		chunk[i] = byte(i % 256)
   528  	}
   529  	for i := 0; i < 6000; i++ {
   530  		_, err = file.Write(chunk)
   531  		c.Assert(err, jc.ErrorIsNil)
   532  	}
   533  	return path
   534  }
   535  
   536  // setupConfigFile creates a configuration file for testing set
   537  // with the --file argument specifying a configuration file.
   538  func setupConfigFile(c *gc.C, dir string) string {
   539  	ctx := cmdtesting.ContextForDir(c, dir)
   540  	path := ctx.AbsPath("testconfig.yaml")
   541  	content := []byte(yamlConfigValue)
   542  	err := ioutil.WriteFile(path, content, 0666)
   543  	c.Assert(err, jc.ErrorIsNil)
   544  	return path
   545  }