mongo 2.1.0.rc0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +5 -2
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +2 -2
  5. data/lib/mongo.rb +2 -1
  6. data/lib/mongo/address.rb +11 -5
  7. data/lib/mongo/address/ipv4.rb +6 -1
  8. data/lib/mongo/auth/cr/conversation.rb +1 -1
  9. data/lib/mongo/auth/ldap/conversation.rb +1 -1
  10. data/lib/mongo/auth/scram/conversation.rb +1 -1
  11. data/lib/mongo/auth/user/view.rb +2 -2
  12. data/lib/mongo/auth/x509/conversation.rb +1 -1
  13. data/lib/mongo/bulk_write.rb +12 -9
  14. data/lib/mongo/bulk_write/transformable.rb +20 -5
  15. data/lib/mongo/client.rb +11 -11
  16. data/lib/mongo/cluster.rb +2 -2
  17. data/lib/mongo/collection.rb +21 -8
  18. data/lib/mongo/collection/view.rb +1 -0
  19. data/lib/mongo/collection/view/aggregation.rb +11 -5
  20. data/lib/mongo/collection/view/iterable.rb +6 -2
  21. data/lib/mongo/collection/view/map_reduce.rb +39 -5
  22. data/lib/mongo/collection/view/readable.rb +35 -30
  23. data/lib/mongo/collection/view/writable.rb +26 -18
  24. data/lib/mongo/database.rb +12 -2
  25. data/lib/mongo/database/view.rb +4 -3
  26. data/lib/mongo/dbref.rb +4 -4
  27. data/lib/mongo/grid/fs_bucket.rb +8 -1
  28. data/lib/mongo/grid/stream/read.rb +1 -1
  29. data/lib/mongo/index.rb +5 -0
  30. data/lib/mongo/index/view.rb +2 -2
  31. data/lib/mongo/monitoring/command_log_subscriber.rb +9 -3
  32. data/lib/mongo/monitoring/event.rb +1 -0
  33. data/lib/mongo/monitoring/event/command_started.rb +2 -1
  34. data/lib/mongo/monitoring/event/command_succeeded.rb +6 -3
  35. data/lib/mongo/monitoring/event/secure.rb +58 -0
  36. data/lib/mongo/operation.rb +31 -1
  37. data/lib/mongo/operation/commands/collections_info.rb +2 -0
  38. data/lib/mongo/operation/commands/collections_info/result.rb +39 -0
  39. data/lib/mongo/operation/commands/list_indexes/result.rb +2 -1
  40. data/lib/mongo/operation/commands/map_reduce/result.rb +1 -1
  41. data/lib/mongo/operation/read/query.rb +2 -0
  42. data/lib/mongo/operation/read/query/result.rb +40 -0
  43. data/lib/mongo/operation/result.rb +13 -1
  44. data/lib/mongo/operation/write/bulk/delete.rb +2 -2
  45. data/lib/mongo/operation/write/bulk/update.rb +3 -3
  46. data/lib/mongo/operation/write/delete.rb +2 -2
  47. data/lib/mongo/operation/write/update.rb +9 -4
  48. data/lib/mongo/options.rb +1 -0
  49. data/lib/mongo/options/redacted.rb +156 -0
  50. data/lib/mongo/protocol/insert.rb +25 -6
  51. data/lib/mongo/protocol/query.rb +45 -31
  52. data/lib/mongo/protocol/reply.rb +29 -6
  53. data/lib/mongo/protocol/serializers.rb +1 -1
  54. data/lib/mongo/retryable.rb +83 -0
  55. data/lib/mongo/server.rb +16 -3
  56. data/lib/mongo/server/connectable.rb +21 -3
  57. data/lib/mongo/server/connection.rb +38 -4
  58. data/lib/mongo/server/connection_pool.rb +12 -0
  59. data/lib/mongo/server/connection_pool/queue.rb +15 -0
  60. data/lib/mongo/server/monitor/connection.rb +2 -2
  61. data/lib/mongo/server_selector.rb +5 -0
  62. data/lib/mongo/server_selector/selectable.rb +16 -9
  63. data/lib/mongo/socket.rb +6 -2
  64. data/lib/mongo/uri.rb +1 -1
  65. data/lib/mongo/version.rb +1 -1
  66. data/spec/mongo/bulk_write/ordered_combiner_spec.rb +11 -11
  67. data/spec/mongo/bulk_write/unordered_combiner_spec.rb +10 -10
  68. data/spec/mongo/client_spec.rb +101 -18
  69. data/spec/mongo/collection_spec.rb +44 -0
  70. data/spec/mongo/connection_string_spec.rb +36 -58
  71. data/spec/mongo/database_spec.rb +20 -0
  72. data/spec/mongo/grid/fs_bucket_spec.rb +1 -1
  73. data/spec/mongo/grid/stream/write_spec.rb +2 -2
  74. data/spec/mongo/monitoring/event/command_started_spec.rb +26 -0
  75. data/spec/mongo/monitoring/event/command_succeeded_spec.rb +26 -0
  76. data/spec/mongo/monitoring/event/secure_spec.rb +57 -0
  77. data/spec/mongo/operation/commands/aggregate_spec.rb +0 -16
  78. data/spec/mongo/operation/commands/command_spec.rb +0 -18
  79. data/spec/mongo/operation/kill_cursors_spec.rb +0 -16
  80. data/spec/mongo/operation/read/get_more_spec.rb +0 -16
  81. data/spec/mongo/operation/read/query_spec.rb +19 -16
  82. data/spec/mongo/operation/write/bulk/delete_spec.rb +16 -16
  83. data/spec/mongo/operation/write/bulk/update_spec.rb +6 -6
  84. data/spec/mongo/operation/write/command/delete_spec.rb +0 -16
  85. data/spec/mongo/operation/write/command/insert_spec.rb +0 -16
  86. data/spec/mongo/operation/write/command/update_spec.rb +0 -16
  87. data/spec/mongo/operation/write/delete_spec.rb +3 -3
  88. data/spec/mongo/operation/write/update_spec.rb +6 -6
  89. data/spec/mongo/options/redacted_spec.rb +350 -0
  90. data/spec/mongo/protocol/query_spec.rb +15 -1
  91. data/spec/mongo/retryable_spec.rb +147 -0
  92. data/spec/mongo/server/connection_pool/queue_spec.rb +16 -0
  93. data/spec/mongo/server/connection_pool_spec.rb +32 -0
  94. data/spec/mongo/server/connection_spec.rb +37 -0
  95. data/spec/mongo/server_discovery_and_monitoring_spec.rb +24 -59
  96. data/spec/mongo/server_selection_rtt_spec.rb +37 -57
  97. data/spec/mongo/server_selection_spec.rb +2 -0
  98. data/spec/mongo/server_selector/nearest_spec.rb +1 -0
  99. data/spec/mongo/server_selector/primary_preferred_spec.rb +1 -0
  100. data/spec/mongo/server_selector/primary_spec.rb +8 -2
  101. data/spec/mongo/server_selector/secondary_preferred_spec.rb +1 -0
  102. data/spec/mongo/server_selector/secondary_spec.rb +1 -0
  103. data/spec/mongo/server_spec.rb +68 -1
  104. data/spec/mongo/socket/ssl_spec.rb +29 -5
  105. data/spec/mongo/uri_spec.rb +20 -20
  106. data/spec/support/crud.rb +7 -1
  107. data/spec/support/matchers.rb +1 -1
  108. data/spec/support/shared/server_selector.rb +58 -2
  109. metadata +20 -5
  110. metadata.gz.sig +0 -0
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  require 'spec_helper'
2
3
 
