em-synchrony-moped 0.9.4 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,138 @@
1
+ # encoding: utf-8
2
+ require 'spec_helper'
3
+
4
+ require 'moped'
5
+ require 'em-synchrony/moped'
6
+
7
+ describe Moped::Node do
8
+ let(:mongod_options) { {} }
9
+ let(:server) { FakeMongodServer.new(mongod_options) }
10
+ let(:server_port) { server.port }
11
+ after { server.stop }
12
+
13
+ let(:node_options) { {} }
14
+ let(:node) do
15
+ options = node_options.merge(timeout: 1)
16
+ host = options.delete(:host) || 'localhost'
17
+ Moped::Node.new("#{host}:#{server_port}", options)
18
+ end
19
+
20
+ shared_context 'common node' do
21
+ context 'with a running server' do
22
+ it 'should connect' do
23
+ node.refresh
24
+ node.should be_primary
25
+ node.should be_connected
26
+ end
27
+
28
+ it 'should detect a disconnect' do
29
+ node.refresh
30
+ node.should be_primary
31
+ node.should be_connected
32
+ server.stop
33
+ expect do
34
+ node.command('admin', ismaster: 1)
35
+ end.to raise_error(
36
+ Moped::Errors::ConnectionFailure # TODO: check the message
37
+ )
38
+ node.should_not be_connected
39
+ end
40
+ end
41
+
42
+ context 'with an unpresponsive host' do
43
+ # 127.0.0.2 seems to timeout for my tests...
44
+ let(:node_options) { { host: '127.0.0.2' } }
45
+ it 'should raise a timeout error' do
46
+ expect { node.refresh }.to raise_error(
47
+ Moped::Errors::ConnectionFailure,
48
+ /^Timed out connection to Mongo on/)
49
+ end
50
+ end
51
+
52
+ context 'with an unknown host' do
53
+ let(:node_options) { { host: 'this.host-could-not-possibly-exist.com' } }
54
+ it 'should raise an error' do
55
+ # FIXME: this can't be right...
56
+ expect { node.refresh }.not_to raise_error
57
+ end
58
+ end
59
+
60
+ context 'without a server' do
61
+ it 'should raise a connection error on connection refused' do
62
+ server.stop
63
+ expect { node.refresh }.to raise_error(
64
+ Moped::Errors::ConnectionFailure, /ECONNREFUSED/)
65
+ end
66
+ end
67
+ end
68
+
69
+ shared_context 'common node ssl' do
70
+ context 'with ssl server' do
71
+ let(:mongod_options) do
72
+ {
73
+ ssl: {
74
+ private_key_file: "#{SSL_DIR}/server.key",
75
+ cert_chain_file: "#{SSL_DIR}/server.crt",
76
+ verify_peer: false
77
+ }
78
+ }
79
+ end
80
+
81
+ context 'without verifying peer' do
82
+ let(:node_options) { { ssl: { verify_peer: false } } }
83
+ it 'should connect' do
84
+ node.refresh
85
+ node.should be_primary
86
+ end
87
+ end
88
+
89
+ context 'when verifying peer' do
90
+ let(:node_options) do
91
+ { ssl: {
92
+ verify_peer: true,
93
+ verify_cert: "#{SSL_DIR}/ca_cert.pem",
94
+ verify_host: 'localhost'
95
+ }
96
+ }
97
+ end
98
+ it 'should connect' do
99
+ node.refresh
100
+ node.should be_primary
101
+ end
102
+
103
+ context 'with untrusted key on server' do
104
+ let(:mongod_options) do
105
+ {
106
+ ssl: {
107
+ private_key_file: "#{SSL_DIR}/untrusted.key",
108
+ cert_chain_file: "#{SSL_DIR}/untrusted.crt",
109
+ verify_peer: false
110
+ }
111
+ }
112
+ end
113
+
114
+ it 'should connect and fail to verify peer' do
115
+ expect do
116
+ node.refresh
117
+ node.should be_primary
118
+ end.to raise_error(
119
+ Moped::Errors::ConnectionFailure,
120
+ /Failed to verify SSL certificate of peer/
121
+ )
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ context 'evented' do
129
+ include_context 'with em-synchrony'
130
+ include_context 'common node'
131
+ include_context 'common node ssl'
132
+ end
133
+ context 'threaded' do
134
+ include_context 'without em-synchrony'
135
+ include_context 'common node'
136
+ end
137
+
138
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,15 +1,43 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
1
+ # encoding: UTF-8
3
2
 
