mongo-proxy 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+ require File.expand_path("../lib/mongo-proxy.rb", __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.add_runtime_dependency 'json'
6
+ gem.add_runtime_dependency 'bson'
7
+ gem.add_runtime_dependency 'bson_ext'
8
+ gem.add_runtime_dependency 'em-proxy'
9
+ gem.add_runtime_dependency 'trollop'
10
+
11
+ gem.add_development_dependency 'mongo'
12
+ gem.add_development_dependency 'rake'
13
+ gem.add_development_dependency 'rake-compiler'
14
+ gem.add_development_dependency 'rspec'
15
+ gem.add_development_dependency 'mocha'
16
+ gem.add_development_dependency 'autotest-standalone'
17
+ gem.add_development_dependency 'rack-test'
18
+
19
+ gem.authors = ["Peter Bakkum"]
20
+ gem.bindir = 'bin'
21
+ gem.description = %q{A proxy server for MongoDB.}
22
+ gem.email = ['pbb7c@virginia.edu']
23
+ gem.executables = ['mongo-proxy']
24
+ gem.extra_rdoc_files = ['LICENSE.md', 'README.md']
25
+ gem.files = Dir['LICENSE.md', 'README.md', 'mongo-proxy.gemspec', 'Gemfile', '.rspec', '.travis.yml', 'lib/**/*', 'bin/*', 'spec/**/*']
26
+ gem.homepage = 'http://github.com/bakks/mongo-proxy'
27
+ gem.name = 'mongo-proxy'
28
+ gem.rdoc_options = ["--charset=UTF-8"]
29
+ gem.require_paths = ['lib']
30
+ gem.required_rubygems_version = Gem::Requirement.new(">= 1.3.6")
31
+ gem.summary = %q{A proxy server for MongoDB.}
32
+ gem.test_files = Dir['spec/**/*']
33
+ gem.version = MongoProxy::VERSION
34
+ gem.license = 'MIT'
35
+ end
36
+
@@ -0,0 +1,294 @@
1
+ require 'spec_helper'
2
+ require 'mongo'
3
+ require 'pty'
4
+
5
+ describe MongoProxy do
6
+ def mongo_test_data
7
+ mongotestdb['test'].remove
8
+ mongotestdb['sample'].remove
9
+ mongotestdb['big'].remove
10
+
11
+ for i in 0..9
12
+ mongotestdb['test'].insert({:x => i})
13
+ end
14
+
15
+ for i in 0..9
16
+ mongotestdb['sample'].insert({:_id => i, :x => i})
17
+ end
18
+
19
+ for i in 0...1200
20
+ mongotestdb['big'].insert({:_id => i, :x => i})
21
+ end
22
+ end
23
+
24
+ before :all do
25
+ mongo_test_data
26
+ config = {
27
+ :motd => "foo\nbar",
28
+ :client_port => 27017,
29
+ :server_port => 27018,
30
+ :read_only => true
31
+ }
32
+ @gate_thread = Thread.new do
33
+ m = MongoProxy.new(config)
34
+ m.start
35
+ end
36
+ sleep 0.5
37
+ end
38
+
39
+ after :all do
40
+ @gate_thread.kill
41
+ end
42
+
43
+ it 'should accept public connections' do
44
+ mongo = Mongo::Connection.new
45
+ names = mongo.database_names
46
+ names.should include 'mongo_proxy_test'
47
+
48
+ cnames = mongo[TEST_DB].collection_names
49
+ cnames.should include 'test'
50
+ cnames.should include 'sample'
51
+ cnames.should include 'big'
52
+ end
53
+
54
+ it 'should accept connections from mongo driver' do
55
+ mongo = Mongo::Connection.new
56
+
57
+ cursor = mongo[TEST_DB]['test'].find
58
+ mongo[TEST_DB]['test'].count.should == 10
59
+
60
+ cursor = mongo[TEST_DB]['big'].find
61
+ i = 0
62
+ while cursor.next
63
+ i += 1
64
+ end
65
+ i.should == 1200
66
+ end
67
+
68
+ it 'should handle kill cursor' do
69
+ mongo = Mongo::Connection.new
70
+
71
+ cursor = mongo[TEST_DB]['big'].find
72
+ cursor.count.should == 1200
73
+ cursor.next
74
+ cursor.close
75
+ mongo.close
76
+ end
77
+
78
+ it 'should handle reconnections' do
79
+ for i in 0..10
80
+ mongo = Mongo::Connection.new
81
+ cursor = mongo[TEST_DB]['big'].find
82
+ i = 0
83
+ while cursor.next
84
+ i += 1
85
+ end
86
+ i.should == 1200
87
+ mongo.close
88
+ end
89
+ end
90
+
91
+ it 'should block where' do
92
+ mongo = Mongo::Connection.new
93
+ expect {
94
+ cursor = mongo[TEST_DB]['big'].find({'$where' => 'true'})
95
+ cursor.next
96
+ }.to raise_error
97
+ mongo.close
98
+ end
99
+
100
+ it 'should block mapreduce' do
101
+ mongo = Mongo::Connection.new
102
+ expect do
103
+ x = mongo[TEST_DB]['big'].mapreduce('function() { emit(this.x, 1) }', 'function(k, v) { return 1 }', {:out => {:inline => 1}, :raw => true})
104
+ end.to raise_error
105
+ mongo.close
106
+ end
107
+
108
+ it 'should handle getmore' do
109
+ mongo = Mongo::Connection.new
110
+ coll = mongo[TEST_DB]['big']
111
+
112
+ cursor = coll.find({}, {:sort => ['x', :asc]})
113
+ i = 0
114
+
115
+ while doc = cursor.next
116
+ doc['x'].should == i
117
+ i += 1
118
+ end
119
+
120
+ i.should == 1200
121
+ end
122
+
123
+ it 'should send motd' do
124
+ mongo = Mongo::Connection.new
125
+ admin = mongo['admin']
126
+ x = admin.command({'getLog' => 'startupWarnings'})
127
+ x['ok'].should == 1.0
128
+ x['totalLinesWritten'].should be > 1
129
+ x['log'].size.should be > 1
130
+ end
131
+
132
+ it 'should accept connections from shell driver' do
133
+ cmd = `echo "db.test.find()" | mongo localhost/mongo_proxy_test`
134
+ cmd.split("\n")[2..-2].size.should be >= 10
135
+ end
136
+
137
+ it 'should block arbitrary commands' do
138
+ mongo = Mongo::Connection.new
139
+ expect { mongo[TEST_DB].command({'repairDatabase' => 1}) }.to raise_error
140
+ expect { mongo[TEST_DB].command({'fsync' => 1}) }.to raise_error
141
+ expect { mongo[TEST_DB].command({'enableSharding' => 1}) }.to raise_error
142
+ expect { mongo[TEST_DB].command({'shutdown' => 1}) }.to raise_error
143
+ expect { mongo[TEST_DB].command({'ping' => 1}) }.to raise_error
144
+ end
145
+
146
+ it 'should allow ismaster' do
147
+ mongo = Mongo::Connection.new
148
+ r = mongo['admin'].command({'ismaster' => 1})
149
+ r['ismaster'].should == true
150
+ r = mongo['admin'].command({'isMaster' => 1})
151
+ r['ismaster'].should == true
152
+ end
153
+
154
+ it 'should block writes' do
155
+ mongo = Mongo::Connection.new
156
+ db = mongo[TEST_DB]
157
+ coll = db['big']
158
+ expect { coll.insert({:foo => 'bar'}) }.to raise_error
159
+ expect { coll.remove }.to raise_error
160
+ expect { coll.update({:x => 0}, {:x => 1}) }.to raise_error
161
+ expect { coll.ensure_index({:x => 1}) }.to raise_error
162
+
163
+ coll.count.should == 1200
164
+
165
+ cursor = coll.find({}, {:sort => ['x', :asc]})
166
+ i = 0
167
+
168
+ while doc = cursor.next
169
+ doc['x'].should == i
170
+ i += 1
171
+ end
172
+
173
+ i.should == 1200
174
+
175
+ coll.index_information.size.should == 1
176
+ end
177
+
178
+ it 'should allow writes when not in read_only mode' do
179
+ config = {
180
+ :read_only => false,
181
+ :client_port => 29017,
182
+ :server_port => 27018
183
+ }
184
+ gate_thread2 = Thread.new do
185
+ begin
186
+ MongoProxy.new(config).start
187
+ rescue Exception => e
188
+ p [e.inspect, e.backtrace.first]
189
+ end
190
+ end
191
+ sleep 0.5
192
+
193
+ mongo = Mongo::Connection.new('127.0.0.1', 29017)
194
+ db = mongo[TEST_DB]
195
+ coll = db['big']
196
+ coll.size.should == 1200
197
+ coll.insert({:foo => 'xxxx'})
198
+ coll.size.should == 1201
199
+
200
+ gate_thread2.kill
201
+ end
202
+
203
+ it 'should allow front middleware' do
204
+ config = {
205
+ :read_only => false,
206
+ :client_port => 29018,
207
+ :server_port => 27018
208
+ }
209
+ i = 0
210
+
211
+ gate_thread2 = Thread.new do
212
+ m = MongoProxy.new(config)
213
+
214
+ # add middleware that returns null so it can't connect
215
+ m.add_callback_to_front do |conn, msg|
216
+ nil
217
+ end
218
+
219
+ m.add_callback_to_front do |conn, msg|
220
+ i += 1
221
+ msg
222
+ end
223
+
224
+ m.start
225
+ end
226
+ sleep 0.5
227
+
228
+ expect { mongo = Mongo::Connection.new('localhost', 29018, :connect_timeout => 0.2) }.to raise_error
229
+ i.should == 1
230
+
231
+ gate_thread2.kill
232
+ end
233
+
234
+ it 'should allow back middleware' do
235
+ config = {
236
+ :read_only => false,
237
+ :client_port => 29018,
238
+ :server_port => 27018
239
+ }
240
+ i = 0
241
+
242
+ gate_thread2 = Thread.new do
243
+ m = MongoProxy.new(config)
244
+
245
+ # add middleware that returns null so it can't connect
246
+ m.add_callback_to_back do |conn, msg|
247
+ nil
248
+ end
249
+
250
+ m.add_callback_to_back do |conn, msg|
251
+ i += 1
252
+ msg
253
+ end
254
+
255
+ m.start
256
+ end
257
+ sleep 0.5
258
+
259
+ expect { mongo = Mongo::Connection.new('localhost', 29018, :connect_timeout => 0.2) }.to raise_error
260
+ i.should == 0
261
+
262
+ gate_thread2.kill
263
+ end
264
+
265
+ it 'should shape traffic' do
266
+ config = {
267
+ :read_only => false,
268
+ :client_port => 29020,
269
+ :server_port => 27018
270
+ }
271
+
272
+ gate_thread2 = Thread.new do
273
+ m = MongoProxy.new(config)
274
+ m.add_callback_to_back do |conn, msg|
275
+ if msg[:header][:opCode] == :insert
276
+ msg[:documents] = [{:foo => 1}]
277
+ end
278
+ msg
279
+ end
280
+ m.start
281
+ end
282
+ sleep 0.5
283
+
284
+ mongo = Mongo::Connection.new('localhost', 29020, :connect_timeout => 0.2)
285
+ coll = mongo[TEST_DB]['test']
286
+ coll.remove
287
+ coll.insert({:x => 1})
288
+ coll.insert({:x => 1})
289
+ coll.count({:foo => 1}).should == 2
290
+
291
+ gate_thread2.kill
292
+ end
293
+ end
294
+
@@ -0,0 +1,317 @@
1
+ require 'spec_helper'
2
+
3
+ describe WireMongo do
4
+ let (:reply_sample) {"W\x00\x00\x00\x0E\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x003\x00\x00\x00\bismaster\x00\x01\x10maxBsonObjectSize\x00\x00\x00\x00\x01\x01ok\x00\x00\x00\x00\x00\x00\x00\xF0?\x00"}
5
+ let (:reply_sample2) {"\"\u0002\u0000\u0000\xAE{\u0000\u0000\u000E\u0000\u0000\u0000\u0001\u0000\u0000\u0000\b\u0000\u0000\u00002\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\n\u0000\u0000\u00003\u0000\u0000\u0000\u0002_id\u0000%\u0000\u0000\u00003427b4fa-98d3-b465-9725-013b0627c6f3\u0000\u00003\u0000\u0000\u0000\u0002_id\u0000%\u0000\u0000\u0000dabe4ffc-98d3-b465-9725-013b0627c6f9\u0000\u00003\u0000\u0000\u0000\u0002_id\u0000%\u0000\u0000\u0000268a9cfc-98d3-b465-9725-013b0627c6fc\u0000\u00003\u0000\u0000\u0000\u0002_id\u0000%\u0000\u0000\u00007156e9fd-98d3-b465-9725-013b0627c6fd\u0000\u00003\u0000\u0000\u0000\u0002_id\u0000%\u0000\u0000\u0000cc1237fe-98d3-b465-9725-013b0627c700\u0000\u00003\u0000\u0000\u0000\u0002_id\u0000%\u0000\u0000\u000047709144-98d3-b465-9725-013b0627c70a\u0000\u00003\u0000\u0000\u0000\u0002_id\u0000%\u0000\u0000\u00002b3751f8-98d3-b465-9725-013b0627c713\u0000\u00003\u0000\u0000\u0000\u0002_id\u0000%\u0000\u0000\u00007603aef9-98d3-b465-9725-013b0627c716\u0000\u00003\u0000\u0000\u0000\u0002_id\u0000%\u0000\u0000\u0000b332d3fc-98d3-b465-9725-013b0627c719\u0000\u00003\u0000\u0000\u0000\u0002_id\u0000%\u0000\u0000\u0000a595bbfe-98d3-b465-9725-013b0627c71c\u0000\u0000"}
6
+
7
+ let (:reply_sample_doc) {{
8
+ "ismaster" => true,
9
+ "maxBsonObjectSize" => 16777216,
10
+ "ok" => 1.0
11
+ }}
12
+
13
+ let (:reply_sample_docs2) {[
14
+ {"_id" => "3427b4fa-98d3-b465-9725-013b0627c6f3"},
15
+ {"_id" => "dabe4ffc-98d3-b465-9725-013b0627c6f9"},
16
+ {"_id" => "268a9cfc-98d3-b465-9725-013b0627c6fc"},
17
+ {"_id" => "7156e9fd-98d3-b465-9725-013b0627c6fd"},
18
+ {"_id" => "cc1237fe-98d3-b465-9725-013b0627c700"},
19
+ {"_id" => "47709144-98d3-b465-9725-013b0627c70a"},
20
+ {"_id" => "2b3751f8-98d3-b465-9725-013b0627c713"},
21
+ {"_id" => "7603aef9-98d3-b465-9725-013b0627c716"},
22
+ {"_id" => "b332d3fc-98d3-b465-9725-013b0627c719"},
23
+ {"_id" => "a595bbfe-98d3-b465-9725-013b0627c71c"}
24
+ ]}
25
+
26
+ it 'should read OP_REPLY' do
27
+ message, x = WireMongo.receive(reply_sample)
28
+ message.should == reply_sample
29
+
30
+ x.should == {
31
+ :responseFlags => 8,
32
+ :cursorID => 0,
33
+ :startingFrom => 0,
34
+ :numberReturned => 1,
35
+ :documents => [reply_sample_doc],
36
+ :header => {
37
+ :messageLength => 87,
38
+ :requestID => 14,
39
+ :responseTo => 1,
40
+ :opCode => :reply
41
+ }
42
+ }
43
+
44
+ message, x = WireMongo.receive(reply_sample2)
45
+ message.should == reply_sample2
46
+ x.should == {
47
+ :responseFlags => 8,
48
+ :startingFrom => 0,
49
+ :numberReturned => 10,
50
+ :cursorID => 50,
51
+ :documents => reply_sample_docs2,
52
+ :header => {
53
+ :messageLength => 546,
54
+ :requestID => 31662,
55
+ :responseTo => 14,
56
+ :opCode => :reply
57
+ }
58
+ }
59
+ end
60
+
61
+ it 'should build OP_REPLY' do
62
+ raw, x = WireMongo.receive(reply_sample)
63
+ x[:header].delete(:messageLength)
64
+ WireMongo.build_reply(reply_sample_doc, 14, 1, 8).should == x
65
+
66
+ raw, x = WireMongo.receive(reply_sample2)
67
+ x[:header].delete(:messageLength)
68
+ WireMongo.build_reply(reply_sample_docs2, 31662, 14, 8, 50, 0).should == x
69
+ end
70
+
71
+ it 'should write OP_REPLY' do
72
+ x = WireMongo.build_reply(reply_sample_doc, 14, 1, 8)
73
+ WireMongo.write(x).should == reply_sample
74
+
75
+ x = WireMongo.build_reply(reply_sample_docs2, 31662, 14, 8, 50, 0)
76
+ WireMongo.write(x).should == reply_sample2
77
+ end
78
+
79
+ let (:update_sample) {"d\x00\x00\x00\x0E\x00\x00\x00\x00\x00\x00\x00\xD1\a\x00\x00\x00\x00\x00\x00test.test\x00\x03\x00\x00\x00\x1C\x00\x00\x00\x02testkey\x00\n\x00\x00\x00testvalue\x00\x00&\x00\x00\x00\x03$set\x00\e\x00\x00\x00\x02testkey\x00\t\x00\x00\x00otherval\x00\x00\x00"}
80
+
81
+ it 'should read OP_UPDATE' do
82
+ message, x = WireMongo.receive(update_sample)
83
+ message.should == update_sample
84
+
85
+ x.should == {
86
+ :database => 'test',
87
+ :collection => 'test',
88
+ :flags => 3,
89
+ :selector => {
90
+ 'testkey' => 'testvalue',
91
+ },
92
+ :update => {
93
+ '$set' => {
94
+ 'testkey' => 'otherval'
95
+ }
96
+ },
97
+ :header => {
98
+ :opCode => :update,
99
+ :requestID => 14,
100
+ :messageLength => 100,
101
+ :responseTo => 0
102
+ }
103
+ }
104
+ end
105
+
106
+ it 'should build OP_UPDATE' do
107
+ raw, x = WireMongo.receive(update_sample)
108
+ x[:header].delete(:messageLength)
109
+ WireMongo.build_update(14, 'test', 'test', {'testkey' => 'testvalue'},
110
+ {'$set' => {'testkey' => 'otherval'}}, [:upsert, :multi]).should == x
111
+ end
112
+
113
+ it 'should write OP_UPDATE' do
114
+ x = WireMongo.build_update(14, 'test', 'test', {'testkey' => 'testvalue'},
115
+ {'$set' => {'testkey' => 'otherval'}}, [:upsert, :multi])
116
+ WireMongo.write(x).should == update_sample
117
+ end
118
+
119
+ let (:insert_sample) {"K\x00\x00\x00\a\x00\x00\x00\x00\x00\x00\x00\xD2\a\x00\x00\x00\x00\x00\x00test.test\x00-\x00\x00\x00\a_id\x00P\x8C\xA2Ax\xB1\x0E%\xD6\x00\x00\x05\x02testkey\x00\n\x00\x00\x00testvalue\x00\x00"}
120
+
121
+ INSERT_DOC = {
122
+ "_id" => BSON::ObjectId('508ca24178b10e25d6000005'),
123
+ "testkey" => "testvalue"
124
+ }
125
+
126
+ it 'should read OP_INSERT' do
127
+ message, x = WireMongo.receive(insert_sample)
128
+ message.should == insert_sample
129
+
130
+ x.should == {
131
+ :flags => 0,
132
+ :database => 'test',
133
+ :collection => 'test',
134
+ :documents => [INSERT_DOC],
135
+ :header => {
136
+ :messageLength => 75,
137
+ :requestID => 7,
138
+ :responseTo => 0,
139
+ :opCode => :insert
140
+ }
141
+ }
142
+ end
143
+
144
+ it 'should build OP_INSERT' do
145
+ raw, x = WireMongo.receive(insert_sample)
146
+ x[:header].delete(:messageLength)
147
+ WireMongo.build_insert(7, 'test', 'test', INSERT_DOC).should == x
148
+ end
149
+
150
+ it 'should write OP_INSERT' do
151
+ x = WireMongo.build_insert(7, 'test', 'test', INSERT_DOC)
152
+ WireMongo.write(x).should == insert_sample
153
+ end
154
+
155
+ let (:query_sample) { ":\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\xD4\a\x00\x00\x00\x00\x00\x00admin.$cmd\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x13\x00\x00\x00\x10ismaster\x00\x01\x00\x00\x00\x00" }
156
+
157
+ it 'should read OP_QUERY' do
158
+ message, x = WireMongo.receive(query_sample)
159
+ message.should == query_sample
160
+
161
+ x.should == {
162
+ :flags => 0,
163
+ :database => 'admin',
164
+ :collection => '$cmd',
165
+ :numberToSkip => 0,
166
+ :numberToReturn => 4294967295,
167
+ :query => {
168
+ "ismaster" => 1
169
+ },
170
+ :returnFieldSelector => nil,
171
+ :header => {
172
+ :messageLength => 58,
173
+ :requestID => 1,
174
+ :responseTo => 0,
175
+ :opCode => :query
176
+ }
177
+ }
178
+ end
179
+
180
+ it 'should build OP_QUERY' do
181
+ raw, x = WireMongo.receive(query_sample)
182
+ x[:header].delete(:messageLength)
183
+ WireMongo.build_query(1, 'admin', '$cmd', {'ismaster' => 1}, nil, 4294967295).should == x
184
+ end
185
+
186
+ it 'should write OP_QUERY' do
187
+ x = WireMongo.build_query(1, 'admin', '$cmd', {'ismaster' => 1}, nil, 4294967295)
188
+ WireMongo.write(x).should == query_sample
189
+ end
190
+
191
+ let (:get_more_sample) {"0\x00\x00\x00\t\x00\x00\x00\xFF\xFF\xFF\xFF\xD5\a\x00\x00\x00\x00\x00\x00bakks.submarine\x00\x00\x00\x00\x00'\xD7\xC6\xD8!\x8CK\x13"}
192
+ let (:get_more_sample2) {"*\u0000\u0000\u0000\xAC\t\u0000\u0000\u0000\u0000\u0000\u0000\xD5\a\u0000\u0000\u0000\u0000\u0000\u0000bakks.big\u0000\u0000\u0000\u0000\u0000먤\b\xEEe\x84\u0006"}
193
+
194
+ it 'should read OP_GET_MORE' do
195
+ message, x = WireMongo.receive(get_more_sample)
196
+ message.should == get_more_sample
197
+
198
+ x.should == {
199
+ :database => 'bakks',
200
+ :collection => 'submarine',
201
+ :numberToReturn => 0,
202
+ :cursorID => 1390358986972649255,
203
+ :header => {
204
+ :messageLength => 48,
205
+ :requestID => 9,
206
+ :responseTo => 4294967295,
207
+ :opCode => :get_more
208
+ }
209
+ }
210
+
211
+ message, x = WireMongo.receive(get_more_sample2)
212
+ message.should == get_more_sample2
213
+
214
+ x.should == {
215
+ :database => 'bakks',
216
+ :collection => 'big',
217
+ :numberToReturn => 0,
218
+ :cursorID => 469612334175004907,
219
+ :header => {
220
+ :messageLength => 42,
221
+ :requestID => 2476,
222
+ :responseTo => 0,
223
+ :opCode => :get_more
224
+ }
225
+ }
226
+ end
227
+
228
+ it 'should build OP_GET_MORE' do
229
+ raw, x = WireMongo.receive(get_more_sample)
230
+ x[:header].delete(:messageLength)
231
+ WireMongo.build_get_more(9, 4294967295, 'bakks', 'submarine', 1390358986972649255).should == x
232
+
233
+ raw, x = WireMongo.receive(get_more_sample2)
234
+ x[:header].delete(:messageLength)
235
+ WireMongo.build_get_more(2476, 0, 'bakks', 'big', 469612334175004907).should == x
236
+ end
237
+
238
+ it 'should write OP_GET_MORE' do
239
+ x = WireMongo.build_get_more(9, 4294967295, 'bakks', 'submarine', 1390358986972649255)
240
+ WireMongo.write(x).should == get_more_sample
241
+
242
+ x = WireMongo.build_get_more(2476, 0, 'bakks', 'big', 469612334175004907)
243
+ WireMongo.write(x).should == get_more_sample2
244
+ end
245
+
246
+ let(:delete_sample) {"'\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\xD6\a\x00\x00\x00\x00\x00\x00test.test\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00"}
247
+
248
+ it 'should read OP_DELETE' do
249
+ message, x = WireMongo.receive(delete_sample)
250
+ message.should == delete_sample
251
+
252
+ x.should == {
253
+ :database => 'test',
254
+ :collection => 'test',
255
+ :flags => 0,
256
+ :selector => {},
257
+ :header => {
258
+ :messageLength => 39,
259
+ :requestID => 2,
260
+ :responseTo => 0,
261
+ :opCode => :delete
262
+ }
263
+ }
264
+ end
265
+
266
+ it 'should build OP_DELETE' do
267
+ raw, x = WireMongo.receive(delete_sample)
268
+ x[:header].delete(:messageLength)
269
+ WireMongo.build_delete(2, 'test', 'test', {}).should == x
270
+ end
271
+
272
+ it 'should write OP_DELETE' do
273
+ x = WireMongo.build_delete(2, 'test', 'test', {})
274
+ WireMongo.write(x).should == delete_sample
275
+ end
276
+
277
+ let (:kill_cursors_sample) {" \u0000\u0000\u0000\x92\t\u0000\u0000\u0000\u0000\u0000\u0000\xD7\a\u0000\u0000\u0000\u0000\u0000\u0000\u0001\u0000\u0000\u0000\xC9e\x9A^R\x8A\xF2\u0006"}
278
+
279
+ it 'should read OP_KILL_CURSORS' do
280
+ message, x = WireMongo.receive(kill_cursors_sample)
281
+ message.should == kill_cursors_sample
282
+
283
+ x.should == {
284
+ :cursorIDs => [500614594970674633],
285
+ :header => {
286
+ :messageLength => 32,
287
+ :requestID => 2450,
288
+ :responseTo => 0,
289
+ :opCode => :kill_cursors
290
+ }
291
+ }
292
+ end
293
+
294
+ it 'should build OP_KILL_CURSORS' do
295
+ raw, x = WireMongo.receive(kill_cursors_sample)
296
+ x[:header].delete(:messageLength)
297
+ WireMongo.build_kill_cursors(2450, 0, [500614594970674633]).should == x
298
+ end
299
+
300
+ it 'should write OP_KILL_CURSORS' do
301
+ x = WireMongo.build_kill_cursors(2450, 0, [500614594970674633])
302
+ WireMongo.write(x).should == kill_cursors_sample
303
+ end
304
+
305
+ it 'should hash query' do
306
+ doc1 = WireMongo::build_query(10, 'foo', 'bar', {:x => 100}, {:x => 1})
307
+ hash1 = WireMongo::hash doc1
308
+ hash1.should =~ /^[0-9a-fA-F]{40}$/
309
+
310
+ doc1[:header][:requestID] = 20
311
+ doc1[:header][:responseTo] = 50
312
+ WireMongo::hash(doc1).should == hash1
313
+
314
+ doc2 = WireMongo::build_query(10, 'foo', 'bar', {:x => 100}, {:x => 0})
315
+ WireMongo::hash(doc2).should_not == hash1
316
+ end
317
+ end