From 7910476a460c3c332f8de77436844db03a563677 Mon Sep 17 00:00:00 2001 From: Saghm Rossi Date: Tue, 13 Nov 2018 14:18:17 -0500 Subject: [PATCH 01/11] implement uri option spec tests --- lib/mongo/uri.rb | 119 ++++++++++++++++- spec/lite_spec_helper.rb | 1 + .../data/uri_options/auth-options.yml | 17 +++ .../data/uri_options/compression-options.yml | 36 +++++ .../data/uri_options/concern-options.yml | 62 +++++++++ .../data/uri_options/connection-options.yml | 76 +++++++++++ .../uri_options/connection-pool-options.yml | 32 +++++ .../uri_options/read-preference-options.yml | 40 ++++++ .../data/uri_options/tls-options.yml | 64 +++++++++ spec/spec_tests/uri_options_spec.rb | 123 ++++++++++++++++++ spec/support/connection_string.rb | 2 +- 11 files changed, 566 insertions(+), 6 deletions(-) create mode 100644 spec/spec_tests/data/uri_options/auth-options.yml create mode 100644 spec/spec_tests/data/uri_options/compression-options.yml create mode 100644 spec/spec_tests/data/uri_options/concern-options.yml create mode 100644 spec/spec_tests/data/uri_options/connection-options.yml create mode 100644 spec/spec_tests/data/uri_options/connection-pool-options.yml create mode 100644 spec/spec_tests/data/uri_options/read-preference-options.yml create mode 100644 spec/spec_tests/data/uri_options/tls-options.yml create mode 100644 spec/spec_tests/uri_options_spec.rb diff --git a/lib/mongo/uri.rb b/lib/mongo/uri.rb index 0e76be63bd..a6ef1064e2 100644 --- a/lib/mongo/uri.rb +++ b/lib/mongo/uri.rb @@ -430,17 +430,19 @@ def self.uri_option(uri_key, name, extra = {}) uri_option 'sockettimeoutms', :socket_timeout, :type => :ms_convert uri_option 'serverselectiontimeoutms', :server_selection_timeout, :type => :ms_convert uri_option 'localthresholdms', :local_threshold, :type => :ms_convert + uri_option 'heartbeatfrequencyms', :heartbeat_frequency, :type => :ms_convert + uri_option 'maxidletimems', :max_idle_time, :type => :ms_convert # Write Options uri_option 'w', :w, :group => :write - uri_option 'journal', :j, :group => :write + uri_option 'journal', :j, :group => :write, :type => :bool uri_option 'fsync', :fsync, :group => :write - uri_option 'wtimeoutms', :timeout, :group => :write + uri_option 'wtimeoutms', :timeout, :group => :write, :type => :unsigned_int # Read Options uri_option 'readpreference', :mode, :group => :read, :type => :read_mode uri_option 'readpreferencetags', :tag_sets, :group => :read, :type => :read_tags - uri_option 'maxstalenessseconds', :max_staleness, :group => :read + uri_option 'maxstalenessseconds', :max_staleness, :group => :read, :type => :max_staleness # Pool options uri_option 'minpoolsize', :min_pool_size @@ -449,6 +451,13 @@ def self.uri_option(uri_key, name, extra = {}) # Security Options uri_option 'ssl', :ssl + uri_option 'tls', :ssl + uri_option 'tlsallowinvalidcertificates', :ssl_verify, :type => :inverse_bool + uri_option 'tlscafilepath', :ssl_ca_cert + uri_option 'tlsclientcertfilepath', :ssl_cert + uri_option 'tlsclientkeyfilepath', :ssl_key + uri_option 'tlsclientkeypassword', :ssl_key_pass_phrase + # Topology options uri_option 'connect', :connect @@ -461,7 +470,9 @@ def self.uri_option(uri_key, name, extra = {}) # Client Options uri_option 'appname', :app_name uri_option 'compressors', :compressors, :type => :array - uri_option 'zlibcompressionlevel', :zlib_compression_level + uri_option 'readconcernlevel', :read_concern + uri_option 'retrywrites', :retry_writes, :type => :bool + uri_option 'zlibcompressionlevel', :zlib_compression_level, :type => :zlib_compression_level # Casts option values that do not have a specifically provided # transformation to the appropriate type. @@ -571,7 +582,7 @@ def auth_source(value) # # @return [Symbol] The transformed authentication mechanism. def auth_mech(value) - AUTH_MECH_MAP[value.upcase] + AUTH_MECH_MAP[value.upcase] || log_warn("#{value} is not a valid auth mechanism") end # Read preference mode transformation. @@ -615,6 +626,94 @@ def auth_mech_props(value) properties end + # Parses the zlib compression level. + # + # @param value [ String ] The zlib compression level string. + # + # @return [ Integer | nil ] The compression level value if it is between -1 and 9 (inclusive), + # otherwise nil (and a warning will be raised). + def zlib_compression_level(value) + if /^-?\d+$/ =~ value + i = value.to_i + + if i >= -1 && i <= 9 + return i + end + end + + log_warn("#{value} is not a valid zlibCompressionLevel") + nil + end + + + # Parses a boolean value. + # + # @param value [ String ] The URI option value. + # + # @return [ true | false | nil ] The boolean value parsed out, otherwise nil (and a warning + # will be raised). + def bool(value) + case value + when "true" + true + when "false" + false + else + log_warn("invalid boolean: #{value}") + nil + end + end + + # Parses a boolean value and returns its inverse. This is used for options where the spec + # defines the boolean value semantics of enabling/disabling something in the reverse way that + # the driver does. For instance, the client option `ssl_verify` will disable certificate + # checking when the value is false, but the spec defines the option + # `tlsAllowInvalidCertificates`, which disables certificate checking when the value is true. + # + # @param value [ String ] The URI option. + # + # @return [ true | false | nil ] The inverse of boolean value parsed out, otherwise nil (and a + # warning will be raised). + def inverse_bool(value) + !bool(value) + end + + # Parses the max staleness value, which must be either "0" or an integer greater or equal to 90. + # + # @param value [ String ] The max staleness string. + # + # @return [ Integer | nil ] The max staleness integer parsed out if it is valid, otherwise nil + # (and a warning will be raised). + def max_staleness(value) + if /^\d+$/ =~ value + int = value.to_i + + if int >= 0 && int < 90 + log_warn("max staleness must be either 0 or greater than 90: #{value}") + end + + return int + end + + log_warn("Invalid max staleness value: #{value}") + nil + end + + # Parses an unsigned integer value. + # + # @param value [ String ] The URI option value. + # + # @return [ Integer | nil ] The integer parsed out, otherwise nil (and a warning will be + # raised). + def unsigned_int(value) + unless /^?\d+$/ =~ value + log_warn("Invalid unsigned integer value: #{value}") + return nil + end + + value.to_i + end + # Ruby's convention is to provide timeouts in seconds, not milliseconds and # to use fractions where more precision is necessary. The connection string # options are always in MS so we provide an easy conversion type. @@ -625,6 +724,11 @@ def auth_mech_props(value) # # @since 2.0.0 def ms_convert(value) + unless /^-?\d+(\.\d+)?$/ =~ value + log_warn("Invalid ms value: #{value}") + return nil + end + value.to_f / 1000 end @@ -636,6 +740,11 @@ def ms_convert(value) def hash_extractor(value) value.split(',').reduce({}) do |set, tag| k, v = tag.split(':') + if v.nil? + log_warn("#{value} is not a valid URI hash") + return nil + end + set.merge(decode(k).downcase.to_sym => decode(v)) end end diff --git a/spec/lite_spec_helper.rb b/spec/lite_spec_helper.rb index 2be3d80178..a2fedb6ede 100644 --- a/spec/lite_spec_helper.rb +++ b/spec/lite_spec_helper.rb @@ -9,6 +9,7 @@ RETRYABLE_WRITES_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/retryable_writes/**/*.yml") COMMAND_MONITORING_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/command_monitoring/**/*.yml") CONNECTION_STRING_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/connection_string/*.yml") +URI_OPTIONS_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/uri_options/*.yml") DNS_SEEDLIST_DISCOVERY_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/dns_seedlist_discovery/*.yml") GRIDFS_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/gridfs/*.yml") TRANSACTIONS_TESTS = Dir.glob("#{CURRENT_PATH}/spec_tests/data/transactions/*.yml") diff --git a/spec/spec_tests/data/uri_options/auth-options.yml b/spec/spec_tests/data/uri_options/auth-options.yml new file mode 100644 index 0000000000..aa788274f7 --- /dev/null +++ b/spec/spec_tests/data/uri_options/auth-options.yml @@ -0,0 +1,17 @@ +tests: + - + description: "Valid auth options are parsed correctly" + uri: "mongodb://example.com/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true&authSource=$external" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + authmechanism: "GSSAPI" + authMechanismProperties: + SERVICE_NAME: "other" + CANONICALIZE_HOST_NAME: "true" + authSource: "$external" \ No newline at end of file diff --git a/spec/spec_tests/data/uri_options/compression-options.yml b/spec/spec_tests/data/uri_options/compression-options.yml new file mode 100644 index 0000000000..55b31adcf6 --- /dev/null +++ b/spec/spec_tests/data/uri_options/compression-options.yml @@ -0,0 +1,36 @@ +tests: + - + description: "Valid compression options are parsed correctly" + uri: "mongodb://example.com/?compressors=zlib&zlibCompressionLevel=9" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + compressors: "zlib" + zlibCompressionLevel: "9" + - + description: "Invalid compressors cause a warning" + uri: "mongodb://example.com/?compressors=jpeg" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} + - + description: "Invalid zlibCompressionLevel causes a warning" + uri: "mongodb://example.com/?compressors=zlib&zlibCompressionLevel=invalid" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} diff --git a/spec/spec_tests/data/uri_options/concern-options.yml b/spec/spec_tests/data/uri_options/concern-options.yml new file mode 100644 index 0000000000..fb25790c30 --- /dev/null +++ b/spec/spec_tests/data/uri_options/concern-options.yml @@ -0,0 +1,62 @@ +tests: + - + description: "Valid read and write concern are parsed correctly" + uri: "mongodb://example.com/?readConcernLevel=majority&w=5&wTimeoutMS=30000&journal=false" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + readConcernLevel: "majority" + w: "5" + wTimeoutMS: "30000" + journal: "false" + - + description: "Arbitrary string readConcernLevel does not cause a warning" + uri: "mongodb://example.com/?readConcernLevel=arbitraryButStillValid" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + readConcernLevel: "arbitraryButStillValid" + - + description: "Arbitrary string w doesn't cause a warning" + uri: "mongodb://example.com/?w=arbitraryButStillValid" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + w: "arbitraryButStillValid" + - + description: "Invalid wTimeoutMS causes a warning" + uri: "mongodb://example.com/?wTimeoutMS=invalid" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} + - + description: "Invalid journal causes a warning" + uri: "mongodb://example.com/?journal=invalid" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} diff --git a/spec/spec_tests/data/uri_options/connection-options.yml b/spec/spec_tests/data/uri_options/connection-options.yml new file mode 100644 index 0000000000..58aa807c9b --- /dev/null +++ b/spec/spec_tests/data/uri_options/connection-options.yml @@ -0,0 +1,76 @@ +tests: + - + description: "Valid connection and timeout options are parsed correctly" + uri: "mongodb://example.com/?appname=URI-OPTIONS-SPEC-TEST&connectTimeoutMS=20000&heartbeatFrequencyMS=5000&localThresholdMS=3000&replicaSet=uri-options-spec&retryWrites=true&serverSelectionTimeoutMS=15000&socketTimeoutMS=7500" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + appname: "URI-OPTIONS-SPEC-TEST" + connectTimeoutMS: "20000" + heartbeatFrequencyMS: "5000" + localThresholdMS: "3000" + maxIdleTimeMS: "50000" + replicaSet: "uri-options-spec" + retryWrites: "true" + serverSelectionTimeoutMS: "15000" + socketTimeoutMS: "7500" + - + description: "Invalid connectTimeoutMS causes a warning" + uri: "mongodb://example.com/?connectTimeoutMS=invalid" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} + - + description: "Invalid heartbeatFrequencyMS causes a warning" + uri: "mongodb://example.com/?heartbeatFrequencyMS=invalid" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} + - + description: "Invalid localThresholdMS causes a warning" + uri: "mongodb://example.com/?localThresholdMS=invalid" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} + - + description: "Invalid serverSelectionTimeoutMS causes a warning" + uri: "mongodb://example.com/?serverSelectionTimeoutMS=invalid" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} + - + description: "Invalid socketTimeoutMS causes a warning" + uri: "mongodb://example.com/?socketTimeoutMS=invalid" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} diff --git a/spec/spec_tests/data/uri_options/connection-pool-options.yml b/spec/spec_tests/data/uri_options/connection-pool-options.yml new file mode 100644 index 0000000000..71f43d474b --- /dev/null +++ b/spec/spec_tests/data/uri_options/connection-pool-options.yml @@ -0,0 +1,32 @@ +tests: + - + description: "Valid connection pool options are parsed correctly" + uri: "mongodb://example.com/?maxIdleTimeMS=50000" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + appname: "URI-OPTIONS-SPEC-TEST" + connectTimeoutMS: "20000" + heartbeatFrequencyMS: "5000" + localThresholdMS: "3000" + maxIdleTimeMS: "50000" + replicaSet: "uri-options-spec" + retryWrites: "true" + serverSelectionTimeoutMS: "15000" + socketTimeoutMS: "7500" + - + description: "Invalid maxIdleTimeMS causes a warning" + uri: "mongodb://example.com/?maxIdleTimeMS=invalid" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} \ No newline at end of file diff --git a/spec/spec_tests/data/uri_options/read-preference-options.yml b/spec/spec_tests/data/uri_options/read-preference-options.yml new file mode 100644 index 0000000000..9c556bd3a7 --- /dev/null +++ b/spec/spec_tests/data/uri_options/read-preference-options.yml @@ -0,0 +1,40 @@ +tests: + - + description: "Valid connection and timeout options are parsed correctly" + uri: "mongodb://example.com/?readPreference=primaryPreferred&readPreferenceTags=dc:ny,rack:1&maxStalenessSeconds=120&readPreferenceTags=dc:ny" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + readPreference: "primaryPreferred" + readPreferenceTags: + - "dc:ny,rack" + - "dc:ny" + maxStalenessSeconds: "120" + - + description: "Invalid readPreferenceTags causes a warning" + uri: "mongodb://example.com/?readPreferenceTags=invalid" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} + - + description: "Invalid maxStalenessSeconds causes a warning" + uri: "mongodb://example.com/?maxStalenessSeconds=invalid" + valid: true + warning: true + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: {} + diff --git a/spec/spec_tests/data/uri_options/tls-options.yml b/spec/spec_tests/data/uri_options/tls-options.yml new file mode 100644 index 0000000000..1cc325038a --- /dev/null +++ b/spec/spec_tests/data/uri_options/tls-options.yml @@ -0,0 +1,64 @@ +tests: + - + description: "Valid required tls options are parsed correctly" + uri: "mongodb://example.com/?tls=true&tlsCAFilePath=ca.pem&tlsClientCertFilePath=cert.pem&tlsClientKeyPassword=hunter2" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + tls: "true" + tlsCAFilePath: "ca.pem" + tlsClientCertFilePath: "cert.pem" + tlsClientKeyPassword: "hunter2" + - + description: "tlsAllowInvalidCertificates is parsed correctly" + uri: "mongodb://example.com/?tlsAllowInvalidCertificates=true" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + tlsAllowInvalidCertificates: "true" + - + description: "tlsAllowInvalidHostnames is parsed correctly" + uri: "mongodb://example.com/?tlsAllowInvalidHostnames=true" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + tlsAllowInvalidHostnames: "true" + - + description: "tlsInsecure is parsed correctly" + uri: "mongodb://example.com/?tlsInsecure=true" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + tlsInsecure: "true" + - + description: "tlsClientKeyFilePath is parsed correctly" + uri: "mongodb://example.com/?tlsClientKeyFilePath=client.pem" + valid: true + warning: false + hosts: ~ + auth: + username: ~ + password: ~ + db: ~ + options: + tlsClientKeyFilePath: "client.pem" diff --git a/spec/spec_tests/uri_options_spec.rb b/spec/spec_tests/uri_options_spec.rb new file mode 100644 index 0000000000..53b206d6ef --- /dev/null +++ b/spec/spec_tests/uri_options_spec.rb @@ -0,0 +1,123 @@ +require 'lite_spec_helper' + +describe 'Uri Options' do + include Mongo::ConnectionString + + URI_OPTIONS_TESTS.each do |file| + + spec = Mongo::ConnectionString::Spec.new(file) + + context(spec.description) do + + before(:all) do + + module Mongo + class Address + + private + + alias :original_create_resolver :create_resolver + def create_resolver(timeout, ssl_options) + family = (host == 'localhost') ? ::Socket::AF_INET : ::Socket::AF_UNSPEC + info = ::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM) + FAMILY_MAP[info.first[4]].new(info[3], port, host) + end + end + + class Server + + # The constructor keeps the same API, but does not instantiate a + # monitor and run it. + alias :original_initialize :initialize + def initialize(address, cluster, monitoring, event_listeners, options = {}) + @address = address + @cluster = cluster + @monitoring = monitoring + @options = options.freeze + @monitor = Monitor.new(address, event_listeners, Monitoring.new, options) + end + + # Disconnect simply needs to return true since we have no monitor and + # no connection. + alias :original_disconnect! :disconnect! + def disconnect!; true; end + end + end + end + + after(:all) do + + module Mongo + # Return the implementations to their originals for the other + # tests in the suite. + class Address + alias :create_resolver :original_create_resolver + remove_method(:original_create_resolver) + end + + class Server + alias :initialize :original_initialize + remove_method(:original_initialize) + + alias :disconnect! :original_disconnect! + remove_method(:original_disconnect!) + end + end + end + + spec.tests.each do |test| + + # Skip optional tests for options the driver doesn't support. + if test.description.start_with?('tlsAllowInvalidHostnames') || test.description.start_with?('tlsInsecure') + next + end + + context "#{test.description}" do + + context 'when the uri is invalid', unless: test.valid? do + + it 'raises an error' do + expect{ + test.uri + }.to raise_exception(Mongo::Error::InvalidURI) + end + end + + context 'when the uri should warn', if: test.warn? do + + before do + expect(Mongo::Logger.logger).to receive(:warn) + end + + it 'warns' do + expect(test.client).to be_a(Mongo::Client) + end + end + + context 'when the uri is valid', if: test.valid? && !test.warn? do + + before do + expect(Mongo::Logger.logger).not_to receive(:warn) + end + + it 'does not raise an exception or warning' do + expect(test.uri).to be_a(Mongo::URI) + end + + it 'creates a client with the correct hosts' do + expect(test.client).to have_hosts(test) + end + + it 'creates a client with the correct authentication properties' do + expect(test.client).to match_auth(test) + end + + it 'creates a client with the correct options' do + expect(test.client).to match_options(test) + end + end + end + end + end + end +end diff --git a/spec/support/connection_string.rb b/spec/support/connection_string.rb index fb0e4597bc..0e40f03fd1 100644 --- a/spec/support/connection_string.rb +++ b/spec/support/connection_string.rb @@ -142,7 +142,7 @@ def warn? end def hosts - @hosts ||= @spec['hosts'].collect do |host| + @hosts ||= (@spec['hosts'] || []).collect do |host| Host.new(host) end end From f57decb002df07819fa4ab2500d0254a964e8107 Mon Sep 17 00:00:00 2001 From: Saghm Rossi Date: Thu, 29 Nov 2018 17:21:19 -0500 Subject: [PATCH 02/11] code review feedback --- lib/mongo/uri.rb | 82 +++++++++++++++++++---------- spec/spec_tests/uri_options_spec.rb | 70 ++++++++---------------- 2 files changed, 76 insertions(+), 76 deletions(-) diff --git a/lib/mongo/uri.rb b/lib/mongo/uri.rb index a6ef1064e2..013fa834c0 100644 --- a/lib/mongo/uri.rb +++ b/lib/mongo/uri.rb @@ -435,9 +435,9 @@ def self.uri_option(uri_key, name, extra = {}) # Write Options uri_option 'w', :w, :group => :write - uri_option 'journal', :j, :group => :write, :type => :bool + uri_option 'journal', :j, :group => :write, :type => :journal uri_option 'fsync', :fsync, :group => :write - uri_option 'wtimeoutms', :timeout, :group => :write, :type => :unsigned_int + uri_option 'wtimeoutms', :timeout, :group => :write, :type => :wtimeout # Read Options uri_option 'readpreference', :mode, :group => :read, :type => :read_mode @@ -452,7 +452,7 @@ def self.uri_option(uri_key, name, extra = {}) # Security Options uri_option 'ssl', :ssl uri_option 'tls', :ssl - uri_option 'tlsallowinvalidcertificates', :ssl_verify, :type => :inverse_bool + uri_option 'tlsallowinvalidcertificates', :ssl_verify, :type => :ssl_verify uri_option 'tlscafilepath', :ssl_ca_cert uri_option 'tlsclientcertfilepath', :ssl_cert uri_option 'tlsclientkeyfilepath', :ssl_key @@ -471,7 +471,7 @@ def self.uri_option(uri_key, name, extra = {}) uri_option 'appname', :app_name uri_option 'compressors', :compressors, :type => :array uri_option 'readconcernlevel', :read_concern - uri_option 'retrywrites', :retry_writes, :type => :bool + uri_option 'retrywrites', :retry_writes, :type => :retry_writes uri_option 'zlibcompressionlevel', :zlib_compression_level, :type => :zlib_compression_level # Casts option values that do not have a specifically provided @@ -582,7 +582,9 @@ def auth_source(value) # # @return [Symbol] The transformed authentication mechanism. def auth_mech(value) - AUTH_MECH_MAP[value.upcase] || log_warn("#{value} is not a valid auth mechanism") + AUTH_MECH_MAP[value.upcase].tap do |mech| + log_warn("#{value} is not a valid auth mechanism") unless mech + end end # Read preference mode transformation. @@ -631,9 +633,9 @@ def auth_mech_props(value) # @param value [ String ] The zlib compression level string. # # @return [ Integer | nil ] The compression level value if it is between -1 and 9 (inclusive), - # otherwise nil (and a warning will be raised). + # otherwise nil (and a warning will be logged). def zlib_compression_level(value) - if /^-?\d+$/ =~ value + if /\A-?\d+\z/ =~ value i = value.to_i if i >= -1 && i <= 9 @@ -645,6 +647,42 @@ def zlib_compression_level(value) nil end + # Parses the journal value. + # + # @param value [ String ] The journal value. + # + # @return [ true | false | nil ] The journal value parsed out, otherwise nil (and a warning + # will be raised). + def journal(value) + bool('journal', value) + end + + # Parses the ssl_verify value. Note that this will be the inverse of the value of + # tlsAllowInvalidCertificates (if present). + # + # @param value [ String ] The tlsAllowInvalidCertificates value. + # + # @return [ true | false | nil ] The ssl_verify value parsed out, otherwise nil (and a warning + # will be raised). + def ssl_verify(value) + b = bool('tlsAllowInvalidCertificates', value) + + if b.nil? + nil + else + !b + end + end + + # Parses the retryWrites value. + # + # @param value [ String ] The retryWrites value. + # + # @return [ true | false | nil ] The boolean value parsed out, otherwise nil (and a warning + # will be raised). + def retry_writes(value) + bool('retryWrites', value) + end # Parses a boolean value. # @@ -652,40 +690,26 @@ def zlib_compression_level(value) # # @return [ true | false | nil ] The boolean value parsed out, otherwise nil (and a warning # will be raised). - def bool(value) + def bool(name, value) case value when "true" true when "false" false else - log_warn("invalid boolean: #{value}") + log_warn("invalid boolean option for #{name}: #{value}") nil end end - # Parses a boolean value and returns its inverse. This is used for options where the spec - # defines the boolean value semantics of enabling/disabling something in the reverse way that - # the driver does. For instance, the client option `ssl_verify` will disable certificate - # checking when the value is false, but the spec defines the option - # `tlsAllowInvalidCertificates`, which disables certificate checking when the value is true. - # - # @param value [ String ] The URI option. - # - # @return [ true | false | nil ] The inverse of boolean value parsed out, otherwise nil (and a - # warning will be raised). - def inverse_bool(value) - !bool(value) - end - # Parses the max staleness value, which must be either "0" or an integer greater or equal to 90. # # @param value [ String ] The max staleness string. # # @return [ Integer | nil ] The max staleness integer parsed out if it is valid, otherwise nil - # (and a warning will be raised). + # (and a warning will be logged). def max_staleness(value) - if /^\d+$/ =~ value + if /\A\d+\z/ =~ value int = value.to_i if int >= 0 && int < 90 @@ -705,9 +729,9 @@ def max_staleness(value) # # @return [ Integer | nil ] The integer parsed out, otherwise nil (and a warning will be # raised). - def unsigned_int(value) - unless /^?\d+$/ =~ value - log_warn("Invalid unsigned integer value: #{value}") + def wtimeout(value) + unless /\A\d+\z/ =~ value + log_warn("Invalid wtimeoutMS value: #{value}") return nil end @@ -724,7 +748,7 @@ def unsigned_int(value) # # @since 2.0.0 def ms_convert(value) - unless /^-?\d+(\.\d+)?$/ =~ value + unless /\A-?\d+(\.\d+)?\z/ =~ value log_warn("Invalid ms value: #{value}") return nil end diff --git a/spec/spec_tests/uri_options_spec.rb b/spec/spec_tests/uri_options_spec.rb index 53b206d6ef..3d79caa2f4 100644 --- a/spec/spec_tests/uri_options_spec.rb +++ b/spec/spec_tests/uri_options_spec.rb @@ -23,25 +23,6 @@ def create_resolver(timeout, ssl_options) FAMILY_MAP[info.first[4]].new(info[3], port, host) end end - - class Server - - # The constructor keeps the same API, but does not instantiate a - # monitor and run it. - alias :original_initialize :initialize - def initialize(address, cluster, monitoring, event_listeners, options = {}) - @address = address - @cluster = cluster - @monitoring = monitoring - @options = options.freeze - @monitor = Monitor.new(address, event_listeners, Monitoring.new, options) - end - - # Disconnect simply needs to return true since we have no monitor and - # no connection. - alias :original_disconnect! :disconnect! - def disconnect!; true; end - end end end @@ -54,14 +35,6 @@ class Address alias :create_resolver :original_create_resolver remove_method(:original_create_resolver) end - - class Server - alias :initialize :original_initialize - remove_method(:original_initialize) - - alias :disconnect! :original_disconnect! - remove_method(:original_disconnect!) - end end end @@ -83,26 +56,7 @@ class Server end end - context 'when the uri should warn', if: test.warn? do - - before do - expect(Mongo::Logger.logger).to receive(:warn) - end - - it 'warns' do - expect(test.client).to be_a(Mongo::Client) - end - end - - context 'when the uri is valid', if: test.valid? && !test.warn? do - - before do - expect(Mongo::Logger.logger).not_to receive(:warn) - end - - it 'does not raise an exception or warning' do - expect(test.uri).to be_a(Mongo::URI) - end + context 'when the uri is valid', if: test.valid? do it 'creates a client with the correct hosts' do expect(test.client).to have_hosts(test) @@ -115,6 +69,28 @@ class Server it 'creates a client with the correct options' do expect(test.client).to match_options(test) end + + context 'when the uri should not warn', if: !test.warn? do + + before do + expect(Mongo::Logger.logger).not_to receive(:warn) + end + + it 'does not raise an exception or warning' do + expect(test.uri).to be_a(Mongo::URI) + end + end + + context 'when the uri should warn', if: test.warn? do + + before do + expect(Mongo::Logger.logger).to receive(:warn) + end + + it 'warns' do + expect(test.client).to be_a(Mongo::Client) + end + end end end end From ffc3704e2e0923fdd15d242950677192c11b4e22 Mon Sep 17 00:00:00 2001 From: Saghm Rossi Date: Fri, 30 Nov 2018 13:19:43 -0500 Subject: [PATCH 03/11] more cr feedback --- lib/mongo/uri.rb | 114 ++++++++++++++++++++++------ spec/spec_tests/uri_options_spec.rb | 38 +++++----- 2 files changed, 110 insertions(+), 42 deletions(-) diff --git a/lib/mongo/uri.rb b/lib/mongo/uri.rb index 013fa834c0..3cdc1a225a 100644 --- a/lib/mongo/uri.rb +++ b/lib/mongo/uri.rb @@ -426,12 +426,12 @@ def self.uri_option(uri_key, name, extra = {}) uri_option 'replicaset', :replica_set, :type => :replica_set # Timeout Options - uri_option 'connecttimeoutms', :connect_timeout, :type => :ms_convert - uri_option 'sockettimeoutms', :socket_timeout, :type => :ms_convert - uri_option 'serverselectiontimeoutms', :server_selection_timeout, :type => :ms_convert - uri_option 'localthresholdms', :local_threshold, :type => :ms_convert - uri_option 'heartbeatfrequencyms', :heartbeat_frequency, :type => :ms_convert - uri_option 'maxidletimems', :max_idle_time, :type => :ms_convert + uri_option 'connecttimeoutms', :connect_timeout, :type => :connect_timeout + uri_option 'sockettimeoutms', :socket_timeout, :type => :socket_timeout + uri_option 'serverselectiontimeoutms', :server_selection_timeout, :type => :server_selection_timeout + uri_option 'localthresholdms', :local_threshold, :type => :local_threshold + uri_option 'heartbeatfrequencyms', :heartbeat_frequency, :type => :heartbeat_frequency + uri_option 'maxidletimems', :max_idle_time, :type => :max_idle_time # Write Options uri_option 'w', :w, :group => :write @@ -447,7 +447,7 @@ def self.uri_option(uri_key, name, extra = {}) # Pool options uri_option 'minpoolsize', :min_pool_size uri_option 'maxpoolsize', :max_pool_size - uri_option 'waitqueuetimeoutms', :wait_queue_timeout, :type => :ms_convert + uri_option 'waitqueuetimeoutms', :wait_queue_timeout, :type => :wait_queue_timeout # Security Options uri_option 'ssl', :ssl @@ -611,7 +611,7 @@ def read_tags(value) # # @return [Hash] The tag set hash. def read_set(value) - hash_extractor(value) + hash_extractor('readPreferenceTags', value) end # Auth mechanism properties extractor. @@ -620,7 +620,7 @@ def read_set(value) # # @return [ Hash ] The auth mechanism properties hash. def auth_mech_props(value) - properties = hash_extractor(value) + properties = hash_extractor('authMechanismProperties', value) if properties[:canonicalize_host_name] properties.merge!(canonicalize_host_name: properties[:canonicalize_host_name] == 'true') @@ -652,7 +652,7 @@ def zlib_compression_level(value) # @param value [ String ] The journal value. # # @return [ true | false | nil ] The journal value parsed out, otherwise nil (and a warning - # will be raised). + # will be logged). def journal(value) bool('journal', value) end @@ -663,7 +663,7 @@ def journal(value) # @param value [ String ] The tlsAllowInvalidCertificates value. # # @return [ true | false | nil ] The ssl_verify value parsed out, otherwise nil (and a warning - # will be raised). + # will be logged). def ssl_verify(value) b = bool('tlsAllowInvalidCertificates', value) @@ -679,7 +679,7 @@ def ssl_verify(value) # @param value [ String ] The retryWrites value. # # @return [ true | false | nil ] The boolean value parsed out, otherwise nil (and a warning - # will be raised). + # will be logged). def retry_writes(value) bool('retryWrites', value) end @@ -689,7 +689,7 @@ def retry_writes(value) # @param value [ String ] The URI option value. # # @return [ true | false | nil ] The boolean value parsed out, otherwise nil (and a warning - # will be raised). + # will be logged). def bool(name, value) case value when "true" @@ -723,17 +723,87 @@ def max_staleness(value) nil end - # Parses an unsigned integer value. + # Parses the connectTimeoutMS value. # - # @param value [ String ] The URI option value. + # @param value [ String ] The connectTimeoutMS value. + # + # @return [ Integer | nil ] The integer parsed out, otherwise nil (and a warning will be + # logged). + def connect_timeout(value) + ms_convert('connectTimeoutMS', value) + end + + # Parses the localThresholdMS value. + # + # @param value [ String ] The localThresholdMS value. # # @return [ Integer | nil ] The integer parsed out, otherwise nil (and a warning will be - # raised). + # logged). + def local_threshold(value) + ms_convert('localThresholdMS', value) + end + + # Parses the heartbeatFrequencyMS value. + # + # @param value [ String ] The heartbeatFrequencyMS value. + # + # @return [ Integer | nil ] The integer parsed out, otherwise nil (and a warning will be + # logged). + def heartbeat_frequency(value) + ms_convert('heartbeatFrequencyMS', value) + end + + # Parses the maxIdleTimeMS value. + # + # @param value [ String ] The maxIdleTimeMS value. + # + # @return [ Integer | nil ] The integer parsed out, otherwise nil (and a warning will be + # logged). + def max_idle_time(value) + ms_convert('maxIdleTimeMS', value) + end + + # Parses the serverSelectionMS value. + # + # @param value [ String ] The serverSelectionMS value. + # + # @return [ Integer | nil ] The integer parsed out, otherwise nil (and a warning will be + # logged). + def server_selection_timeout(value) + ms_convert('serverSelectionTimeoutMS', value) + end + + # Parses the socketTimeoutMS value. + # + # @param value [ String ] The socketTimeoutMS value. + # + # @return [ Integer | nil ] The integer parsed out, otherwise nil (and a warning will be + # logged). + def socket_timeout(value) + ms_convert('socketTimeoutMS', value) + end + + # Parses the waitQueueTimeoutMS value. + # + # @param value [ String ] The waitQueueTimeoutMS value. + # + # @return [ Integer | nil ] The integer parsed out, otherwise nil (and a warning will be + # logged). + def wait_queue_timeout(value) + ms_convert('MS', value) + end + + # Parses the wtimeoutMS value. + # + # @param value [ String ] The wtimeoutMS value. + # + # @return [ Integer | nil ] The integer parsed out, otherwise nil (and a warning will be + # logged). def wtimeout(value) - unless /\A\d+\z/ =~ value + unless /\A\d+\z/ =~ value log_warn("Invalid wtimeoutMS value: #{value}") return nil - end + end value.to_i end @@ -747,9 +817,9 @@ def wtimeout(value) # @return [ Float ] The seconds value. # # @since 2.0.0 - def ms_convert(value) + def ms_convert(name, value) unless /\A-?\d+(\.\d+)?\z/ =~ value - log_warn("Invalid ms value: #{value}") + log_warn("Invalid ms value for #{name}: #{value}") return nil end @@ -761,11 +831,11 @@ def ms_convert(value) # @param value [ String ] The string to build a hash from. # # @return [ Hash ] The hash built from the string. - def hash_extractor(value) + def hash_extractor(name, value) value.split(',').reduce({}) do |set, tag| k, v = tag.split(':') if v.nil? - log_warn("#{value} is not a valid URI hash") + log_warn("Invalid hash value for #{name}: #{value}") return nil end diff --git a/spec/spec_tests/uri_options_spec.rb b/spec/spec_tests/uri_options_spec.rb index 3d79caa2f4..4713b9626f 100644 --- a/spec/spec_tests/uri_options_spec.rb +++ b/spec/spec_tests/uri_options_spec.rb @@ -41,12 +41,21 @@ class Address spec.tests.each do |test| # Skip optional tests for options the driver doesn't support. - if test.description.start_with?('tlsAllowInvalidHostnames') || test.description.start_with?('tlsInsecure') - next - end + next if test.description.start_with?('tlsAllowInvalidHostnames', 'tlsInsecure') context "#{test.description}" do + context 'when the uri should warn', if: test.warn? do + + before do + expect(Mongo::Logger.logger).to receive(:warn) + end + + it 'warns' do + expect(test.client).to be_a(Mongo::Client) + end + end + context 'when the uri is invalid', unless: test.valid? do it 'raises an error' do @@ -69,27 +78,16 @@ class Address it 'creates a client with the correct options' do expect(test.client).to match_options(test) end + end - context 'when the uri should not warn', if: !test.warn? do - - before do - expect(Mongo::Logger.logger).not_to receive(:warn) - end + context 'when the uri should not warn', if: !test.warn? do - it 'does not raise an exception or warning' do - expect(test.uri).to be_a(Mongo::URI) - end + before do + expect(Mongo::Logger.logger).not_to receive(:warn) end - context 'when the uri should warn', if: test.warn? do - - before do - expect(Mongo::Logger.logger).to receive(:warn) - end - - it 'warns' do - expect(test.client).to be_a(Mongo::Client) - end + it 'does not raise an exception or warning' do + expect(test.client).to be_a(Mongo::Client) end end end From 7355473384890434e820a489de14452f7d5a2a53 Mon Sep 17 00:00:00 2001 From: Saghm Rossi Date: Tue, 4 Dec 2018 15:53:50 -0500 Subject: [PATCH 04/11] clean up client tutorial file --- docs/tutorials/ruby-driver-create-client.txt | 112 +++++++++---------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/docs/tutorials/ruby-driver-create-client.txt b/docs/tutorials/ruby-driver-create-client.txt index edb04bc20b..d81be10ee1 100644 --- a/docs/tutorials/ruby-driver-create-client.txt +++ b/docs/tutorials/ruby-driver-create-client.txt @@ -76,12 +76,12 @@ Since the URI options are required in camel case, which is not the Ruby standard following table shows the option in the URI and its corresponding option if passed to the constructor in Ruby. -.. note:: - +.. note:: + The options passed directly should be symbols. The options are explained in detail in the :manual:`Connection URI reference -`. +`. .. note:: Options that are set in **milliseconds** in the URI are @@ -97,8 +97,20 @@ URI Options Conversions * - URI Option - Ruby Option - * - replicaSet=String - - ``:replica_set => String`` + * - appName=String + - ``:app_name => String`` + + * - authMechanism=String + - ``:auth_mech => Symbol`` + + * - authMechanismProperties=Strings + - ``{ :auth_mech_properties => { :service_realm => String, :canonicalize_host_name => true|false, :service_name => String } }`` + + * - authSource=String + - ``:auth_source => String`` + + * - compressors=Strings + - ``:compressors => Array`` * - connect=String - ``:connect => Symbol`` @@ -109,11 +121,11 @@ URI Options Conversions * - connectTimeoutMS=Integer - ``:connect_timeout => Float`` - * - socketTimeoutMS=Integer - - ``:socket_timeout => Float`` + * - fsync=Boolean + - ``{ :write => { :fsync => true|false }}`` - * - serverSelectionTimeoutMS=Integer - - ``:server_selection_timeout => Float`` + * - journal=Boolean + - ``{ :write => { :j => true|false }}`` * - localThresholdMS=Integer - ``:local_threshold => Float`` @@ -124,41 +136,29 @@ URI Options Conversions * - minPoolSize=Integer - ``:min_pool_size => Integer`` - * - waitQueueTimeoutMS=Integer - - ``:wait_queue_timeout => Float`` - - * - w=Integer|String - - ``{ :write => { :w => Integer|String }}`` - - * - wtimeoutMS=Integer - - ``{ :write => { :wtimeout => Float }}`` - - * - journal=Boolean - - ``{ :write => { :j => true|false }}`` - - * - fsync=Boolean - - ``{ :write => { :fsync => true|false }}`` - * - readPreference=String - ``{ :read => { :mode => Symbol }}`` * - readPreferenceTags=Strings - ``{ :read => { :tag_sets => Array }}`` - * - authSource=String - - ``:auth_source => String`` + * - replicaSet=String + - ``:replica_set => String`` - * - authMechanism=String - - ``:auth_mech => Symbol`` + * - serverSelectionTimeoutMS=Integer + - ``:server_selection_timeout => Float`` - * - authMechanismProperties=Strings - - ``{ :auth_mech_properties => { :service_realm => String, :canonicalize_host_name => true|false, :service_name => String } }`` + * - socketTimeoutMS=Integer + - ``:socket_timeout => Float`` - * - appName=String - - ``:app_name => String`` + * - w=Integer|String + - ``{ :write => { :w => Integer|String }}`` - * - compressors=Strings - - ``:compressors => Array`` + * - waitQueueTimeoutMS=Integer + - ``:wait_queue_timeout => Float`` + + * - wtimeoutMS=Integer + - ``{ :write => { :wtimeout => Float }}`` * - zlibCompressionLevel=Integer - ``:zlib_compression_level => Integer`` @@ -178,12 +178,12 @@ Ruby Options * - ``:replica_set`` - When connecting to a replica set, this is the name of the set to - filter servers by. + filter servers by. - ``String`` - none * - ``:ssl`` - - Tell the client to connect to the servers via SSL. + - Tell the client to connect to the servers via SSL. - ``Boolean`` - false @@ -255,30 +255,30 @@ Ruby Options * - ``:connect_timeout`` - The number of seconds to wait to establish a socket connection - before raising an exception. + before raising an exception. - ``Float`` - 10 seconds * - ``:socket_timeout`` - The number of seconds to wait for an operation to execute on a - socket before raising an exception. + socket before raising an exception. - ``Float`` - 5 seconds * - ``:max_pool_size`` - - The maximum size of the connection pool for each server. + - The maximum size of the connection pool for each server. - ``Integer`` - 5 * - ``:min_pool_size`` - The minimum number of connections in the connection pool for each - server. + server. - ``Integer`` - 1 * - ``:wait_queue_timeout`` - The number of seconds to wait for a connection in the connection - pool to become available. + pool to become available. - ``Float`` - 1 @@ -291,22 +291,22 @@ Ruby Options { :write => { :w => 2 } } - ``Hash`` - ``{ :w => 1 }`` - + * - ``:read`` - Specifies the read preference mode and tag sets for selecting servers as a ``Hash``. Keys in the hash are ``:mode`` and ``:tag_sets``. .. code-block:: ruby - { :read => - { :mode => :secondary, - :tag_sets => [ "berlin" ] - } + { :read => + { :mode => :secondary, + :tag_sets => [ "berlin" ] + } } - ``Hash`` - ``{ :mode => :primary }`` - + * - ``:auth_source`` - Specifies the authentication source. - ``String`` @@ -316,7 +316,7 @@ Ruby Options * - ``:auth_mech`` - Specifies the authenticaion mechanism to use. Can be one of: - ``:mongodb_cr``, ``:mongodb_x509``, ``:plain``, ``:scram``. + ``:mongodb_cr``, ``:mongodb_x509``, ``:plain``, ``:scram``. - ``Symbol`` - MongoDB 3.0 and later: ``:scram`` if user credentials are supplied but an ``:auth_mech`` is not. 2.6 and earlier: @@ -343,7 +343,7 @@ Ruby Options ``:replica_set`` or ``:sharded``. - ``Symbol`` - none - + * - ``:heartbeat_frequency`` - The number of seconds for the server monitors to refresh server states asynchronously. @@ -437,9 +437,9 @@ Details on Timeout Options ``connect_timeout`` On initialization of a connection to a server, this setting is the - number of seconds to wait to connect before raising an exception. + number of seconds to wait to connect before raising an exception. This timeout is also used when monitor threads ping their servers. - The default is 10 seconds. See the `socket timeout for monitoring + The default is 10 seconds. See the `socket timeout for monitoring specification `_ for further explanation. @@ -457,7 +457,7 @@ Details on Timeout Options The number of seconds to wait for the driver to find an appropriate server to which an operation can be sent before raising an exception. Defaults to 30. It should take the speed of :manual:`elections` - during a failover into account. See the + during a failover into account. See the `serverSelectionTimeoutMS specification `_ for further information. @@ -466,10 +466,10 @@ Details on Timeout Options The maximum latency in seconds between the nearest server and the servers that can be considered available to send an operation to. Defaults to 0.015. -.. note:: +.. note:: This is not the latency window between the driver and a server, but rather the latency between the nearest server and other servers. See - `the localThresholdMS specification + `the localThresholdMS specification `_. ``wait_queue_timeout`` @@ -483,7 +483,7 @@ Details on Timeout Options ``min_pool_size`` Minimum number of connections in the connection pool for each server. - Increase this number to create connections when the pool is + Increase this number to create connections when the pool is initialized and to reduce the overhead of creating new connections later on. Defaults to 1. @@ -669,7 +669,7 @@ You can either use the default global driver logger or set your own. To set your Mongo::Logger.logger = other_logger See the `Ruby Logger documentation `_ -for more information on the default logger API and available levels. +for more information on the default logger API and available levels. Changing the Logger Level ````````````````````````` From e396935447b59a9cf05b2622cb579227623ebdcb Mon Sep 17 00:00:00 2001 From: Saghm Rossi Date: Tue, 4 Dec 2018 15:58:44 -0500 Subject: [PATCH 05/11] add new URI option mappings to client tutorial --- docs/tutorials/ruby-driver-create-client.txt | 27 ++++++++++++++++++++ lib/mongo/uri.rb | 8 +++--- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/ruby-driver-create-client.txt b/docs/tutorials/ruby-driver-create-client.txt index d81be10ee1..71ee85be73 100644 --- a/docs/tutorials/ruby-driver-create-client.txt +++ b/docs/tutorials/ruby-driver-create-client.txt @@ -124,12 +124,18 @@ URI Options Conversions * - fsync=Boolean - ``{ :write => { :fsync => true|false }}`` + * - heartbeatFrequencyMS=Integer + - ``:heartbeat_frequency => Float`` + * - journal=Boolean - ``{ :write => { :j => true|false }}`` * - localThresholdMS=Integer - ``:local_threshold => Float`` + * - maxIdleTimeMS=Integer + - ``:max_idle_time => Float`` + * - maxPoolSize=Integer - ``:max_pool_size => Integer`` @@ -151,6 +157,27 @@ URI Options Conversions * - socketTimeoutMS=Integer - ``:socket_timeout => Float`` + * - tls=Boolean + - ``:ssl => boolean`` + + * - tlsAllowInvalidCertificates=Boolean + - ``:ssl_verify => boolean`` + + * - tlsCAFile=String + - ``:ssl_ca_cert => String`` + + * - tlsClientCertFile=String + - ``:ssl_cert => String`` + + * - tlsClientKeyFile=String + - ``:ssl_key => String`` + + * - tlsClientKeyPassword=String + - ``:ssl_key_pass_phrase => String`` + + * - tlsInsecure=Boolean + - ``:ssl_verify => boolean`` + * - w=Integer|String - ``{ :write => { :w => Integer|String }}`` diff --git a/lib/mongo/uri.rb b/lib/mongo/uri.rb index 3cdc1a225a..0ac66a129e 100644 --- a/lib/mongo/uri.rb +++ b/lib/mongo/uri.rb @@ -453,11 +453,11 @@ def self.uri_option(uri_key, name, extra = {}) uri_option 'ssl', :ssl uri_option 'tls', :ssl uri_option 'tlsallowinvalidcertificates', :ssl_verify, :type => :ssl_verify - uri_option 'tlscafilepath', :ssl_ca_cert - uri_option 'tlsclientcertfilepath', :ssl_cert - uri_option 'tlsclientkeyfilepath', :ssl_key + uri_option 'tlscafile', :ssl_ca_cert + uri_option 'tlsclientcertfile', :ssl_cert + uri_option 'tlsclientkeyfile', :ssl_key uri_option 'tlsclientkeypassword', :ssl_key_pass_phrase - + uri_option 'tlsinsecure', :ssl_verify, :type => :ssl_verify # Topology options uri_option 'connect', :connect From 2fefd93165d1ee4052d1fa122a9f68d78bd1a4c1 Mon Sep 17 00:00:00 2001 From: Saghm Rossi Date: Wed, 5 Dec 2018 16:29:31 -0500 Subject: [PATCH 06/11] update documentation for insecure tls options --- docs/tutorials/ruby-driver-create-client.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/tutorials/ruby-driver-create-client.txt b/docs/tutorials/ruby-driver-create-client.txt index 71ee85be73..dff5a22e9d 100644 --- a/docs/tutorials/ruby-driver-create-client.txt +++ b/docs/tutorials/ruby-driver-create-client.txt @@ -163,6 +163,10 @@ URI Options Conversions * - tlsAllowInvalidCertificates=Boolean - ``:ssl_verify => boolean`` + NOTE: Because ``tlsAllowInvalidCertificates`` uses ``true`` to sigify that verification + should be disabled and ``ssl_verify`` uses ``false`` to signify that verification should be + disabled, the boolean is inverted before being used to set ``ssl_verify`` + * - tlsCAFile=String - ``:ssl_ca_cert => String`` @@ -178,6 +182,10 @@ URI Options Conversions * - tlsInsecure=Boolean - ``:ssl_verify => boolean`` + NOTE: Because tlsInsecure uses ``true`` to sigify that verification should be disabled and + ``ssl_verify`` uses ``false`` to signify that verification should be disabled, the boolean + is inverted before being used to set ``ssl_verify`` + * - w=Integer|String - ``{ :write => { :w => Integer|String }}`` From 61066ca0dcea5e53b457b0e6a5342e5fb6476037 Mon Sep 17 00:00:00 2001 From: Saghm Rossi Date: Thu, 6 Dec 2018 15:03:40 -0500 Subject: [PATCH 07/11] update spec files --- lib/mongo/uri.rb | 4 +- .../data/uri_options/auth-options.yml | 7 +-- .../data/uri_options/compression-options.yml | 15 ++---- .../data/uri_options/concern-options.yml | 25 ++------- .../data/uri_options/connection-options.yml | 30 +++-------- .../uri_options/connection-pool-options.yml | 20 ++------ .../uri_options/read-preference-options.yml | 17 ++----- .../data/uri_options/tls-options.yml | 51 ++++++++----------- spec/spec_tests/uri_options_spec.rb | 2 +- 9 files changed, 48 insertions(+), 123 deletions(-) diff --git a/lib/mongo/uri.rb b/lib/mongo/uri.rb index 0ac66a129e..d98712a64d 100644 --- a/lib/mongo/uri.rb +++ b/lib/mongo/uri.rb @@ -454,9 +454,9 @@ def self.uri_option(uri_key, name, extra = {}) uri_option 'tls', :ssl uri_option 'tlsallowinvalidcertificates', :ssl_verify, :type => :ssl_verify uri_option 'tlscafile', :ssl_ca_cert - uri_option 'tlsclientcertfile', :ssl_cert + uri_option 'tlscertificatekeyfile', :ssl_cert uri_option 'tlsclientkeyfile', :ssl_key - uri_option 'tlsclientkeypassword', :ssl_key_pass_phrase + uri_option 'tlscertificatekeypassword', :ssl_key_pass_phrase uri_option 'tlsinsecure', :ssl_verify, :type => :ssl_verify # Topology options diff --git a/spec/spec_tests/data/uri_options/auth-options.yml b/spec/spec_tests/data/uri_options/auth-options.yml index aa788274f7..f55f2c9af6 100644 --- a/spec/spec_tests/data/uri_options/auth-options.yml +++ b/spec/spec_tests/data/uri_options/auth-options.yml @@ -5,13 +5,10 @@ tests: valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: authmechanism: "GSSAPI" authMechanismProperties: SERVICE_NAME: "other" CANONICALIZE_HOST_NAME: "true" - authSource: "$external" \ No newline at end of file + authSource: "$external" diff --git a/spec/spec_tests/data/uri_options/compression-options.yml b/spec/spec_tests/data/uri_options/compression-options.yml index 55b31adcf6..d8ea3eb006 100644 --- a/spec/spec_tests/data/uri_options/compression-options.yml +++ b/spec/spec_tests/data/uri_options/compression-options.yml @@ -5,10 +5,7 @@ tests: valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: compressors: "zlib" zlibCompressionLevel: "9" @@ -18,10 +15,7 @@ tests: valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: {} - description: "Invalid zlibCompressionLevel causes a warning" @@ -29,8 +23,5 @@ tests: valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: {} diff --git a/spec/spec_tests/data/uri_options/concern-options.yml b/spec/spec_tests/data/uri_options/concern-options.yml index fb25790c30..174a4c24cd 100644 --- a/spec/spec_tests/data/uri_options/concern-options.yml +++ b/spec/spec_tests/data/uri_options/concern-options.yml @@ -5,10 +5,7 @@ tests: valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: readConcernLevel: "majority" w: "5" @@ -20,10 +17,7 @@ tests: valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: readConcernLevel: "arbitraryButStillValid" - @@ -32,10 +26,7 @@ tests: valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: w: "arbitraryButStillValid" - @@ -44,10 +35,7 @@ tests: valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: {} - description: "Invalid journal causes a warning" @@ -55,8 +43,5 @@ tests: valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: {} diff --git a/spec/spec_tests/data/uri_options/connection-options.yml b/spec/spec_tests/data/uri_options/connection-options.yml index 58aa807c9b..dcee131949 100644 --- a/spec/spec_tests/data/uri_options/connection-options.yml +++ b/spec/spec_tests/data/uri_options/connection-options.yml @@ -5,10 +5,7 @@ tests: valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: appname: "URI-OPTIONS-SPEC-TEST" connectTimeoutMS: "20000" @@ -25,10 +22,7 @@ tests: valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: {} - description: "Invalid heartbeatFrequencyMS causes a warning" @@ -36,10 +30,7 @@ tests: valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: {} - description: "Invalid localThresholdMS causes a warning" @@ -47,10 +38,7 @@ tests: valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: {} - description: "Invalid serverSelectionTimeoutMS causes a warning" @@ -58,10 +46,7 @@ tests: valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: {} - description: "Invalid socketTimeoutMS causes a warning" @@ -69,8 +54,5 @@ tests: valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: {} diff --git a/spec/spec_tests/data/uri_options/connection-pool-options.yml b/spec/spec_tests/data/uri_options/connection-pool-options.yml index 71f43d474b..fb4b62b8a2 100644 --- a/spec/spec_tests/data/uri_options/connection-pool-options.yml +++ b/spec/spec_tests/data/uri_options/connection-pool-options.yml @@ -5,28 +5,14 @@ tests: valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: - appname: "URI-OPTIONS-SPEC-TEST" - connectTimeoutMS: "20000" - heartbeatFrequencyMS: "5000" - localThresholdMS: "3000" maxIdleTimeMS: "50000" - replicaSet: "uri-options-spec" - retryWrites: "true" - serverSelectionTimeoutMS: "15000" - socketTimeoutMS: "7500" - description: "Invalid maxIdleTimeMS causes a warning" uri: "mongodb://example.com/?maxIdleTimeMS=invalid" valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ - options: {} \ No newline at end of file + auth: ~ + options: {} diff --git a/spec/spec_tests/data/uri_options/read-preference-options.yml b/spec/spec_tests/data/uri_options/read-preference-options.yml index 9c556bd3a7..1ad24fba01 100644 --- a/spec/spec_tests/data/uri_options/read-preference-options.yml +++ b/spec/spec_tests/data/uri_options/read-preference-options.yml @@ -1,14 +1,11 @@ tests: - - description: "Valid connection and timeout options are parsed correctly" + description: "Valid read preference options are parsed correctly" uri: "mongodb://example.com/?readPreference=primaryPreferred&readPreferenceTags=dc:ny,rack:1&maxStalenessSeconds=120&readPreferenceTags=dc:ny" valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: readPreference: "primaryPreferred" readPreferenceTags: @@ -21,10 +18,7 @@ tests: valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: {} - description: "Invalid maxStalenessSeconds causes a warning" @@ -32,9 +26,6 @@ tests: valid: true warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: {} diff --git a/spec/spec_tests/data/uri_options/tls-options.yml b/spec/spec_tests/data/uri_options/tls-options.yml index 1cc325038a..ebc8a352af 100644 --- a/spec/spec_tests/data/uri_options/tls-options.yml +++ b/spec/spec_tests/data/uri_options/tls-options.yml @@ -1,29 +1,23 @@ tests: - description: "Valid required tls options are parsed correctly" - uri: "mongodb://example.com/?tls=true&tlsCAFilePath=ca.pem&tlsClientCertFilePath=cert.pem&tlsClientKeyPassword=hunter2" + uri: "mongodb://example.com/?tls=true&tlsCAFile=ca.pem&tlsCertificateKeyFile=cert.pem&tlsCertificateKeyPassword=hunter2" valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: tls: "true" - tlsCAFilePath: "ca.pem" - tlsClientCertFilePath: "cert.pem" - tlsClientKeyPassword: "hunter2" + tlsCAFile: "ca.pem" + tlsCertificateKeyFile: "cert.pem" + tlsCertificateKeyPassword: "hunter2" - description: "tlsAllowInvalidCertificates is parsed correctly" uri: "mongodb://example.com/?tlsAllowInvalidCertificates=true" valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: tlsAllowInvalidCertificates: "true" - @@ -32,10 +26,7 @@ tests: valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: tlsAllowInvalidHostnames: "true" - @@ -44,21 +35,23 @@ tests: valid: true warning: false hosts: ~ - auth: - username: ~ - password: ~ - db: ~ + auth: ~ options: tlsInsecure: "true" - - description: "tlsClientKeyFilePath is parsed correctly" - uri: "mongodb://example.com/?tlsClientKeyFilePath=client.pem" + description: "tlsInsecure=true and tlsAllowInvalidCertificates=false warns" + uri: "mongodb://example.com/?tlsInsecure=true&tlsAllowInvalidCertificates=false" valid: true - warning: false + warning: true hosts: ~ - auth: - username: ~ - password: ~ - db: ~ - options: - tlsClientKeyFilePath: "client.pem" + auth: ~ + options: ~ + - + description: "tlsInsecure=true and tlsAllowInvalidHostnames=false warns" + uri: "mongodb://example.com/?tlsInsecure=true&tlsAllowInvalidHostnames=false" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~ + diff --git a/spec/spec_tests/uri_options_spec.rb b/spec/spec_tests/uri_options_spec.rb index 4713b9626f..a5848d618d 100644 --- a/spec/spec_tests/uri_options_spec.rb +++ b/spec/spec_tests/uri_options_spec.rb @@ -41,7 +41,7 @@ class Address spec.tests.each do |test| # Skip optional tests for options the driver doesn't support. - next if test.description.start_with?('tlsAllowInvalidHostnames', 'tlsInsecure') + next if test.description.start_with?('tlsAllowInvalidHostnames') context "#{test.description}" do From 80fcbe7dc6e7e2e4c4f858c06500e09f18c123a0 Mon Sep 17 00:00:00 2001 From: Saghm Rossi Date: Thu, 6 Dec 2018 15:13:45 -0500 Subject: [PATCH 08/11] update URI option documentation --- docs/tutorials/ruby-driver-create-client.txt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/tutorials/ruby-driver-create-client.txt b/docs/tutorials/ruby-driver-create-client.txt index dff5a22e9d..3492c633cb 100644 --- a/docs/tutorials/ruby-driver-create-client.txt +++ b/docs/tutorials/ruby-driver-create-client.txt @@ -106,11 +106,14 @@ URI Options Conversions * - authMechanismProperties=Strings - ``{ :auth_mech_properties => { :service_realm => String, :canonicalize_host_name => true|false, :service_name => String } }`` + Specified as comma-separated key:value pairs, e.g. ``"SERVICE_REALM:foo,CANONICALIZE_HOSTNAME:TRUE"`` + * - authSource=String - ``:auth_source => String`` * - compressors=Strings - ``:compressors => Array`` + Specified as a comma-separated list, e.g. "zlib,snappy" * - connect=String - ``:connect => Symbol`` @@ -146,7 +149,9 @@ URI Options Conversions - ``{ :read => { :mode => Symbol }}`` * - readPreferenceTags=Strings - - ``{ :read => { :tag_sets => Array }}`` + - ``{ :read => { :tag_sets => Array }}`` + + Each instance of the readPreferenceTags field is a comma-separated key:value pair which will appear in the :tag_sets array in the order they are specified. For instance, ``"readPreferenceTags=dc:ny,rack:1&readPreferenceTags=dc:ny"`` will be converted to ``[ { 'dc' => 'ny', 'rack' => '1' }, { 'dc' => 'ny' }]``. * - replicaSet=String - ``:replica_set => String`` @@ -163,7 +168,7 @@ URI Options Conversions * - tlsAllowInvalidCertificates=Boolean - ``:ssl_verify => boolean`` - NOTE: Because ``tlsAllowInvalidCertificates`` uses ``true`` to sigify that verification + Because ``tlsAllowInvalidCertificates`` uses ``true`` to signify that verification should be disabled and ``ssl_verify`` uses ``false`` to signify that verification should be disabled, the boolean is inverted before being used to set ``ssl_verify`` @@ -182,7 +187,7 @@ URI Options Conversions * - tlsInsecure=Boolean - ``:ssl_verify => boolean`` - NOTE: Because tlsInsecure uses ``true`` to sigify that verification should be disabled and + Because tlsInsecure uses ``true`` to signify that verification should be disabled and ``ssl_verify`` uses ``false`` to signify that verification should be disabled, the boolean is inverted before being used to set ``ssl_verify`` From c0e34b935da382ef7b779907a9e6eced601bbb58 Mon Sep 17 00:00:00 2001 From: Saghm Rossi Date: Mon, 10 Dec 2018 15:48:04 -0500 Subject: [PATCH 09/11] fix typos in URI options docs --- docs/tutorials/ruby-driver-create-client.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/ruby-driver-create-client.txt b/docs/tutorials/ruby-driver-create-client.txt index 3492c633cb..ca6291a913 100644 --- a/docs/tutorials/ruby-driver-create-client.txt +++ b/docs/tutorials/ruby-driver-create-client.txt @@ -106,14 +106,15 @@ URI Options Conversions * - authMechanismProperties=Strings - ``{ :auth_mech_properties => { :service_realm => String, :canonicalize_host_name => true|false, :service_name => String } }`` - Specified as comma-separated key:value pairs, e.g. ``"SERVICE_REALM:foo,CANONICALIZE_HOSTNAME:TRUE"`` + Specified as comma-separated key:value pairs, e.g. ``"SERVICE_REALM:foo,CANONICALIZE_HOSTNAME:TRUE"``. * - authSource=String - ``:auth_source => String`` * - compressors=Strings - ``:compressors => Array`` - Specified as a comma-separated list, e.g. "zlib,snappy" + + Specified as a comma-separated list, e.g. "zlib,snappy". * - connect=String - ``:connect => Symbol`` @@ -170,7 +171,7 @@ URI Options Conversions Because ``tlsAllowInvalidCertificates`` uses ``true`` to signify that verification should be disabled and ``ssl_verify`` uses ``false`` to signify that verification should be - disabled, the boolean is inverted before being used to set ``ssl_verify`` + disabled, the boolean is inverted before being used to set ``ssl_verify``. * - tlsCAFile=String - ``:ssl_ca_cert => String`` @@ -189,7 +190,7 @@ URI Options Conversions Because tlsInsecure uses ``true`` to signify that verification should be disabled and ``ssl_verify`` uses ``false`` to signify that verification should be disabled, the boolean - is inverted before being used to set ``ssl_verify`` + is inverted before being used to set ``ssl_verify``. * - w=Integer|String - ``{ :write => { :w => Integer|String }}`` From e9de6b7f400576d381d3e9503851956421bed331 Mon Sep 17 00:00:00 2001 From: Saghm Rossi Date: Mon, 10 Dec 2018 16:03:53 -0500 Subject: [PATCH 10/11] update compression URI option documentation --- docs/tutorials/ruby-driver-create-client.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/tutorials/ruby-driver-create-client.txt b/docs/tutorials/ruby-driver-create-client.txt index ca6291a913..e405177d4a 100644 --- a/docs/tutorials/ruby-driver-create-client.txt +++ b/docs/tutorials/ruby-driver-create-client.txt @@ -114,7 +114,12 @@ URI Options Conversions * - compressors=Strings - ``:compressors => Array`` - Specified as a comma-separated list, e.g. "zlib,snappy". + Specified as a comma-separated list. Note that the Ruby driver only supports zlib + compression; however, other drivers may support snappy. For maximum compatibility with + drivers, specify ``"snappy,zlib"``; if compatibility with other drivers is not a concern, + specify ``"zlib".`` Compression is not enabled by default and when using MongoDB 4.0 and + earlier, so zlib compression must be manually enabled on the server in order for the Ruby + driver to compress wire protocol data. * - connect=String - ``:connect => Symbol`` From 729a3ecd5581d45b32355743ec1f1c2ac4d99d4c Mon Sep 17 00:00:00 2001 From: Saghm Rossi Date: Tue, 11 Dec 2018 15:03:18 -0500 Subject: [PATCH 11/11] update spec tests --- lib/mongo/uri.rb | 5 ++ .../data/uri_options/compression-options.yml | 21 +++++- .../data/uri_options/concern-options.yml | 16 +++-- .../data/uri_options/connection-options.yml | 71 +++++++++++++++---- .../uri_options/connection-pool-options.yml | 12 +++- .../uri_options/read-preference-options.yml | 12 +++- .../data/uri_options/tls-options.yml | 40 +++++++++-- spec/spec_tests/uri_options_spec.rb | 22 +++--- 8 files changed, 162 insertions(+), 37 deletions(-) diff --git a/lib/mongo/uri.rb b/lib/mongo/uri.rb index d98712a64d..14c30ffa00 100644 --- a/lib/mongo/uri.rb +++ b/lib/mongo/uri.rb @@ -823,6 +823,11 @@ def ms_convert(name, value) return nil end + if value[0] == '-' + log_warn("#{name} cannot be a negative number") + return nil + end + value.to_f / 1000 end diff --git a/spec/spec_tests/data/uri_options/compression-options.yml b/spec/spec_tests/data/uri_options/compression-options.yml index d8ea3eb006..2dfd19eb1e 100644 --- a/spec/spec_tests/data/uri_options/compression-options.yml +++ b/spec/spec_tests/data/uri_options/compression-options.yml @@ -8,7 +8,7 @@ tests: auth: ~ options: compressors: "zlib" - zlibCompressionLevel: "9" + zlibCompressionLevel: 9 - description: "Invalid compressors cause a warning" uri: "mongodb://example.com/?compressors=jpeg" @@ -18,10 +18,27 @@ tests: auth: ~ options: {} - - description: "Invalid zlibCompressionLevel causes a warning" + description: "Non-numeric zlibCompressionLevel causes a warning" uri: "mongodb://example.com/?compressors=zlib&zlibCompressionLevel=invalid" valid: true warning: true hosts: ~ auth: ~ options: {} + - + description: "Too low zlibCompressionLevel causes a warning" + uri: "mongodb://example.com/?compressors=zlib&zlibCompressionLevel=-2" + valid: true + warning: true + hosts: ~ + auth: ~ + options: {} + - + description: "Too high zlibCompressionLevel causes a warning" + uri: "mongodb://example.com/?compressors=zlib&zlibCompressionLevel=10" + valid: true + warning: true + hosts: ~ + auth: ~ + options: {} + diff --git a/spec/spec_tests/data/uri_options/concern-options.yml b/spec/spec_tests/data/uri_options/concern-options.yml index 174a4c24cd..c883241739 100644 --- a/spec/spec_tests/data/uri_options/concern-options.yml +++ b/spec/spec_tests/data/uri_options/concern-options.yml @@ -8,9 +8,9 @@ tests: auth: ~ options: readConcernLevel: "majority" - w: "5" - wTimeoutMS: "30000" - journal: "false" + w: 5 + wTimeoutMS: 30000 + journal: false - description: "Arbitrary string readConcernLevel does not cause a warning" uri: "mongodb://example.com/?readConcernLevel=arbitraryButStillValid" @@ -30,13 +30,21 @@ tests: options: w: "arbitraryButStillValid" - - description: "Invalid wTimeoutMS causes a warning" + description: "Non-numeric wTimeoutMS causes a warning" uri: "mongodb://example.com/?wTimeoutMS=invalid" valid: true warning: true hosts: ~ auth: ~ options: {} + - + description: "Too low wTimeoutMS causes a warning" + uri: "mongodb://example.com/?wTimeoutMS=-2" + valid: true + warning: true + hosts: ~ + auth: ~ + options: {} - description: "Invalid journal causes a warning" uri: "mongodb://example.com/?journal=invalid" diff --git a/spec/spec_tests/data/uri_options/connection-options.yml b/spec/spec_tests/data/uri_options/connection-options.yml index dcee131949..db1ea6be36 100644 --- a/spec/spec_tests/data/uri_options/connection-options.yml +++ b/spec/spec_tests/data/uri_options/connection-options.yml @@ -8,16 +8,16 @@ tests: auth: ~ options: appname: "URI-OPTIONS-SPEC-TEST" - connectTimeoutMS: "20000" - heartbeatFrequencyMS: "5000" - localThresholdMS: "3000" - maxIdleTimeMS: "50000" + connectTimeoutMS: 20000 + heartbeatFrequencyMS: 5000 + localThresholdMS: 3000 + maxIdleTimeMS: 50000 replicaSet: "uri-options-spec" - retryWrites: "true" - serverSelectionTimeoutMS: "15000" - socketTimeoutMS: "7500" + retryWrites: true + serverSelectionTimeoutMS: 15000 + socketTimeoutMS: 7500 - - description: "Invalid connectTimeoutMS causes a warning" + description: "Non-numeric connectTimeoutMS causes a warning" uri: "mongodb://example.com/?connectTimeoutMS=invalid" valid: true warning: true @@ -25,7 +25,15 @@ tests: auth: ~ options: {} - - description: "Invalid heartbeatFrequencyMS causes a warning" + description: "Too low connectTimeoutMS causes a warning" + uri: "mongodb://example.com/?connectTimeoutMS=-2" + valid: true + warning: true + hosts: ~ + auth: ~ + options: {} + - + description: "Non-numeric heartbeatFrequencyMS causes a warning" uri: "mongodb://example.com/?heartbeatFrequencyMS=invalid" valid: true warning: true @@ -33,7 +41,15 @@ tests: auth: ~ options: {} - - description: "Invalid localThresholdMS causes a warning" + description: "Too low heartbeatFrequencyMS causes a warning" + uri: "mongodb://example.com/?heartbeatFrequencyMS=-2" + valid: true + warning: true + hosts: ~ + auth: ~ + options: {} + - + description: "Non-numeric localThresholdMS causes a warning" uri: "mongodb://example.com/?localThresholdMS=invalid" valid: true warning: true @@ -41,7 +57,23 @@ tests: auth: ~ options: {} - - description: "Invalid serverSelectionTimeoutMS causes a warning" + description: "Too low localThresholdMS causes a warning" + uri: "mongodb://example.com/?localThresholdMS=-2" + valid: true + warning: true + hosts: ~ + auth: ~ + options: {} + - + description: "Invalid retryWrites causes a warning" + uri: "mongodb://example.com/?retryWrites=invalid" + valid: true + warning: true + hosts: ~ + auth: ~ + options: {} + - + description: "Non-numeric serverSelectionTimeoutMS causes a warning" uri: "mongodb://example.com/?serverSelectionTimeoutMS=invalid" valid: true warning: true @@ -49,10 +81,25 @@ tests: auth: ~ options: {} - - description: "Invalid socketTimeoutMS causes a warning" + description: "Too low serverSelectionTimeoutMS causes a warning" + uri: "mongodb://example.com/?serverSelectionTimeoutMS=-2" + valid: true + warning: true + hosts: ~ + auth: ~ + options: {} + - + description: "Non-numeric socketTimeoutMS causes a warning" uri: "mongodb://example.com/?socketTimeoutMS=invalid" valid: true warning: true hosts: ~ auth: ~ options: {} + - + description: "Too low socketTimeoutMS causes a warning" + uri: "mongodb://example.com/?socketTimeoutMS=-2" + valid: true + warning: true + hosts: ~ + auth: ~ diff --git a/spec/spec_tests/data/uri_options/connection-pool-options.yml b/spec/spec_tests/data/uri_options/connection-pool-options.yml index fb4b62b8a2..54cee220b5 100644 --- a/spec/spec_tests/data/uri_options/connection-pool-options.yml +++ b/spec/spec_tests/data/uri_options/connection-pool-options.yml @@ -7,12 +7,20 @@ tests: hosts: ~ auth: ~ options: - maxIdleTimeMS: "50000" + maxIdleTimeMS: 50000 - - description: "Invalid maxIdleTimeMS causes a warning" + description: "Non-numeric maxIdleTimeMS causes a warning" uri: "mongodb://example.com/?maxIdleTimeMS=invalid" valid: true warning: true hosts: ~ auth: ~ options: {} + - + description: "Too low maxIdleTimeMS causes a warning" + uri: "mongodb://example.com/?maxIdleTimeMS=-2" + valid: true + warning: true + hosts: ~ + auth: ~ + options: {} diff --git a/spec/spec_tests/data/uri_options/read-preference-options.yml b/spec/spec_tests/data/uri_options/read-preference-options.yml index 1ad24fba01..425447aec3 100644 --- a/spec/spec_tests/data/uri_options/read-preference-options.yml +++ b/spec/spec_tests/data/uri_options/read-preference-options.yml @@ -11,7 +11,7 @@ tests: readPreferenceTags: - "dc:ny,rack" - "dc:ny" - maxStalenessSeconds: "120" + maxStalenessSeconds: 120 - description: "Invalid readPreferenceTags causes a warning" uri: "mongodb://example.com/?readPreferenceTags=invalid" @@ -21,11 +21,19 @@ tests: auth: ~ options: {} - - description: "Invalid maxStalenessSeconds causes a warning" + description: "Non-numeric maxStalenessSeconds causes a warning" uri: "mongodb://example.com/?maxStalenessSeconds=invalid" valid: true warning: true hosts: ~ auth: ~ options: {} + - + description: "Too low maxStalenessSeconds causes a warning" + uri: "mongodb://example.com/?maxStalenessSeconds=-2" + valid: true + warning: true + hosts: ~ + auth: ~ + options: {} diff --git a/spec/spec_tests/data/uri_options/tls-options.yml b/spec/spec_tests/data/uri_options/tls-options.yml index ebc8a352af..fa31ab1b87 100644 --- a/spec/spec_tests/data/uri_options/tls-options.yml +++ b/spec/spec_tests/data/uri_options/tls-options.yml @@ -7,10 +7,18 @@ tests: hosts: ~ auth: ~ options: - tls: "true" + tls: true tlsCAFile: "ca.pem" tlsCertificateKeyFile: "cert.pem" tlsCertificateKeyPassword: "hunter2" + - + description: "Invalid tlsAllowInvalidCertificates causes a warning" + uri: "mongodb://example.com/?tlsAllowInvalidCertificates=invalid" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~ - description: "tlsAllowInvalidCertificates is parsed correctly" uri: "mongodb://example.com/?tlsAllowInvalidCertificates=true" @@ -19,7 +27,15 @@ tests: hosts: ~ auth: ~ options: - tlsAllowInvalidCertificates: "true" + tlsAllowInvalidCertificates: true + - + description: "Invalid tlsAllowInvalidCertificates causes a warning" + uri: "mongodb://example.com/?tlsAllowInvalidCertificates=invalid" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~ - description: "tlsAllowInvalidHostnames is parsed correctly" uri: "mongodb://example.com/?tlsAllowInvalidHostnames=true" @@ -28,7 +44,15 @@ tests: hosts: ~ auth: ~ options: - tlsAllowInvalidHostnames: "true" + tlsAllowInvalidHostnames: true + - + description: "Invalid tlsAllowInvalidHostnames causes a warning" + uri: "mongodb://example.com/?tlsAllowInvalidHostnames=invalid" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~ - description: "tlsInsecure is parsed correctly" uri: "mongodb://example.com/?tlsInsecure=true" @@ -37,7 +61,15 @@ tests: hosts: ~ auth: ~ options: - tlsInsecure: "true" + tlsInsecure: true + - + description: "Invalid tlsAllowInsecure causes a warning" + uri: "mongodb://example.com/?tlsAllowInsecure=invalid" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~ - description: "tlsInsecure=true and tlsAllowInvalidCertificates=false warns" uri: "mongodb://example.com/?tlsInsecure=true&tlsAllowInvalidCertificates=false" diff --git a/spec/spec_tests/uri_options_spec.rb b/spec/spec_tests/uri_options_spec.rb index a5848d618d..da3cd8e331 100644 --- a/spec/spec_tests/uri_options_spec.rb +++ b/spec/spec_tests/uri_options_spec.rb @@ -65,6 +65,17 @@ class Address end end + context 'when the uri should not warn', if: !test.warn? do + + before do + expect(Mongo::Logger.logger).not_to receive(:warn) + end + + it 'does not raise an exception or warning' do + expect(test.client).to be_a(Mongo::Client) + end + end + context 'when the uri is valid', if: test.valid? do it 'creates a client with the correct hosts' do @@ -79,17 +90,6 @@ class Address expect(test.client).to match_options(test) end end - - context 'when the uri should not warn', if: !test.warn? do - - before do - expect(Mongo::Logger.logger).not_to receive(:warn) - end - - it 'does not raise an exception or warning' do - expect(test.client).to be_a(Mongo::Client) - end - end end end end