4
- require "rspec"
3
+ require 'rubygems'
4
+ require 'spork'
5
+ # uncomment the following line to use spork with the debugger
6
+ # require 'spork/ext/ruby-debug'
5
7
 
6
- require 'em-synchrony'
8
+ Spork.prefork do
9
+ # Loading more in this block will cause your tests to run faster. However,
10
+ # if you change any configuration or code from libraries loaded here, you'll
11
+ # need to restart spork for it take effect.
7
12
 
8
- Dir[File.expand_path("../support/**/*.rb", __FILE__)].each { |f| require f }
13
+ require 'rspec'
14
+ require 'simplecov'
15
+ SimpleCov.start do
16
+ add_group 'Lib', 'lib'
17
+ add_filter '/spec/'
18
+ end
9
19
 
10
- SSL_DIR = File.expand_path("../ssl", __FILE__)
20
+ Dir[File.expand_path('../support/**/*.rb', __FILE__)].each { |f| require f }
11
21
 
12
- RSpec.configure do |config|
22
+ SSL_DIR = File.expand_path('../ssl', __FILE__)
13
23
 
24
+ RSpec.configure do |config|
25
+ config.treat_symbols_as_metadata_keys_with_true_values = true
26
+ config.run_all_when_everything_filtered = true
27
+ config.filter_run :focus
28
+
29
+ # Run specs in random order to surface order dependencies. If you find an
30
+ # order dependency and want to debug it, you can fix the order by providing
31
+ # the seed, which is printed after each run.
32
+ # --seed 1234
33
+ config.order = 'random'
34
+
35
+ # config.before { $stderr.reopen("/dev/null") }
36
+ end
37
+
38
+ end
39
+
40
+ Spork.each_run do
41
+ # This code will be run each time you run your specs.
14
42
 
15
43
  end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ shared_context 'with em-synchrony' do
4
+ around(:each) do |example|
5
+ require 'em-synchrony'
6
+ EventMachine.error_handler do |e|
7
+ puts "Error in Eventmachine: #{e.inspect}"
8
+ EM.stop
9
+ end
10
+ EventMachine.synchrony do
11
+ example.run
12
+ EM.stop if EM.reactor_running?
13
+ end
14
+ end
15
+ end
16
+
17
+ shared_context 'without em-synchrony' do
18
+ before(:each) do
19
+ EventMachine.error_handler do |e|
20
+ puts "Error in Eventmachine: #{e.inspect}"
21
+ EM.stop
22
+ end
23
+ queue = Queue.new
24
+ @em_thread = Thread.new { EventMachine.run { queue << true } }
25
+ queue.pop
26
+ end
27
+
28
+ after(:each) do
29
+ EM.stop
30
+ @em_thread.join
31
+ end
32
+ end
@@ -1,13 +1,15 @@
1
+ # encoding: utf-8
1
2
  require 'eventmachine'
2
3
 
4
+ # Load order here is important. Message must be loaded so we can
5
+ # add deserialization support to moped/protocol/query
3
6
  require 'moped/protocol/message'
7
+
4
8
  module Moped
5
9
  module Protocol
6
-
7
10
  # This patch is so we can parse a query as a server
8
11
  module Message
9
12
  module ClassMethods
10
-
11
13
  alias_method :_old_cstring, :cstring
12
14
  def cstring(name)
13
15
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
@@ -22,7 +24,7 @@ module Moped
22
24
  RUBY
23
25
  _old_cstring(name)
24
26
  end
25
-
27
+
26
28
  alias_method :_old_document, :document
27
29
  def document(name, options = {})
28
30
  if options[:optional]
@@ -42,8 +44,9 @@ module Moped
42
44
  end
43
45
  end
44
46
  end
45
-
46
- # now that the class DSL is patched, load the message classes we need to patch further
47
+
48
+ # now that the class DSL is patched, load the message classes we need to
49
+ # patch further
47
50
 
48
51
  # This patch is so we can parse a query as a server
49
52
  require 'moped/protocol/query'
@@ -58,8 +61,7 @@ module Moped
58
61
  end
59
62
  end
60
63
  end
61
-
62
-
64
+
63
65
  # This patch is so we can create a Reply object as a server
64
66
  require 'moped/protocol/reply'
65
67
  class Reply
@@ -72,71 +74,98 @@ module Moped
72
74
  @op_code = 1
73
75
  end
74
76
  end
75
-
76
-
77
77
  end
78
78
  end
79
79
 
