mongo 2.13.0.beta1 → 2.13.0.rc1

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 (170) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -5
  4. data/Rakefile +15 -9
  5. data/lib/mongo.rb +4 -2
  6. data/lib/mongo/auth/aws/request.rb +4 -2
  7. data/lib/mongo/bulk_write.rb +1 -0
  8. data/lib/mongo/client.rb +143 -21
  9. data/lib/mongo/cluster.rb +53 -17
  10. data/lib/mongo/cluster/sdam_flow.rb +13 -10
  11. data/lib/mongo/cluster/topology/replica_set_no_primary.rb +3 -2
  12. data/lib/mongo/cluster/topology/sharded.rb +1 -1
  13. data/lib/mongo/cluster/topology/single.rb +1 -1
  14. data/lib/mongo/collection.rb +17 -13
  15. data/lib/mongo/collection/view/readable.rb +3 -1
  16. data/lib/mongo/collection/view/writable.rb +41 -5
  17. data/lib/mongo/database.rb +31 -4
  18. data/lib/mongo/database/view.rb +19 -4
  19. data/lib/mongo/distinguishing_semaphore.rb +55 -0
  20. data/lib/mongo/error.rb +1 -0
  21. data/lib/mongo/error/invalid_session.rb +2 -1
  22. data/lib/mongo/error/operation_failure.rb +6 -0
  23. data/lib/mongo/error/sessions_not_supported.rb +35 -0
  24. data/lib/mongo/event/base.rb +6 -0
  25. data/lib/mongo/grid/file.rb +5 -0
  26. data/lib/mongo/grid/file/chunk.rb +2 -0
  27. data/lib/mongo/grid/fs_bucket.rb +15 -13
  28. data/lib/mongo/grid/stream/write.rb +9 -3
  29. data/lib/mongo/monitoring.rb +38 -0
  30. data/lib/mongo/monitoring/command_log_subscriber.rb +10 -2
  31. data/lib/mongo/monitoring/event/command_failed.rb +11 -0
  32. data/lib/mongo/monitoring/event/command_started.rb +37 -2
  33. data/lib/mongo/monitoring/event/command_succeeded.rb +11 -0
  34. data/lib/mongo/monitoring/event/server_closed.rb +1 -1
  35. data/lib/mongo/monitoring/event/server_description_changed.rb +27 -4
  36. data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +9 -2
  37. data/lib/mongo/monitoring/event/server_heartbeat_started.rb +9 -2
  38. data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +9 -2
  39. data/lib/mongo/monitoring/event/server_opening.rb +1 -1
  40. data/lib/mongo/monitoring/event/topology_changed.rb +1 -1
  41. data/lib/mongo/monitoring/event/topology_closed.rb +1 -1
  42. data/lib/mongo/monitoring/event/topology_opening.rb +1 -1
  43. data/lib/mongo/monitoring/publishable.rb +6 -3
  44. data/lib/mongo/monitoring/server_description_changed_log_subscriber.rb +9 -1
  45. data/lib/mongo/monitoring/topology_changed_log_subscriber.rb +1 -1
  46. data/lib/mongo/protocol/message.rb +36 -8
  47. data/lib/mongo/protocol/msg.rb +14 -0
  48. data/lib/mongo/protocol/serializers.rb +5 -2
  49. data/lib/mongo/server.rb +10 -3
  50. data/lib/mongo/server/connection.rb +4 -4
  51. data/lib/mongo/server/connection_base.rb +3 -1
  52. data/lib/mongo/server/description.rb +5 -0
  53. data/lib/mongo/server/monitor.rb +76 -44
  54. data/lib/mongo/server/monitor/connection.rb +55 -7
  55. data/lib/mongo/server/pending_connection.rb +14 -4
  56. data/lib/mongo/server/push_monitor.rb +173 -0
  57. data/{spec/runners/transactions/context.rb → lib/mongo/server/push_monitor/connection.rb} +9 -14
  58. data/lib/mongo/server_selector.rb +0 -1
  59. data/lib/mongo/server_selector/base.rb +579 -1
  60. data/lib/mongo/server_selector/nearest.rb +1 -6
  61. data/lib/mongo/server_selector/primary.rb +1 -6
  62. data/lib/mongo/server_selector/primary_preferred.rb +7 -10
  63. data/lib/mongo/server_selector/secondary.rb +1 -6
  64. data/lib/mongo/server_selector/secondary_preferred.rb +1 -7
  65. data/lib/mongo/session.rb +2 -0
  66. data/lib/mongo/socket.rb +20 -8
  67. data/lib/mongo/socket/ssl.rb +1 -1
  68. data/lib/mongo/socket/tcp.rb +1 -1
  69. data/lib/mongo/topology_version.rb +9 -0
  70. data/lib/mongo/utils.rb +62 -0
  71. data/lib/mongo/version.rb +1 -1
  72. data/spec/README.aws-auth.md +2 -2
  73. data/spec/integration/awaited_ismaster_spec.rb +28 -0
  74. data/spec/integration/change_stream_examples_spec.rb +6 -2
  75. data/spec/integration/check_clean_slate_spec.rb +16 -0
  76. data/spec/integration/client_construction_spec.rb +1 -0
  77. data/spec/integration/connect_single_rs_name_spec.rb +5 -2
  78. data/spec/integration/connection_spec.rb +7 -4
  79. data/spec/integration/crud_spec.rb +4 -4
  80. data/spec/integration/docs_examples_spec.rb +6 -0
  81. data/spec/integration/grid_fs_bucket_spec.rb +48 -0
  82. data/spec/integration/heartbeat_events_spec.rb +4 -23
  83. data/spec/integration/read_concern_spec.rb +1 -1
  84. data/spec/integration/retryable_errors_spec.rb +1 -1
  85. data/spec/integration/retryable_writes/shared/performs_legacy_retries.rb +2 -2
  86. data/spec/integration/retryable_writes/shared/performs_modern_retries.rb +3 -3
  87. data/spec/integration/retryable_writes/shared/performs_no_retries.rb +2 -2
  88. data/spec/integration/sdam_error_handling_spec.rb +37 -15
  89. data/spec/integration/sdam_events_spec.rb +77 -6
  90. data/spec/integration/sdam_prose_spec.rb +64 -0
  91. data/spec/integration/server_monitor_spec.rb +25 -1
  92. data/spec/integration/size_limit_spec.rb +7 -3
  93. data/spec/integration/size_limit_spec.rb~12e1e9c4f... RUBY-2242 Fix zlib compression (#2021) +98 -0
  94. data/spec/integration/ssl_uri_options_spec.rb +2 -2
  95. data/spec/integration/zlib_compression_spec.rb +25 -0
  96. data/spec/lite_spec_helper.rb +12 -5
  97. data/spec/mongo/auth/aws/request_spec.rb +76 -0
  98. data/spec/mongo/auth/scram_spec.rb +1 -1
  99. data/spec/mongo/client_construction_spec.rb +207 -0
  100. data/spec/mongo/client_spec.rb +38 -3
  101. data/spec/mongo/cluster/topology/replica_set_spec.rb +52 -9
  102. data/spec/mongo/cluster/topology/single_spec.rb +4 -2
  103. data/spec/mongo/cluster_spec.rb +34 -35
  104. data/spec/mongo/collection/view/change_stream_resume_spec.rb +6 -6
  105. data/spec/mongo/collection_spec.rb +500 -0
  106. data/spec/mongo/database_spec.rb +245 -8
  107. data/spec/mongo/distinguishing_semaphore_spec.rb +63 -0
  108. data/spec/mongo/error/operation_failure_spec.rb +40 -0
  109. data/spec/mongo/index/view_spec.rb +2 -2
  110. data/spec/mongo/monitoring/event/server_description_changed_spec.rb +1 -4
  111. data/spec/mongo/protocol/msg_spec.rb +10 -0
  112. data/spec/mongo/semaphore_spec.rb +51 -0
  113. data/spec/mongo/server/connection_auth_spec.rb +2 -2
  114. data/spec/mongo/server_selector/nearest_spec.rb +23 -23
  115. data/spec/mongo/server_selector/primary_preferred_spec.rb +26 -26
  116. data/spec/mongo/server_selector/primary_spec.rb +9 -9
  117. data/spec/mongo/server_selector/secondary_preferred_spec.rb +22 -22
  118. data/spec/mongo/server_selector/secondary_spec.rb +18 -18
  119. data/spec/mongo/server_selector_spec.rb +4 -4
  120. data/spec/mongo/session_spec.rb +35 -0
  121. data/spec/runners/change_streams/test.rb +2 -2
  122. data/spec/runners/cmap.rb +1 -1
  123. data/spec/runners/command_monitoring.rb +3 -34
  124. data/spec/runners/crud/context.rb +9 -5
  125. data/spec/runners/crud/operation.rb +59 -27
  126. data/spec/runners/crud/spec.rb +0 -8
  127. data/spec/runners/crud/test.rb +1 -1
  128. data/spec/runners/sdam.rb +2 -2
  129. data/spec/runners/server_selection.rb +242 -28
  130. data/spec/runners/transactions.rb +12 -12
  131. data/spec/runners/transactions/operation.rb +151 -25
  132. data/spec/runners/transactions/test.rb +60 -16
  133. data/spec/spec_tests/command_monitoring_spec.rb +22 -12
  134. data/spec/spec_tests/crud_spec.rb +1 -1
  135. data/spec/spec_tests/data/change_streams/change-streams-errors.yml +4 -8
  136. data/spec/spec_tests/data/change_streams/change-streams-resume-whitelist.yml +66 -0
  137. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/MaxStalenessTooSmall.yml +15 -0
  138. data/spec/spec_tests/data/max_staleness/ReplicaSetNoPrimary/NoKnownServers.yml +4 -3
  139. data/spec/spec_tests/data/max_staleness/Unknown/SmallMaxStaleness.yml +1 -0
  140. data/spec/spec_tests/data/sdam_integration/cancel-server-check.yml +96 -0
  141. data/spec/spec_tests/data/sdam_integration/connectTimeoutMS.yml +88 -0
  142. data/spec/spec_tests/data/sdam_integration/find-network-error.yml +83 -0
  143. data/spec/spec_tests/data/sdam_integration/find-shutdown-error.yml +116 -0
  144. data/spec/spec_tests/data/sdam_integration/insert-network-error.yml +86 -0
  145. data/spec/spec_tests/data/sdam_integration/insert-shutdown-error.yml +115 -0
  146. data/spec/spec_tests/data/sdam_integration/isMaster-command-error.yml +168 -0
  147. data/spec/spec_tests/data/sdam_integration/isMaster-network-error.yml +162 -0
  148. data/spec/spec_tests/data/sdam_integration/isMaster-timeout.yml +229 -0
  149. data/spec/spec_tests/data/sdam_integration/rediscover-quickly-after-step-down.yml +87 -0
  150. data/spec/spec_tests/max_staleness_spec.rb +4 -142
  151. data/spec/spec_tests/retryable_reads_spec.rb +2 -2
  152. data/spec/spec_tests/sdam_integration_spec.rb +13 -0
  153. data/spec/spec_tests/sdam_monitoring_spec.rb +1 -2
  154. data/spec/spec_tests/server_selection_spec.rb +4 -116
  155. data/spec/stress/cleanup_spec.rb +17 -2
  156. data/spec/stress/connection_pool_stress_spec.rb +10 -8
  157. data/spec/support/child_process_helper.rb +78 -0
  158. data/spec/support/client_registry.rb +1 -0
  159. data/spec/support/cluster_config.rb +4 -0
  160. data/spec/support/event_subscriber.rb +123 -33
  161. data/spec/support/keyword_struct.rb +26 -0
  162. data/spec/support/shared/server_selector.rb +13 -1
  163. data/spec/support/spec_config.rb +38 -13
  164. data/spec/support/spec_organizer.rb +129 -0
  165. data/spec/support/spec_setup.rb +1 -1
  166. data/spec/support/utils.rb +46 -0
  167. metadata +992 -942
  168. metadata.gz.sig +0 -0
  169. data/lib/mongo/server_selector/selectable.rb +0 -560
  170. data/spec/runners/sdam_monitoring.rb +0 -89
@@ -5,7 +5,11 @@ describe 'Server::Monitor' do
5
5
  let(:client) do
6
6
  new_local_client([ClusterConfig.instance.primary_address_str],
7
7
  SpecConfig.instance.test_options.merge(SpecConfig.instance.auth_options.merge(
8
- heartbeat_frequency: 1)))
8
+ monitor_options)))
9
+ end
10
+
11
+ let(:monitor_options) do
12
+ {heartbeat_frequency: 1}
9
13
  end