3
4
  describe Mongo::Protocol::Query do
@@ -15,7 +16,7 @@ describe Mongo::Protocol::Query do
15
16
 
16
17
  describe '#initialize' do
17
18
 
18
- it 'sets the namepsace' do
19
+ it 'sets the namespace' do
19
20
  expect(message.namespace).to eq(ns)
20
21
  end
21
22
 
@@ -220,6 +221,19 @@ describe Mongo::Protocol::Query do
220
221
  it 'serializes the namespace' do
221
222
  expect(field).to be_cstring(ns)
222
223
  end
224
+
225
+ context 'when the namespace contains unicode characters' do
226
+ let(:field) { bytes[20..40] }
227
+
228
+ let(:coll) do
229
+ 'områder'
230
+ end
231
+
232
+ it 'serializes the namespace' do
233
+ expect(field).to be_cstring(ns)
234
+ end
235
+
236
+ end
223
237
  end
224
238
 
225
239
  describe 'skip' do
@@ -0,0 +1,147 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Retryable do
4
+
5
+ let(:klass) do
6
+ Class.new do
7
+ include Mongo::Retryable
8
+
9
+ attr_reader :cluster
10
+ attr_reader :operation
11
+
12
+ def initialize(operation, cluster)
13
+ @operation = operation
14
+ @cluster = cluster
15
+ end
16
+
17
+ def read
18
+ read_with_retry do
19
+ operation.execute
20
+ end
21
+ end
22
+
23
+ def write
24
+ write_with_retry do
25
+ operation.execute
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ describe '#read_with_retry' do
32
+
33
+ let(:operation) do
34
+ double('operation')
35
+ end
36
+
37
+ let(:cluster) do
38
+ double('cluster')
39
+ end
40
+
41
+ let(:retryable) do
42
+ klass.new(operation, cluster)
43
+ end
44
+
45
+ context 'when no exception occurs' do
46
+
47
+ before do
48
+ expect(operation).to receive(:execute).and_return(true)
49
+ end
50
+
51
+ it 'executes the operation once' do
52
+ expect(retryable.read).to be true
53
+ end
54
+ end
55
+
56
+ context 'when a socket error occurs' do
57
+
58
+ before do
59
+ expect(operation).to receive(:execute).and_raise(Mongo::Error::SocketError).ordered
60
+ expect(cluster).to receive(:scan!).and_return(true).ordered
61
+ expect(operation).to receive(:execute).and_return(true).ordered
62
+ end
63
+
64
+ it 'executes the operation twice' do
65
+ expect(retryable.read).to be true
66
+ end
67
+ end
68
+
69
+ context 'when a socket timeout error occurs' do
70
+
71
+ before do
72
+ expect(operation).to receive(:execute).and_raise(Mongo::Error::SocketTimeoutError).ordered
73
+ expect(cluster).to receive(:scan!).and_return(true).ordered
74
+ expect(operation).to receive(:execute).and_return(true).ordered
75
+ end
76
+
77
+ it 'executes the operation twice' do
78
+ expect(retryable.read).to be true
79
+ end
80
+ end
81
+
82
+ context 'when an operation failure occurs' do
83
+
84
+ before do
85
+ expect(operation).to receive(:execute).and_raise(Mongo::Error::OperationFailure).ordered
86
+ end
87
+
88
+ it 'raises an exception' do
89
+ expect {
90
+ retryable.read
91
+ }.to raise_error(Mongo::Error::OperationFailure)
92
+ end
93
+ end
94
+ end
95
+
96
+ describe '#write_with_retry' do
97
+
98
+ let(:operation) do
99
+ double('operation')
100
+ end
101
+
102
+ let(:cluster) do
103
+ double('cluster')
104
+ end
105
+
106
+ let(:retryable) do
107
+ klass.new(operation, cluster)
108
+ end
109
+
110
+ context 'when no exception occurs' do
111
+
112
+ before do
113
+ expect(operation).to receive(:execute).and_return(true)
114
+ end
115
+
116
+ it 'executes the operation once' do
117
+ expect(retryable.write).to be true
118
+ end
119
+ end
120
+
121
+ context 'when a not master error occurs' do
122
+
123
+ before do
124
+ expect(operation).to receive(:execute).and_raise(Mongo::Error::OperationFailure.new('not master')).ordered
125
+ expect(cluster).to receive(:scan!).and_return(true).ordered
126
+ expect(operation).to receive(:execute).and_return(true).ordered
127
+ end
128
+
129
+ it 'executes the operation twice' do
130
+ expect(retryable.write).to be true
131
+ end
132
+ end
133
+
134
+ context 'when a normal operation failure occurs' do
135
+
136
+ before do
137
+ expect(operation).to receive(:execute).and_raise(Mongo::Error::OperationFailure).ordered
138
+ end
139
+
140
+ it 'raises an exception' do
141
+ expect {
142
+ retryable.write
143
+ }.to raise_error(Mongo::Error::OperationFailure)
144
+ end
145
+ end
146
+ end
147
+ end
@@ -47,6 +47,22 @@ describe Mongo::Server::ConnectionPool::Queue do
47
47
  end