80
-
80
+ # Eventmachine connection for FakeMongod
81
81
  class FakeMongod < EventMachine::Connection
82
- def initialize(options)
83
- @options = options
82
+ def initialize(options, server)
83
+ @options = {
84
+ master: 1
85
+ }.merge(options)
86
+ @server = server
84
87
  @request_id = 0
85
88
  end
86
-
89
+
87
90
  def post_init
88
- if @options[:ssl]
89
- start_tls(@options[:ssl])
90
- end
91
+ @server.add_connection(self)
92
+ start_tls(@options[:ssl]) if @options[:ssl]
91
93
  end
92
-
94
+
93
95
  def receive_data(data)
94
96
  query = Moped::Protocol::Query.deserialize(StringIO.new(data))
95
97
  if query.full_collection_name == 'admin.$cmd'
96
- if query.selector == {'ismaster' => 1}
97
- send_reply(query,
98
- :ok => 1,
99
- :ismaster => 1
100
- )
101
- elsif query.selector == {'listDatabases' => 1}
102
- send_reply(query,
103
- :ok => 1,
104
- :databases => [{
105
- :name => 'test_db'
106
- }]
107
- )
98
+ if query.selector == { 'ismaster' => 1 }
99
+ if @options[:master] == 1
100
+ send_reply(query, ok: 1, ismaster: 1)
101
+ else
102
+ send_reply(query, ok: 1, secondary: 1)
103
+ end
104
+ elsif query.selector == { 'listDatabases' => 1 }
105
+ send_reply(query, ok: 1, databases: [{ name: 'test_db' }])
108
106
  end
109
107
  end
110
108
  end
111
-
109
+
112
110
  def send_reply(query, *documents)
113
111
  @request_id += 1
114
112
  reply = Moped::Protocol::Reply.new(
115
113
  documents,
116
- :request_id => @request_ud,
117
- :response_to => query.request_id
114
+ request_id: @request_ud,
115
+ response_to: query.request_id
118
116
  )
119
117
  send_data reply.serialize
120
118
  end
121
-
119
+
120
+ def unbind
121
+ @server.remove_connection(self)
122
+ end
122
123
  end
123
124
 
124
- module FakeMongodHelper
125
-
126
- BASE_PORT = 37017
127
-
128
- def start_mongod(options={})
129
- @server = EventMachine.start_server('127.0.0.1', BASE_PORT, FakeMongod, options)
125
+ class FakeMongodServer
126
+ attr_reader :port, :host, :options
127
+
128
+ def initialize(options = {})
129
+ @options = {
130
+ host: '127.0.0.1'
131
+ }.merge(options)
132
+ @host = @options.delete(:host)
133
+ @connections = []
134
+ ensure_reactor do
135
+ @server = EventMachine.start_server(
136
+ @host, 0, FakeMongod, @options, self)
137
+ @port = Socket.unpack_sockaddr_in(EM.get_sockname(@server))[0]
138
+ end
130
139
  end
131
140
 
141
+ def stop
142
+ return unless @server
143
+ ensure_reactor do
144
+ EventMachine.stop_server(@server)
145
+ # stopping the server only stops the listener. We must now stop
146
+ # all current connections
147
+ @connections.each { |c| c.close_connection }
148
+ @server = nil
149
+ end
150
+ end
132
151
 
133
- def stop_mongod
134
- EventMachine.stop_server(@server)
152
+ def add_connection(connection)
153
+ @connections << connection
135
154
  end
136
-
137
- end
138
155
 
139
- RSpec.configure do |config|
140
- config.include FakeMongodHelper
156
+ def remove_connection(connection)
157
+ @connections.delete(connection)
158
+ end
159
+
160
+ private
141
161
 
142
- end
162
+ def ensure_reactor(&block)
163
+ if EventMachine.reactor_thread?
164
+ block.call
165
+ elsif EventMachine.reactor_running?
166
+ queue = Queue.new
167
+ EventMachine.next_tick { queue << block.call }
168
+ queue.pop
169
+ end
170
+ end
171
+ end
metadata CHANGED
@@ -1,36 +1,32 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: em-synchrony-moped
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.4
5
- prerelease:
4
+ version: 1.0.0.beta.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Adam Lebsack
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-05-22 00:00:00.000000000 Z
11
+ date: 2013-11-12 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: eventmachine
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - ~>
20
18
  - !ruby/object:Gem::Version
21
- version: '0'
19
+ version: '1.0'
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - ~>
28
25
  - !ruby/object:Gem::Version
