github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/cmd/juju/service/set_test.go (about)

     1  // Copyright 2012-2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package service_test
     5  
     6  import (
     7  	"bytes"
     8  	"io/ioutil"
     9  	"os"
    10  	"strings"
    11  	"unicode/utf8"
    12  
    13  	"github.com/juju/cmd"
    14  	jc "github.com/juju/testing/checkers"
    15  	"github.com/juju/utils"
    16  	gc "gopkg.in/check.v1"
    17  
    18  	"github.com/juju/juju/apiserver/common"
    19  	"github.com/juju/juju/cmd/juju/service"
    20  	coretesting "github.com/juju/juju/testing"
    21  )
    22  
    23  type SetSuite struct {
    24  	coretesting.FakeJujuXDGDataHomeSuite
    25  	dir            string
    26  	fakeServiceAPI *fakeServiceAPI
    27  }
    28  
    29  var _ = gc.Suite(&SetSuite{})
    30  
    31  var (
    32  	validSetTestValue   = "a value with spaces\nand newline\nand UTF-8 characters: \U0001F604 / \U0001F44D"
    33  	invalidSetTestValue = "a value with an invalid UTF-8 sequence: " + string([]byte{0xFF, 0xFF})
    34  	yamlConfigValue     = "dummy-service:\n  skill-level: 9000\n  username: admin001\n\n"
    35  )
    36  
    37  func (s *SetSuite) SetUpTest(c *gc.C) {
    38  	s.FakeJujuXDGDataHomeSuite.SetUpTest(c)
    39  	s.fakeServiceAPI = &fakeServiceAPI{serviceName: "dummy-service"}
    40  
    41  	s.dir = c.MkDir()
    42  	c.Assert(utf8.ValidString(validSetTestValue), jc.IsTrue)
    43  	c.Assert(utf8.ValidString(invalidSetTestValue), jc.IsFalse)
    44  	setupValueFile(c, s.dir, "valid.txt", validSetTestValue)
    45  	setupValueFile(c, s.dir, "invalid.txt", invalidSetTestValue)
    46  	setupBigFile(c, s.dir)
    47  	setupConfigFile(c, s.dir)
    48  }
    49  
    50  func (s *SetSuite) TestSetCommandInit(c *gc.C) {
    51  	// missing args
    52  	err := coretesting.InitCommand(service.NewSetCommandForTest(s.fakeServiceAPI), []string{})
    53  	c.Assert(err, gc.ErrorMatches, "no service name specified")
    54  
    55  	// missing service name
    56  	err = coretesting.InitCommand(service.NewSetCommandForTest(s.fakeServiceAPI), []string{"name=foo"})
    57  	c.Assert(err, gc.ErrorMatches, "no service name specified")
    58  
    59  	// --config path, but no service
    60  	err = coretesting.InitCommand(service.NewSetCommandForTest(s.fakeServiceAPI), []string{"--config", "testconfig.yaml"})
    61  	c.Assert(err, gc.ErrorMatches, "no service name specified")
    62  
    63  	// --config and options specified
    64  	err = coretesting.InitCommand(service.NewSetCommandForTest(s.fakeServiceAPI), []string{"service", "--config", "testconfig.yaml", "bees="})
    65  	c.Assert(err, gc.ErrorMatches, "cannot specify --config when using key=value arguments")
    66  
    67  	// --to-default and no config name provided
    68  	err = coretesting.InitCommand(service.NewSetCommandForTest(s.fakeServiceAPI), []string{"service", "--to-default"})
    69  	c.Assert(err, gc.ErrorMatches, "no configuration options specified")
    70  
    71  }
    72  
    73  func (s *SetSuite) TestSetOptionSuccess(c *gc.C) {
    74  	s.assertSetSuccess(c, s.dir, []string{
    75  		"username=hello",
    76  		"outlook=hello@world.tld",
    77  	}, map[string]interface{}{
    78  		"username": "hello",
    79  		"outlook":  "hello@world.tld",
    80  	})
    81  	s.assertSetSuccess(c, s.dir, []string{
    82  		"username=hello=foo",
    83  	}, map[string]interface{}{
    84  		"username": "hello=foo",
    85  		"outlook":  "hello@world.tld",
    86  	})
    87  	s.assertSetSuccess(c, s.dir, []string{
    88  		"username=@valid.txt",
    89  	}, map[string]interface{}{
    90  		"username": validSetTestValue,
    91  		"outlook":  "hello@world.tld",
    92  	})
    93  	s.assertSetSuccess(c, s.dir, []string{
    94  		"username=",
    95  	}, map[string]interface{}{
    96  		"username": "",
    97  		"outlook":  "hello@world.tld",
    98  	})
    99  }
   100  
   101  func (s *SetSuite) TestSetSameValue(c *gc.C) {
   102  	s.assertSetSuccess(c, s.dir, []string{
   103  		"username=hello",
   104  		"outlook=hello@world.tld",
   105  	}, map[string]interface{}{
   106  		"username": "hello",
   107  		"outlook":  "hello@world.tld",
   108  	})
   109  	s.assertSetWarning(c, s.dir, []string{
   110  		"username=hello",
   111  	}, "the configuration setting \"username\" already has the value \"hello\"")
   112  	s.assertSetWarning(c, s.dir, []string{
   113  		"outlook=hello@world.tld",
   114  	}, "the configuration setting \"outlook\" already has the value \"hello@world.tld\"")
   115  
   116  }
   117  
   118  func (s *SetSuite) TestSetOptionFail(c *gc.C) {
   119  	s.assertSetFail(c, s.dir, []string{"foo", "bar"}, "error: expected \"key=value\", got \"foo\"\n")
   120  	s.assertSetFail(c, s.dir, []string{"=bar"}, "error: expected \"key=value\", got \"=bar\"\n")
   121  	s.assertSetFail(c, s.dir, []string{
   122  		"username=@missing.txt",
   123  	}, "error: cannot read option from file \"missing.txt\": .* "+utils.NoSuchFileErrRegexp+"\n")
   124  	s.assertSetFail(c, s.dir, []string{
   125  		"username=@big.txt",
   126  	}, "error: size of option file is larger than 5M\n")
   127  	s.assertSetFail(c, s.dir, []string{
   128  		"username=@invalid.txt",
   129  	}, "error: value for option \"username\" contains non-UTF-8 sequences\n")
   130  }
   131  
   132  func (s *SetSuite) TestSetConfig(c *gc.C) {
   133  	s.assertSetFail(c, s.dir, []string{
   134  		"--config",
   135  		"missing.yaml",
   136  	}, "error.* "+utils.NoSuchFileErrRegexp+"\n")
   137  
   138  	ctx := coretesting.ContextForDir(c, s.dir)
   139  	code := cmd.Main(service.NewSetCommandForTest(s.fakeServiceAPI), ctx, []string{
   140  		"dummy-service",
   141  		"--config",
   142  		"testconfig.yaml"})
   143  
   144  	c.Check(code, gc.Equals, 0)
   145  	c.Check(s.fakeServiceAPI.config, gc.Equals, yamlConfigValue)
   146  }
   147  
   148  func (s *SetSuite) TestSetConfigToDefault(c *gc.C) {
   149  	s.fakeServiceAPI = &fakeServiceAPI{serviceName: "dummy-service", values: map[string]interface{}{
   150  		"username": "hello",
   151  	}}
   152  	s.assertSetSuccess(c, s.dir, []string{
   153  		"--to-default",
   154  		"username",
   155  	}, make(map[string]interface{}))
   156  }
   157  
   158  func (s *SetSuite) TestBlockSetConfig(c *gc.C) {
   159  	// Block operation
   160  	s.fakeServiceAPI.err = common.OperationBlockedError("TestBlockSetConfig")
   161  	ctx := coretesting.ContextForDir(c, s.dir)
   162  	code := cmd.Main(service.NewSetCommandForTest(s.fakeServiceAPI), ctx, []string{
   163  		"dummy-service",
   164  		"--config",
   165  		"testconfig.yaml"})
   166  	c.Check(code, gc.Equals, 1)
   167  	// msg is logged
   168  	stripped := strings.Replace(c.GetTestLog(), "\n", "", -1)
   169  	c.Check(stripped, gc.Matches, ".*TestBlockSetConfig.*")
   170  }
   171  
   172  // assertSetSuccess sets configuration options and checks the expected settings.
   173  func (s *SetSuite) assertSetSuccess(c *gc.C, dir string, args []string, expect map[string]interface{}) {
   174  	ctx := coretesting.ContextForDir(c, dir)
   175  	code := cmd.Main(service.NewSetCommandForTest(s.fakeServiceAPI), ctx, append([]string{"dummy-service"}, args...))
   176  	c.Assert(code, gc.Equals, 0)
   177  }
   178  
   179  // assertSetFail sets configuration options and checks the expected error.
   180  func (s *SetSuite) assertSetFail(c *gc.C, dir string, args []string, err string) {
   181  	ctx := coretesting.ContextForDir(c, dir)
   182  	code := cmd.Main(service.NewSetCommandForTest(s.fakeServiceAPI), ctx, append([]string{"dummy-service"}, args...))
   183  	c.Check(code, gc.Not(gc.Equals), 0)
   184  	c.Assert(ctx.Stderr.(*bytes.Buffer).String(), gc.Matches, err)
   185  }
   186  
   187  func (s *SetSuite) assertSetWarning(c *gc.C, dir string, args []string, w string) {
   188  	ctx := coretesting.ContextForDir(c, dir)
   189  	code := cmd.Main(service.NewSetCommandForTest(s.fakeServiceAPI), ctx, append([]string{"dummy-service"}, args...))
   190  	c.Check(code, gc.Equals, 0)
   191  
   192  	c.Assert(strings.Replace(c.GetTestLog(), "\n", " ", -1), gc.Matches, ".*WARNING.*"+w+".*")
   193  }
   194  
   195  // setupValueFile creates a file containing one value for testing
   196  // set with name=@filename.
   197  func setupValueFile(c *gc.C, dir, filename, value string) string {
   198  	ctx := coretesting.ContextForDir(c, dir)
   199  	path := ctx.AbsPath(filename)
   200  	content := []byte(value)
   201  	err := ioutil.WriteFile(path, content, 0666)
   202  	c.Assert(err, jc.ErrorIsNil)
   203  	return path
   204  }
   205  
   206  // setupBigFile creates a too big file for testing
   207  // set with name=@filename.
   208  func setupBigFile(c *gc.C, dir string) string {
   209  	ctx := coretesting.ContextForDir(c, dir)
   210  	path := ctx.AbsPath("big.txt")
   211  	file, err := os.Create(path)
   212  	c.Assert(err, jc.ErrorIsNil)
   213  	defer file.Close()
   214  	chunk := make([]byte, 1024)
   215  	for i := 0; i < cap(chunk); i++ {
   216  		chunk[i] = byte(i % 256)
   217  	}
   218  	for i := 0; i < 6000; i++ {
   219  		_, err = file.Write(chunk)
   220  		c.Assert(err, jc.ErrorIsNil)
   221  	}
   222  	return path
   223  }
   224  
   225  // setupConfigFile creates a configuration file for testing set
   226  // with the --config argument specifying a configuration file.
   227  func setupConfigFile(c *gc.C, dir string) string {
   228  	ctx := coretesting.ContextForDir(c, dir)
   229  	path := ctx.AbsPath("testconfig.yaml")
   230  	content := []byte(yamlConfigValue)
   231  	err := ioutil.WriteFile(path, content, 0666)
   232  	c.Assert(err, jc.ErrorIsNil)
   233  	return path
   234  }