48
48
  end
49
49
 
50
+ describe '#disconnect!' do
51
+
52
+ let(:connection) do
53
+ double('connection')
54
+ end
55
+
56
+ let(:queue) do
57
+ described_class.new(:max_pool_size => 1) { connection }
58
+ end
59
+
60
+ it 'disconnects all connections in the queue' do
61
+ expect(connection).to receive(:disconnect!)
62
+ queue.disconnect!
63
+ end
64
+ end
65
+
50
66
  describe '#enqueue' do
51
67
 
52
68
  let(:connection) do
@@ -28,6 +28,10 @@ describe Mongo::Server::ConnectionPool do
28
28
  described_class.get(server)
29
29
  end
30
30
 
31
+ after do
32
+ server.disconnect!
33
+ end
34
+
31
35
  context 'when a connection is checked out on the thread' do
32
36
 
33
37
  let!(:connection) do
@@ -96,6 +100,26 @@ describe Mongo::Server::ConnectionPool do
96
100
  end
97
101
  end
98
102
 
103
+ describe '#disconnect!' do
104
+
105
+ let(:server) do
106
+ Mongo::Server.new(address, double('cluster'), monitoring, listeners, options)
107
+ end
108
+
109
+ let!(:pool) do
110
+ described_class.get(server)
111
+ end
112
+
113
+ after do
114
+ server.disconnect!
115
+ end
116
+
117
+ it 'disconnects the queue' do
118
+ expect(pool.send(:queue)).to receive(:disconnect!).twice.and_call_original
119
+ pool.disconnect!
120
+ end
121
+ end
122
+
99
123
  describe '.get' do