29
- version: '0'
26
+ version: '1.0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: em-synchrony
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ~>
36
32
  - !ruby/object:Gem::Version
@@ -38,7 +34,6 @@ dependencies:
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ~>
44
39
  - !ruby/object:Gem::Version
@@ -46,23 +41,20 @@ dependencies:
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: moped
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
45
  - - ~>
52
46
  - !ruby/object:Gem::Version
53
- version: 1.4.5
47
+ version: 1.5.1
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
52
  - - ~>
60
53
  - !ruby/object:Gem::Version
61
- version: 1.4.5
54
+ version: 1.5.1
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: em-resolv-replace
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
59
  - - ~>
68
60
  - !ruby/object:Gem::Version
@@ -70,7 +62,6 @@ dependencies:
70
62
  type: :runtime
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
66
  - - ~>
76
67
  - !ruby/object:Gem::Version
@@ -78,7 +69,6 @@ dependencies:
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rspec
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
73
  - - ~>
84
74
  - !ruby/object:Gem::Version
@@ -86,11 +76,108 @@ dependencies:
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
80
  - - ~>
92
81
  - !ruby/object:Gem::Version
93
82
  version: 2.12.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: guard-bundler
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: guard-rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ! '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ! '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: spork
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ! '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ! '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ - !ruby/object:Gem::Dependency
168
+ name: simplecov
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ! '>='
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
94
181
  description: EM-Synchrony-Moped is a Moped driver patch for EM-Synchtony, allowing
95
182
  your asynchronous application use non-blocking connections to MongoDB. Moped is
96
183
  the MongoDB driver for the Mongoid ORM.
@@ -101,49 +188,58 @@ extra_rdoc_files: []
101
188
  files:
102
189
  - .gitignore
103
190
  - Gemfile
191
+ - Guardfile
104
192
  - README.md
105
193
  - Rakefile
106
194
  - em-synchrony-moped.gemspec
107
195
  - lib/em-synchrony/moped.rb
108
- - spec/moped_spec.rb
196
+ - lib/em-synchrony/moped/cluster.rb
197
+ - lib/em-synchrony/moped/connection.rb
198
+ - lib/em-synchrony/moped/node.rb
199
+ - spec/lib/em-synchrony/moped/cluster_spec.rb
200
+ - spec/lib/em-synchrony/moped/connection_spec.rb
201
+ - spec/lib/em-synchrony/moped/node_spec.rb
109
202
  - spec/spec_helper.rb
110
203
  - spec/ssl/ca_cert.pem
111
204
  - spec/ssl/server.crt
112
205
  - spec/ssl/server.key
113
206
  - spec/ssl/untrusted.crt
114
207
  - spec/ssl/untrusted.key
208
+ - spec/support/contexts.rb
115
209
  - spec/support/simulated_mongod.rb
116
210
  homepage:
117
211
  licenses: []
212
+ metadata: {}
118
213
  post_install_message:
119
214
  rdoc_options: []
120
215
  require_paths:
121
216
  - lib
122
217
  required_ruby_version: !ruby/object:Gem::Requirement
123
- none: false
124
218
  requirements:
125
219
  - - ! '>='
126
220
  - !ruby/object:Gem::Version
127
221
  version: '0'
128
222
  required_rubygems_version: !ruby/object:Gem::Requirement
129
- none: false
130
223
  requirements:
131
224
  - - ! '>='
132
225
  - !ruby/object:Gem::Version
133
226
  version: '0'
134
227
  requirements: []
135
228
  rubyforge_project:
136
- rubygems_version: 1.8.25
229
+ rubygems_version: 2.1.7
137
230
  signing_key:
138
- specification_version: 3
231
+ specification_version: 4
139
232
  summary: Moped driver for EM-Synchrony
140
233
  test_files:
141
- - spec/moped_spec.rb
234
+ - spec/lib/em-synchrony/moped/cluster_spec.rb
235
+ - spec/lib/em-synchrony/moped/connection_spec.rb
236
+ - spec/lib/em-synchrony/moped/node_spec.rb
142
237
  - spec/spec_helper.rb
143
238
  - spec/ssl/ca_cert.pem
144
239
  - spec/ssl/server.crt
145
240
  - spec/ssl/server.key
146
241
  - spec/ssl/untrusted.crt
147
242
  - spec/ssl/untrusted.key
243
+ - spec/support/contexts.rb
148
244
  - spec/support/simulated_mongod.rb
149
245
  has_rdoc: