~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/state/settings_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2012, 2013 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package state
 
5
 
 
6
import (
 
7
        "github.com/juju/errors"
 
8
        jc "github.com/juju/testing/checkers"
 
9
        gc "gopkg.in/check.v1"
 
10
        "gopkg.in/mgo.v2/txn"
 
11
)
 
12
 
 
13
type SettingsSuite struct {
 
14
        internalStateSuite
 
15
        key        string
 
16
        collection string
 
17
}
 
18
 
 
19
var _ = gc.Suite(&SettingsSuite{})
 
20
 
 
21
func (s *SettingsSuite) SetUpTest(c *gc.C) {
 
22
        s.internalStateSuite.SetUpTest(c)
 
23
        s.key = "config"
 
24
        s.collection = settingsC
 
25
}
 
26
 
 
27
func (s *SettingsSuite) createSettings(key string, values map[string]interface{}) (*Settings, error) {
 
28
        return createSettings(s.state, s.collection, key, values)
 
29
}
 
30
 
 
31
func (s *SettingsSuite) readSettings() (*Settings, error) {
 
32
        return readSettings(s.state, s.collection, s.key)
 
33
}
 
34
 
 
35
func (s *SettingsSuite) TestCreateEmptySettings(c *gc.C) {
 
36
        node, err := s.createSettings(s.key, nil)
 
37
        c.Assert(err, jc.ErrorIsNil)
 
38
        c.Assert(node.Keys(), gc.DeepEquals, []string{})
 
39
}
 
40
 
 
41
func (s *SettingsSuite) TestCannotOverwrite(c *gc.C) {
 
42
        _, err := s.createSettings(s.key, nil)
 
43
        c.Assert(err, jc.ErrorIsNil)
 
44
        _, err = s.createSettings(s.key, nil)
 
45
        c.Assert(err, gc.ErrorMatches, "cannot overwrite existing settings")
 
46
}
 
47
 
 
48
func (s *SettingsSuite) TestCannotReadMissing(c *gc.C) {
 
49
        _, err := s.readSettings()
 
50
        c.Assert(err, gc.ErrorMatches, "settings not found")
 
51
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
52
}
 
53
 
 
54
func (s *SettingsSuite) TestCannotWriteMissing(c *gc.C) {
 
55
        node, err := s.createSettings(s.key, nil)
 
56
        c.Assert(err, jc.ErrorIsNil)
 
57
 
 
58
        err = removeSettings(s.state, s.collection, s.key)
 
59
        c.Assert(err, jc.ErrorIsNil)
 
60
 
 
61
        node.Set("foo", "bar")
 
62
        _, err = node.Write()
 
63
        c.Assert(err, gc.ErrorMatches, "settings not found")
 
64
        c.Assert(err, jc.Satisfies, errors.IsNotFound)
 
65
}
 
66
 
 
67
func (s *SettingsSuite) TestUpdateWithWrite(c *gc.C) {
 
68
        node, err := s.createSettings(s.key, nil)
 
69
        c.Assert(err, jc.ErrorIsNil)
 
70
        options := map[string]interface{}{"alpha": "beta", "one": 1}
 
71
        node.Update(options)
 
72
        changes, err := node.Write()
 
73
        c.Assert(err, jc.ErrorIsNil)
 
74
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
75
                {ItemAdded, "alpha", nil, "beta"},
 
76
                {ItemAdded, "one", nil, 1},
 
77
        })
 
78
 
 
79
        // Check local state.
 
80
        c.Assert(node.Map(), gc.DeepEquals, options)
 
81
 
 
82
        // Check MongoDB state.
 
83
        var mgoData struct {
 
84
                Settings settingsMap
 
85
        }
 
86
        settings, closer := s.state.getCollection(settingsC)
 
87
        defer closer()
 
88
        err = settings.FindId(s.key).One(&mgoData)
 
89
        c.Assert(err, jc.ErrorIsNil)
 
90
        c.Assert(map[string]interface{}(mgoData.Settings), gc.DeepEquals, options)
 
91
}
 
