diff --git a/lib/mongo/client.rb b/lib/mongo/client.rb index 70f5768628..e6049ad872 100644 --- a/lib/mongo/client.rb +++ b/lib/mongo/client.rb @@ -1362,75 +1362,26 @@ def cluster_modifying?(new_options) # The argument may contain a subset of options that the client will # eventually have; this method validates each of the provided options # but does not check for interactions between combinations of options. - def validate_new_options!(opts) - return Options::Redacted.new unless opts - if opts[:read_concern] - # Raise an error for non user-settable options - if opts[:read_concern][:after_cluster_time] - raise Mongo::Error::InvalidReadConcern.new( - 'The after_cluster_time read_concern option cannot be specified by the user' - ) + def validate_new_options!(options) + return Options::Redacted.new unless options + + Options::Redacted.new(options).tap do |opts| + validate_read_concern!(opts[:read_concern]) + validate_server_api!(opts[:server_api]) + validate_max_min_pool_size!(opts) + validate_max_connecting!(opts) + validate_read!(opts) + validate_compressors!(opts) + validate_srv_max_hosts!(opts) + + invalid_options = opts.keys.map(&:to_sym) - VALID_OPTIONS + if invalid_options.any? + log_warn("Unsupported client options: #{invalid_options.join(', ')}. These will be ignored.") + opts.delete_if { |key,| !VALID_OPTIONS.include?(key.to_sym) } end - given_keys = opts[:read_concern].keys.map(&:to_s) - allowed_keys = ['level'] - invalid_keys = given_keys - allowed_keys - # Warn that options are invalid but keep it and forward to the server - unless invalid_keys.empty? - log_warn("Read concern has invalid keys: #{invalid_keys.join(',')}.") - end - end - - if server_api = opts[:server_api] - unless server_api.is_a?(Hash) - raise ArgumentError, ":server_api value must be a hash: #{server_api}" - end - - extra_keys = server_api.keys - %w(version strict deprecation_errors) - unless extra_keys.empty? - raise ArgumentError, "Unknown keys under :server_api: #{extra_keys.map(&:inspect).join(', ')}" - end - - if version = server_api[:version] - unless VALID_SERVER_API_VERSIONS.include?(version) - raise ArgumentError, "Unknown server API version: #{version}" - end - end - end - - Lint.validate_underscore_read_preference(opts[:read]) - Lint.validate_read_concern_option(opts[:read_concern]) - opts.each.inject(Options::Redacted.new) do |_options, (k, v)| - key = k.to_sym - if VALID_OPTIONS.include?(key) - validate_max_min_pool_size!(key, opts) - validate_max_connecting!(key, opts) - validate_read!(key, opts) - if key == :compressors - compressors = valid_compressors(v) - - if compressors.include?('snappy') - validate_snappy_compression! - end - - if compressors.include?('zstd') - validate_zstd_compression! - end - - _options[key] = compressors unless compressors.empty? - elsif key == :srv_max_hosts - if v && (!v.is_a?(Integer) || v < 0) - log_warn("#{v} is not a valid integer for srv_max_hosts") - else - _options[key] = v - end - else - _options[key] = v - end - else - log_warn("Unsupported client option '#{k}'. It will be ignored.") - end - _options + Lint.validate_underscore_read_preference(opts[:read]) + Lint.validate_read_concern_option(opts[:read_concern]) end end @@ -1569,6 +1520,48 @@ def validate_options!(addresses = nil, is_srv: nil) end end + ALLOWED_READ_CONCERN_KEYS = %w[ level ].freeze + + def validate_read_concern!(read_concern) + return unless read_concern + + # Raise an error for non user-settable options + if read_concern[:after_cluster_time] + raise Mongo::Error::InvalidReadConcern.new( + 'The after_cluster_time read_concern option cannot be specified by the user' + ) + end + + given_keys = read_concern.keys.map(&:to_s) + invalid_keys = given_keys - ALLOWED_READ_CONCERN_KEYS + + # Warn that options are invalid but keep it and forward to the server + unless invalid_keys.empty? + log_warn("Read concern has invalid keys: #{invalid_keys.join(',')}.") + end + end + + ALLOWED_SERVER_API_KEYS = %w[ version strict deprecation_errors ].freeze + + def validate_server_api!(server_api) + return unless server_api + + unless server_api.is_a?(Hash) + raise ArgumentError, ":server_api value must be a hash: #{server_api}" + end + + extra_keys = server_api.keys - ALLOWED_SERVER_API_KEYS + unless extra_keys.empty? + raise ArgumentError, "Unknown keys under :server_api: #{extra_keys.map(&:inspect).join(', ')}" + end + + if version = server_api[:version] + unless VALID_SERVER_API_VERSIONS.include?(version) + raise ArgumentError, "Unknown server API version: #{version}" + end + end + end + # Validates all authentication-related options after they are set on the client # This method is intended to catch combinations of options which are not allowed def validate_authentication_options! @@ -1639,6 +1632,26 @@ def valid_compressors(compressors) end end + def validate_compressors!(opts) + return unless opts[:compressors] + + compressors = valid_compressors(opts[:compressors]) + + if compressors.include?('snappy') + validate_snappy_compression! + end + + if compressors.include?('zstd') + validate_zstd_compression! + end + + if compressors.empty? + opts.delete(:compressors) + else + opts[:compressors] = compressors + end + end + def validate_snappy_compression! return if defined?(Snappy) require 'snappy' @@ -1657,14 +1670,25 @@ def validate_zstd_compression! "\"bundle install\" to install the gem. (#{e.class}: #{e})" end - def validate_max_min_pool_size!(option, opts) - if option == :min_pool_size && opts[:min_pool_size] - max = opts[:max_pool_size] || Server::ConnectionPool::DEFAULT_MAX_SIZE - if max != 0 && opts[:min_pool_size] > max - raise Error::InvalidMinPoolSize.new(opts[:min_pool_size], max) - end + def validate_max_min_pool_size!(opts) + return unless opts[:min_pool_size] + + max = opts[:max_pool_size] || Server::ConnectionPool::DEFAULT_MAX_SIZE + if max != 0 && opts[:min_pool_size] > max + raise Error::InvalidMinPoolSize.new(opts[:min_pool_size], max) + end + end + + def validate_srv_max_hosts!(opts) + return unless opts.key?(:srv_max_hosts) + + srv_max_hosts = opts[:srv_max_hosts] + return unless srv_max_hosts + + if !srv_max_hosts.is_a?(Integer) || srv_max_hosts < 0 + log_warn("#{srv_max_hosts} is not a valid integer for srv_max_hosts") + opts.delete(:srv_max_hosts) end - true end # Validates whether the max_connecting option is valid. @@ -1673,35 +1697,34 @@ def validate_max_min_pool_size!(option, opts) # @param [ Hash ] opts The client options. # # @return [ true ] If the option is valid. - # @raise [ Error::InvalidMaxConnecting ] If the option is invalid. - def validate_max_connecting!(option, opts) - if option == :max_connecting && opts.key?(:max_connecting) - max_connecting = opts[:max_connecting] || Server::ConnectionPool::DEFAULT_MAX_CONNECTING - if max_connecting <= 0 - raise Error::InvalidMaxConnecting.new(opts[:max_connecting]) - end + def validate_max_connecting!(opts) + return unless opts.key?(:max_connecting) + + max_connecting = opts[:max_connecting] || Server::ConnectionPool::DEFAULT_MAX_CONNECTING + if max_connecting <= 0 + opts[:max_connecting] = Server::ConnectionPool::DEFAULT_MAX_CONNECTING + log_warn("Invalid max_connecting: #{max_connecting}. Please ensure that it is greater than zero.") end - true end - def validate_read!(option, opts) - if option == :read && opts.has_key?(:read) - read = opts[:read] - # We could check if read is a Hash, but this would fail - # for custom classes implementing key access ([]). - # Instead reject common cases of strings and symbols. - if read.is_a?(String) || read.is_a?(Symbol) - raise Error::InvalidReadOption.new(read, "the read preference must be specified as a hash: { mode: #{read.inspect} }") - end + def validate_read!(opts) + return unless opts.has_key?(:read) - if mode = read[:mode] - mode = mode.to_sym - unless Mongo::ServerSelector::PREFERENCES.include?(mode) - raise Error::InvalidReadOption.new(read, "mode #{mode} is not one of recognized modes") - end + read = opts[:read] + + # We could check if read is a Hash, but this would fail + # for custom classes implementing key access ([]). + # Instead reject common cases of strings and symbols. + if read.is_a?(String) || read.is_a?(Symbol) + raise Error::InvalidReadOption.new(read, "the read preference must be specified as a hash: { mode: #{read.inspect} }") + end + + if mode = read[:mode] + mode = mode.to_sym + unless Mongo::ServerSelector::PREFERENCES.include?(mode) + raise Error::InvalidReadOption.new(read, "mode #{mode} is not one of recognized modes") end end - true end def assert_not_closed diff --git a/lib/mongo/uri.rb b/lib/mongo/uri.rb index 0b891a858c..215eeb6d65 100644 --- a/lib/mongo/uri.rb +++ b/lib/mongo/uri.rb @@ -505,17 +505,17 @@ def validate_uri_options! end unless uri_options[:ssl_verify_hostname].nil? - raise_invalid_error_no_fmt!("tlsInsecure' and 'tlsAllowInvalidHostnames' cannot both be specified") + raise_invalid_error_no_fmt!("'tlsInsecure' and 'tlsAllowInvalidHostnames' cannot both be specified") end unless uri_options[:ssl_verify_ocsp_endpoint].nil? - raise_invalid_error_no_fmt!("tlsInsecure' and 'tlsDisableOCSPEndpointCheck' cannot both be specified") + raise_invalid_error_no_fmt!("'tlsInsecure' and 'tlsDisableOCSPEndpointCheck' cannot both be specified") end end unless uri_options[:ssl_verify_certificate].nil? unless uri_options[:ssl_verify_ocsp_endpoint].nil? - raise_invalid_error_no_fmt!("tlsAllowInvalidCertificates' and 'tlsDisableOCSPEndpointCheck' cannot both be specified") + raise_invalid_error_no_fmt!("'tlsAllowInvalidCertificates' and 'tlsDisableOCSPEndpointCheck' cannot both be specified") end end diff --git a/lib/mongo/uri/options_mapper.rb b/lib/mongo/uri/options_mapper.rb index eac2f59c3b..30247506e2 100644 --- a/lib/mongo/uri/options_mapper.rb +++ b/lib/mongo/uri/options_mapper.rb @@ -62,7 +62,7 @@ def initialize(**opts) def add_uri_option(key, value, uri_options) strategy = URI_OPTION_MAP[key.downcase] if strategy.nil? - log_warn("Unsupported URI option '#{key}' on URI '#{@string}'. It will be ignored.") + warn_unsupported_option(key, @string) return end @@ -91,7 +91,7 @@ def smc_to_ruby(opts) opts.each do |key, value| strategy = URI_OPTION_MAP[key.downcase] if strategy.nil? - log_warn("Unsupported URI option '#{key}' on URI '#{@string}'. It will be ignored.") + warn_unsupported_option(key, @string) return end @@ -206,6 +206,10 @@ def ruby_to_string(opts) private + def warn_unsupported_option(key, uri) + log_warn("Unsupported URI option '#{key}' on URI '#{uri}'. It will be ignored.") + end + # Applies URI value transformation by either using the default cast # or a transformation appropriate for the given type. # diff --git a/spec/mongo/client_construction_spec.rb b/spec/mongo/client_construction_spec.rb index 442c0480b3..3fff84cc4b 100644 --- a/spec/mongo/client_construction_spec.rb +++ b/spec/mongo/client_construction_spec.rb @@ -817,8 +817,9 @@ { max_connecting: -5 } end - it 'raises an exception' do - expect { client }.to raise_error(Mongo::Error::InvalidMaxConnecting) + it 'logs a warning' do + expect(Mongo::Logger.logger).to receive(:warn).with(/Invalid max_connecting/) + client end end end @@ -1035,13 +1036,14 @@ end end - context 'when max_connecting is a negative integer' do + context 'when max_connecting is zero' do let(:uri) do 'mongodb://127.0.0.1:27017/?maxConnecting=0' end - it 'raises an exception' do - expect { client }.to raise_error(Mongo::Error::InvalidMaxConnecting) + it 'logs a warning' do + expect(Mongo::Logger.logger).to receive(:warn).with(/Invalid max_connecting/) + client end end end diff --git a/spec/spec_tests/data/uri_options/auth-options.yml b/spec/spec_tests/data/uri_options/auth-options.yml index f06ac012c0..4a46516f13 100644 --- a/spec/spec_tests/data/uri_options/auth-options.yml +++ b/spec/spec_tests/data/uri_options/auth-options.yml @@ -1,7 +1,7 @@ tests: - description: "Valid auth options are parsed correctly (GSSAPI)" - uri: "mongodb://foo:bar@example.com/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true&authSource=$external" + uri: "mongodb://foo:bar@example.com/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forward,SERVICE_HOST:example.com&authSource=$external" valid: true warning: false hosts: ~ @@ -10,32 +10,8 @@ tests: authMechanism: "GSSAPI" authMechanismProperties: SERVICE_NAME: "other" - CANONICALIZE_HOST_NAME: true - authSource: "$external" - - - description: "Mixed case in auth mechanism properties is preserved" - uri: "mongodb://foo:bar@example.com/?authMechanism=GSSAPI&authMechanismProperties=PropertyName:PropertyValue&authSource=$external" - valid: true - warning: false - hosts: ~ - auth: ~ - options: - authMechanism: "GSSAPI" - authMechanismProperties: - PropertyName: PropertyValue - service_name: mongodb - authSource: "$external" - - - description: "Auth mechanism properties are all invalid" - uri: "mongodb://foo:bar@example.com/?authMechanism=GSSAPI&authMechanismProperties=PropertyName&authSource=$external" - valid: true - warning: true - hosts: ~ - auth: ~ - options: - authMechanism: "GSSAPI" - authMechanismProperties: - service_name: mongodb + SERVICE_HOST: "example.com" + CANONICALIZE_HOST_NAME: "forward" authSource: "$external" - description: "Valid auth options are parsed correctly (SCRAM-SHA-1)" diff --git a/spec/spec_tests/data/uri_options/compression-options.yml b/spec/spec_tests/data/uri_options/compression-options.yml index 78cb9cbfa9..5e140e59c9 100644 --- a/spec/spec_tests/data/uri_options/compression-options.yml +++ b/spec/spec_tests/data/uri_options/compression-options.yml @@ -7,7 +7,7 @@ tests: hosts: ~ auth: ~ options: - compressors: + compressors: - "zlib" zlibCompressionLevel: 9 - @@ -28,7 +28,6 @@ tests: warning: true hosts: ~ auth: ~ - # https://jira.mongodb.org/browse/DRIVERS-1368 options: ~ - description: "Too low zlibCompressionLevel causes a warning" @@ -37,7 +36,6 @@ tests: warning: true hosts: ~ auth: ~ - # https://jira.mongodb.org/browse/DRIVERS-1368 options: ~ - description: "Too high zlibCompressionLevel causes a warning" @@ -46,6 +44,5 @@ tests: warning: true hosts: ~ auth: ~ - # https://jira.mongodb.org/browse/DRIVERS-1368 options: ~ diff --git a/spec/spec_tests/data/uri_options/concern-options.yml b/spec/spec_tests/data/uri_options/concern-options.yml index c883241739..7d31453491 100644 --- a/spec/spec_tests/data/uri_options/concern-options.yml +++ b/spec/spec_tests/data/uri_options/concern-options.yml @@ -36,7 +36,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Too low wTimeoutMS causes a warning" uri: "mongodb://example.com/?wTimeoutMS=-2" @@ -44,7 +44,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Invalid journal causes a warning" uri: "mongodb://example.com/?journal=invalid" @@ -52,4 +52,4 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ diff --git a/spec/spec_tests/data/uri_options/connection-options.yml b/spec/spec_tests/data/uri_options/connection-options.yml index 5f0a914bfd..2d312b0861 100644 --- a/spec/spec_tests/data/uri_options/connection-options.yml +++ b/spec/spec_tests/data/uri_options/connection-options.yml @@ -1,7 +1,7 @@ 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&maxIdleTimeMS=50000&replicaSet=uri-options-spec&retryWrites=true&serverSelectionTimeoutMS=15000&socketTimeoutMS=7500" + uri: "mongodb://example.com/?appname=URI-OPTIONS-SPEC-TEST&connectTimeoutMS=20000&heartbeatFrequencyMS=5000&localThresholdMS=3000&maxIdleTimeMS=50000&replicaSet=uri-options-spec&retryWrites=true&serverSelectionTimeoutMS=15000&socketTimeoutMS=7500&timeoutMS=100" valid: true warning: false hosts: ~ @@ -16,6 +16,7 @@ tests: retryWrites: true serverSelectionTimeoutMS: 15000 socketTimeoutMS: 7500 + timeoutMS: 100 - description: "Non-numeric connectTimeoutMS causes a warning" uri: "mongodb://example.com/?connectTimeoutMS=invalid" @@ -23,7 +24,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Too low connectTimeoutMS causes a warning" uri: "mongodb://example.com/?connectTimeoutMS=-2" @@ -31,7 +32,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Non-numeric heartbeatFrequencyMS causes a warning" uri: "mongodb://example.com/?heartbeatFrequencyMS=invalid" @@ -39,7 +40,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Too low heartbeatFrequencyMS causes a warning" uri: "mongodb://example.com/?heartbeatFrequencyMS=-2" @@ -47,7 +48,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Non-numeric localThresholdMS causes a warning" uri: "mongodb://example.com/?localThresholdMS=invalid" @@ -55,7 +56,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Too low localThresholdMS causes a warning" uri: "mongodb://example.com/?localThresholdMS=-2" @@ -63,15 +64,15 @@ tests: warning: true hosts: ~ auth: ~ - options: {} - - + options: ~ + - description: "Invalid retryWrites causes a warning" uri: "mongodb://example.com/?retryWrites=invalid" valid: true warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Non-numeric serverSelectionTimeoutMS causes a warning" uri: "mongodb://example.com/?serverSelectionTimeoutMS=invalid" @@ -79,7 +80,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Too low serverSelectionTimeoutMS causes a warning" uri: "mongodb://example.com/?serverSelectionTimeoutMS=-2" @@ -87,7 +88,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Non-numeric socketTimeoutMS causes a warning" uri: "mongodb://example.com/?socketTimeoutMS=invalid" @@ -95,7 +96,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Too low socketTimeoutMS causes a warning" uri: "mongodb://example.com/?socketTimeoutMS=-2" @@ -103,8 +104,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} - + options: ~ - description: directConnection=true uri: "mongodb://example.com/?directConnection=true" @@ -121,6 +121,7 @@ tests: warning: false hosts: ~ auth: ~ + options: ~ - description: directConnection=false uri: "mongodb://example.com/?directConnection=false" @@ -146,7 +147,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: loadBalanced=true uri: "mongodb://example.com/?loadBalanced=true" @@ -182,7 +183,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: loadBalanced=true with multiple hosts causes an error uri: "mongodb://example1,example2/?loadBalanced=true" @@ -190,7 +191,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: loadBalanced=true with directConnection=true causes an error uri: "mongodb://example.com/?loadBalanced=true&directConnection=true" @@ -198,7 +199,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: loadBalanced=true with replicaSet causes an error uri: "mongodb://example.com/?loadBalanced=true&replicaSet=replset" @@ -206,4 +207,29 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ + - + description: "timeoutMS=0" + uri: "mongodb://example.com/?timeoutMS=0" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + timeoutMS: 0 + - + description: "Non-numeric timeoutMS causes a warning" + uri: "mongodb://example.com/?timeoutMS=invalid" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~ + - + description: "Too low timeoutMS causes a warning" + uri: "mongodb://example.com/?timeoutMS=-2" + valid: true + warning: true + hosts: ~ + 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 54cee220b5..bb73093be8 100644 --- a/spec/spec_tests/data/uri_options/connection-pool-options.yml +++ b/spec/spec_tests/data/uri_options/connection-pool-options.yml @@ -1,13 +1,16 @@ tests: - description: "Valid connection pool options are parsed correctly" - uri: "mongodb://example.com/?maxIdleTimeMS=50000" + uri: "mongodb://example.com/?maxIdleTimeMS=50000&maxPoolSize=5&minPoolSize=3&maxConnecting=1" valid: true warning: false hosts: ~ auth: ~ options: maxIdleTimeMS: 50000 + maxPoolSize: 5 + minPoolSize: 3 + maxConnecting: 1 - description: "Non-numeric maxIdleTimeMS causes a warning" uri: "mongodb://example.com/?maxIdleTimeMS=invalid" @@ -15,7 +18,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Too low maxIdleTimeMS causes a warning" uri: "mongodb://example.com/?maxIdleTimeMS=-2" @@ -23,4 +26,42 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ + + - + description: "maxPoolSize=0 does not error" + uri: "mongodb://example.com/?maxPoolSize=0" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + maxPoolSize: 0 + + - + description: "minPoolSize=0 does not error" + uri: "mongodb://example.com/?minPoolSize=0" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + minPoolSize: 0 + + - + description: "maxConnecting=0 causes a warning" + uri: "mongodb://example.com/?maxConnecting=0" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~ + + - + description: "maxConnecting<0 causes a warning" + uri: "mongodb://example.com/?maxConnecting=-1" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~ diff --git a/spec/spec_tests/data/uri_options/custom-tests.yml b/spec/spec_tests/data/uri_options/custom-tests.yml new file mode 100644 index 0000000000..86223df268 --- /dev/null +++ b/spec/spec_tests/data/uri_options/custom-tests.yml @@ -0,0 +1,101 @@ +tests: + - + description: "Mixed case in auth mechanism properties is preserved" + uri: "mongodb://foo:bar@example.com/?authMechanism=GSSAPI&authMechanismProperties=PropertyName:PropertyValue&authSource=$external" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + authMechanism: "GSSAPI" + authMechanismProperties: + PropertyName: PropertyValue + service_name: mongodb + authSource: "$external" + - + description: "Auth mechanism properties are all invalid" + uri: "mongodb://foo:bar@example.com/?authMechanism=GSSAPI&authMechanismProperties=PropertyName&authSource=$external" + valid: true + warning: true + hosts: ~ + auth: ~ + options: + authMechanism: "GSSAPI" + authMechanismProperties: + service_name: mongodb + authSource: "$external" + # https://jira.mongodb.org/browse/DRIVERS-1369 + - + description: "Valid and invalid readPreferenceTags mix" + uri: "mongodb://example.com/?readPreferenceTags=a:b,invalid" + valid: true + warning: true + hosts: ~ + auth: ~ + options: + readPreferenceTags: + - + a: b + - + description: Equal sign in auth mechanism properties + uri: "mongodb://foo:bar@example.com/?authMechanismProperties=foo:a=bar&authMechanism=MONGODB-AWS" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + authMechanismProperties: + foo: a=bar + authMechanism: MONGODB-AWS + - + description: directConnection=true and connect=direct + uri: "mongodb://example.com/?directConnection=true&connect=direct" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + directConnection: true + connect: direct + - + description: directConnection=false and connect=direct + uri: "mongodb://example.com/?directConnection=false&connect=direct" + valid: false + warning: false + hosts: ~ + auth: ~ + - + description: directConnection=true and connect=replica_set + uri: "mongodb://example.com/?directConnection=true&connect=replica_set&replicaSet=foo" + valid: false + warning: false + hosts: ~ + auth: ~ + - + description: directConnection=false and connect=replica_set + uri: "mongodb://example.com/?directConnection=false&connect=replica_set&replicaSet=foo" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + directConnection: false + connect: replica_set + replicaSet: foo + - + description: directConnection=true and connect=sharded + uri: "mongodb://example.com/?directConnection=true&connect=sharded" + valid: false + warning: false + hosts: ~ + auth: ~ + - + description: directConnection=false and connect=replica_set + uri: "mongodb://example.com/?directConnection=false&connect=sharded" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + directConnection: false + connect: sharded diff --git a/spec/spec_tests/data/uri_options/proxy-options.yml b/spec/spec_tests/data/uri_options/proxy-options.yml new file mode 100644 index 0000000000..a97863dd59 --- /dev/null +++ b/spec/spec_tests/data/uri_options/proxy-options.yml @@ -0,0 +1,121 @@ +tests: + - + description: "proxyPort without proxyHost" + uri: "mongodb://localhost/?proxyPort=1080" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "proxyUsername without proxyHost" + uri: "mongodb://localhost/?proxyUsername=abc" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "proxyPassword without proxyHost" + uri: "mongodb://localhost/?proxyPassword=def" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "all other proxy options without proxyHost" + uri: "mongodb://localhost/?proxyPort=1080&proxyUsername=abc&proxyPassword=def" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "proxyUsername without proxyPassword" + uri: "mongodb://localhost/?proxyHost=localhost&proxyUsername=abc" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "proxyPassword without proxyUsername" + uri: "mongodb://localhost/?proxyHost=localhost&proxyPassword=def" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "multiple proxyHost parameters" + uri: "mongodb://localhost/?proxyHost=localhost&proxyHost=localhost2" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "multiple proxyPort parameters" + uri: "mongodb://localhost/?proxyHost=localhost&proxyPort=1234&proxyPort=12345" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "multiple proxyUsername parameters" + uri: "mongodb://localhost/?proxyHost=localhost&proxyUsername=abc&proxyUsername=def&proxyPassword=123" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "multiple proxyPassword parameters" + uri: "mongodb://localhost/?proxyHost=localhost&proxyUsername=abc&proxyPassword=123&proxyPassword=456" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "only host present" + uri: "mongodb://localhost/?proxyHost=localhost" + valid: true + warning: false + hosts: ~ + auth: ~ + options: {} + - + description: "host and default port present" + uri: "mongodb://localhost/?proxyHost=localhost&proxyPort=1080" + valid: true + warning: false + hosts: ~ + auth: ~ + options: {} + - + description: "host and non-default port present" + uri: "mongodb://localhost/?proxyHost=localhost&proxyPort=12345" + valid: true + warning: false + hosts: ~ + auth: ~ + options: {} + - + description: "replicaset, host and non-default port present" + uri: "mongodb://rs1,rs2,rs3/?proxyHost=localhost&proxyPort=12345" + valid: true + warning: false + hosts: ~ + auth: ~ + options: {} + - + description: "all options present" + uri: "mongodb://rs1,rs2,rs3/?proxyHost=localhost&proxyPort=12345&proxyUsername=asdf&proxyPassword=qwerty" + valid: true + warning: false + 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 b148be2d67..267454c0ea 100644 --- a/spec/spec_tests/data/uri_options/read-preference-options.yml +++ b/spec/spec_tests/data/uri_options/read-preference-options.yml @@ -9,44 +9,42 @@ tests: options: readPreference: "primaryPreferred" readPreferenceTags: - - + - dc: "ny" rack: "1" - dc: "ny" maxStalenessSeconds: 120 - - description: "Case is preserved in read preference tag names and values" - uri: "mongodb://example.com/?readPreference=secondary&readPreferenceTags=DataCenter:NewYork" + description: "Single readPreferenceTags is parsed as array of size one" + uri: "mongodb://example.com/?readPreference=secondary&readPreferenceTags=dc:ny" valid: true warning: false hosts: ~ auth: ~ options: - readPreference: "secondary" readPreferenceTags: - - - DataCenter: NewYork + - + dc: "ny" - - description: "Invalid readPreferenceTags causes a warning" - uri: "mongodb://example.com/?readPreferenceTags=invalid" + description: "Read preference tags are case sensitive" + uri: "mongodb://example.com/?readPreference=secondary&readPreferenceTags=dc:NY" valid: true - warning: true + warning: false hosts: ~ auth: ~ - options: {} - # https://jira.mongodb.org/browse/DRIVERS-1369 + options: + readPreferenceTags: + - + dc: "NY" - - description: "Valid and invalid readPreferenceTags mix" - uri: "mongodb://example.com/?readPreferenceTags=a:b,invalid" + description: "Invalid readPreferenceTags causes a warning" + uri: "mongodb://example.com/?readPreferenceTags=invalid" valid: true warning: true hosts: ~ auth: ~ - options: - readPreferenceTags: - - - a: b + options: ~ - description: "Non-numeric maxStalenessSeconds causes a warning" uri: "mongodb://example.com/?maxStalenessSeconds=invalid" @@ -54,7 +52,7 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "Too low maxStalenessSeconds causes a warning" uri: "mongodb://example.com/?maxStalenessSeconds=-2" @@ -62,5 +60,5 @@ tests: warning: true hosts: ~ auth: ~ - options: {} + options: ~ diff --git a/spec/spec_tests/data/uri_options/ruby-auth-options.yml b/spec/spec_tests/data/uri_options/ruby-auth-options.yml deleted file mode 100644 index a6bf6d1b4c..0000000000 --- a/spec/spec_tests/data/uri_options/ruby-auth-options.yml +++ /dev/null @@ -1,12 +0,0 @@ -tests: - - - description: Equal sign in auth mechanism properties - uri: "mongodb://foo:bar@example.com/?authMechanismProperties=foo:a=bar&authMechanism=MONGODB-AWS" - valid: true - warning: false - hosts: ~ - auth: ~ - options: - authMechanismProperties: - foo: a=bar - authMechanism: MONGODB-AWS diff --git a/spec/spec_tests/data/uri_options/ruby-connection-options.yml b/spec/spec_tests/data/uri_options/ruby-connection-options.yml deleted file mode 100644 index e2e9253dfd..0000000000 --- a/spec/spec_tests/data/uri_options/ruby-connection-options.yml +++ /dev/null @@ -1,58 +0,0 @@ -tests: - - - description: directConnection=true and connect=direct - uri: "mongodb://example.com/?directConnection=true&connect=direct" - valid: true - warning: false - hosts: ~ - auth: ~ - options: - directConnection: true - connect: direct - - - - description: directConnection=false and connect=direct - uri: "mongodb://example.com/?directConnection=false&connect=direct" - valid: false - warning: false - hosts: ~ - auth: ~ - - - - description: directConnection=true and connect=replica_set - uri: "mongodb://example.com/?directConnection=true&connect=replica_set&replicaSet=foo" - valid: false - warning: false - hosts: ~ - auth: ~ - - - - description: directConnection=false and connect=replica_set - uri: "mongodb://example.com/?directConnection=false&connect=replica_set&replicaSet=foo" - valid: true - warning: false - hosts: ~ - auth: ~ - options: - directConnection: false - connect: replica_set - replicaSet: foo - - - - description: directConnection=true and connect=sharded - uri: "mongodb://example.com/?directConnection=true&connect=sharded" - valid: false - warning: false - hosts: ~ - auth: ~ - - - - description: directConnection=false and connect=replica_set - uri: "mongodb://example.com/?directConnection=false&connect=sharded" - valid: true - warning: false - hosts: ~ - auth: ~ - options: - directConnection: false - connect: sharded diff --git a/spec/spec_tests/data/uri_options/sdam-options.yml b/spec/spec_tests/data/uri_options/sdam-options.yml new file mode 100644 index 0000000000..92294b6e52 --- /dev/null +++ b/spec/spec_tests/data/uri_options/sdam-options.yml @@ -0,0 +1,35 @@ +tests: + - description: "serverMonitoringMode=auto" + uri: "mongodb://example.com/?serverMonitoringMode=auto" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + serverMonitoringMode: "auto" + + - description: "serverMonitoringMode=stream" + uri: "mongodb://example.com/?serverMonitoringMode=stream" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + serverMonitoringMode: "stream" + + - description: "serverMonitoringMode=poll" + uri: "mongodb://example.com/?serverMonitoringMode=poll" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + serverMonitoringMode: "poll" + + - description: "invalid serverMonitoringMode" + uri: "mongodb://example.com/?serverMonitoringMode=invalid" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~ diff --git a/spec/spec_tests/data/uri_options/single-threaded-options.yml b/spec/spec_tests/data/uri_options/single-threaded-options.yml new file mode 100644 index 0000000000..1a94c8e07d --- /dev/null +++ b/spec/spec_tests/data/uri_options/single-threaded-options.yml @@ -0,0 +1,18 @@ +tests: + - + description: "Valid options specific to single-threaded drivers are parsed correctly" + uri: "mongodb://example.com/?serverSelectionTryOnce=false" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + serverSelectionTryOnce: false + - + description: "Invalid serverSelectionTryOnce causes a warning" + uri: "mongodb://example.com/?serverSelectionTryOnce=invalid" + valid: true + warning: true + hosts: ~ + auth: ~ + options: ~ diff --git a/spec/spec_tests/data/uri_options/srv-options.yml b/spec/spec_tests/data/uri_options/srv-options.yml index 8c6f7557c1..991749b0ef 100644 --- a/spec/spec_tests/data/uri_options/srv-options.yml +++ b/spec/spec_tests/data/uri_options/srv-options.yml @@ -7,14 +7,13 @@ tests: auth: ~ options: srvServiceName: "customname" - tls: true - description: "Non-SRV URI with custom srvServiceName" uri: "mongodb://example.com/?srvServiceName=customname" valid: false warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "SRV URI with srvMaxHosts" uri: "mongodb+srv://test1.test.build.10gen.cc/?srvMaxHosts=2" valid: true @@ -23,30 +22,27 @@ tests: auth: ~ options: srvMaxHosts: 2 - tls: true - description: "SRV URI with negative integer for srvMaxHosts" uri: "mongodb+srv://test1.test.build.10gen.cc/?srvMaxHosts=-1" valid: true warning: true hosts: ~ auth: ~ - options: - tls: true + options: ~ - description: "SRV URI with invalid type for srvMaxHosts" uri: "mongodb+srv://test1.test.build.10gen.cc/?srvMaxHosts=foo" valid: true warning: true hosts: ~ auth: ~ - options: - tls: true + options: ~ - description: "Non-SRV URI with srvMaxHosts" uri: "mongodb://example.com/?srvMaxHosts=2" valid: false warning: false hosts: ~ auth: ~ - options: {} + options: ~ # Note: Testing URI validation for srvMaxHosts conflicting with either # loadBalanced=true or replicaSet specified via TXT records is covered by # the Initial DNS Seedlist Discovery test suite. @@ -56,14 +52,14 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "SRV URI with positive srvMaxHosts and loadBalanced=true" uri: "mongodb+srv://test1.test.build.10gen.cc/?srvMaxHosts=2&loadBalanced=true" valid: false warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "SRV URI with positive srvMaxHosts and loadBalanced=false" uri: "mongodb+srv://test1.test.build.10gen.cc/?srvMaxHosts=2&loadBalanced=false" valid: true @@ -73,7 +69,6 @@ tests: options: loadBalanced: false srvMaxHosts: 2 - tls: true - description: "SRV URI with srvMaxHosts=0 and replicaSet" uri: "mongodb+srv://test1.test.build.10gen.cc/?srvMaxHosts=0&replicaSet=foo" valid: true @@ -83,7 +78,6 @@ tests: options: replicaSet: foo srvMaxHosts: 0 - tls: true - description: "SRV URI with srvMaxHosts=0 and loadBalanced=true" uri: "mongodb+srv://test3.test.build.10gen.cc/?srvMaxHosts=0&loadBalanced=true" valid: true @@ -93,4 +87,3 @@ tests: options: loadBalanced: true srvMaxHosts: 0 - tls: true \ No newline at end of file diff --git a/spec/spec_tests/data/uri_options/tls-options.yml b/spec/spec_tests/data/uri_options/tls-options.yml index 3e5f898e48..891b4582a7 100644 --- a/spec/spec_tests/data/uri_options/tls-options.yml +++ b/spec/spec_tests/data/uri_options/tls-options.yml @@ -19,14 +19,14 @@ tests: auth: ~ options: tlsCertificateKeyFilePassword: "hunter2" - - + - description: "Invalid tlsAllowInvalidCertificates causes a warning" uri: "mongodb://example.com/?tlsAllowInvalidCertificates=invalid" valid: true warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsAllowInvalidCertificates is parsed correctly" uri: "mongodb://example.com/?tlsAllowInvalidCertificates=true" @@ -36,14 +36,6 @@ tests: auth: ~ options: 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" @@ -53,14 +45,14 @@ tests: auth: ~ options: tlsAllowInvalidHostnames: true - - + - description: "Invalid tlsAllowInvalidHostnames causes a warning" uri: "mongodb://example.com/?tlsAllowInvalidHostnames=invalid" valid: true warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsInsecure is parsed correctly" uri: "mongodb://example.com/?tlsInsecure=true" @@ -70,14 +62,14 @@ tests: auth: ~ options: tlsInsecure: true - - + - description: "Invalid tlsInsecure causes a warning" uri: "mongodb://example.com/?tlsInsecure=invalid" valid: true warning: true hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsInsecure and tlsAllowInvalidCertificates both present (and true) raises an error" uri: "mongodb://example.com/?tlsInsecure=true&tlsAllowInvalidCertificates=true" @@ -85,7 +77,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsInsecure and tlsAllowInvalidCertificates both present (and false) raises an error" uri: "mongodb://example.com/?tlsInsecure=false&tlsAllowInvalidCertificates=false" @@ -93,7 +85,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsAllowInvalidCertificates and tlsInsecure both present (and true) raises an error" uri: "mongodb://example.com/?tlsAllowInvalidCertificates=true&tlsInsecure=true" @@ -101,7 +93,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsAllowInvalidCertificates and tlsInsecure both present (and false) raises an error" uri: "mongodb://example.com/?tlsAllowInvalidCertificates=false&tlsInsecure=false" @@ -109,7 +101,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsInsecure and tlsAllowInvalidHostnames both present (and true) raises an error" uri: "mongodb://example.com/?tlsInsecure=true&tlsAllowInvalidHostnames=true" @@ -117,7 +109,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsInsecure and tlsAllowInvalidHostnames both present (and false) raises an error" uri: "mongodb://example.com/?tlsInsecure=false&tlsAllowInvalidHostnames=false" @@ -125,7 +117,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsAllowInvalidHostnames and tlsInsecure both present (and true) raises an error" uri: "mongodb://example.com/?tlsAllowInvalidHostnames=true&tlsInsecure=true" @@ -133,7 +125,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsAllowInvalidHostnames and tlsInsecure both present (and false) raises an error" uri: "mongodb://example.com/?tlsAllowInvalidHostnames=false&tlsInsecure=false" @@ -141,7 +133,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tls=true and ssl=true doesn't warn" uri: "mongodb://example.com/?tls=true&ssl=true" @@ -149,8 +141,7 @@ tests: warning: false hosts: ~ auth: ~ - # https://jira.mongodb.org/browse/DRIVERS-1368 - options: ~ + options: {} - description: "tls=false and ssl=false doesn't warn" uri: "mongodb://example.com/?tls=false&ssl=false" @@ -158,8 +149,7 @@ tests: warning: false hosts: ~ auth: ~ - # https://jira.mongodb.org/browse/DRIVERS-1368 - options: ~ + options: {} - description: "ssl=true and tls=true doesn't warn" uri: "mongodb://example.com/?ssl=true&tls=true" @@ -167,8 +157,7 @@ tests: warning: false hosts: ~ auth: ~ - # https://jira.mongodb.org/browse/DRIVERS-1368 - options: ~ + options: {} - description: "ssl=false and tls=false doesn't warn" uri: "mongodb://example.com/?ssl=false&tls=false" @@ -176,8 +165,7 @@ tests: warning: false hosts: ~ auth: ~ - # https://jira.mongodb.org/browse/DRIVERS-1368 - options: ~ + options: {} - description: "tls=false and ssl=true raises error" uri: "mongodb://example.com/?tls=false&ssl=true" @@ -185,7 +173,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tls=true and ssl=false raises error" uri: "mongodb://example.com/?tls=true&ssl=false" @@ -193,7 +181,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "ssl=false and tls=true raises error" uri: "mongodb://example.com/?ssl=false&tls=true" @@ -201,7 +189,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "ssl=true and tls=false raises error" uri: "mongodb://example.com/?ssl=true&tls=false" @@ -209,7 +197,225 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ + - + description: "tlsDisableCertificateRevocationCheck can be set to true" + uri: "mongodb://example.com/?tls=true&tlsDisableCertificateRevocationCheck=true" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + tls: true + tlsDisableCertificateRevocationCheck: true + - + description: "tlsDisableCertificateRevocationCheck can be set to false" + uri: "mongodb://example.com/?tls=true&tlsDisableCertificateRevocationCheck=false" + valid: true + warning: false + hosts: ~ + auth: ~ + options: + tls: true + tlsDisableCertificateRevocationCheck: false + # 4 permutations of [tlsAllowInvalidCertificates=true/false, tlsDisableCertificateRevocationCheck=true/false] + - + description: "tlsAllowInvalidCertificates and tlsDisableCertificateRevocationCheck both present (and true) raises an error" + uri: "mongodb://example.com/?tlsAllowInvalidCertificates=true&tlsDisableCertificateRevocationCheck=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsAllowInvalidCertificates=true and tlsDisableCertificateRevocationCheck=false raises an error" + uri: "mongodb://example.com/?tlsAllowInvalidCertificates=true&tlsDisableCertificateRevocationCheck=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsAllowInvalidCertificates=false and tlsDisableCertificateRevocationCheck=true raises an error" + uri: "mongodb://example.com/?tlsAllowInvalidCertificates=false&tlsDisableCertificateRevocationCheck=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsAllowInvalidCertificates and tlsDisableCertificateRevocationCheck both present (and false) raises an error" + uri: "mongodb://example.com/?tlsAllowInvalidCertificates=false&tlsDisableCertificateRevocationCheck=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + # 4 permutations of [tlsDisableCertificateRevocationCheck=true/false, tlsAllowInvalidCertificates=true/false] + - + description: "tlsDisableCertificateRevocationCheck and tlsAllowInvalidCertificates both present (and true) raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=true&tlsAllowInvalidCertificates=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableCertificateRevocationCheck=true and tlsAllowInvalidCertificates=false raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=true&tlsAllowInvalidCertificates=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableCertificateRevocationCheck=false and tlsAllowInvalidCertificates=true raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=false&tlsAllowInvalidCertificates=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableCertificateRevocationCheck and tlsAllowInvalidCertificates both present (and false) raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=false&tlsAllowInvalidCertificates=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + # 4 permutations of [tlsInsecure=true/false, tlsDisableCertificateRevocationCheck=true/false] + - + description: "tlsInsecure and tlsDisableCertificateRevocationCheck both present (and true) raises an error" + uri: "mongodb://example.com/?tlsInsecure=true&tlsDisableCertificateRevocationCheck=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsInsecure=true and tlsDisableCertificateRevocationCheck=false raises an error" + uri: "mongodb://example.com/?tlsInsecure=true&tlsDisableCertificateRevocationCheck=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsInsecure=false and tlsDisableCertificateRevocationCheck=true raises an error" + uri: "mongodb://example.com/?tlsInsecure=false&tlsDisableCertificateRevocationCheck=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsInsecure and tlsDisableCertificateRevocationCheck both present (and false) raises an error" + uri: "mongodb://example.com/?tlsInsecure=false&tlsDisableCertificateRevocationCheck=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + # 4 permutations of [tlsDisableCertificateRevocationCheck=true/false, tlsInsecure=true/false] + - + description: "tlsDisableCertificateRevocationCheck and tlsInsecure both present (and true) raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=true&tlsInsecure=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableCertificateRevocationCheck=true and tlsInsecure=false raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=true&tlsInsecure=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableCertificateRevocationCheck=false and tlsInsecure=true raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=false&tlsInsecure=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableCertificateRevocationCheck and tlsInsecure both present (and false) raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=false&tlsInsecure=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + # 4 permutations of [tlsDisableCertificateRevocationCheck=true/false, tlsDisableOCSPEndpointCheck=true/false] + - + description: "tlsDisableCertificateRevocationCheck and tlsDisableOCSPEndpointCheck both present (and true) raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=true&tlsDisableOCSPEndpointCheck=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableCertificateRevocationCheck=true and tlsDisableOCSPEndpointCheck=false raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=true&tlsDisableOCSPEndpointCheck=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableCertificateRevocationCheck=false and tlsDisableOCSPEndpointCheck=true raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=false&tlsDisableOCSPEndpointCheck=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableCertificateRevocationCheck and tlsDisableOCSPEndpointCheck both present (and false) raises an error" + uri: "mongodb://example.com/?tlsDisableCertificateRevocationCheck=false&tlsDisableOCSPEndpointCheck=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + # 4 permutations of [tlsDisableOCSPEndpointCheck=true/false, tlsDisableCertificateRevocationCheck=true/false] + - + description: "tlsDisableOCSPEndpointCheck and tlsDisableCertificateRevocationCheck both present (and true) raises an error" + uri: "mongodb://example.com/?tlsDisableOCSPEndpointCheck=true&tlsDisableCertificateRevocationCheck=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableOCSPEndpointCheck=true and tlsDisableCertificateRevocationCheck=false raises an error" + uri: "mongodb://example.com/?tlsDisableOCSPEndpointCheck=true&tlsDisableCertificateRevocationCheck=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableOCSPEndpointCheck=false and tlsDisableCertificateRevocationCheck=true raises an error" + uri: "mongodb://example.com/?tlsDisableOCSPEndpointCheck=false&tlsDisableCertificateRevocationCheck=true" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ + - + description: "tlsDisableOCSPEndpointCheck and tlsDisableCertificateRevocationCheck both present (and false) raises an error" + uri: "mongodb://example.com/?tlsDisableOCSPEndpointCheck=false&tlsDisableCertificateRevocationCheck=false" + valid: false + warning: false + hosts: ~ + auth: ~ + options: ~ - description: "tlsDisableOCSPEndpointCheck can be set to true" uri: "mongodb://example.com/?tls=true&tlsDisableOCSPEndpointCheck=true" @@ -238,7 +444,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsInsecure=true and tlsDisableOCSPEndpointCheck=false raises an error" uri: "mongodb://example.com/?tlsInsecure=true&tlsDisableOCSPEndpointCheck=false" @@ -246,7 +452,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsInsecure=false and tlsDisableOCSPEndpointCheck=true raises an error" uri: "mongodb://example.com/?tlsInsecure=false&tlsDisableOCSPEndpointCheck=true" @@ -254,7 +460,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsInsecure and tlsDisableOCSPEndpointCheck both present (and false) raises an error" uri: "mongodb://example.com/?tlsInsecure=false&tlsDisableOCSPEndpointCheck=false" @@ -262,7 +468,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ # 4 permutations of [tlsDisableOCSPEndpointCheck=true/false, tlsInsecure=true/false] - description: "tlsDisableOCSPEndpointCheck and tlsInsecure both present (and true) raises an error" @@ -271,7 +477,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsDisableOCSPEndpointCheck=true and tlsInsecure=false raises an error" uri: "mongodb://example.com/?tlsDisableOCSPEndpointCheck=true&tlsInsecure=false" @@ -279,7 +485,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsDisableOCSPEndpointCheck=false and tlsInsecure=true raises an error" uri: "mongodb://example.com/?tlsDisableOCSPEndpointCheck=false&tlsInsecure=true" @@ -287,7 +493,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsDisableOCSPEndpointCheck and tlsInsecure both present (and false) raises an error" uri: "mongodb://example.com/?tlsDisableOCSPEndpointCheck=false&tlsInsecure=false" @@ -295,7 +501,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ # 4 permutations of [tlsAllowInvalidCertificates=true/false, tlsDisableOCSPEndpointCheck=true/false] - description: "tlsAllowInvalidCertificates and tlsDisableOCSPEndpointCheck both present (and true) raises an error" @@ -304,7 +510,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsAllowInvalidCertificates=true and tlsDisableOCSPEndpointCheck=false raises an error" uri: "mongodb://example.com/?tlsAllowInvalidCertificates=true&tlsDisableOCSPEndpointCheck=false" @@ -312,7 +518,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsAllowInvalidCertificates=false and tlsDisableOCSPEndpointCheck=true raises an error" uri: "mongodb://example.com/?tlsAllowInvalidCertificates=false&tlsDisableOCSPEndpointCheck=true" @@ -320,7 +526,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsAllowInvalidCertificates and tlsDisableOCSPEndpointCheck both present (and false) raises an error" uri: "mongodb://example.com/?tlsAllowInvalidCertificates=false&tlsDisableOCSPEndpointCheck=false" @@ -328,7 +534,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ # 4 permutations of [tlsDisableOCSPEndpointCheck=true/false, tlsAllowInvalidCertificates=true/false] - description: "tlsDisableOCSPEndpointCheck and tlsAllowInvalidCertificates both present (and true) raises an error" @@ -337,7 +543,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsDisableOCSPEndpointCheck=true and tlsAllowInvalidCertificates=false raises an error" uri: "mongodb://example.com/?tlsDisableOCSPEndpointCheck=true&tlsAllowInvalidCertificates=false" @@ -345,7 +551,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsDisableOCSPEndpointCheck=false and tlsAllowInvalidCertificates=true raises an error" uri: "mongodb://example.com/?tlsDisableOCSPEndpointCheck=false&tlsAllowInvalidCertificates=true" @@ -353,7 +559,7 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ - description: "tlsDisableOCSPEndpointCheck and tlsAllowInvalidCertificates both present (and false) raises an error" uri: "mongodb://example.com/?tlsDisableOCSPEndpointCheck=false&tlsAllowInvalidCertificates=false" @@ -361,4 +567,4 @@ tests: warning: false hosts: ~ auth: ~ - options: {} + options: ~ diff --git a/spec/spec_tests/uri_options_spec.rb b/spec/spec_tests/uri_options_spec.rb index 4d8a248c02..cdfe387f0f 100644 --- a/spec/spec_tests/uri_options_spec.rb +++ b/spec/spec_tests/uri_options_spec.rb @@ -5,6 +5,50 @@ require 'runners/connection_string' +# returns the descriptions of all specs from the given uri-options +# file name +def load_uri_options_specs_from(filename) + path = File.join(__dir__, 'data', 'uri_options', filename) + data = File.read(path) + yaml = YAML.load(data) + + yaml['tests'].map { |spec| spec['description'] } +end + +# Find all tests in tls-options.yml that refer to +# tlsDisableCertificateRevocationCheck and return a Hash that will be used +# by URI_SPECS_TO_SKIP to indicate that these specs should be skipped. +def tlsDisableCertificateRevocationCheck_options_tests + load_uri_options_specs_from('tls-options.yml'). + grep(/tlsDisableCertificateRevocationCheck/). + each_with_object({}) { |desc, hash| hash[desc] = 'Ruby driver has opted not to support tlsDisableCertificateRevocationCheck (https://jira.mongodb.org/browse/RUBY-2192)' } +end + +def socks5_proxy_options_tests + load_uri_options_specs_from('proxy-options.yml'). + each_with_object({}) { |desc, hash| hash[desc] = 'Ruby driver has opted not to implement SOCKS5 proxy (https://jira.mongodb.org/browse/RUBY-2809)' } +end + +def sdam_polling_options_tests + load_uri_options_specs_from('sdam-options.yml'). + each_with_object({}) { |desc, hash| hash[desc] = 'Ruby driver has not yet implemented https://jira.mongodb.org/browse/RUBY-3241' } +end + +def single_threaded_options_tests + load_uri_options_specs_from('single-threaded-options.yml'). + each_with_object({}) { |desc, hash| hash[desc] = 'Ruby driver is multi-threaded and does not implement single-threaded options.' } +end + +URI_SPECS_TO_SKIP = { + # put one-off specs to skip here, in the form of: + # 'Test description string' => 'Reason for skipping' + }. + merge(tlsDisableCertificateRevocationCheck_options_tests). + merge(socks5_proxy_options_tests). + merge(sdam_polling_options_tests). + merge(single_threaded_options_tests). + freeze + describe 'URI options' do include Mongo::ConnectionString @@ -13,6 +57,7 @@ # threads warning and interfering with these assertions clean_slate_for_all_if_possible + skipped_specs = [] URI_OPTIONS_TESTS.each do |file| spec = Mongo::ConnectionString::Spec.new(file) @@ -21,6 +66,15 @@ spec.tests.each do |test| context "#{test.description}" do + skip_reason = URI_SPECS_TO_SKIP[test.description] + if skip_reason + skipped_specs << test.description + + before do + skip skip_reason + end + end + if test.description.downcase.include?("gssapi") require_mongo_kerberos end @@ -71,10 +125,11 @@ it 'creates a client with the correct options' do mapped = Mongo::URI::OptionsMapper.new.ruby_to_smc(test.client.options) - expected = Mongo::ConnectionString.adjust_expected_mongo_client_options( - opts, - ) - mapped.should == expected + expected = Mongo::ConnectionString.adjust_expected_mongo_client_options(opts) + + expected.each do |key, expected_value| + expect(mapped[key]).to be == expected_value + end end end @@ -90,4 +145,13 @@ end end end + + skipped_specs_not_seen = URI_SPECS_TO_SKIP.keys - skipped_specs + if skipped_specs_not_seen.any? + context 'URI_SPECS_TO_SKIP' do + it 'does not include stale specs' do + fail "the following specs do not exist any more: #{skipped_specs_not_seen.inspect}" + end + end + end end