10
14
 
11
15
  it 'refreshes server descriptions in background', retry: 3 do
@@ -25,4 +29,24 @@ describe 'Server::Monitor' do
25
29
 
26
30
  expect(server.description).not_to be_unknown
27
31
  end
32
+
33
+ context 'server-pushed ismaster' do
34
+ min_server_fcv '4.4'
35
+ require_topology :replica_set
36
+
37
+ let(:monitor_options) do
38
+ {heartbeat_frequency: 20}
39
+ end
40
+
41
+ it 'updates server description' do
42
+ starting_primary_address = client.cluster.next_primary.address
43
+
44
+ ClusterTools.instance.step_down
45
+
46
+ sleep 2
47
+
48
+ new_primary_address = client.cluster.next_primary.address
49
+ new_primary_address.should_not == starting_primary_address
50
+ end
51
+ end
28
52
  end
@@ -36,7 +36,7 @@ describe 'BSON & command size limits' do
36
36
  end
37
37
 
38
38
  authorized_collection.insert_many(documents)
39
- authorized_collection.count_documents({}).should == 8
39
+ authorized_collection.count_documents.should == 8
40
40
  end
41
41
 
42
42
  # This test ensures that document which are too big definitely fail insertion.
@@ -49,7 +49,7 @@ describe 'BSON & command size limits' do
49
49
  lambda do