92
 
 
93
func (s *SettingsSuite) TestConflictOnSet(c *gc.C) {
 
94
        // Check version conflict errors.
 
95
        nodeOne, err := s.createSettings(s.key, nil)
 
96
        c.Assert(err, jc.ErrorIsNil)
 
97
        nodeTwo, err := s.readSettings()
 
98
        c.Assert(err, jc.ErrorIsNil)
 
99
 
 
100
        optionsOld := map[string]interface{}{"alpha": "beta", "one": 1}
 
101
        nodeOne.Update(optionsOld)
 
102
        nodeOne.Write()
 
103
 
 
104
        nodeTwo.Update(optionsOld)
 
105
        changes, err := nodeTwo.Write()
 
106
        c.Assert(err, jc.ErrorIsNil)
 
107
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
108
                {ItemAdded, "alpha", nil, "beta"},
 
109
                {ItemAdded, "one", nil, 1},
 
110
        })
 
111
 
 
112
        // First test node one.
 
113
        c.Assert(nodeOne.Map(), gc.DeepEquals, optionsOld)
 
114
 
 
115
        // Write on node one.
 
116
        optionsNew := map[string]interface{}{"alpha": "gamma", "one": "two"}
 
117
        nodeOne.Update(optionsNew)
 
118
        changes, err = nodeOne.Write()
 
119
        c.Assert(err, jc.ErrorIsNil)
 
120
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
121
                {ItemModified, "alpha", "beta", "gamma"},
 
122
                {ItemModified, "one", 1, "two"},
 
123
        })
 
124
 
 
125
        // Verify that node one reports as expected.
 
126
        c.Assert(nodeOne.Map(), gc.DeepEquals, optionsNew)
 
127
 
 
128
        // Verify that node two has still the old data.
 
129
        c.Assert(nodeTwo.Map(), gc.DeepEquals, optionsOld)
 
130
 
 
131
        // Now issue a Set/Write from node two. This will
 
132
        // merge the data deleting 'one' and updating
 
133
        // other values.
 
134
        optionsMerge := map[string]interface{}{"alpha": "cappa", "new": "next"}
 
135
        nodeTwo.Update(optionsMerge)
 
136
        nodeTwo.Delete("one")
 
137
 
 
138
        expected := map[string]interface{}{"alpha": "cappa", "new": "next"}
 
139
        changes, err = nodeTwo.Write()
 
140
        c.Assert(err, jc.ErrorIsNil)
 
141
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
142
                {ItemModified, "alpha", "beta", "cappa"},
 
143
                {ItemAdded, "new", nil, "next"},
 
144
                {ItemDeleted, "one", 1, nil},
 
145
        })
 
146
        c.Assert(expected, gc.DeepEquals, nodeTwo.Map())
 
147
 
 
148
        // But node one still reflects the former data.
 
149
        c.Assert(nodeOne.Map(), gc.DeepEquals, optionsNew)
 
150
}
 
151
 
 
152
func (s *SettingsSuite) TestSetItem(c *gc.C) {
 
153
        // Check that Set works as expected.
 
154
        node, err := s.createSettings(s.key, nil)
 
155
        c.Assert(err, jc.ErrorIsNil)
 
156
        options := map[string]interface{}{"alpha": "beta", "one": 1}
 
157
        node.Set("alpha", "beta")
 
158
        node.Set("one", 1)
 
159
        changes, err := node.Write()
 
160
        c.Assert(err, jc.ErrorIsNil)
 
161
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
162
                {ItemAdded, "alpha", nil, "beta"},
 
163
                {ItemAdded, "one", nil, 1},
 
164
        })
 
165
        // Check local state.
 
166
        c.Assert(node.Map(), gc.DeepEquals, options)
 
167
        // Check MongoDB state.
 
168
        var mgoData struct {
 
169
                Settings settingsMap
 
170
        }
 
171
        settings, closer := s.state.getCollection(settingsC)
 
172
        defer closer()
 
173
        err = settings.FindId(s.key).One(&mgoData)
 
174
        c.Assert(err, jc.ErrorIsNil)
 
