couch_docs 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,170 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe CouchDocs::CommandLine do
4
+ it "should be able to run a single instance of a command line" do
5
+ CouchDocs::CommandLine.
6
+ should_receive(:new).
7
+ with('foo', 'bar').
8
+ and_return(mock("Command Line").as_null_object)
9
+
10
+ CouchDocs::CommandLine.run('foo', 'bar')
11
+ end
12
+
13
+ it "should run the command line instance" do
14
+ command_line = mock("Command Line").as_null_object
15
+ command_line.
16
+ should_receive(:run)
17
+
18
+ CouchDocs::CommandLine.stub!(:new).and_return(command_line)
19
+
20
+ CouchDocs::CommandLine.run('foo', 'bar')
21
+ end
22
+
23
+ context "an instance that dumps a CouchDB database" do
24
+ it "should dump CouchDB documents from uri to dir when run" do
25
+ @it = CouchDocs::CommandLine.new(['dump', 'uri', 'dir'])
26
+
27
+ CouchDocs.
28
+ should_receive(:dump).
29
+ with("uri", "dir", nil)
30
+
31
+ @it.run
32
+ end
33
+
34
+ it "should be able to dump only design documents" do
35
+ @it = CouchDocs::CommandLine.new(['dump', 'uri', 'dir', '-d'])
36
+
37
+ CouchDocs.
38
+ should_receive(:dump).
39
+ with("uri", "dir", :design)
40
+
41
+ @it.run
42
+ end
43
+
44
+ it "should be able to dump only regular documents" do
45
+ @it = CouchDocs::CommandLine.new(['dump', 'uri', 'dir', '-D'])
46
+
47
+ CouchDocs.
48
+ should_receive(:dump).
49
+ with("uri", "dir", :doc)
50
+
51
+ @it.run
52
+ end
53
+
54
+ it "should be an initial add if everything is an add" do
55
+ @it = CouchDocs::CommandLine.new(['push', 'uri'])
56
+ args = [mock(:type => :added),
57
+ mock(:type => :added)]
58
+ @it.should be_initial_add(args)
59
+ end
60
+
61
+ it "should not be an initial add if something is not an add" do
62
+ @it = CouchDocs::CommandLine.new(['push', 'uri'])
63
+ args = [mock(:type => :foo),
64
+ mock(:type => :added)]
65
+ @it.should_not be_initial_add(args)
66
+ end
67
+
68
+ it "should be a design docs update if something changes in _design" do
69
+ @it = CouchDocs::CommandLine.new(['push', 'uri'])
70
+ args = [mock(:path => "foo"),
71
+ mock(:path => "_design")]
72
+ @it.should be_design_doc_update(args)
73
+ end
74
+
75
+ it "should know document updates" do
76
+ @it = CouchDocs::CommandLine.new(['push', 'uri'])
77
+ doc_update = mock(:path => "foo")
78
+ args = [doc_update,
79
+ mock(:path => "_design")]
80
+
81
+ @it.
82
+ documents(args).
83
+ should == [doc_update]
84
+ end
85
+
86
+
87
+ context "updates on the filesystem" do
88
+ before(:each) do
89
+ @args = mock("args")
90
+ @it = CouchDocs::CommandLine.new(%w(push uri dir))
91
+ end
92
+ it "should only update design docs if only local design docs have changed" do
93
+ CouchDocs.
94
+ should_receive(:put_dir)
95
+
96
+ @it.stub!(:initial_add?).and_return(true)
97
+ @it.directory_watcher_update(@args)
98
+ end
99
+ context "not an inital add" do
100
+ before(:each) do
101
+ @it.stub!(:initial_add?).and_return(false)
102
+ @it.stub!(:design_doc_update?).and_return(false)
103
+ @it.stub!(:documents).and_return([])
104
+ CouchDocs.stub!(:put_design_dir)
105
+ end
106
+ it "should update design docs if there are design document updates" do
107
+ CouchDocs.
108
+ should_receive(:put_design_dir)
109
+
110
+ @it.stub!(:design_doc_update?).and_return(true)
111
+ @it.directory_watcher_update(@args)
112
+ end
113
+ it "should update documents (if any)" do
114
+ file_mock = mock("File", :path => "/foo")
115
+ @it.stub!(:documents).and_return([file_mock])
116
+
117
+ CouchDocs.
118
+ should_receive(:put_file).
119
+ with("uri", "/foo")
120
+
121
+ @it.directory_watcher_update(@args)
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ context "pushing" do
128
+ before(:each) do
129
+ CouchDocs.stub!(:put_dir)
130
+
131
+ @dw = mock("Directory Watcher").as_null_object
132
+ DirectoryWatcher.stub!(:new).and_return(@dw)
133
+ end
134
+
135
+ it "should know watch" do
136
+ @it = CouchDocs::CommandLine.new(%w(push uri dir -w))
137
+ @it.options[:watch].should be_true
138
+ end
139
+
140
+ it "should run once normally" do
141
+ @dw.should_receive(:run_once)
142
+
143
+ @it = CouchDocs::CommandLine.new(%w(push uri dir))
144
+ @it.run
145
+ end
146
+
147
+ it "should start a watcher with -w" do
148
+ @dw.should_receive(:start)
149
+
150
+ @it = CouchDocs::CommandLine.new(%w(push uri dir -w))
151
+ @it.stub!(:active?).and_return(false)
152
+ @it.run
153
+ end
154
+ end
155
+
156
+ context "an instance that uploads to a CouchDB database" do
157
+ before(:each) do
158
+ @it = CouchDocs::CommandLine.new(['load', 'dir', 'uri'])
159
+ end
160
+
161
+ it "should load CouchDB documents from dir to uri when run" do
162
+ CouchDocs.
163
+ should_receive(:put_dir).
164
+ with("uri", "dir")
165
+
166
+ @it.run
167
+ end
168
+ end
169
+
170
+ end
@@ -0,0 +1,197 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe CouchDocs::DesignDirectory do
4
+ it "should require a root directory for instantiation" do
5
+ lambda { CouchDocs::DesignDirectory.new }.
6
+ should raise_error
7
+
8
+ lambda { CouchDocs::DesignDirectory.new("foo") }.
9
+ should raise_error
10
+
11
+ lambda { CouchDocs::DesignDirectory.new("fixtures/_design")}.
12
+ should_not raise_error
13
+ end
14
+
15
+ it "should convert arrays into deep hashes" do
16
+ CouchDocs::DesignDirectory.
17
+ a_to_hash(%w{a b c d}).
18
+ should == {
19
+ 'a' => {
20
+ 'b' => {
21
+ 'c' => 'd'
22
+ }
23
+ }
24
+ }
25
+ end
26
+
27
+ context "a valid directory" do
28
+ before(:each) do
29
+ @it = CouchDocs::DesignDirectory.new("fixtures/_design")
30
+ end
31
+
32
+ it "should list dirs, basename and contents of a js file" do
33
+ @it.expand_file("fixtures/_design/a/b/c.js").
34
+ should == ['a', 'b', 'c', 'function(doc) { return true; }']
35
+ end
36
+
37
+ it "should list dirs, basename and contents of a json file" do
38
+ @it.expand_file("fixtures/_design/a/e.json").
39
+ should == ['a', 'e', [{"one" => "2"}]]
40
+ end
41
+
42
+ it "should assemble all documents into a single docs structure" do
43
+ @it.to_hash['a'].
44
+ should == {
45
+ 'b' => {
46
+ 'c' => 'function(doc) { return true; }',
47
+ 'd' => 'function(doc) { return true; }'
48
+ },
49
+ 'e' => [{"one" => "2"}]
50
+ }
51
+ end
52
+
53
+ it "should process code macros when assembling" do
54
+ @it.to_hash['x'].
55
+ should == {
56
+ 'z' =>
57
+ "// !begin code foo.js\n" +
58
+ "function foo () { return \"foo\"; }\n" +
59
+ "// !end code foo.js\n" +
60
+ "function bar () { return \"bar\"; }\n"
61
+ }
62
+ end
63
+
64
+ it "should ignore macro escape sequence when reading JSON" do
65
+ @it.to_hash['j'].
66
+ should == {'q' => ["!code foo.js"]}
67
+ end
68
+
69
+ it "should work with absolute !code paths"
70
+
71
+ it "should replace !code macros with the contents of the referenced file in lib" do
72
+ @it.stub!(:read_from_lib).and_return("awesome javascript")
73
+
74
+ @it.
75
+ process_code_macro(" // !code foo/bar.js ").
76
+ should =~ /awesome javascript/
77
+ end
78
+
79
+ it "should not affect normal lines when processing macros" do
80
+ @it.
81
+ process_code_macro(" var foo = 'bar'; ").
82
+ should == " var foo = 'bar'; "
83
+ end
84
+
85
+ it "should find files with relative paths in __lib" do
86
+ File.
87
+ should_receive(:read).
88
+ with("fixtures/_design/__lib/foo.js")
89
+
90
+ @it.read_from_lib("foo.js")
91
+ end
92
+
93
+ end
94
+
95
+ context "saving a JSON attribute" do
96
+ before(:each) do
97
+ @it = CouchDocs::DesignDirectory.new("/tmp")
98
+
99
+ FileUtils.stub!(:mkdir_p)
100
+ @file = mock("File").as_null_object
101
+ File.stub!(:new).and_return(@file)
102
+ end
103
+
104
+ it "should not mangle json valued attributes" do
105
+ @file.
106
+ should_receive(:write).
107
+ with(%{["bar","baz"]})
108
+
109
+ @it.save_js(nil, "_design/foo", { "foo" => ["bar","baz"] })
110
+ end
111
+
112
+ it "should save in a .json file" do
113
+ File.
114
+ should_receive(:new).
115
+ with("/tmp/_design/foo/foo.json", "w+").
116
+ and_return(@file)
117
+
118
+ @it.save_js(nil, "_design/foo", { "foo" => ["bar","baz"] })
119
+ end
120
+ end
121
+
122
+ context "saving a JS attribute" do
123
+ before(:each) do
124
+ @it = CouchDocs::DesignDirectory.new("/tmp")
125
+
126
+ FileUtils.stub!(:mkdir_p)
127
+ @file = mock("File").as_null_object
128
+ File.stub!(:new).and_return(@file)
129
+ end
130
+
131
+ it "should not store _id" do
132
+ File.
133
+ should_not_receive(:new).
134
+ with("/tmp/_design/foo/_id.js", "w+")
135
+
136
+ @it.save_js(nil, "_design/foo", { "_id" => "_design/foo"})
137
+ end
138
+
139
+ it "should create map the design document attribute to the filesystem" do
140
+ FileUtils.
141
+ should_receive(:mkdir_p).
142
+ with("/tmp/_design/foo")
143
+
144
+ @it.save_js("_design/foo", "bar", "json")
145
+ end
146
+
147
+ it "should store the attribute to the filesystem" do
148
+ File.
149
+ should_receive(:new).
150
+ with("/tmp/_design/foo/bar.js", "w+")
151
+
152
+ @it.save_js("_design/foo", "bar", "json")
153
+ end
154
+
155
+ it "should store hash values to the filesystem" do
156
+ File.
157
+ should_receive(:new).
158
+ with("/tmp/_design/foo/bar/baz.js", "w+")
159
+
160
+ @it.save_js("_design/foo", "bar", { "baz" => "json" })
161
+ end
162
+
163
+ it "should store the attribute to the filesystem" do
164
+ @file.
165
+ should_receive(:write).
166
+ with("json")
167
+
168
+ @it.save_js("_design/foo", "bar", "json")
169
+ end
170
+
171
+ it "should store the attributes with slashes to the filesystem" do
172
+ File.
173
+ should_receive(:new).
174
+ with("/tmp/_design/foo/bar%2Fbaz.js", "w+")
175
+
176
+ @it.save_js("_design/foo", "bar/baz", "json")
177
+ end
178
+
179
+ it "should strip lib code when dumping" do
180
+ js = <<_JS
181
+ // !begin code foo.js
182
+ function foo () { return 'foo'; }
183
+ // !end code foo.js
184
+ // !begin code bar.js
185
+ function bar () { return 'bar'; }
186
+ // !end code bar.js
187
+ function baz () { return 'baz'; }
188
+ _JS
189
+
190
+ @it.
191
+ remove_code_macros(js).
192
+ should == "// !code foo.js\n" +
193
+ "// !code bar.js\n" +
194
+ "function baz () { return 'baz'; }\n"
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,212 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe CouchDocs::DocumentDirectory do
4
+ it "should require a root directory for instantiation" do
5
+ lambda { CouchDocs::DocumentDirectory.new }.
6
+ should raise_error
7
+
8
+ lambda { CouchDocs::DocumentDirectory.new("foo") }.
9
+ should raise_error
10
+
11
+ lambda { CouchDocs::DocumentDirectory.new("fixtures")}.
12
+ should_not raise_error
13
+ end
14
+
15
+ context "a valid directory" do
16
+ before(:each) do
17
+ @it = CouchDocs::DocumentDirectory.new("fixtures")
18
+ end
19
+
20
+ it "should be able to iterate over the documents" do
21
+ everything = []
22
+ @it.each_document do |name, contents|
23
+ everything << [name, contents]
24
+ end
25
+ everything.
26
+ should include ['bar', {"bar" => "2"}]
27
+
28
+ everything.
29
+ should include ['foo', {"foo" => "1"}]
30
+ end
31
+
32
+ it "should be able to store a document" do
33
+ file = mock("File", :write => 42, :close => true)
34
+ File.
35
+ should_receive(:new).
36
+ with("fixtures/foo.json", "w+").
37
+ and_return(file)
38
+
39
+ @it.store_document({'_id' => 'foo'})
40
+ end
41
+
42
+ it "should be able to save a document as JSON" do
43
+ file = mock("File", :close => true)
44
+ File.stub!(:new).and_return(file)
45
+
46
+ file.should_receive(:write).with(%Q|{"_id":"foo"}|)
47
+
48
+ @it.store_document({'_id' => 'foo'})
49
+ end
50
+
51
+ context "pushing attachments to CouchDB" do
52
+ before(:each) do
53
+ @spacer_b64 = "R0lGODlhAQABAPcAAAAAAIAAAACAAICAAAAAgIAAgACAgICAgMDAwP8AAAD/AP//AAAA//8A/wD//////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMwAAZgAAmQAAzAAA/wAzAAAzMwAzZgAzmQAzzAAz/wBmAABmMwBmZgBmmQBmzABm/wCZAACZMwCZZgCZmQCZzACZ/wDMAADMMwDMZgDMmQDMzADM/wD/AAD/MwD/ZgD/mQD/zAD//zMAADMAMzMAZjMAmTMAzDMA/zMzADMzMzMzZjMzmTMzzDMz/zNmADNmMzNmZjNmmTNmzDNm/zOZADOZMzOZZjOZmTOZzDOZ/zPMADPMMzPMZjPMmTPMzDPM/zP/ADP/MzP/ZjP/mTP/zDP//2YAAGYAM2YAZmYAmWYAzGYA/2YzAGYzM2YzZmYzmWYzzGYz/2ZmAGZmM2ZmZmZmmWZmzGZm/2aZAGaZM2aZZmaZmWaZzGaZ/2bMAGbMM2bMZmbMmWbMzGbM/2b/AGb/M2b/Zmb/mWb/zGb//5kAAJkAM5kAZpkAmZkAzJkA/5kzAJkzM5kzZpkzmZkzzJkz/5lmAJlmM5lmZplmmZlmzJlm/5mZAJmZM5mZZpmZmZmZzJmZ/5nMAJnMM5nMZpnMmZnMzJnM/5n/AJn/M5n/Zpn/mZn/zJn//8wAAMwAM8wAZswAmcwAzMwA/8wzAMwzM8wzZswzmcwzzMwz/8xmAMxmM8xmZsxmmcxmzMxm/8yZAMyZM8yZZsyZmcyZzMyZ/8zMAMzMM8zMZszMmczMzMzM/8z/AMz/M8z/Zsz/mcz/zMz///8AAP8AM/8AZv8Amf8AzP8A//8zAP8zM/8zZv8zmf8zzP8z//9mAP9mM/9mZv9mmf9mzP9m//+ZAP+ZM/+ZZv+Zmf+ZzP+Z///MAP/MM//MZv/Mmf/MzP/M////AP//M///Zv//mf//zP///yH5BAEAABAALAAAAAABAAEAAAgEALkFBAA7"
54
+ end
55
+
56
+ it "should connect attachments by sub-directory name (foo.json => foo/)" do
57
+ @it.stub!(:mime_type)
58
+
59
+ everything = []
60
+ @it.each_document do |name, contents|
61
+ everything << [name, contents]
62
+ end
63
+
64
+ everything.
65
+ should include(['baz_with_attachments',
66
+ {'baz' => '3',
67
+ "_attachments" => { "spacer.gif" => {"data" => @spacer_b64} } }])
68
+ end
69
+ it "should mime 64 encode attachments" do
70
+ # covered above
71
+ end
72
+ it "should ignore non-file attachments" do
73
+ # covered above
74
+ end
75
+
76
+ context "infering mime type" do
77
+ before(:each) do
78
+ File.stub!(:read).and_return("asdf")
79
+ Base64.stub!(:encode64).and_return("asdf")
80
+ end
81
+
82
+ it "should guess gif mime type" do
83
+ @it.file_as_attachment("spacer.gif").
84
+ should == {
85
+ "data" => "asdf",
86
+ "content_type" => "image/gif"
87
+ }
88
+ end
89
+
90
+ it "should guess jpeg mime type" do
91
+ @it.file_as_attachment("spacer.jpg").
92
+ should == {
93
+ "data" => "asdf",
94
+ "content_type" => "image/jpeg"
95
+ }
96
+ end
97
+
98
+ it "should guess png mime type" do
99
+ @it.file_as_attachment("spacer.png").
100
+ should == {
101
+ "data" => "asdf",
102
+ "content_type" => "image/png"
103
+ }
104
+ end
105
+
106
+ it "should default to no mime type" do
107
+ @it.file_as_attachment("spacer.foo").
108
+ should == {
109
+ "data" => "asdf"
110
+ }
111
+ end
112
+ end
113
+
114
+ it "should give precedence to filesystem attachments" do
115
+ @it.stub!(:mime_type)
116
+
117
+ JSON.stub!(:parse).
118
+ and_return({ "baz" => "3",
119
+ "_attachments" => {
120
+ "spacer.gif" => "asdf",
121
+ "baz.jpg" => "asdf"
122
+ }
123
+ })
124
+
125
+ everything = []
126
+ @it.each_document do |name, contents|
127
+ everything << [name, contents]
128
+ end
129
+
130
+ everything.
131
+ should include(['baz_with_attachments',
132
+ {'baz' => '3',
133
+ "_attachments" => { "spacer.gif" => {"data" => @spacer_b64}, "baz.jpg" => "asdf" } }])
134
+ end
135
+
136
+ end
137
+ context "dump attachments from CouchDB" do
138
+ before(:each) do
139
+ FileUtils.stub!(:mkdir_p)
140
+ end
141
+
142
+ it "should store attachments" do
143
+ file = mock("File").as_null_object
144
+ File.stub!(:new).and_return(file)
145
+
146
+ @it.
147
+ should_receive(:store_attachments).
148
+ with('foo', 'bar')
149
+
150
+ @it.store_document({'_id' => 'foo',
151
+ '_attachments' => 'bar'})
152
+ end
153
+
154
+ context "storing attachments" do
155
+ before(:each) do
156
+ @attachments = { 'foo.txt' => { 'data' => 'attachment data' } }
157
+ end
158
+
159
+ it "should make a directory to hold the attachments" do
160
+ @it.
161
+ should_receive(:make_attachment_dir).
162
+ with('foo')
163
+
164
+ @it.stub!(:save_attachment)
165
+ @it.store_attachments('foo', @attachments)
166
+ end
167
+
168
+ it "should create a sub-directory with document ID" do
169
+ FileUtils.
170
+ should_receive(:mkdir_p).
171
+ with("fixtures/foo")
172
+
173
+ @it.stub!(:save_attachment)
174
+ @it.make_attachment_dir('foo')
175
+ end
176
+
177
+ it "should save attachments to the filesystem" do
178
+ @it.
179
+ should_receive(:save_attachment).
180
+ with('foo', 'foo.txt', 'attachment data')
181
+
182
+ @it.stub!(:save_attachment)
183
+ @it.store_attachments('foo', @attachments)
184
+ end
185
+
186
+ it "should dump with native encoding (non-mime64)" do
187
+ file = mock("File").as_null_object
188
+ File.stub!(:new).and_return(file)
189
+
190
+ file.
191
+ should_receive(:write)
192
+
193
+ @it.save_attachment('foo', 'foo.txt', 'ZGF0YQ==')
194
+ end
195
+ end
196
+
197
+ it "should not include the attachments attribute" do
198
+ file = mock("File", :close => true)
199
+ File.stub!(:new).and_return(file)
200
+
201
+ file.
202
+ should_receive(:write).
203
+ with('{"_id":"foo"}')
204
+
205
+ @it.stub!(:store_attachments)
206
+
207
+ @it.store_document({'_id' => 'foo',
208
+ '_attachments' => 'foo'})
209
+ end
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,98 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
2
+
3
+ describe CouchDocs::Store do
4
+ it "should require a CouchDB URL Root for instantiation" do
5
+ lambda { CouchDocs::Store.new }.
6
+ should raise_error
7
+
8
+ lambda { CouchDocs::Store.new("uri") }.
9
+ should_not raise_error
10
+ end
11
+
12
+ context "a valid store" do
13
+ before(:each) do
14
+ @it = CouchDocs::Store.new("uri")
15
+
16
+ @hash = {
17
+ 'a' => {
18
+ 'b' => {
19
+ 'c' => 'function(doc) { return true; }'
20
+ }
21
+ }
22
+ }
23
+ end
24
+
25
+ it "should be able to put a new document" do
26
+ CouchDocs::Store.
27
+ should_receive(:put).
28
+ with("uri", { })
29
+
30
+ CouchDocs::Store.put!("uri", { })
31
+ end
32
+
33
+ it "should delete existing docs if first put fails" do
34
+ CouchDocs::Store.
35
+ stub!(:put).
36
+ and_raise(RestClient::RequestFailed)
37
+
38
+ CouchDocs::Store.
39
+ should_receive(:delete_and_put).
40
+ with("uri", { })
41
+
42
+ CouchDocs::Store.put!("uri", { })
43
+ end
44
+
45
+ it "should be able to delete and put" do
46
+ CouchDocs::Store.
47
+ should_receive(:delete).
48
+ with("uri")
49
+
50
+ CouchDocs::Store.
51
+ should_receive(:put).
52
+ with("uri", { })
53
+
54
+ CouchDocs::Store.delete_and_put("uri", { })
55
+ end
56
+
57
+ it "should be able to load a hash into design docs" do
58
+ RestClient.
59
+ should_receive(:put).
60
+ with("uri/_design/a",
61
+ '{"b":{"c":"function(doc) { return true; }"}}',
62
+ :content_type => 'application/json')
63
+ @it.put_design_documents(@hash)
64
+ end
65
+
66
+ it "should be able to retrieve an existing document" do
67
+ RestClient.
68
+ stub!(:get).
69
+ and_return('{"_rev":"1234"}')
70
+
71
+ CouchDocs::Store.get("uri").should == { '_rev' => "1234" }
72
+ end
73
+
74
+ it "should be able to delete an existing document" do
75
+ CouchDocs::Store.stub!(:get).and_return({ '_rev' => '1234' })
76
+
77
+ RestClient.
78
+ should_receive(:delete).
79
+ with("uri?rev=1234")
80
+
81
+ CouchDocs::Store.delete("uri")
82
+ end
83
+
84
+ it "should be able to load each document" do
85
+ CouchDocs::Store.stub!(:get).
86
+ with("uri/_all_docs").
87
+ and_return({ "total_rows" => 2,
88
+ "offset" => 0,
89
+ "rows" => [{"id"=>"1", "value"=>{}, "key"=>"1"},
90
+ {"id"=>"2", "value"=>{}, "key"=>"2"}]})
91
+
92
+ CouchDocs::Store.stub!(:get).with("uri/1?attachments=true")
93
+ CouchDocs::Store.should_receive(:get).with("uri/2?attachments=true")
94
+
95
+ @it.each { }
96
+ end
97
+ end
98
+ end