mongo 2.1.0.rc0 → 2.1.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.
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')