175
        c.Assert(map[string]interface{}(mgoData.Settings), gc.DeepEquals, options)
 
176
}
 
177
 
 
178
func (s *SettingsSuite) TestSetItemEscape(c *gc.C) {
 
179
        // Check that Set works as expected.
 
180
        node, err := s.createSettings(s.key, nil)
 
181
        c.Assert(err, jc.ErrorIsNil)
 
182
        options := map[string]interface{}{"$bar": 1, "foo.alpha": "beta"}
 
183
        node.Set("foo.alpha", "beta")
 
184
        node.Set("$bar", 1)
 
185
        changes, err := node.Write()
 
186
        c.Assert(err, jc.ErrorIsNil)
 
187
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
188
                {ItemAdded, "$bar", nil, 1},
 
189
                {ItemAdded, "foo.alpha", nil, "beta"},
 
190
        })
 
191
        // Check local state.
 
192
        c.Assert(node.Map(), gc.DeepEquals, options)
 
193
 
 
194
        // Check MongoDB state.
 
195
        mgoOptions := map[string]interface{}{"\uff04bar": 1, "foo\uff0ealpha": "beta"}
 
196
        var mgoData struct {
 
197
                Settings map[string]interface{}
 
198
        }
 
199
        settings, closer := s.state.getCollection(settingsC)
 
200
        defer closer()
 
201
        err = settings.FindId(s.key).One(&mgoData)
 
202
        c.Assert(err, jc.ErrorIsNil)
 
203
        c.Assert(mgoData.Settings, gc.DeepEquals, mgoOptions)
 
204
 
 
205
        // Now get another state by reading from the database instance and
 
206
        // check read state has replaced '.' and '$' after fetching from
 
207
        // MongoDB.
 
208
        nodeTwo, err := s.readSettings()
 
209
        c.Assert(err, jc.ErrorIsNil)
 
210
        c.Assert(nodeTwo.disk, gc.DeepEquals, options)
 
211
        c.Assert(nodeTwo.core, gc.DeepEquals, options)
 
212
}
 
213
 
 
214
func (s *SettingsSuite) TestReplaceSettingsEscape(c *gc.C) {
 
215
        // Check that replaceSettings works as expected.
 
216
        node, err := s.createSettings(s.key, nil)
 
217
        c.Assert(err, jc.ErrorIsNil)
 
218
        node.Set("foo.alpha", "beta")
 
219
        node.Set("$bar", 1)
 
220
        _, err = node.Write()
 
221
        c.Assert(err, jc.ErrorIsNil)
 
222
 
 
223
        options := map[string]interface{}{"$baz": 1, "foo.bar": "beta"}
 
224
        rop, settingsChanged, err := replaceSettingsOp(s.state, s.collection, s.key, options)
 
225
        c.Assert(err, jc.ErrorIsNil)
 
226
        ops := []txn.Op{rop}
 
227
        err = node.st.runTransaction(ops)
 
228
        c.Assert(err, jc.ErrorIsNil)
 
229
 
 
230
        changed, err := settingsChanged()
 
231
        c.Assert(err, jc.ErrorIsNil)
 
232
        c.Assert(changed, jc.IsTrue)
 
233
 
 
234
        // Check MongoDB state.
 
235
        mgoOptions := map[string]interface{}{"\uff04baz": 1, "foo\uff0ebar": "beta"}
 
236
        var mgoData struct {
 
237
                Settings map[string]interface{}
 
238
        }
 
239
        settings, closer := s.state.getCollection(settingsC)
 
240
        defer closer()
 
241
        err = settings.FindId(s.key).One(&mgoData)
 
242
        c.Assert(err, jc.ErrorIsNil)
 
243
        c.Assert(mgoData.Settings, gc.DeepEquals, mgoOptions)
 
244
}
 
