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