50
50
  authorized_collection.insert_many(documents)
51
51
  end.should raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
52
- authorized_collection.count_documents({}).should == 0
52
+ authorized_collection.count_documents.should == 0
53
53
  end
54
54
 
55
55
  it 'allows user-provided documents to be exactly 16MiB' do
@@ -81,6 +81,10 @@ describe 'BSON & command size limits' do
81
81
  end
82
82
 
83
83
  it 'allows bulk writes of multiple documents of exactly 16 MiB each' do
84
+ if SpecConfig.instance.compressors
85
+ pending "RUBY-2234"
86
+ end
87
+
84
88
  documents = []
85
89
  1.upto(3) do |index|
86
90
  document = { key: 'a' * (max_document_size - 28), _id: "in#{index}" }
@@ -89,6 +93,6 @@ describe 'BSON & command size limits' do
89
93
  end
90
94
 
91
95
  authorized_collection.insert_many(documents)
92
- authorized_collection.count_documents({}).should == 3
96
+ authorized_collection.count_documents.should == 3
93
97
  end
94
98
  end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'BSON & command size limits' do
4
+ let(:max_document_size) { 16*1024*1024 }
5
+
6
+ before do
7
+ authorized_collection.delete_many
8
+ end
9
+
10
+ # This test uses a large document that is significantly smaller than the
11
+ # size limit. It is a basic sanity check.
12
+ it 'allows user-provided documents to be 15MiB' do
13
+ document = { key: 'a' * 15*1024*1024, _id: 'foo' }
14
+
15
+ authorized_collection.insert_one(document)
16
+ end
17
+
18
+ # This test uses a large document that is significantly larger than the
19
+ # size limit. It is a basic sanity check.
20
+ it 'fails single write of oversized documents' do
21
+ document = { key: 'a' * 17*1024*1024, _id: 'foo' }
22
+
23
+ lambda do
24
+ authorized_collection.insert_one(document)
25
+ end.should raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
26
+ end
27
+
28
+ # This test checks our bulk write splitting when documents are not close
29
+ # to the limit, but where splitting is definitely required.
30
+ it 'allows split bulk write of medium sized documents' do
31
+ # 8 documents of 4 MiB each = 32 MiB total data, should be split over
32
+ # either 2 or 3 bulk writes depending on how well the driver splits
33
+ documents = []
34
+ 1.upto(8) do |index|
35
+ documents << { key: 'a' * 4*1024*1024, _id: "in#{index}" }
36
+ end
37
+
38
+ authorized_collection.insert_many(documents)
39
+ authorized_collection.count_documents({}).should == 8
40
+ end
41
+
42
+ # This test ensures that document which are too big definitely fail insertion.
43
+ it 'fails bulk write of oversized documents' do
44
+ documents = []
45
+ 1.upto(3) do |index|
46
+ documents << { key: 'a' * 17*1024*1024, _id: "in#{index}" }
47
+ end
48
+
49
+ lambda do
50
+ authorized_collection.insert_many(documents)
51
+ end.should raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
52
+ authorized_collection.count_documents({}).should == 0
53
+ end
54
+
55
+ it 'allows user-provided documents to be exactly 16MiB' do
56
+ # The document must contain the _id field, otherwise the server will
57
+ # add it which will increase the size of the document as persisted by
58
+ # the server.
59
+ document = { key: 'a' * (max_document_size - 28), _id: 'foo' }
60
+ expect(document.to_bson.length).to eq(max_document_size)
61
+
62
+ authorized_collection.insert_one(document)
63
+ end
64
+
65
+ it 'fails on the server when a document larger than 16MiB is inserted' do
66
+ document = { key: 'a' * (max_document_size - 27), _id: 'foo' }
67
+ expect(document.to_bson.length).to eq(max_document_size+1)
68
+
69
+ lambda do
70
+ authorized_collection.insert_one(document)
71
+ end.should raise_error(Mongo::Error::OperationFailure, /object to insert too large/)
72
+ end
73
+
74
+ it 'fails in the driver when a document larger than 16MiB+16KiB is inserted' do
75
+ document = { key: 'a' * (max_document_size - 27 + 16*1024), _id: 'foo' }
76
+ expect(document.to_bson.length).to eq(max_document_size+16*1024+1)
77
+
78
+ lambda do
79
+ authorized_collection.insert_one(document)
80
+ end.should raise_error(Mongo::Error::MaxBSONSize, /The document exceeds maximum allowed BSON object size after serialization/)
81
+ end
82
+
83
+ it 'allows bulk writes of multiple documents of exactly 16 MiB each' do
84
+ if SpecConfig.instance.compressors
85
+ pending "RUBY-2234"
86
+ end
87
+
88
+ documents = []
89
+ 1.upto(3) do |index|
90
+ document = { key: 'a' * (max_document_size - 28), _id: "in#{index}" }
91
+ expect(document.to_bson.length).to eq(max_document_size)
92
+ documents << document
93
+ end
94
+
95
+ authorized_collection.insert_many(documents)
96
+ authorized_collection.count_documents({}).should == 3
97
+ end
98
+ end
@@ -20,6 +20,6 @@ describe 'SSL connections with URI options' do
20
20
 