245
 
 
246
func (s *SettingsSuite) TestcreateSettingsEscape(c *gc.C) {
 
247
        // Check that createSettings works as expected.
 
248
        options := map[string]interface{}{"$baz": 1, "foo.bar": "beta"}
 
249
        node, err := s.createSettings(s.key, options)
 
250
        c.Assert(err, jc.ErrorIsNil)
 
251
 
 
252
        // Check local state.
 
253
        c.Assert(node.Map(), gc.DeepEquals, options)
 
254
 
 
255
        // Check MongoDB state.
 
256
        mgoOptions := map[string]interface{}{"\uff04baz": 1, "foo\uff0ebar": "beta"}
 
257
        var mgoData struct {
 
258
                Settings map[string]interface{}
 
259
        }
 
260
        settings, closer := s.state.getCollection(settingsC)
 
261
        defer closer()
 
262
 
 
263
        err = settings.FindId(s.key).One(&mgoData)
 
264
        c.Assert(err, jc.ErrorIsNil)
 
265
        c.Assert(mgoData.Settings, gc.DeepEquals, mgoOptions)
 
266
}
 
267
 
 
268
func (s *SettingsSuite) TestMultipleReads(c *gc.C) {
 
269
        // Check that reads without writes always resets the data.
 
270
        nodeOne, err := s.createSettings(s.key, nil)
 
271
        c.Assert(err, jc.ErrorIsNil)
 
272
        nodeOne.Update(map[string]interface{}{"alpha": "beta", "foo": "bar"})
 
273
        value, ok := nodeOne.Get("alpha")
 
274
        c.Assert(ok, jc.IsTrue)
 
275
        c.Assert(value, gc.Equals, "beta")
 
276
        value, ok = nodeOne.Get("foo")
 
277
        c.Assert(ok, jc.IsTrue)
 
278
        c.Assert(value, gc.Equals, "bar")
 
279
        value, ok = nodeOne.Get("baz")
 
280
        c.Assert(ok, jc.IsFalse)
 
281
 
 
282
        // A read resets the data to the empty state.
 
283
        err = nodeOne.Read()
 
284
        c.Assert(err, jc.ErrorIsNil)
 
285
        c.Assert(nodeOne.Map(), gc.DeepEquals, map[string]interface{}{})
 
286
        nodeOne.Update(map[string]interface{}{"alpha": "beta", "foo": "bar"})
 
287
        changes, err := nodeOne.Write()
 
288
        c.Assert(err, jc.ErrorIsNil)
 
289
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
290
                {ItemAdded, "alpha", nil, "beta"},
 
291
                {ItemAdded, "foo", nil, "bar"},
 
292
        })
 
293
 
 
294
        // A write retains the newly set values.
 
295
        value, ok = nodeOne.Get("alpha")
 
296
        c.Assert(ok, jc.IsTrue)
 
297
        c.Assert(value, gc.Equals, "beta")
 
298
        value, ok = nodeOne.Get("foo")
 
299
        c.Assert(ok, jc.IsTrue)
 
300
        c.Assert(value, gc.Equals, "bar")
 
301
 
 
302
        // Now get another state instance and change underlying state.
 
303
        nodeTwo, err := s.readSettings()
 
304
        c.Assert(err, jc.ErrorIsNil)
 
305
        nodeTwo.Update(map[string]interface{}{"foo": "different"})
 
306
        changes, err = nodeTwo.Write()
 
307
        c.Assert(err, jc.ErrorIsNil)
 
308
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
309
                {ItemModified, "foo", "bar", "different"},
 
310
        })
 
311
 
 
312
        // This should pull in the new state into node one.
 
313
        err = nodeOne.Read()
 
314
        c.Assert(err, jc.ErrorIsNil)
 
315
        value, ok = nodeOne.Get("alpha")
 
316
        c.Assert(ok, jc.IsTrue)
 
317
        c.Assert(value, gc.Equals, "beta")
 
318
        value, ok = nodeOne.Get("foo")
 
319
        c.Assert(ok, jc.IsTrue)
 
320
        c.Assert(value, gc.Equals, "different")
 
321
}
 