100
124
 
101
125
  let(:server) do
@@ -106,6 +130,10 @@ describe Mongo::Server::ConnectionPool do
106
130
  described_class.get(server)
107
131
  end
108
132
 
133
+ after do
134
+ server.disconnect!
135
+ end
136
+
109
137
  it 'returns the pool for the server' do
110
138
  expect(pool).to eql(described_class.get(server))
111
139
  end
@@ -121,6 +149,10 @@ describe Mongo::Server::ConnectionPool do
121
149
  described_class.get(server)
122
150
  end
123
151
 
152
+ after do
153
+ server.disconnect!
154
+ end
155
+
124
156
  it 'includes the object id' do
125
157
  expect(pool.inspect).to include(pool.object_id.to_s)
126
158
  end
@@ -18,6 +18,43 @@ describe Mongo::Server::Connection do
18
18
  Mongo::Server.new(address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
19
19
  end
20
20
 
21
+ after do
22
+ server.disconnect!
23
+ end
24
+
25
+ describe '#connectable?' do
26
+
27
+ # context 'when the connection is connectable' do
28
+
29
+ # let(:connection) do
30
+ # described_class.new(server)
31
+ # end
32
+
33
+ # it 'returns true' do
34
+ # expect(connection).to be_connectable
35
+ # end
36
+ # end
37
+
38
+ context 'when the connection is not connectable' do
39
+
40
+ let(:bad_address) do
41
+ Mongo::Address.new('127.0.0.1:666')
42
+ end
43
+
44
+ let(:bad_server) do
45
+ Mongo::Server.new(bad_address, double('cluster'), monitoring, listeners, TEST_OPTIONS)
46
+ end
47
+
48
+ let(:connection) do
49
+ described_class.new(bad_server)
50
+ end
51
+
52
+ it 'returns false' do
53
+ expect(connection).to_not be_connectable
54
+ end
55
+ end
56
+ end
57
+
21
58
  describe '#connect!' do
22
59
 
23
60
  context 'when no socket exists' do
@@ -11,40 +11,26 @@ describe 'Server Discovery and Monitoring' do
11
11
 
12
12
  before(:all) do
13
13
 
14
- # We monkey-patch the address, so that looking up the spec's hostname does
15
- # not throw an error.
16
- #
17
- # @since 2.0.0
18
- class Mongo::Address
19
- private
20
-
21
- def family(host)
22
- fam = host == 'localhost' ? ::Socket::AF_INET : ::Socket::AF_UNSPEC
23
- ::Socket.getaddrinfo(host, nil, fam, ::Socket::SOCK_STREAM).first[4]
24
- rescue SocketError
25
- end
26
- end
14
+ module Mongo
15
+ # We monkey-patch the server here, so the monitors do not run and no
16
+ # real TCP connection is attempted. Thus we can control the server
17
+ # descriptions per-phase.
18
+ #
19
+ # @since 2.0.0
20
+ class Server
21
+
22
+ alias :original_initialize :initialize
23
+ def initialize(address, cluster, monitoring, event_listeners, options = {})
24
+ @address = address
25
+ @cluster = cluster
26
+ @monitoring = monitoring
27
+ @options = options.freeze
28
+ @monitor = Monitor.new(address, event_listeners, options)
29
+ end
27
30
 
28
- # We monkey-patch the server here, so the monitors do not run and no
29
- # real TCP connection is attempted. Thus we can control the server
30
- # descriptions per-phase.
31
- #
32
- # @since 2.0.0
33
- class Mongo::Server
34
-
35
- # The constructor keeps the same API, but does not instantiate a
36
- # monitor and run it.
37
- def initialize(address, cluster, monitoring, event_listeners, options = {})
38
- @address = address
39
- @cluster = cluster
40
- @monitoring = monitoring
41
- @options = options.freeze
42
- @monitor = Monitor.new(address, event_listeners, options)
31
+ alias :original_disconnect! :disconnect!
32
+ def disconnect!; true; end
43
33
  end
44
-
45
- # Disconnect simply needs to return true since we have no monitor and
46
- # no connection.
47
- def disconnect!; true; end
48
34
  end
49
35
 
50
36
  # Client is set as an instance variable inside the scope of the spec to
@@ -58,34 +44,13 @@ describe 'Server Discovery and Monitoring' do
58
44
 
59
45
  # Return the server implementation to its original for the other
60
46
  # tests in the suite.
61
- class Mongo::Server
62
-
63
- # Returns the constructor to its original implementation.
64
- def initialize(address, cluster, monitoring, event_listeners, options = {})
65
- @address = address
66
- @cluster = cluster
67
- @monitoring = monitoring
68
- @options = options.freeze
69
- @monitor = Monitor.new(address, event_listeners, options)
70
- @monitor.scan!
71
- @monitor.run!
72
- end
73
-
74
- # Returns disconnect! to its original implementation.
75
- def disconnect!
76
- context.with_connection do |connection|
77
- connection.disconnect!
78
- end
79
- @monitor.stop! and true
80
- end
81
- end
82
-
83
- class Mongo::Address
84
- private
47
+ module Mongo
48
+ class Server
49
+ alias :initialize :original_initialize
50
+ remove_method(:original_initialize)
85
51
 
86
- def family(host)
87
- fam = host == 'localhost' ? ::Socket::AF_INET : ::Socket::AF_UNSPEC
88
- ::Socket.getaddrinfo(host, nil, fam, ::Socket::SOCK_STREAM).first[4]
52
+ alias :disconnect! :original_disconnect!
53
+ remove_method(:original_disconnect!)
89
54
  end
90
55
  end
91
56
  end
@@ -8,80 +8,60 @@ describe 'Server Selection moving average round trip time calculation' do
8
8
 
9
9
  spec = Mongo::ServerSelection::RTT::Spec.new(file)
10
10
 
11
- before(:all) do
12
-
13
- module Mongo
14
- class Server
15
-
16
- # We monkey-patch the monitor here, so the last average rtt can be controlled.
17
- # We keep the API of Monitor#initialize but add in an extra option and set the last rtt.
18
- #
19
- # @since 2.0.0
20
- class Monitor
21
-
22
- def initialize(address, listeners, options = {})
23
- @description = Mongo::Server::Description.new(address, {})
24
- @inspector = Mongo::Server::Description::Inspector.new(listeners)
25
- @options = options.freeze
26
- @connection = Connection.new(address, options)
27
- @last_round_trip_time = options[:avg_rtt_ms]
28
- @mutex = Mutex.new
29
- end
11
+ context(spec.description) do
30
12
 
31
- private
13
+ before(:all) do
32
14
 
33
- # We monkey patch this method to use an instance variable instead of calculating time elapsed.
15
+ module Mongo
16
+ class Server
17
+
18
+ # We monkey-patch the monitor here, so the last average rtt can be controlled.
19
+ # We keep the API of Monitor#initialize but add in an extra option and set the last rtt.
34
20
  #
35
21
  # @since 2.0.0
36
- def average_round_trip_time(start)
37
- new_rtt = @new_rtt_ms
38
- RTT_WEIGHT_FACTOR * new_rtt + (1 - RTT_WEIGHT_FACTOR) * (@last_round_trip_time || new_rtt)
22
+ class Monitor
23
+
24
+ alias :original_initialize :initialize
25
+ def initialize(address, listeners, options = {})
26
+ @description = Mongo::Server::Description.new(address, {})
27
+ @inspector = Mongo::Server::Description::Inspector.new(listeners)
28
+ @options = options.freeze
29
+ @connection = Connection.new(address, options)
30
+ @last_round_trip_time = options[:avg_rtt_ms]
31
+ @mutex = Mutex.new
32
+ end
33
+
34
+ # We monkey patch this method to use an instance variable instead of calculating time elapsed.
35
+ #
36
+ # @since 2.0.0
37
+ alias :original_average_round_trip_time :average_round_trip_time
38
+ def average_round_trip_time(start)
39
+ new_rtt = @new_rtt_ms
40
+ RTT_WEIGHT_FACTOR * new_rtt + (1 - RTT_WEIGHT_FACTOR) * (@last_round_trip_time || new_rtt)
41
+ end
39
42
  end
40
43
  end
41
44
  end
42
45
  end
43
- end
44
46
 
45
- after(:all) do
47
+ after(:all) do
46
48
 
47
- module Mongo
48
- class Server
49
+ module Mongo
50
+ class Server
49
51
 
50
- # Return the monitor implementation to its original for the other
51
- # tests in the suite.
52
- class Monitor
52
+ # Return the monitor implementation to its original for the other
53
+ # tests in the suite.
54
+ class Monitor
53
55
 
54
- # Create the new server monitor.
55
- #
56
- # @example Create the server monitor.
57
- # Mongo::Server::Monitor.new(address, listeners)
58
- #
59
- # @param [ Address ] address The address to monitor.
60
- # @param [ Event::Listeners ] listeners The event listeners.
61
- # @param [ Hash ] options The options.
62
- #
63
- # @since 2.0.0
64
- def initialize(address, listeners, options = {})
65
- @description = Description.new(address, {})
66
- @inspector = Description::Inspector.new(listeners)
67
- @options = options.freeze
68
- @connection = Connection.new(address, options)
69
- @last_round_trip_time = nil
70
- @mutex = Mutex.new
71
- end
72
-
73
- private
56
+ alias :initialize :original_initialize
57
+ remove_method(:original_initialize)
74
58
 
75
- def average_round_trip_time(start)
76
- new_rtt = Time.now - start
77
- RTT_WEIGHT_FACTOR * new_rtt + (1 - RTT_WEIGHT_FACTOR) * (@last_round_trip_time || new_rtt)
59
+ alias :average_round_trip_time :original_average_round_trip_time
60
+ remove_method(:original_average_round_trip_time)
78
61
  end
79
62
  end
80
63
  end
81
64
  end
82
- end
83
-
84
- context(spec.description) do
85
65
 
86
66
  let(:address) do
87
67
  Mongo::Address.new('127.0.0.1:27017')