21
21
  it 'successfully connects and runs an operation' do
22
22
  client = new_local_client(uri)
23
- expect { client[:foo].count_documents({}) }.not_to raise_error
23
+ expect { client[:foo].count_documents }.not_to raise_error
24
24
  end
25
- end
25
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Zlib compression' do
4
+ require_compression
5
+
6
+ before do
7
+ authorized_client['test'].drop
8
+ end
9
+
10
+ context 'when client has zlib compressor option enabled' do
11
+ it 'compresses the message to the server' do
12
+ # Double check that the client has zlib compression enabled
13
+ expect(authorized_client.options[:compressors]).to include('zlib')
14
+
15
+ expect(Mongo::Protocol::Compressed).to receive(:new).twice.and_call_original
16
+ expect(Zlib::Deflate).to receive(:deflate).twice.and_call_original
17
+ expect(Zlib::Inflate).to receive(:inflate).twice.and_call_original
18
+
19
+ authorized_client['test'].insert_one(_id: 1, text: 'hello world')
20
+ document = authorized_client['test'].find(_id: 1).first
21
+
22
+ expect(document['text']).to eq('hello world')
23
+ end
24
+ end
25
+ end
@@ -4,8 +4,6 @@ CURRENT_PATH = File.expand_path(File.dirname(__FILE__))
4
4
  SERVER_DISCOVERY_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/sdam/**/*.yml").sort