322
 
 
323
func (s *SettingsSuite) TestDeleteEmptiesState(c *gc.C) {
 
324
        node, err := s.createSettings(s.key, nil)
 
325
        c.Assert(err, jc.ErrorIsNil)
 
326
        node.Set("a", "foo")
 
327
        changes, err := node.Write()
 
328
        c.Assert(err, jc.ErrorIsNil)
 
329
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
330
                {ItemAdded, "a", nil, "foo"},
 
331
        })
 
332
        node.Delete("a")
 
333
        changes, err = node.Write()
 
334
        c.Assert(err, jc.ErrorIsNil)
 
335
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
336
                {ItemDeleted, "a", "foo", nil},
 
337
        })
 
338
        c.Assert(node.Map(), gc.DeepEquals, map[string]interface{}{})
 
339
}
 
340
 
 
341
func (s *SettingsSuite) TestReadResync(c *gc.C) {
 
342
        // Check that read pulls the data into the node.
 
343
        nodeOne, err := s.createSettings(s.key, nil)
 
344
        c.Assert(err, jc.ErrorIsNil)
 
345
        nodeOne.Set("a", "foo")
 
346
        changes, err := nodeOne.Write()
 
347
        c.Assert(err, jc.ErrorIsNil)
 
348
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
349
                {ItemAdded, "a", nil, "foo"},
 
350
        })
 
351
        nodeTwo, err := s.readSettings()
 
352
        c.Assert(err, jc.ErrorIsNil)
 
353
        nodeTwo.Delete("a")
 
354
        changes, err = nodeTwo.Write()
 
355
        c.Assert(err, jc.ErrorIsNil)
 
356
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
357
                {ItemDeleted, "a", "foo", nil},
 
358
        })
 
359
        nodeTwo.Set("a", "bar")
 
360
        changes, err = nodeTwo.Write()
 
361
        c.Assert(err, jc.ErrorIsNil)
 
362
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
363
                {ItemAdded, "a", nil, "bar"},
 
364
        })
 
365
        // Read of node one should pick up the new value.
 
366
        err = nodeOne.Read()
 
367
        c.Assert(err, jc.ErrorIsNil)
 
368
        value, ok := nodeOne.Get("a")
 
369
        c.Assert(ok, jc.IsTrue)
 
370
        c.Assert(value, gc.Equals, "bar")
 
371
}
 
372
 
 
373
func (s *SettingsSuite) TestMultipleWrites(c *gc.C) {
 
374
        // Check that multiple writes only do the right changes.
 
375
        node, err := s.createSettings(s.key, nil)
 
376
        c.Assert(err, jc.ErrorIsNil)
 
377
        node.Update(map[string]interface{}{"foo": "bar", "this": "that"})
 
378
        changes, err := node.Write()
 
379
        c.Assert(err, jc.ErrorIsNil)
 
380
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
381
                {ItemAdded, "foo", nil, "bar"},
 
382
                {ItemAdded, "this", nil, "that"},
 
383
        })
 
384
        node.Delete("this")
 
385
        node.Set("another", "value")
 
386
        changes, err = node.Write()
 
387
        c.Assert(err, jc.ErrorIsNil)
 
388
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
389
                {ItemAdded, "another", nil, "value"},
 
390
                {ItemDeleted, "this", "that", nil},
 
391
        })
 
392
 
 
393
        expected := map[string]interface{}{"foo": "bar", "another": "value"}
 
394
        c.Assert(expected, gc.DeepEquals, node.Map())
 
395
 
 
396
        changes, err = node.Write()
 
397
        c.Assert(err, jc.ErrorIsNil)
 
398
        c.Assert(changes, gc.DeepEquals, []ItemChange{})
 
399
 
 
400
        err = node.Read()
 
401
        c.Assert(err, jc.ErrorIsNil)
 
402
        c.Assert(expected, gc.DeepEquals, node.Map())
 
403
 
 
404
        changes, err = node.Write()
 
405
        c.Assert(err, jc.ErrorIsNil)
 
406
        c.Assert(changes, gc.DeepEquals, []ItemChange{})
 
407
}
 
