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 }