1
// Copyright 2012, 2013 Canonical Ltd.
2
// Copyright 2014 Cloudbase Solutions SRL
3
// Licensed under the AGPLv3, see LICENCE file for details.
14
jc "github.com/juju/testing/checkers"
15
gc "gopkg.in/check.v1"
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"
22
type RelationSetSuite struct {
26
var _ = gc.Suite(&RelationSetSuite{})
28
var helpTests = []struct {
31
}{{-1, ""}, {0, "peer0:0"}}
33
func (s *RelationSetSuite) TestHelp(c *gc.C) {
34
for i, t := range helpTests {
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 ...]
50
file containing key-value pairs
52
deprecated format flag
54
specify a relation by id
57
"relation-set" writes the local unit's settings for some relation.
58
If no relation is specified then the current relation is used. The
59
setting values are not inspected and are stored as strings. Setting
60
an empty string causes the setting to be removed. Duplicate settings
63
The --file option should be used when one or more key-value pairs are
64
too long to fit within the command length limit of the shell or
65
operating system. The file will contain a YAML map containing the
66
settings. Settings in the file will be overridden by any duplicate
67
key-value arguments. A value of "-" for the filename means <stdin>.
69
c.Assert(bufferString(ctx.Stderr), gc.Equals, "")
73
type relationSetInitTest struct {
80
settings map[string]string
83
func (t relationSetInitTest) log(c *gc.C, i int) {
86
summary = " - " + t.summary
88
c.Logf("test %d%s", i, summary)
91
func (t relationSetInitTest) filename() (string, int) {
92
for i, arg := range t.args {
94
if arg == "--file" && next < len(t.args) {
95
return t.args[next], next
101
func (t relationSetInitTest) init(c *gc.C, s *RelationSetSuite) (cmd.Command, []string, *cmd.Context) {
102
args := make([]string, len(t.args))
105
hctx, _ := s.newHookContext(t.ctxrelid, "")
106
com, err := jujuc.NewCommand(hctx, cmdString("relation-set"))
107
c.Assert(err, jc.ErrorIsNil)
109
ctx := testing.Context(c)
111
// Adjust the args and context for the filename.
112
filename, i := t.filename()
114
ctx.Stdin = bytes.NewBufferString(t.content)
115
} else if filename != "" {
116
filename = filepath.Join(c.MkDir(), filename)
118
err := ioutil.WriteFile(filename, []byte(t.content), 0644)
119
c.Assert(err, jc.ErrorIsNil)
122
return com, args, ctx
125
func (t relationSetInitTest) check(c *gc.C, com cmd.Command, err error) {
127
if !c.Check(err, jc.ErrorIsNil) {
131
rset := com.(*jujuc.RelationSetCommand)
132
c.Check(rset.RelationId, gc.Equals, t.relid)
134
settings := t.settings
136
settings = map[string]string{}
138
c.Check(rset.Settings, jc.DeepEquals, settings)
140
c.Logf("%#v", com.(*jujuc.RelationSetCommand).Settings)
141
c.Check(err, gc.ErrorMatches, t.err)
145
var relationSetInitTests = []relationSetInitTest{
147
// compatibility: 0 args is valid.
150
err: `no relation id specified`,
153
args: []string{"-r", "one"},
154
err: `invalid value "one" for flag -r: invalid relation id`,
157
args: []string{"-r", "one"},
158
err: `invalid value "one" for flag -r: invalid relation id`,
161
args: []string{"-r", "ignored:one"},
162
err: `invalid value "ignored:one" for flag -r: invalid relation id`,
165
args: []string{"-r", "ignored:one"},
166
err: `invalid value "ignored:one" for flag -r: invalid relation id`,
169
args: []string{"-r", "2"},
170
err: `invalid value "2" for flag -r: relation not found`,
173
args: []string{"-r", "ignored:2"},
174
err: `invalid value "ignored:2" for flag -r: relation not found`,
177
err: `no relation id specified`,
180
args: []string{"-r", "ignored:0"},
184
args: []string{"-r", "0"},
188
args: []string{"-r", "1"},
192
args: []string{"-r", "1"},
196
args: []string{"haha"},
197
err: `expected "key=value", got "haha"`,
200
args: []string{"=haha"},
201
err: `expected "key=value", got "=haha"`,
204
args: []string{"foo="},
206
settings: map[string]string{"foo": ""},
209
args: []string{"foo='"},
211
settings: map[string]string{"foo": "'"},
214
args: []string{"foo=bar"},
216
settings: map[string]string{"foo": "bar"},
219
args: []string{"foo=bar=baz=qux"},
221
settings: map[string]string{"foo": "bar=baz=qux"},
224
args: []string{"foo=foo: bar"},
226
settings: map[string]string{"foo": "foo: bar"},
229
args: []string{"-r", "1", "foo=bar"},
231
settings: map[string]string{"foo": "bar"},
234
args: []string{"foo=123", "bar=true", "baz=4.5", "qux="},
236
settings: map[string]string{"foo": "123", "bar": "true", "baz": "4.5", "qux": ""},
238
summary: "file with a valid setting",
239
args: []string{"--file", "spam"},
240
content: "{foo: bar}",
241
settings: map[string]string{"foo": "bar"},
243
summary: "file with multiple settings on a line",
244
args: []string{"--file", "spam"},
245
content: "{foo: bar, spam: eggs}",
246
settings: map[string]string{"foo": "bar", "spam": "eggs"},
248
summary: "file with multiple lines",
249
args: []string{"--file", "spam"},
250
content: "{\n foo: bar,\n spam: eggs\n}",
251
settings: map[string]string{"foo": "bar", "spam": "eggs"},
253
summary: "an empty file",
254
args: []string{"--file", "spam"},
256
settings: map[string]string{},
258
summary: "an empty map",
259
args: []string{"--file", "spam"},
261
settings: map[string]string{},
263
summary: "accidental same format as command-line",
264
args: []string{"--file", "spam"},
265
content: "foo=bar ham=eggs good=bad",
266
err: "yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `foo=bar...` into map.*",
268
summary: "scalar instead of map",
269
args: []string{"--file", "spam"},
271
err: "yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `haha` into map.*",
273
summary: "sequence instead of map",
274
args: []string{"--file", "spam"},
276
err: "yaml: unmarshal errors:\n line 1: cannot unmarshal !!seq into map.*",
278
summary: "multiple maps",
279
args: []string{"--file", "spam"},
280
content: "{a: b}\n{c: d}",
283
summary: "value with a space",
284
args: []string{"--file", "spam"},
285
content: "{foo: 'bar baz'}",
286
settings: map[string]string{"foo": "bar baz"},
288
summary: "value with an equal sign",
289
args: []string{"--file", "spam"},
290
content: "{foo: foo=bar, base64: YmFzZTY0IGV4YW1wbGU=}",
291
settings: map[string]string{"foo": "foo=bar", "base64": "YmFzZTY0IGV4YW1wbGU="},
293
summary: "values with brackets",
294
args: []string{"--file", "spam"},
295
content: "{foo: '[x]', bar: '{y}'}",
296
settings: map[string]string{"foo": "[x]", "bar": "{y}"},
298
summary: "a messy file",
299
args: []string{"--file", "spam"},
300
content: "\n { \n # a comment \n\n \nfoo: bar, \nham: eggs,\n\n good: bad,\nup: down, left: right\n}\n",
301
settings: map[string]string{"foo": "bar", "ham": "eggs", "good": "bad", "up": "down", "left": "right"},
303
summary: "file + settings",
304
args: []string{"--file", "spam", "foo=bar"},
305
content: "{ham: eggs}",
306
settings: map[string]string{"ham": "eggs", "foo": "bar"},
308
summary: "file overridden by settings",
309
args: []string{"--file", "spam", "foo=bar"},
310
content: "{foo: baz}",
311
settings: map[string]string{"foo": "bar"},
313
summary: "read from stdin",
314
args: []string{"--file", "-"},
315
content: "{foo: bar}",
316
settings: map[string]string{"foo": "bar"},
320
func (s *RelationSetSuite) TestInit(c *gc.C) {
321
for i, t := range relationSetInitTests {
323
com, args, ctx := t.init(c, s)
325
err := testing.InitCommand(com, args)
327
err = jujuc.HandleSettingsFile(com.(*jujuc.RelationSetCommand), ctx)
333
// Tests start with a relation with the settings {"base": "value"}
334
var relationSetRunTests = []struct {
335
change map[string]string
336
expect jujuctesting.Settings
339
map[string]string{"base": ""},
340
jujuctesting.Settings{},
342
map[string]string{"foo": "bar"},
343
jujuctesting.Settings{"base": "value", "foo": "bar"},
345
map[string]string{"base": "changed"},
346
jujuctesting.Settings{"base": "changed"},
350
func (s *RelationSetSuite) TestRun(c *gc.C) {
351
hctx, info := s.newHookContext(0, "")
352
for i, t := range relationSetRunTests {
355
pristine := jujuctesting.Settings{"pristine": "untouched"}
356
info.rels[0].Units["u/0"] = pristine
357
basic := jujuctesting.Settings{"base": "value"}
358
info.rels[1].Units["u/0"] = basic
361
com, err := jujuc.NewCommand(hctx, cmdString("relation-set"))
362
c.Assert(err, jc.ErrorIsNil)
363
rset := com.(*jujuc.RelationSetCommand)
365
rset.Settings = t.change
366
ctx := testing.Context(c)
368
c.Assert(err, jc.ErrorIsNil)
371
c.Assert(info.rels[0].Units["u/0"], gc.DeepEquals, pristine)
372
c.Assert(info.rels[1].Units["u/0"], gc.DeepEquals, t.expect)
376
func (s *RelationSetSuite) TestRunDeprecationWarning(c *gc.C) {
377
hctx, _ := s.newHookContext(0, "")
378
com, _ := jujuc.NewCommand(hctx, cmdString("relation-set"))
380
// The rel= is needed to make this a valid command.
381
ctx, err := testing.RunCommand(c, com, "--format", "foo", "rel=")
383
c.Assert(err, jc.ErrorIsNil)
384
c.Assert(testing.Stdout(ctx), gc.Equals, "")
385
c.Assert(testing.Stderr(ctx), gc.Equals, "--format flag deprecated for command \"relation-set\"")