github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/worker/uniter/runner/jujuc/relation-set_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Copyright 2014 Cloudbase Solutions SRL 3 // Licensed under the AGPLv3, see LICENCE file for details. 4 5 package jujuc_test 6 7 import ( 8 "bytes" 9 "fmt" 10 "io/ioutil" 11 "path/filepath" 12 13 "github.com/juju/cmd" 14 jc "github.com/juju/testing/checkers" 15 gc "gopkg.in/check.v1" 16 17 "github.com/juju/juju/testing" 18 "github.com/juju/juju/worker/uniter/runner/jujuc" 19 jujuctesting "github.com/juju/juju/worker/uniter/runner/jujuc/testing" 20 ) 21 22 type RelationSetSuite struct { 23 relationSuite 24 } 25 26 var _ = gc.Suite(&RelationSetSuite{}) 27 28 var helpTests = []struct { 29 relid int 30 expect string 31 }{{-1, ""}, {0, "peer0:0"}} 32 33 func (s *RelationSetSuite) TestHelp(c *gc.C) { 34 for i, t := range helpTests { 35 c.Logf("test %d", i) 36 hctx, _ := s.newHookContext(t.relid, "") 37 com, err := jujuc.NewCommand(hctx, cmdString("relation-set")) 38 c.Assert(err, jc.ErrorIsNil) 39 ctx := testing.Context(c) 40 code := cmd.Main(com, ctx, []string{"--help"}) 41 c.Assert(code, gc.Equals, 0) 42 c.Assert(bufferString(ctx.Stdout), gc.Equals, fmt.Sprintf(` 43 usage: relation-set [options] key=value [key=value ...] 44 purpose: set relation settings 45 46 options: 47 --file (= ) 48 file containing key-value pairs 49 --format (= "") 50 deprecated format flag 51 -r, --relation (= %s) 52 specify a relation by id 53 54 "relation-set" writes the local unit's settings for some relation. 55 If no relation is specified then the current relation is used. The 56 setting values are not inspected and are stored as strings. Setting 57 an empty string causes the setting to be removed. Duplicate settings 58 are not allowed. 59 60 The --file option should be used when one or more key-value pairs are 61 too long to fit within the command length limit of the shell or 62 operating system. The file will contain a YAML map containing the 63 settings. Settings in the file will be overridden by any duplicate 64 key-value arguments. A value of "-" for the filename means <stdin>. 65 `[1:], t.expect)) 66 c.Assert(bufferString(ctx.Stderr), gc.Equals, "") 67 } 68 } 69 70 type relationSetInitTest struct { 71 summary string 72 ctxrelid int 73 args []string 74 content string 75 err string 76 relid int 77 settings map[string]string 78 } 79 80 func (t relationSetInitTest) log(c *gc.C, i int) { 81 var summary string 82 if t.summary != "" { 83 summary = " - " + t.summary 84 } 85 c.Logf("test %d%s", i, summary) 86 } 87 88 func (t relationSetInitTest) filename() (string, int) { 89 for i, arg := range t.args { 90 next := i + 1 91 if arg == "--file" && next < len(t.args) { 92 return t.args[next], next 93 } 94 } 95 return "", -1 96 } 97 98 func (t relationSetInitTest) init(c *gc.C, s *RelationSetSuite) (cmd.Command, []string, *cmd.Context) { 99 args := make([]string, len(t.args)) 100 copy(args, t.args) 101 102 hctx, _ := s.newHookContext(t.ctxrelid, "") 103 com, err := jujuc.NewCommand(hctx, cmdString("relation-set")) 104 c.Assert(err, jc.ErrorIsNil) 105 106 ctx := testing.Context(c) 107 108 // Adjust the args and context for the filename. 109 filename, i := t.filename() 110 if filename == "-" { 111 ctx.Stdin = bytes.NewBufferString(t.content) 112 } else if filename != "" { 113 filename = filepath.Join(c.MkDir(), filename) 114 args[i] = filename 115 err := ioutil.WriteFile(filename, []byte(t.content), 0644) 116 c.Assert(err, jc.ErrorIsNil) 117 } 118 119 return com, args, ctx 120 } 121 122 func (t relationSetInitTest) check(c *gc.C, com cmd.Command, err error) { 123 if t.err == "" { 124 if !c.Check(err, jc.ErrorIsNil) { 125 return 126 } 127 128 rset := com.(*jujuc.RelationSetCommand) 129 c.Check(rset.RelationId, gc.Equals, t.relid) 130 131 settings := t.settings 132 if settings == nil { 133 settings = map[string]string{} 134 } 135 c.Check(rset.Settings, jc.DeepEquals, settings) 136 } else { 137 c.Logf("%#v", com.(*jujuc.RelationSetCommand).Settings) 138 c.Check(err, gc.ErrorMatches, t.err) 139 } 140 } 141 142 var relationSetInitTests = []relationSetInitTest{ 143 { 144 // compatibility: 0 args is valid. 145 }, { 146 ctxrelid: -1, 147 err: `no relation id specified`, 148 }, { 149 ctxrelid: -1, 150 args: []string{"-r", "one"}, 151 err: `invalid value "one" for flag -r: invalid relation id`, 152 }, { 153 ctxrelid: 1, 154 args: []string{"-r", "one"}, 155 err: `invalid value "one" for flag -r: invalid relation id`, 156 }, { 157 ctxrelid: -1, 158 args: []string{"-r", "ignored:one"}, 159 err: `invalid value "ignored:one" for flag -r: invalid relation id`, 160 }, { 161 ctxrelid: 1, 162 args: []string{"-r", "ignored:one"}, 163 err: `invalid value "ignored:one" for flag -r: invalid relation id`, 164 }, { 165 ctxrelid: -1, 166 args: []string{"-r", "2"}, 167 err: `invalid value "2" for flag -r: unknown relation id`, 168 }, { 169 ctxrelid: 1, 170 args: []string{"-r", "ignored:2"}, 171 err: `invalid value "ignored:2" for flag -r: unknown relation id`, 172 }, { 173 ctxrelid: -1, 174 err: `no relation id specified`, 175 }, { 176 ctxrelid: 1, 177 args: []string{"-r", "ignored:0"}, 178 relid: 0, 179 }, { 180 ctxrelid: 1, 181 args: []string{"-r", "0"}, 182 relid: 0, 183 }, { 184 ctxrelid: -1, 185 args: []string{"-r", "1"}, 186 relid: 1, 187 }, { 188 ctxrelid: 0, 189 args: []string{"-r", "1"}, 190 relid: 1, 191 }, { 192 ctxrelid: 1, 193 args: []string{"haha"}, 194 err: `expected "key=value", got "haha"`, 195 }, { 196 ctxrelid: 1, 197 args: []string{"=haha"}, 198 err: `expected "key=value", got "=haha"`, 199 }, { 200 ctxrelid: 1, 201 args: []string{"foo="}, 202 relid: 1, 203 settings: map[string]string{"foo": ""}, 204 }, { 205 ctxrelid: 1, 206 args: []string{"foo='"}, 207 relid: 1, 208 settings: map[string]string{"foo": "'"}, 209 }, { 210 ctxrelid: 1, 211 args: []string{"foo=bar"}, 212 relid: 1, 213 settings: map[string]string{"foo": "bar"}, 214 }, { 215 ctxrelid: 1, 216 args: []string{"foo=bar=baz=qux"}, 217 relid: 1, 218 settings: map[string]string{"foo": "bar=baz=qux"}, 219 }, { 220 ctxrelid: 1, 221 args: []string{"foo=foo: bar"}, 222 relid: 1, 223 settings: map[string]string{"foo": "foo: bar"}, 224 }, { 225 ctxrelid: 0, 226 args: []string{"-r", "1", "foo=bar"}, 227 relid: 1, 228 settings: map[string]string{"foo": "bar"}, 229 }, { 230 ctxrelid: 1, 231 args: []string{"foo=123", "bar=true", "baz=4.5", "qux="}, 232 relid: 1, 233 settings: map[string]string{"foo": "123", "bar": "true", "baz": "4.5", "qux": ""}, 234 }, { 235 summary: "file with a valid setting", 236 args: []string{"--file", "spam"}, 237 content: "{foo: bar}", 238 settings: map[string]string{"foo": "bar"}, 239 }, { 240 summary: "file with multiple settings on a line", 241 args: []string{"--file", "spam"}, 242 content: "{foo: bar, spam: eggs}", 243 settings: map[string]string{"foo": "bar", "spam": "eggs"}, 244 }, { 245 summary: "file with multiple lines", 246 args: []string{"--file", "spam"}, 247 content: "{\n foo: bar,\n spam: eggs\n}", 248 settings: map[string]string{"foo": "bar", "spam": "eggs"}, 249 }, { 250 summary: "an empty file", 251 args: []string{"--file", "spam"}, 252 content: "", 253 settings: map[string]string{}, 254 }, { 255 summary: "an empty map", 256 args: []string{"--file", "spam"}, 257 content: "{}", 258 settings: map[string]string{}, 259 }, { 260 summary: "accidental same format as command-line", 261 args: []string{"--file", "spam"}, 262 content: "foo=bar ham=eggs good=bad", 263 err: `expected YAML map, got .*`, 264 }, { 265 summary: "scalar instead of map", 266 args: []string{"--file", "spam"}, 267 content: "haha", 268 err: `expected YAML map, got "haha"`, 269 }, { 270 summary: "sequence instead of map", 271 args: []string{"--file", "spam"}, 272 content: "[haha]", 273 err: `expected YAML map, got \[]string{"haha"}`, 274 }, { 275 summary: "multiple maps", 276 args: []string{"--file", "spam"}, 277 content: "{a: b}\n{c: d}", 278 err: `.*YAML error: .*`, 279 }, { 280 summary: "value with a space", 281 args: []string{"--file", "spam"}, 282 content: "{foo: 'bar baz'}", 283 settings: map[string]string{"foo": "bar baz"}, 284 }, { 285 summary: "value with an equal sign", 286 args: []string{"--file", "spam"}, 287 content: "{foo: foo=bar, base64: YmFzZTY0IGV4YW1wbGU=}", 288 settings: map[string]string{"foo": "foo=bar", "base64": "YmFzZTY0IGV4YW1wbGU="}, 289 }, { 290 summary: "values with brackets", 291 args: []string{"--file", "spam"}, 292 content: "{foo: '[x]', bar: '{y}'}", 293 settings: map[string]string{"foo": "[x]", "bar": "{y}"}, 294 }, { 295 summary: "a messy file", 296 args: []string{"--file", "spam"}, 297 content: "\n { \n # a comment \n\n \nfoo: bar, \nham: eggs,\n\n good: bad,\nup: down, left: right\n}\n", 298 settings: map[string]string{"foo": "bar", "ham": "eggs", "good": "bad", "up": "down", "left": "right"}, 299 }, { 300 summary: "file + settings", 301 args: []string{"--file", "spam", "foo=bar"}, 302 content: "{ham: eggs}", 303 settings: map[string]string{"ham": "eggs", "foo": "bar"}, 304 }, { 305 summary: "file overridden by settings", 306 args: []string{"--file", "spam", "foo=bar"}, 307 content: "{foo: baz}", 308 settings: map[string]string{"foo": "bar"}, 309 }, { 310 summary: "read from stdin", 311 args: []string{"--file", "-"}, 312 content: "{foo: bar}", 313 settings: map[string]string{"foo": "bar"}, 314 }, 315 } 316 317 func (s *RelationSetSuite) TestInit(c *gc.C) { 318 for i, t := range relationSetInitTests { 319 t.log(c, i) 320 com, args, ctx := t.init(c, s) 321 322 err := testing.InitCommand(com, args) 323 if err == nil { 324 err = jujuc.HandleSettingsFile(com.(*jujuc.RelationSetCommand), ctx) 325 } 326 t.check(c, com, err) 327 } 328 } 329 330 // Tests start with a relation with the settings {"base": "value"} 331 var relationSetRunTests = []struct { 332 change map[string]string 333 expect jujuctesting.Settings 334 }{ 335 { 336 map[string]string{"base": ""}, 337 jujuctesting.Settings{}, 338 }, { 339 map[string]string{"foo": "bar"}, 340 jujuctesting.Settings{"base": "value", "foo": "bar"}, 341 }, { 342 map[string]string{"base": "changed"}, 343 jujuctesting.Settings{"base": "changed"}, 344 }, 345 } 346 347 func (s *RelationSetSuite) TestRun(c *gc.C) { 348 hctx, info := s.newHookContext(0, "") 349 for i, t := range relationSetRunTests { 350 c.Logf("test %d", i) 351 352 pristine := jujuctesting.Settings{"pristine": "untouched"} 353 info.rels[0].Units["u/0"] = pristine 354 basic := jujuctesting.Settings{"base": "value"} 355 info.rels[1].Units["u/0"] = basic 356 357 // Run the command. 358 com, err := jujuc.NewCommand(hctx, cmdString("relation-set")) 359 c.Assert(err, jc.ErrorIsNil) 360 rset := com.(*jujuc.RelationSetCommand) 361 rset.RelationId = 1 362 rset.Settings = t.change 363 ctx := testing.Context(c) 364 err = com.Run(ctx) 365 c.Assert(err, jc.ErrorIsNil) 366 367 // Check changes. 368 c.Assert(info.rels[0].Units["u/0"], gc.DeepEquals, pristine) 369 c.Assert(info.rels[1].Units["u/0"], gc.DeepEquals, t.expect) 370 } 371 } 372 373 func (s *RelationSetSuite) TestRunDeprecationWarning(c *gc.C) { 374 hctx, _ := s.newHookContext(0, "") 375 com, _ := jujuc.NewCommand(hctx, cmdString("relation-set")) 376 377 // The rel= is needed to make this a valid command. 378 ctx, err := testing.RunCommand(c, com, "--format", "foo", "rel=") 379 380 c.Assert(err, jc.ErrorIsNil) 381 c.Assert(testing.Stdout(ctx), gc.Equals, "") 382 c.Assert(testing.Stderr(ctx), gc.Equals, "--format flag deprecated for command \"relation-set\"") 383 }