5
5
  SDAM_MONITORING_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/sdam_monitoring/*.yml").sort
6
6
  SERVER_SELECTION_RTT_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/server_selection_rtt/*.yml").sort
7
- SERVER_SELECTION_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/server_selection/**/*.yml").sort
8
- MAX_STALENESS_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/max_staleness/**/*.yml").sort
9
7
  CRUD_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/crud/**/*.yml").sort
10
8
  CRUD2_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/crud_v2/**/*.yml").sort
11
9
  RETRYABLE_WRITES_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/retryable_writes/**/*.yml").sort
@@ -22,7 +20,11 @@ CMAP_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/cmap/*.yml").sort
22
20
  AUTH_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/auth/*.yml").sort
23
21
  CLIENT_SIDE_ENCRYPTION_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/client_side_encryption/*.yml").sort
24
22
 
25
- if ENV['CI']
23
+ # Disable output buffering: https://www.rubyguides.com/2019/02/ruby-io/
24
+ STDOUT.sync = true
25
+ STDERR.sync = true
26
+
27
+ if %w(1 true yes).include?(ENV['CI']&.downcase)
26
28
  autoload :Byebug, 'byebug'
27
29
  else
28
30
  # Load debuggers before loading the driver code, so that breakpoints
@@ -107,14 +109,19 @@ RSpec.configure do |config|
107
109
  # Tests should take under 10 seconds ideally but it seems
108
110
  # we have some that run for more than 10 seconds in CI.
109
111
  config.around(:each) do |example|
110
- TimeoutInterrupt.timeout(45) do
112
+ timeout = if %w(1 true yes).include?(ENV['STRESS']&.downcase)
113
+ 210
114
+ else
115
+ 45
116
+ end
117
+ TimeoutInterrupt.timeout(timeout) do
111
118
  example.run
112
119
  end
113
120
  end
114
121
  end
115
122
 
116
123
  if SpecConfig.instance.ci?
117
- if defined?(Rfc)
124
+ if defined?(Rfc::Rif)
118
125
  unless BSON::Environment.jruby?
119
126
  Rfc::Rif.output_object_space_stats = true
120
127
  end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongo::Auth::Aws::Request do
4
+
5
+ describe "#formatted_time" do
6
+ context "when time is provided and frozen" do
7
+ let(:original_time) { Time.at(1592399523).freeze }
8
+ let(:request) do
9
+ described_class.new(access_key_id: 'access_key_id',
10
+ secret_access_key: 'secret_access_key',
11
+ session_token: 'session_token',
12
+ host: 'host',
13
+ server_nonce: 'server_nonce',
14
+ time: original_time
15
+ )
16
+ end
17
+
18
+ it 'doesn\'t modify the time instance variable' do
19
+ expect { request.formatted_time }.to_not raise_error
20
+ end
21
+
22
+ it 'returns the correct formatted time' do
23
+ expect(request.formatted_time).to eq('20200617T131203Z')
24
+ end
25
+ end
26
+
27
+ context "when time is not provided" do
28
+ let(:request) do
29
+ described_class.new(access_key_id: 'access_key_id',
30
+ secret_access_key: 'secret_access_key',
31
+ session_token: 'session_token',
32
+ host: 'host',
33
+ server_nonce: 'server_nonce'
34
+ )
35
+ end
36
+
37
+ it 'doesn\'t raise an error on formatted_time' do
38
+ expect { request.formatted_time }.to_not raise_error
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "#signature" do
44
+ context "when time is provided and frozen" do
45
+ let(:original_time) { Time.at(1592399523).freeze }
46
+ let(:request) do
47
+ described_class.new(access_key_id: 'access_key_id',
48
+ secret_access_key: 'secret_access_key',
49
+ session_token: 'session_token',
50
+ host: 'host',
51
+ server_nonce: 'server_nonce',
52
+ time: original_time
53
+ )
54
+ end
55
+
56
+ it 'doesn\'t raise error on signature' do
57
+ expect { request.signature }.to_not raise_error
58
+ end
59
+ end
60
+
61
+ context "when time is not provided" do
62
+ let(:request) do
63
+ described_class.new(access_key_id: 'access_key_id',
64
+ secret_access_key: 'secret_access_key',
65
+ session_token: 'session_token',
66
+ host: 'host',
67
+ server_nonce: 'server_nonce'
68
+ )
69
+ end
70
+
71
+ it 'doesn\'t raise error on signature' do
72
+ expect { request.signature }.to_not raise_error
73
+ end
74
+ end
75
+ end
76
+ end
@@ -65,7 +65,7 @@ describe Mongo::Auth::Scram do
65
65
  it 'does not compress the message' do
66
66
  expect(Mongo::Protocol::Compressed).not_to receive(:new)
67
67
  expect {
68
- authenticator.login(connection)
68
+ authenticator.login
69
69
  }.to raise_error(Mongo::Auth::Unauthorized)
70
70
  end
71
71
  end
@@ -319,6 +319,104 @@ describe Mongo::Client do
319
319
  end
320
320
  end
321
321
 
322
+ context 'timeout options' do
323
+ let(:client) do
324
+ new_local_client(SpecConfig.instance.addresses,
325
+ SpecConfig.instance.authorized_test_options.merge(options))
326
+ end
327
+
328
+ context 'when network timeouts are zero' do
329
+ let(:options) do
330
+ { socket_timeout: 0, connect_timeout: 0 }
331
+ end
332
+
333
+ it 'sets options to zeros' do
334
+ client.options[:socket_timeout].should == 0
335
+ client.options[:connect_timeout].should == 0
336
+ end
337
+
338
+ it 'connects and performs operations successfully' do
339
+ lambda do
340
+ client.database.command(ping: 1)
341
+ end.should_not raise_error
342
+ end
343
+ end
344
+
345
+ %i(socket_timeout connect_timeout).each do |option|
346
+ context "when #{option} is negative" do
347
+ let(:options) do
348
+ { option => -1 }
349
+ end
350
+
351
+ it 'fails client creation' do
352
+ lambda do
353
+ client
354
+ end.should raise_error(ArgumentError, /#{option} must be a non-negative number/)
355
+ end
356
+ end
357
+
358
+ context "when #{option} is of the wrong type" do
359
+ let(:options) do
360
+ { option => '42' }
361
+ end
362
+
363
+ it 'fails client creation' do
364
+ lambda do
365
+ client
366
+ end.should raise_error(ArgumentError, /#{option} must be a non-negative number/)
367
+ end
368
+ end
369
+ end
370
+
371
+ context "when :connect_timeout is very small" do
372
+ # The driver reads first and checks the deadline second.
373
+ # This means the read (in a monitor) can technically take more than
374
+ # the connect timeout. Restrict to TLS configurations to make
375
+ # the network I/O take longer.
376
+ require_tls
377
+
378
+ let(:options) do
379
+ { connect_timeout: 1e-6, server_selection_timeout: 2 }
380
+ end
381
+
382
+ it 'allows client creation' do
383
+ lambda do
384
+ client
385
+ end.should_not raise_error
386
+ end
387
+
388
+ it 'fails server selection due to very small timeout' do
389
+ lambda do
390
+ client.database.command(ping: 1)
391
+ end.should raise_error(Mongo::Error::NoServerAvailable)
392
+ end
393
+ end
394
+
395
+ context "when :socket_timeout is very small" do
396
+ # The driver reads first and checks the deadline second.
397
+ # This means the read (in a monitor) can technically take more than
398
+ # the connect timeout. Restrict to TLS configurations to make
399
+ # the network I/O take longer.
400
+ require_tls
401
+
402
+ let(:options) do
403
+ { socket_timeout: 1e-6, server_selection_timeout: 2 }
404
+ end
405
+
406
+ it 'allows client creation' do
407
+ lambda do
408
+ client
409
+ end.should_not raise_error
410
+ end
411
+
412
+ it 'fails operations due to very small timeout' do
413
+ lambda do
414
+ client.database.command(ping: 1)
415
+ end.should raise_error(Mongo::Error::SocketTimeoutError)
416
+ end
417
+ end
418
+ end
419
+
322
420
  context 'retry_writes option' do
323
421
  let(:client) do
324
422
  new_local_client_nmio(SpecConfig.instance.addresses, options)
@@ -1138,6 +1236,48 @@ describe Mongo::Client do
1138
1236
  end
1139
1237
  end
1140
1238
 
1239
+ context ':bg_error_backtrace option' do
1240
+ [true, false, nil, 42].each do |valid_value|
1241
+ context "valid value: #{valid_value.inspect}" do
1242
+ let(:options) do
1243
+ {bg_error_backtrace: valid_value}
1244
+ end
1245
+
1246
+ it 'is accepted' do
1247
+ client.options[:bg_error_backtrace].should == valid_value
1248
+ end
1249
+ end
1250
+ end
1251
+
1252
+ context 'invalid value type' do
1253
+ let(:options) do
1254
+ {bg_error_backtrace: 'yes'}
1255
+ end
1256
+
1257
+ it 'is rejected' do
1258
+ lambda do
1259
+ client
1260
+ end.should raise_error(ArgumentError, /:bg_error_backtrace option value must be true, false, nil or a positive integer/)
1261
+ end
1262
+ end
1263
+
1264
+ context 'invalid value' do
1265
+ [0, -1, 42.0].each do |invalid_value|
1266
+ context "invalid value: #{invalid_value.inspect}" do
1267
+ let(:options) do
1268
+ {bg_error_backtrace: invalid_value}
1269
+ end
1270
+
1271
+ it 'is rejected' do
1272
+ lambda do
1273
+ client
1274
+ end.should raise_error(ArgumentError, /:bg_error_backtrace option value must be true, false, nil or a positive integer/)
1275
+ end
1276
+ end
1277
+ end
1278
+ end
1279
+ end
1280
+
1141
1281
  describe ':read option' do
1142
1282
  [
1143
1283
  :primary, :primary_preferred, :secondary, :secondary_preferred, :nearest
@@ -1243,6 +1383,73 @@ describe Mongo::Client do
1243
1383
  end
1244
1384
  =end
1245
1385
  end
1386
+
1387
+ context 'when making a block client' do
1388
+ context 'when the block doesn\'t raise an error' do
1389
+ let(:block_client) do
1390
+ c = nil
1391
+ Mongo::Client.new(
1392
+ SpecConfig.instance.addresses,
1393
+ SpecConfig.instance.test_options.merge(database: SpecConfig.instance.test_db),
1394
+ ) do |client|
1395
+ c = client
1396
+ end
1397
+ c
1398
+ end
1399
+
1400
+ it 'is closed after block' do
1401
+ expect(block_client.cluster.connected?).to eq(false)
1402
+ end
1403
+ end
1404
+
1405
+ context 'when the block raises an error' do
1406
+ it 'it is closed after the block' do
1407
+ block_client_raise = nil
1408
+ expect do
1409
+ Mongo::Client.new(
1410
+ SpecConfig.instance.addresses,
1411
+ SpecConfig.instance.test_options.merge(database: SpecConfig.instance.test_db),
1412
+ ) do |client|
1413
+ block_client_raise = client
1414
+ raise "This is an error!"
1415
+ end
1416
+ end.to raise_error(StandardError, "This is an error!")
1417
+ expect(block_client_raise.cluster.connected?).to eq(false)
1418
+ end
1419
+ end
1420
+
1421
+ context 'when the hosts given include the protocol' do
1422
+ it 'raises an error on mongodb://' do
1423
+ expect do
1424
+ Mongo::Client.new(['mongodb://127.0.0.1:27017/test'])
1425
+ end.to raise_error(ArgumentError, "Host 'mongodb://127.0.0.1:27017/test' should not contain protocol. Did you mean to not use an array?")
1426
+ end
1427
+
1428
+ it 'raises an error on mongodb+srv://' do
1429
+ expect do
1430
+ Mongo::Client.new(['mongodb+srv://127.0.0.1:27017/test'])
1431
+ end.to raise_error(ArgumentError, "Host 'mongodb+srv://127.0.0.1:27017/test' should not contain protocol. Did you mean to not use an array?")
1432
+ end
1433
+
1434
+ it 'raises an error on multiple items' do
1435
+ expect do
1436
+ Mongo::Client.new(['127.0.0.1:27017', 'mongodb+srv://127.0.0.1:27017/test'])
1437
+ end.to raise_error(ArgumentError, "Host 'mongodb+srv://127.0.0.1:27017/test' should not contain protocol. Did you mean to not use an array?")
1438
+ end
1439
+
1440
+ it 'raises an error only at beginning of string' do
1441
+ expect do
1442
+ Mongo::Client.new(['somethingmongodb://127.0.0.1:27017/test', 'mongodb+srv://127.0.0.1:27017/test'])
1443
+ end.to raise_error(ArgumentError, "Host 'mongodb+srv://127.0.0.1:27017/test' should not contain protocol. Did you mean to not use an array?")
1444
+ end
1445
+
1446
+ it 'raises an error with different case' do
1447
+ expect do
1448
+ Mongo::Client.new(['MongOdB://127.0.0.1:27017/test'])
1449
+ end.to raise_error(ArgumentError, "Host 'MongOdB://127.0.0.1:27017/test' should not contain protocol. Did you mean to not use an array?")
1450
+ end
1451
+ end
1452
+ end
1246
1453
  end
1247
1454
 
1248
1455
  shared_examples_for 'duplicated client with duplicated monitoring' do