408
 
 
409
func (s *SettingsSuite) TestMultipleWritesAreStable(c *gc.C) {
 
410
        node, err := s.createSettings(s.key, nil)
 
411
        c.Assert(err, jc.ErrorIsNil)
 
412
        node.Update(map[string]interface{}{"foo": "bar", "this": "that"})
 
413
        _, err = node.Write()
 
414
        c.Assert(err, jc.ErrorIsNil)
 
415
 
 
416
        var mgoData struct {
 
417
                Settings map[string]interface{}
 
418
        }
 
419
        settings, closer := s.state.getCollection(settingsC)
 
420
        defer closer()
 
421
        err = settings.FindId(s.key).One(&mgoData)
 
422
        c.Assert(err, jc.ErrorIsNil)
 
423
        version := mgoData.Settings["version"]
 
424
        for i := 0; i < 100; i++ {
 
425
                node.Set("value", i)
 
426
                node.Set("foo", "bar")
 
427
                node.Delete("value")
 
428
                node.Set("this", "that")
 
429
                _, err := node.Write()
 
430
                c.Assert(err, jc.ErrorIsNil)
 
431
        }
 
432
        mgoData.Settings = make(map[string]interface{})
 
433
        err = settings.FindId(s.key).One(&mgoData)
 
434
        c.Assert(err, jc.ErrorIsNil)
 
435
        newVersion := mgoData.Settings["version"]
 
436
        c.Assert(version, gc.Equals, newVersion)
 
437
}
 
438
 
 
439
func (s *SettingsSuite) TestWriteTwice(c *gc.C) {
 
440
        // Check the correct writing into a node by two config nodes.
 
441
        nodeOne, err := s.createSettings(s.key, nil)
 
442
        c.Assert(err, jc.ErrorIsNil)
 
443
        nodeOne.Set("a", "foo")
 
444
        changes, err := nodeOne.Write()
 
445
        c.Assert(err, jc.ErrorIsNil)
 
446
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
447
                {ItemAdded, "a", nil, "foo"},
 
448
        })
 
449
 
 
450
        nodeTwo, err := s.readSettings()
 
451
        c.Assert(err, jc.ErrorIsNil)
 
452
        nodeTwo.Set("a", "bar")
 
453
        changes, err = nodeTwo.Write()
 
454
        c.Assert(err, jc.ErrorIsNil)
 
455
        c.Assert(changes, gc.DeepEquals, []ItemChange{
 
456
                {ItemModified, "a", "foo", "bar"},
 
457
        })
 
458
 
 
459
        // Shouldn't write again. Changes were already
 
460
        // flushed and acted upon by other parties.
 
461
        changes, err = nodeOne.Write()
 
462
        c.Assert(err, jc.ErrorIsNil)
 
463
        c.Assert(changes, gc.DeepEquals, []ItemChange{})
 
464
 
 
465
        err = nodeOne.Read()
 
466
        c.Assert(err, jc.ErrorIsNil)
 
467
        c.Assert(nodeOne.key, gc.Equals, nodeTwo.key)
 
468
        c.Assert(nodeOne.disk, gc.DeepEquals, nodeTwo.disk)
 
469
        c.Assert(nodeOne.core, gc.DeepEquals, nodeTwo.core)
 
470
}
 
471
 
 
472
func (s *SettingsSuite) TestList(c *gc.C) {
 
473
        _, err := s.createSettings("key#1", map[string]interface{}{"foo1": "bar1"})
 
474
        c.Assert(err, jc.ErrorIsNil)
 
475
        _, err = s.createSettings("key#2", map[string]interface{}{"foo2": "bar2"})
 
476
        c.Assert(err, jc.ErrorIsNil)
 
477
        _, err = s.createSettings("another#1", map[string]interface{}{"foo2": "bar2"})
 
478
        c.Assert(err, jc.ErrorIsNil)
 
479
 
 
480
        nodes, err := listSettings(s.state, s.collection, "key#")
 
481
        c.Assert(err, jc.ErrorIsNil)
 
482
        c.Assert(nodes, jc.DeepEquals, map[string]map[string]interface{}{
 
483
                "key#1": {"foo1": "bar1"},
 
484
                "key#2": {"foo2": "bar2"},
 
485
        })
 
486
}