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 }