PYTHON-959 - Connection string spec compliance.
This commit is contained in:
parent
b9baa8ae8a
commit
193915e636
@ -107,8 +107,6 @@ class ClientOptions(object):
|
||||
def __init__(self, username, password, database, options):
|
||||
self.__options = options
|
||||
|
||||
options = dict([validate(opt, val) for opt, val in iteritems(options)])
|
||||
|
||||
self.__codec_options = _parse_codec_options(options)
|
||||
self.__credentials = _parse_credentials(
|
||||
username, password, database, options)
|
||||
|
||||
@ -16,11 +16,12 @@
|
||||
"""Functions and classes common to multiple pymongo modules."""
|
||||
|
||||
import collections
|
||||
import warnings
|
||||
|
||||
from bson.binary import (STANDARD, PYTHON_LEGACY,
|
||||
JAVA_LEGACY, CSHARP_LEGACY)
|
||||
from bson.codec_options import CodecOptions
|
||||
from bson.py3compat import string_type, integer_types
|
||||
from bson.py3compat import string_type, integer_types, iteritems
|
||||
from pymongo.auth import MECHANISMS
|
||||
from pymongo.errors import ConfigurationError
|
||||
from pymongo.read_preferences import (read_pref_mode_from_name,
|
||||
@ -74,6 +75,7 @@ COMMAND_NOT_FOUND_CODES = (59, 13390, None)
|
||||
# Error codes to ignore if GridFS calls createIndex on a secondary
|
||||
UNAUTHORIZED_CODES = (13, 16547, 16548)
|
||||
|
||||
|
||||
def partition_node(node):
|
||||
"""Split a host:port string into (host, int(port)) pair."""
|
||||
host = node
|
||||
@ -340,15 +342,16 @@ def validate_auth_mechanism_properties(option, value):
|
||||
for opt in value.split(','):
|
||||
try:
|
||||
key, val = opt.split(':')
|
||||
if key not in _MECHANISM_PROPS:
|
||||
raise ValueError("%s is not a supported auth "
|
||||
"mechanism property. Must be one of "
|
||||
"%s." % (key, tuple(_MECHANISM_PROPS)))
|
||||
props[key] = val
|
||||
except ValueError:
|
||||
raise ValueError("auth mechanism properties must be "
|
||||
"key:value pairs like SERVICE_NAME:"
|
||||
"mongodb, not %s." % (opt,))
|
||||
if key not in _MECHANISM_PROPS:
|
||||
raise ValueError("%s is not a supported auth "
|
||||
"mechanism property. Must be one of "
|
||||
"%s." % (key, tuple(_MECHANISM_PROPS)))
|
||||
props[key] = val
|
||||
|
||||
return props
|
||||
|
||||
|
||||
@ -456,6 +459,23 @@ def validate(option, value):
|
||||
return lower, value
|
||||
|
||||
|
||||
def get_validated_options(options):
|
||||
"""Validate each entry in options and raise a warning if it is not valid.
|
||||
Returns a copy of options with invalid entries removed
|
||||
"""
|
||||
validated_options = {}
|
||||
for opt, value in iteritems(options):
|
||||
lower = opt.lower()
|
||||
try:
|
||||
validator = VALIDATORS.get(lower, raise_config_error)
|
||||
value = validator(opt, value)
|
||||
except (ValueError, ConfigurationError) as exc:
|
||||
warnings.warn(str(exc))
|
||||
else:
|
||||
validated_options[lower] = value
|
||||
return validated_options
|
||||
|
||||
|
||||
WRITE_CONCERN_OPTIONS = frozenset([
|
||||
'w',
|
||||
'wtimeout',
|
||||
@ -516,4 +536,3 @@ class BaseObject(object):
|
||||
The :attr:`read_preference` attribute is now read only.
|
||||
"""
|
||||
return self.__read_preference
|
||||
|
||||
|
||||
@ -300,7 +300,7 @@ class MongoClient(common.BaseObject):
|
||||
for entity in host:
|
||||
if "://" in entity:
|
||||
if entity.startswith("mongodb://"):
|
||||
res = uri_parser.parse_uri(entity, port, False)
|
||||
res = uri_parser.parse_uri(entity, port, warn=True)
|
||||
seeds.update(res["nodelist"])
|
||||
username = res["username"] or username
|
||||
password = res["password"] or password
|
||||
@ -321,10 +321,14 @@ class MongoClient(common.BaseObject):
|
||||
monitor_class = kwargs.pop('_monitor_class', None)
|
||||
condition_class = kwargs.pop('_condition_class', None)
|
||||
|
||||
opts['document_class'] = document_class
|
||||
opts['tz_aware'] = tz_aware
|
||||
opts['connect'] = connect
|
||||
opts.update(kwargs)
|
||||
keyword_opts = kwargs
|
||||
keyword_opts['document_class'] = document_class
|
||||
keyword_opts['tz_aware'] = tz_aware
|
||||
keyword_opts['connect'] = connect
|
||||
# Validate all keyword options.
|
||||
keyword_opts = dict(common.validate(k, v)
|
||||
for k, v in keyword_opts.items())
|
||||
opts.update(keyword_opts)
|
||||
self.__options = options = ClientOptions(
|
||||
username, password, dbase, opts)
|
||||
|
||||
@ -792,6 +796,9 @@ class MongoClient(common.BaseObject):
|
||||
else:
|
||||
return 'document_class=%s.%s' % (value.__module__,
|
||||
value.__name__)
|
||||
if "ms" in option:
|
||||
return "%s='%s'" % (option, int(value * 1000))
|
||||
|
||||
return '%s=%r' % (option, value)
|
||||
|
||||
# Host first...
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
|
||||
"""Tools to parse and validate a MongoDB URI."""
|
||||
import warnings
|
||||
|
||||
from bson.py3compat import PY3, iteritems, string_type
|
||||
|
||||
@ -22,7 +23,7 @@ if PY3:
|
||||
else:
|
||||
from urllib import unquote_plus
|
||||
|
||||
from pymongo.common import validate as _validate
|
||||
from pymongo.common import (validate as _validate, get_validated_options)
|
||||
from pymongo.errors import ConfigurationError, InvalidURI
|
||||
|
||||
|
||||
@ -129,6 +130,8 @@ def parse_host(entity, default_port=DEFAULT_PORT):
|
||||
port = default_port
|
||||
if entity[0] == '[':
|
||||
host, port = parse_ipv6_literal_host(entity, default_port)
|
||||
elif entity.endswith(".sock"):
|
||||
return entity, default_port
|
||||
elif entity.find(':') != -1:
|
||||
if entity.count(':') > 1:
|
||||
raise ValueError("Reserved characters such as ':' must be "
|
||||
@ -137,8 +140,9 @@ def parse_host(entity, default_port=DEFAULT_PORT):
|
||||
"and ']' according to RFC 2732.")
|
||||
host, port = host.split(':', 1)
|
||||
if isinstance(port, string_type):
|
||||
if not port.isdigit():
|
||||
raise ValueError("Port number must be an integer.")
|
||||
if not port.isdigit() or int(port) > 65535 or int(port) <= 0:
|
||||
raise ValueError("Port must be an integer between 0 and 65535: %s"
|
||||
% (port,))
|
||||
port = int(port)
|
||||
|
||||
# Normalize hostname to lowercase, since DNS is case-insensitive:
|
||||
@ -148,15 +152,23 @@ def parse_host(entity, default_port=DEFAULT_PORT):
|
||||
return host.lower(), port
|
||||
|
||||
|
||||
def validate_options(opts):
|
||||
def validate_options(opts, warn=False):
|
||||
"""Validates and normalizes options passed in a MongoDB URI.
|
||||
|
||||
Returns a new dictionary of validated and normalized options.
|
||||
Returns a new dictionary of validated and normalized options. If warn is
|
||||
False then errors will be thrown for invalid options, otherwise they will
|
||||
be ignored and a warning will be issued.
|
||||
|
||||
:Parameters:
|
||||
- `opts`: A dict of MongoDB URI options.
|
||||
- `warn` (optional): If ``True`` then warnigns will be logged and
|
||||
invalid options will be ignored. Otherwise invalid options will
|
||||
cause errors.
|
||||
"""
|
||||
return dict([_validate(opt, val) for opt, val in iteritems(opts)])
|
||||
if warn:
|
||||
return get_validated_options(opts)
|
||||
else:
|
||||
return dict([_validate(opt, val) for opt, val in iteritems(opts)])
|
||||
|
||||
|
||||
def _parse_options(opts, delim):
|
||||
@ -172,11 +184,21 @@ def _parse_options(opts, delim):
|
||||
# str(option) to ensure that a unicode URI results in plain 'str'
|
||||
# option names. 'normalized' is then suitable to be passed as
|
||||
# kwargs in all Python versions.
|
||||
options[str(key)] = val
|
||||
if str(key) in options:
|
||||
warnings.warn("Duplicate URI option %s" % (str(key),))
|
||||
options[str(key)] = unquote_plus(val)
|
||||
|
||||
# Special case for deprecated options
|
||||
if "wtimeout" in options:
|
||||
if "wtimeoutMS" in options:
|
||||
options.pop("wtimeout")
|
||||
warnings.warn("Option wtimeout is deprecated, use 'wtimeoutMS'"
|
||||
" instead")
|
||||
|
||||
return options
|
||||
|
||||
|
||||
def split_options(opts, validate=True):
|
||||
def split_options(opts, validate=True, warn=False):
|
||||
"""Takes the options portion of a MongoDB URI, validates each option
|
||||
and returns the options in a dictionary.
|
||||
|
||||
@ -202,7 +224,7 @@ def split_options(opts, validate=True):
|
||||
raise InvalidURI("MongoDB URI options are key=value pairs.")
|
||||
|
||||
if validate:
|
||||
return validate_options(options)
|
||||
return validate_options(options, warn)
|
||||
return options
|
||||
|
||||
|
||||
@ -232,7 +254,7 @@ def split_hosts(hosts, default_port=DEFAULT_PORT):
|
||||
return nodes
|
||||
|
||||
|
||||
def parse_uri(uri, default_port=DEFAULT_PORT, validate=True):
|
||||
def parse_uri(uri, default_port=DEFAULT_PORT, validate=True, warn=False):
|
||||
"""Parse and validate a MongoDB URI.
|
||||
|
||||
Returns a dict of the form::
|
||||
@ -252,6 +274,13 @@ def parse_uri(uri, default_port=DEFAULT_PORT, validate=True):
|
||||
for a host in the URI.
|
||||
- `validate`: If ``True`` (the default), validate and normalize all
|
||||
options.
|
||||
- `warn` (optional): When validating, if ``True`` then will warn
|
||||
the user then ignore any invalid options or values. If ``False``,
|
||||
validation will error when options are unsupported or values are
|
||||
invalid.
|
||||
|
||||
.. versionchanged:: 3.1
|
||||
``warn`` added so invalid options can be ignored.
|
||||
"""
|
||||
if not uri.startswith(SCHEME):
|
||||
raise InvalidURI("Invalid URI scheme: URI "
|
||||
@ -262,7 +291,6 @@ def parse_uri(uri, default_port=DEFAULT_PORT, validate=True):
|
||||
if not scheme_free:
|
||||
raise InvalidURI("Must provide at least one hostname or IP.")
|
||||
|
||||
nodes = None
|
||||
user = None
|
||||
passwd = None
|
||||
dbase = None
|
||||
@ -272,11 +300,14 @@ def parse_uri(uri, default_port=DEFAULT_PORT, validate=True):
|
||||
# Check for unix domain sockets in the uri
|
||||
if '.sock' in scheme_free:
|
||||
host_part, _, path_part = _rpartition(scheme_free, '/')
|
||||
try:
|
||||
parse_uri('%s%s' % (SCHEME, host_part))
|
||||
except (ConfigurationError, InvalidURI):
|
||||
host_part = scheme_free
|
||||
if not host_part:
|
||||
host_part = path_part
|
||||
path_part = ""
|
||||
if '/' in host_part:
|
||||
raise InvalidURI("Any '/' in a unix domain socket must be"
|
||||
" URL encoded: %s" % host_part)
|
||||
host_part = unquote_plus(host_part)
|
||||
path_part = unquote_plus(path_part)
|
||||
else:
|
||||
host_part, _, path_part = _partition(scheme_free, '/')
|
||||
|
||||
@ -302,7 +333,12 @@ def parse_uri(uri, default_port=DEFAULT_PORT, validate=True):
|
||||
dbase, collection = dbase.split('.', 1)
|
||||
|
||||
if opts:
|
||||
options = split_options(opts, validate)
|
||||
options = split_options(opts, validate, warn)
|
||||
|
||||
if dbase is not None:
|
||||
dbase = unquote_plus(dbase)
|
||||
if collection is not None:
|
||||
collection = unquote_plus(collection)
|
||||
|
||||
return {
|
||||
'nodelist': nodes,
|
||||
|
||||
220
test/connection_string/test/invalid-uris.json
Normal file
220
test/connection_string/test/invalid-uris.json
Normal file
@ -0,0 +1,220 @@
|
||||
{
|
||||
"tests": [
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Empty string",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Invalid scheme",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongo://localhost:27017",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Missing host",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Double colon in host identifier",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://localhost::27017",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Double colon in host identifier and trailing slash",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://localhost::27017/",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Double colon in host identifier with missing host and port",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://::",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Double colon in host identifier with missing port",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://localhost,localhost::",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Double colon in host identifier and second host",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://localhost::27017,abc",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Invalid port (negative number) with hostname",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://localhost:-1",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Invalid port (zero) with hostname",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://localhost:0/",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Invalid port (positive number) with hostname",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://localhost:65536",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Invalid port (positive number) with hostname and trailing slash",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://localhost:65536/",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Invalid port (non-numeric string) with hostname",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://localhost:foo",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Invalid port (negative number) with IP literal",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://[::1]:-1",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Invalid port (zero) with IP literal",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://[::1]:0/",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Invalid port (positive number) with IP literal",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://[::1]:65536",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Invalid port (positive number) with IP literal and trailing slash",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://[::1]:65536/",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Invalid port (non-numeric string) with IP literal",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://[::1]:foo",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Missing delimiting slash between hosts and options",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://example.com?w=1",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Incomplete key value pair for option",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://example.com/?w",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Username with password containing an unescaped colon",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://alice:foo:bar@127.0.0.1",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Username containing an unescaped at-sign",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://alice@@127.0.0.1",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Username with password containing an unescaped at-sign",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb://alice@foo:bar@127.0.0.1",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Host with unescaped slash",
|
||||
"hosts": null,
|
||||
"options": null,
|
||||
"uri": "mongodb:///tmp/mongodb-27017.sock/",
|
||||
"valid": false,
|
||||
"warning": null
|
||||
}
|
||||
]
|
||||
}
|
||||
330
test/connection_string/test/valid-auth.json
Normal file
330
test/connection_string/test/valid-auth.json
Normal file
@ -0,0 +1,330 @@
|
||||
{
|
||||
"tests": [
|
||||
{
|
||||
"auth": {
|
||||
"db": null,
|
||||
"password": "foo",
|
||||
"username": "alice"
|
||||
},
|
||||
"description": "User info for single IPv4 host without database",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": null,
|
||||
"type": "ipv4"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://alice:foo@127.0.0.1",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "test",
|
||||
"password": "foo",
|
||||
"username": "alice"
|
||||
},
|
||||
"description": "User info for single IPv4 host with database",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": null,
|
||||
"type": "ipv4"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://alice:foo@127.0.0.1/test",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "t\u0000est",
|
||||
"password": "f\u0000oo",
|
||||
"username": "a\u0000lice"
|
||||
},
|
||||
"description": "User info for single IPv4 host with database (escaped null bytes)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": null,
|
||||
"type": "ipv4"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://a%00lice:f%00oo@127.0.0.1/t%00est",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": null,
|
||||
"password": "bar",
|
||||
"username": "bob"
|
||||
},
|
||||
"description": "User info for single IP literal host without database",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "::1",
|
||||
"port": 27018,
|
||||
"type": "ip_literal"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://bob:bar@[::1]:27018",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin",
|
||||
"password": "bar",
|
||||
"username": "bob"
|
||||
},
|
||||
"description": "User info for single IP literal host with database",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "::1",
|
||||
"port": 27018,
|
||||
"type": "ip_literal"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://bob:bar@[::1]:27018/admin",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": null,
|
||||
"password": "baz",
|
||||
"username": "eve"
|
||||
},
|
||||
"description": "User info for single hostname without database",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://eve:baz@example.com",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "db2",
|
||||
"password": "baz",
|
||||
"username": "eve"
|
||||
},
|
||||
"description": "User info for single hostname with database",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://eve:baz@example.com/db2",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": null,
|
||||
"password": "secret",
|
||||
"username": "alice"
|
||||
},
|
||||
"description": "User info for multiple hosts without database",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": null,
|
||||
"type": "ipv4"
|
||||
},
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": 27018,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://alice:secret@127.0.0.1,example.com:27018",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin",
|
||||
"password": "secret",
|
||||
"username": "alice"
|
||||
},
|
||||
"description": "User info for multiple hosts with database",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
},
|
||||
{
|
||||
"host": "::1",
|
||||
"port": 27019,
|
||||
"type": "ip_literal"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://alice:secret@example.com,[::1]:27019/admin",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": null,
|
||||
"password": null,
|
||||
"username": "alice"
|
||||
},
|
||||
"description": "Username without password",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": null,
|
||||
"type": "ipv4"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://alice@127.0.0.1",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": null,
|
||||
"password": "",
|
||||
"username": "alice"
|
||||
},
|
||||
"description": "Username with empty password",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": null,
|
||||
"type": "ipv4"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://alice:@127.0.0.1",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "my=db",
|
||||
"password": null,
|
||||
"username": "@l:ce"
|
||||
},
|
||||
"description": "Escaped username and database without password",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://%40l%3Ace@example.com/my%3Ddb",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin?",
|
||||
"password": "f:zzb@zz",
|
||||
"username": "$am"
|
||||
},
|
||||
"description": "Escaped user info and database (MONGODB-CR)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": null,
|
||||
"type": "ipv4"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"authmechanism": "MONGODB-CR"
|
||||
},
|
||||
"uri": "mongodb://%24am:f%3Azzb%40zz@127.0.0.1/admin%3F?authMechanism=MONGODB-CR",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": null,
|
||||
"password": null,
|
||||
"username": "CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry"
|
||||
},
|
||||
"description": "Escaped username (MONGODB-X509)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "localhost",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"authmechanism": "MONGODB-X509"
|
||||
},
|
||||
"uri": "mongodb://CN%3DmyName%2COU%3DmyOrgUnit%2CO%3DmyOrg%2CL%3DmyLocality%2CST%3DmyState%2CC%3DmyCountry@localhost/?authMechanism=MONGODB-X509",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": null,
|
||||
"password": "secret",
|
||||
"username": "user@EXAMPLE.COM"
|
||||
},
|
||||
"description": "Escaped username (GSSAPI)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "localhost",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"authmechanism": "GSSAPI",
|
||||
"authmechanismproperties": {
|
||||
"CANONICALIZE_HOST_NAME": true,
|
||||
"SERVICE_NAME": "other"
|
||||
}
|
||||
},
|
||||
"uri": "mongodb://user%40EXAMPLE.COM:secret@localhost/?authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true&authMechanism=GSSAPI",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin",
|
||||
"password": "secret",
|
||||
"username": "alice"
|
||||
},
|
||||
"description": "At-signs in options aren't part of the userinfo",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"replicaset": "my@replicaset"
|
||||
},
|
||||
"uri": "mongodb://alice:secret@example.com/admin?replicaset=my@replicaset",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
}
|
||||
]
|
||||
}
|
||||
154
test/connection_string/test/valid-host_identifiers.json
Normal file
154
test/connection_string/test/valid-host_identifiers.json
Normal file
@ -0,0 +1,154 @@
|
||||
{
|
||||
"tests": [
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Single IPv4 host without port",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": null,
|
||||
"type": "ipv4"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://127.0.0.1",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Single IPv4 host with port",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": 27018,
|
||||
"type": "ipv4"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://127.0.0.1:27018",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Single IP literal host without port",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "::1",
|
||||
"port": null,
|
||||
"type": "ip_literal"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://[::1]",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Single IP literal host with port",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "::1",
|
||||
"port": 27019,
|
||||
"type": "ip_literal"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://[::1]:27019",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Single hostname without port",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://example.com",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Single hostname with port",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": 27020,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://example.com:27020",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Single hostname (resembling IPv4) without port",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "256.0.0.1",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://256.0.0.1",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Multiple hosts (mixed formats)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": null,
|
||||
"type": "ipv4"
|
||||
},
|
||||
{
|
||||
"host": "::1",
|
||||
"port": 27018,
|
||||
"type": "ip_literal"
|
||||
},
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": 27019,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://127.0.0.1,[::1]:27018,example.com:27019",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "UTF-8 hosts",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "b\u00fccher.example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
},
|
||||
{
|
||||
"host": "uml\u00e4ut.example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://b\u00fccher.example.com,uml\u00e4ut.example.com/",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
}
|
||||
]
|
||||
}
|
||||
42
test/connection_string/test/valid-options.json
Normal file
42
test/connection_string/test/valid-options.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"tests": [
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin",
|
||||
"password": "secret",
|
||||
"username": "alice"
|
||||
},
|
||||
"description": "Option names are normalized to lowercase",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"authmechanism": "MONGODB-CR"
|
||||
},
|
||||
"uri": "mongodb://alice:secret@example.com/admin?AUTHMechanism=MONGODB-CR",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Option key and value (escaped null bytes)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"replicaset": "my\u0000rs"
|
||||
},
|
||||
"uri": "mongodb://example.com/?replicaSet=my%00rs",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
}
|
||||
]
|
||||
}
|
||||
251
test/connection_string/test/valid-unix_socket-absolute.json
Normal file
251
test/connection_string/test/valid-unix_socket-absolute.json
Normal file
@ -0,0 +1,251 @@
|
||||
{
|
||||
"tests": [
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unix domain socket (absolute path with trailing slash)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "/tmp/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://%2Ftmp%2Fmongodb-27017.sock/",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unix domain socket (absolute path without trailing slash)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "/tmp/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://%2Ftmp%2Fmongodb-27017.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unix domain socket (absolute path with spaces in path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "/tmp/ /mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://%2Ftmp%2F %2Fmongodb-27017.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Multiple Unix domain sockets (absolute paths)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "/tmp/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
},
|
||||
{
|
||||
"host": "/tmp/mongodb-27018.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://%2Ftmp%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Multiple hosts (absolute path and ipv4)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": 27017,
|
||||
"type": "ipv4"
|
||||
},
|
||||
{
|
||||
"host": "/tmp/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://127.0.0.1:27017,%2Ftmp%2Fmongodb-27017.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Multiple hosts (absolute path and hostname resembling relative path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
},
|
||||
{
|
||||
"host": "/tmp/mongodb-27018.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://mongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin",
|
||||
"password": "foo",
|
||||
"username": "alice"
|
||||
},
|
||||
"description": "Unix domain socket with auth database (absolute path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "/tmp/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://alice:foo@%2Ftmp%2Fmongodb-27017.sock/admin",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unix domain socket with path resembling socket file (absolute path with trailing slash)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "/tmp/path.to.sock/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://%2Ftmp%2Fpath.to.sock%2Fmongodb-27017.sock/",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unix domain socket with path resembling socket file (absolute path without trailing slash)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "/tmp/path.to.sock/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://%2Ftmp%2Fpath.to.sock%2Fmongodb-27017.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin",
|
||||
"password": "bar",
|
||||
"username": "bob"
|
||||
},
|
||||
"description": "Unix domain socket with path resembling socket file and auth (absolute path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "/tmp/path.to.sock/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://bob:bar@%2Ftmp%2Fpath.to.sock%2Fmongodb-27017.sock/admin",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin.sock",
|
||||
"password": null,
|
||||
"username": null
|
||||
},
|
||||
"description": "Multiple Unix domain sockets and auth DB resembling a socket (absolute path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "/tmp/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
},
|
||||
{
|
||||
"host": "/tmp/mongodb-27018.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://%2Ftmp%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock/admin.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin.shoe",
|
||||
"password": null,
|
||||
"username": null
|
||||
},
|
||||
"description": "Multiple Unix domain sockets with auth DB resembling a path (absolute path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "/tmp/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
},
|
||||
{
|
||||
"host": "/tmp/mongodb-27018.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://%2Ftmp%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock/admin.shoe",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin",
|
||||
"password": "bar",
|
||||
"username": "bob"
|
||||
},
|
||||
"description": "Multiple Unix domain sockets with auth and query string (absolute path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "/tmp/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
},
|
||||
{
|
||||
"host": "/tmp/mongodb-27018.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"w": 1
|
||||
},
|
||||
"uri": "mongodb://bob:bar@%2Ftmp%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock/admin?w=1",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
}
|
||||
]
|
||||
}
|
||||
271
test/connection_string/test/valid-unix_socket-relative.json
Normal file
271
test/connection_string/test/valid-unix_socket-relative.json
Normal file
@ -0,0 +1,271 @@
|
||||
{
|
||||
"tests": [
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unix domain socket (relative path with trailing slash)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://rel%2Fmongodb-27017.sock/",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unix domain socket (relative path without trailing slash)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://rel%2Fmongodb-27017.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unix domain socket (relative path with spaces)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/ /mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://rel%2F %2Fmongodb-27017.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Multiple Unix domain sockets (relative paths)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
},
|
||||
{
|
||||
"host": "rel/mongodb-27018.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://rel%2Fmongodb-27017.sock,rel%2Fmongodb-27018.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Multiple Unix domain sockets (relative and absolute paths)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
},
|
||||
{
|
||||
"host": "/tmp/mongodb-27018.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://rel%2Fmongodb-27017.sock,%2Ftmp%2Fmongodb-27018.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Multiple hosts (relative path and ipv4)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "127.0.0.1",
|
||||
"port": 27017,
|
||||
"type": "ipv4"
|
||||
},
|
||||
{
|
||||
"host": "rel/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://127.0.0.1:27017,rel%2Fmongodb-27017.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Multiple hosts (relative path and hostname resembling relative path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
},
|
||||
{
|
||||
"host": "rel/mongodb-27018.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://mongodb-27017.sock,rel%2Fmongodb-27018.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin",
|
||||
"password": "foo",
|
||||
"username": "alice"
|
||||
},
|
||||
"description": "Unix domain socket with auth database (relative path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://alice:foo@rel%2Fmongodb-27017.sock/admin",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unix domain socket with path resembling socket file (relative path with trailing slash)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/path.to.sock/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://rel%2Fpath.to.sock%2Fmongodb-27017.sock/",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unix domain socket with path resembling socket file (relative path without trailing slash)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/path.to.sock/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://rel%2Fpath.to.sock%2Fmongodb-27017.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin",
|
||||
"password": "bar",
|
||||
"username": "bob"
|
||||
},
|
||||
"description": "Unix domain socket with path resembling socket file and auth (relative path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/path.to.sock/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://bob:bar@rel%2Fpath.to.sock%2Fmongodb-27017.sock/admin",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin.sock",
|
||||
"password": null,
|
||||
"username": null
|
||||
},
|
||||
"description": "Multiple Unix domain sockets and auth DB resembling a socket (relative path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
},
|
||||
{
|
||||
"host": "rel/mongodb-27018.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://rel%2Fmongodb-27017.sock,rel%2Fmongodb-27018.sock/admin.sock",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin.shoe",
|
||||
"password": null,
|
||||
"username": null
|
||||
},
|
||||
"description": "Multiple Unix domain sockets with auth DB resembling a path (relative path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
},
|
||||
{
|
||||
"host": "rel/mongodb-27018.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://rel%2Fmongodb-27017.sock,rel%2Fmongodb-27018.sock/admin.shoe",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
},
|
||||
{
|
||||
"auth": {
|
||||
"db": "admin",
|
||||
"password": "bar",
|
||||
"username": "bob"
|
||||
},
|
||||
"description": "Multiple Unix domain sockets with auth and query string (relative path)",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "rel/mongodb-27017.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
},
|
||||
{
|
||||
"host": "rel/mongodb-27018.sock",
|
||||
"port": null,
|
||||
"type": "unix"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"w": 1
|
||||
},
|
||||
"uri": "mongodb://bob:bar@rel%2Fmongodb-27017.sock,rel%2Fmongodb-27018.sock/admin?w=1",
|
||||
"valid": true,
|
||||
"warning": false
|
||||
}
|
||||
]
|
||||
}
|
||||
68
test/connection_string/test/valid-warnings.json
Normal file
68
test/connection_string/test/valid-warnings.json
Normal file
@ -0,0 +1,68 @@
|
||||
{
|
||||
"tests": [
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unrecognized option keys are ignored",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://example.com/?foo=bar",
|
||||
"valid": true,
|
||||
"warning": true
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Unsupported option values are ignored",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": null,
|
||||
"uri": "mongodb://example.com/?fsync=ifPossible",
|
||||
"valid": true,
|
||||
"warning": true
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Repeated option keys",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"replicaset": "test"
|
||||
},
|
||||
"uri": "mongodb://example.com/?replicaSet=test&replicaSet=test",
|
||||
"valid": true,
|
||||
"warning": true
|
||||
},
|
||||
{
|
||||
"auth": null,
|
||||
"description": "Deprecated (or unknown) options are ignored if replacement exists",
|
||||
"hosts": [
|
||||
{
|
||||
"host": "example.com",
|
||||
"port": null,
|
||||
"type": "hostname"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"wtimeoutms": 10
|
||||
},
|
||||
"uri": "mongodb://example.com/?wtimeout=5&wtimeoutMS=10",
|
||||
"valid": true,
|
||||
"warning": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -244,7 +244,7 @@ class TestClient(IntegrationTest):
|
||||
self.assertFalse(client_context.rs_or_standalone_client != c)
|
||||
|
||||
def test_host_w_port(self):
|
||||
with self.assertRaises(AutoReconnect):
|
||||
with self.assertRaises(ValueError):
|
||||
connected(MongoClient("%s:1234567" % host, connectTimeoutMS=1,
|
||||
serverSelectionTimeoutMS=10))
|
||||
|
||||
@ -264,8 +264,8 @@ class TestClient(IntegrationTest):
|
||||
"tz_aware=False, "
|
||||
"connect=False, ",
|
||||
the_repr)
|
||||
self.assertIn("connectTimeoutMS='12345'", the_repr)
|
||||
self.assertIn("replicaSet=", the_repr)
|
||||
self.assertIn("connecttimeoutms='12345'", the_repr)
|
||||
self.assertIn("replicaset=", the_repr)
|
||||
|
||||
self.assertEqual(eval(the_repr), client)
|
||||
|
||||
@ -400,13 +400,14 @@ class TestClient(IntegrationTest):
|
||||
raise SkipTest("UNIX-sockets are not supported on this system")
|
||||
|
||||
mongodb_socket = '/tmp/mongodb-27017.sock'
|
||||
encoded_socket = '%2Ftmp%2Fmongodb-27017.sock'
|
||||
if not os.access(mongodb_socket, os.R_OK):
|
||||
raise SkipTest("Socket file is not accessible")
|
||||
|
||||
if client_context.auth_enabled:
|
||||
uri = "mongodb://%s:%s@%s" % (db_user, db_pwd, mongodb_socket)
|
||||
uri = "mongodb://%s:%s@%s" % (db_user, db_pwd, encoded_socket)
|
||||
else:
|
||||
uri = "mongodb://%s" % mongodb_socket
|
||||
uri = "mongodb://%s" % encoded_socket
|
||||
|
||||
# Confirm we can do operations via the socket.
|
||||
client = MongoClient(uri)
|
||||
@ -417,7 +418,7 @@ class TestClient(IntegrationTest):
|
||||
# Confirm it fails with a missing socket.
|
||||
self.assertRaises(
|
||||
ConnectionFailure,
|
||||
connected, MongoClient("mongodb:///tmp/non-existent.sock",
|
||||
connected, MongoClient("mongodb://%2Ftmp%2Fnon-existent.sock",
|
||||
serverSelectionTimeoutMS=100))
|
||||
|
||||
def test_fork(self):
|
||||
@ -482,7 +483,6 @@ class TestClient(IntegrationTest):
|
||||
self.assertEqual(SON, c.codec_options.document_class)
|
||||
self.assertTrue(isinstance(db.test.find_one(), SON))
|
||||
|
||||
|
||||
def test_timeouts(self):
|
||||
client = rs_or_single_client(connectTimeoutMS=10500)
|
||||
self.assertEqual(10.5, get_pool(client).opts.connect_timeout)
|
||||
@ -547,12 +547,14 @@ class TestClient(IntegrationTest):
|
||||
'mongodb://localhost/?serverSelectionTimeoutMS=0', connect=False)
|
||||
self.assertAlmostEqual(0, client.server_selection_timeout)
|
||||
|
||||
self.assertRaises(ValueError, MongoClient,
|
||||
'mongodb://localhost/?serverSelectionTimeoutMS=-1',
|
||||
connect=False)
|
||||
self.assertRaises(ValueError, MongoClient,
|
||||
'mongodb://localhost/?serverSelectionTimeoutMS=',
|
||||
connect=False)
|
||||
# Test invalid timeout in URI ignored and set to default.
|
||||
client = MongoClient(
|
||||
'mongodb://localhost/?serverSelectionTimeoutMS=-1', connect=False)
|
||||
self.assertAlmostEqual(30, client.server_selection_timeout)
|
||||
|
||||
client = MongoClient(
|
||||
'mongodb://localhost/?serverSelectionTimeoutMS=', connect=False)
|
||||
self.assertAlmostEqual(30, client.server_selection_timeout)
|
||||
|
||||
def test_waitQueueTimeoutMS(self):
|
||||
client = rs_or_single_client(waitQueueTimeoutMS=2000)
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
import copy
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
sys.path[0:0] = [""]
|
||||
|
||||
@ -94,42 +95,94 @@ class TestURI(unittest.TestCase):
|
||||
|
||||
def test_split_options(self):
|
||||
self.assertRaises(ConfigurationError, split_options, 'foo')
|
||||
self.assertRaises(ConfigurationError, split_options, 'foo=bar')
|
||||
self.assertRaises(ConfigurationError, split_options, 'foo=bar;foo')
|
||||
self.assertTrue(split_options('ssl=true'))
|
||||
self.assertTrue(split_options('ssl_match_hostname=true'))
|
||||
|
||||
# Test Invalid URI options that should throw warnings.
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('error')
|
||||
self.assertRaises(Warning, split_options,
|
||||
'foo=bar', warn=True)
|
||||
self.assertRaises(Warning, split_options,
|
||||
'socketTimeoutMS=foo', warn=True)
|
||||
self.assertRaises(Warning, split_options,
|
||||
'socketTimeoutMS=0.0', warn=True)
|
||||
self.assertRaises(Warning, split_options,
|
||||
'connectTimeoutMS=foo', warn=True)
|
||||
self.assertRaises(Warning, split_options,
|
||||
'connectTimeoutMS=0.0', warn=True)
|
||||
self.assertRaises(Warning, split_options,
|
||||
'connectTimeoutMS=1e100000', warn=True)
|
||||
self.assertRaises(Warning, split_options,
|
||||
'connectTimeoutMS=-1e100000', warn=True)
|
||||
self.assertRaises(Warning, split_options,
|
||||
'ssl=foo', warn=True)
|
||||
self.assertRaises(Warning, split_options,
|
||||
'ssl_match_hostname=foo', warn=True)
|
||||
|
||||
# On most platforms float('inf') and float('-inf') represent
|
||||
# +/- infinity, although on Python 2.4 and 2.5 on Windows those
|
||||
# expressions are invalid
|
||||
if not (sys.platform == "win32" and sys.version_info <= (2, 5)):
|
||||
self.assertRaises(Warning, split_options,
|
||||
'connectTimeoutMS=inf', warn=True)
|
||||
self.assertRaises(Warning, split_options,
|
||||
'connectTimeoutMS=-inf', warn=True)
|
||||
|
||||
self.assertRaises(Warning, split_options, 'wtimeoutms=foo',
|
||||
warn=True)
|
||||
self.assertRaises(Warning, split_options, 'wtimeoutms=5.5',
|
||||
warn=True)
|
||||
self.assertRaises(Warning, split_options, 'fsync=foo',
|
||||
warn=True)
|
||||
self.assertRaises(Warning, split_options, 'fsync=5.5',
|
||||
warn=True)
|
||||
self.assertRaises(Warning,
|
||||
split_options, 'authMechanism=foo',
|
||||
warn=True)
|
||||
|
||||
# Test invalid options with warn=False.
|
||||
self.assertRaises(ConfigurationError, split_options, 'foo=bar')
|
||||
self.assertRaises(ValueError, split_options, 'socketTimeoutMS=foo')
|
||||
self.assertRaises(ValueError, split_options, 'socketTimeoutMS=0.0')
|
||||
self.assertRaises(ValueError, split_options, 'connectTimeoutMS=foo')
|
||||
self.assertRaises(ValueError, split_options, 'connectTimeoutMS=0.0')
|
||||
self.assertRaises(ValueError, split_options, 'connectTimeoutMS=1e100000')
|
||||
self.assertRaises(ValueError, split_options, 'connectTimeoutMS=-1e100000')
|
||||
self.assertRaises(ValueError, split_options,
|
||||
'connectTimeoutMS=1e100000')
|
||||
self.assertRaises(ValueError, split_options,
|
||||
'connectTimeoutMS=-1e100000')
|
||||
self.assertRaises(ValueError, split_options, 'ssl=foo')
|
||||
self.assertTrue(split_options('ssl=true'))
|
||||
self.assertRaises(ValueError, split_options, 'ssl_match_hostname=foo')
|
||||
self.assertTrue(split_options('ssl_match_hostname=true'))
|
||||
|
||||
# On most platforms float('inf') and float('-inf') represent
|
||||
# +/- infinity, although on Python 2.4 and 2.5 on Windows those
|
||||
# expressions are invalid
|
||||
if not (sys.platform == "win32" and sys.version_info <= (2, 5)):
|
||||
self.assertRaises(ValueError, split_options, 'connectTimeoutMS=inf')
|
||||
self.assertRaises(ValueError, split_options, 'connectTimeoutMS=-inf')
|
||||
self.assertRaises(ValueError, split_options,
|
||||
'connectTimeoutMS=inf')
|
||||
self.assertRaises(ValueError, split_options,
|
||||
'connectTimeoutMS=-inf')
|
||||
self.assertRaises(ValueError, split_options, 'wtimeoutms=foo')
|
||||
self.assertRaises(ValueError, split_options, 'wtimeoutms=5.5')
|
||||
self.assertRaises(ValueError, split_options, 'fsync=foo')
|
||||
self.assertRaises(ValueError, split_options, 'fsync=5.5')
|
||||
self.assertRaises(ValueError,
|
||||
split_options, 'authMechanism=foo')
|
||||
|
||||
# Test splitting options works when valid.
|
||||
self.assertTrue(split_options('socketTimeoutMS=300'))
|
||||
self.assertTrue(split_options('connectTimeoutMS=300'))
|
||||
self.assertEqual({'sockettimeoutms': 0.3}, split_options('socketTimeoutMS=300'))
|
||||
self.assertEqual({'sockettimeoutms': 0.0001}, split_options('socketTimeoutMS=0.1'))
|
||||
self.assertEqual({'connecttimeoutms': 0.3}, split_options('connectTimeoutMS=300'))
|
||||
self.assertEqual({'connecttimeoutms': 0.0001}, split_options('connectTimeoutMS=0.1'))
|
||||
self.assertEqual({'sockettimeoutms': 0.3},
|
||||
split_options('socketTimeoutMS=300'))
|
||||
self.assertEqual({'sockettimeoutms': 0.0001},
|
||||
split_options('socketTimeoutMS=0.1'))
|
||||
self.assertEqual({'connecttimeoutms': 0.3},
|
||||
split_options('connectTimeoutMS=300'))
|
||||
self.assertEqual({'connecttimeoutms': 0.0001},
|
||||
split_options('connectTimeoutMS=0.1'))
|
||||
self.assertTrue(split_options('connectTimeoutMS=300'))
|
||||
self.assertTrue(isinstance(split_options('w=5')['w'], int))
|
||||
self.assertTrue(isinstance(split_options('w=5.5')['w'], string_type))
|
||||
self.assertTrue(split_options('w=foo'))
|
||||
self.assertTrue(split_options('w=majority'))
|
||||
self.assertRaises(ValueError, split_options, 'wtimeoutms=foo')
|
||||
self.assertRaises(ValueError, split_options, 'wtimeoutms=5.5')
|
||||
self.assertTrue(split_options('wtimeoutms=500'))
|
||||
self.assertRaises(ValueError, split_options, 'fsync=foo')
|
||||
self.assertRaises(ValueError, split_options, 'fsync=5.5')
|
||||
self.assertEqual({'fsync': True}, split_options('fsync=true'))
|
||||
self.assertEqual({'fsync': False}, split_options('fsync=false'))
|
||||
self.assertEqual({'authmechanism': 'GSSAPI'},
|
||||
@ -138,9 +191,8 @@ class TestURI(unittest.TestCase):
|
||||
split_options('authMechanism=MONGODB-CR'))
|
||||
self.assertEqual({'authmechanism': 'SCRAM-SHA-1'},
|
||||
split_options('authMechanism=SCRAM-SHA-1'))
|
||||
self.assertRaises(ValueError,
|
||||
split_options, 'authMechanism=foo')
|
||||
self.assertEqual({'authsource': 'foobar'}, split_options('authSource=foobar'))
|
||||
self.assertEqual({'authsource': 'foobar'},
|
||||
split_options('authSource=foobar'))
|
||||
self.assertEqual({'maxpoolsize': 50}, split_options('maxpoolsize=50'))
|
||||
|
||||
def test_parse_uri(self):
|
||||
@ -204,16 +256,17 @@ class TestURI(unittest.TestCase):
|
||||
parse_uri("mongodb://example1.com:27017,example2.com"
|
||||
":27017/test.yield_historical.in"))
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res['nodelist'] = [("/tmp/mongodb-27017.sock", None)]
|
||||
self.assertEqual(res, parse_uri("mongodb:///tmp/mongodb-27017.sock"))
|
||||
# Test socket path without escaped characters.
|
||||
self.assertRaises(InvalidURI, parse_uri,
|
||||
"mongodb:///tmp/mongodb-27017.sock")
|
||||
|
||||
# Test with escaped characters.
|
||||
res = copy.deepcopy(orig)
|
||||
res['nodelist'] = [("example2.com", 27017),
|
||||
("/tmp/mongodb-27017.sock", None)]
|
||||
self.assertEqual(res,
|
||||
parse_uri("mongodb://example2.com,"
|
||||
"/tmp/mongodb-27017.sock"))
|
||||
"%2Ftmp%2Fmongodb-27017.sock"))
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res['nodelist'] = [("shoe.sock.pants.co.uk", 27017),
|
||||
@ -221,14 +274,14 @@ class TestURI(unittest.TestCase):
|
||||
res['database'] = "nethers_db"
|
||||
self.assertEqual(res,
|
||||
parse_uri("mongodb://shoe.sock.pants.co.uk,"
|
||||
"/tmp/mongodb-27017.sock/nethers_db"))
|
||||
"%2Ftmp%2Fmongodb-27017.sock/nethers_db"))
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res['nodelist'] = [("/tmp/mongodb-27017.sock", None),
|
||||
("example2.com", 27017)]
|
||||
res.update({'database': 'test', 'collection': 'yield_historical.in'})
|
||||
self.assertEqual(res,
|
||||
parse_uri("mongodb:///tmp/mongodb-27017.sock,"
|
||||
parse_uri("mongodb://%2Ftmp%2Fmongodb-27017.sock,"
|
||||
"example2.com:27017"
|
||||
"/test.yield_historical.in"))
|
||||
|
||||
@ -237,9 +290,9 @@ class TestURI(unittest.TestCase):
|
||||
("example2.com", 27017)]
|
||||
res.update({'database': 'test', 'collection': 'yield_historical.sock'})
|
||||
self.assertEqual(res,
|
||||
parse_uri("mongodb:///tmp/mongodb-27017.sock,"
|
||||
"example2.com:27017"
|
||||
"/test.yield_historical.sock"))
|
||||
parse_uri("mongodb://%2Ftmp%2Fmongodb-27017.sock,"
|
||||
"example2.com:27017/test.yield_historical"
|
||||
".sock"))
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res['nodelist'] = [("example2.com", 27017)]
|
||||
@ -252,7 +305,7 @@ class TestURI(unittest.TestCase):
|
||||
res['nodelist'] = [("/tmp/mongodb-27017.sock", None)]
|
||||
res.update({'database': 'test', 'collection': 'mongodb-27017.sock'})
|
||||
self.assertEqual(res,
|
||||
parse_uri("mongodb:///tmp/mongodb-27017.sock"
|
||||
parse_uri("mongodb://%2Ftmp%2Fmongodb-27017.sock"
|
||||
"/test.mongodb-27017.sock"))
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
@ -261,8 +314,8 @@ class TestURI(unittest.TestCase):
|
||||
("2001:0db8:85a3:0000:0000:8a2e:0370:7334", 27018),
|
||||
("192.168.0.212", 27019),
|
||||
("localhost", 27018)]
|
||||
self.assertEqual(res, parse_uri("mongodb:///tmp/mongodb-27020.sock,"
|
||||
"[::1]:27017,[2001:0db8:"
|
||||
self.assertEqual(res, parse_uri("mongodb://%2Ftmp%2Fmongodb-27020.sock"
|
||||
",[::1]:27017,[2001:0db8:"
|
||||
"85a3:0000:0000:8a2e:0370:7334],"
|
||||
"192.168.0.212:27019,localhost",
|
||||
27018))
|
||||
@ -276,8 +329,8 @@ class TestURI(unittest.TestCase):
|
||||
|
||||
res = copy.deepcopy(orig)
|
||||
res['options'] = {'readpreference': ReadPreference.SECONDARY.mode}
|
||||
self.assertEqual(res,
|
||||
parse_uri("mongodb://localhost/?readPreference=secondary"))
|
||||
self.assertEqual(res, parse_uri(
|
||||
"mongodb://localhost/?readPreference=secondary"))
|
||||
|
||||
# Various authentication tests
|
||||
res = copy.deepcopy(orig)
|
||||
@ -371,6 +424,12 @@ class TestURI(unittest.TestCase):
|
||||
"@localhost/foo?uuidrepresentation="
|
||||
"javaLegacy"))
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('error')
|
||||
self.assertRaises(Warning, parse_uri,
|
||||
"mongodb://user%40domain.com:password"
|
||||
"@localhost/foo?uuidrepresentation=notAnOption",
|
||||
warn=True)
|
||||
self.assertRaises(ValueError, parse_uri,
|
||||
"mongodb://user%40domain.com:password"
|
||||
"@localhost/foo?uuidrepresentation=notAnOption")
|
||||
|
||||
127
test/test_uri_spec.py
Normal file
127
test/test_uri_spec.py
Normal file
@ -0,0 +1,127 @@
|
||||
# Copyright 2011-2015 MongoDB, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Test the pymongo uri_parser module is up to spec."""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
sys.path[0:0] = [""]
|
||||
|
||||
from pymongo.uri_parser import parse_uri
|
||||
from test import unittest
|
||||
|
||||
# Location of JSON test specifications.
|
||||
_TEST_PATH = os.path.join(
|
||||
os.path.dirname(os.path.realpath(__file__)),
|
||||
os.path.join('connection_string', 'test'))
|
||||
|
||||
|
||||
class TestAllScenarios(unittest.TestCase):
|
||||
pass
|
||||
|
||||
|
||||
def create_test(scenario_def):
|
||||
def run_scenario(self):
|
||||
self.assertTrue(scenario_def['tests'], "tests cannot be empty")
|
||||
for test in scenario_def['tests']:
|
||||
dsc = test['description']
|
||||
|
||||
warned = False
|
||||
error = False
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('error')
|
||||
try:
|
||||
options = parse_uri(test['uri'], warn=True)
|
||||
except Warning:
|
||||
warned = True
|
||||
except Exception:
|
||||
error = True
|
||||
|
||||
self.assertEqual(not error, test['valid'],
|
||||
"Test failure '%s'" % dsc)
|
||||
|
||||
if test.get("warning", False):
|
||||
self.assertTrue(warned,
|
||||
"Expected warning for test '%s'"
|
||||
% (dsc,))
|
||||
|
||||
# Redo in the case there were warnings that were not expected.
|
||||
if warned:
|
||||
options = parse_uri(test['uri'], warn=True)
|
||||
|
||||
# Compare hosts and port.
|
||||
if test['hosts'] is not None:
|
||||
self.assertEqual(
|
||||
len(test['hosts']), len(options['nodelist']),
|
||||
"Incorrect number of hosts parsed from URI")
|
||||
|
||||
for exp, actual in zip(test['hosts'],
|
||||
options['nodelist']):
|
||||
self.assertEqual(exp['host'], actual[0],
|
||||
"Expected host %s but got %s"
|
||||
% (exp['host'], actual[0]))
|
||||
if exp['port'] is not None:
|
||||
self.assertEqual(exp['port'], actual[1],
|
||||
"Expected port %s but got %s"
|
||||
% (exp['port'], actual))
|
||||
|
||||
# Compare auth options.
|
||||
auth = test['auth']
|
||||
if auth is not None:
|
||||
auth['database'] = auth.pop('db') # db == database
|
||||
# Special case for PyMongo's collection parsing.
|
||||
if options.get('collection') is not None:
|
||||
options['database'] += "." + options['collection']
|
||||
for elm in auth:
|
||||
if auth[elm] is not None:
|
||||
self.assertEqual(auth[elm], options[elm],
|
||||
"Expected %s but got %s"
|
||||
% (auth[elm], options[elm]))
|
||||
|
||||
# Compare URI options.
|
||||
if test['options'] is not None:
|
||||
for opt in test['options']:
|
||||
if options.get(opt) is not None:
|
||||
self.assertEqual(
|
||||
options[opt], test['options'][opt],
|
||||
"For option %s expected %s but got %s"
|
||||
% (opt, options[opt],
|
||||
test['options'][opt]))
|
||||
|
||||
return run_scenario
|
||||
|
||||
|
||||
def create_tests():
|
||||
for dirpath, _, filenames in os.walk(_TEST_PATH):
|
||||
dirname = os.path.split(dirpath)
|
||||
dirname = os.path.split(dirname[-2])[-1] + '_' + dirname[-1]
|
||||
|
||||
for filename in filenames:
|
||||
with open(os.path.join(dirpath, filename)) as scenario_stream:
|
||||
scenario_def = json.load(scenario_stream)
|
||||
# Construct test from scenario.
|
||||
new_test = create_test(scenario_def)
|
||||
test_name = 'test_%s_%s' % (
|
||||
dirname, os.path.splitext(filename)[0])
|
||||
new_test.__name__ = test_name
|
||||
setattr(TestAllScenarios, new_test.__name__, new_test)
|
||||
|
||||
|
||||
create_tests()
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Reference in New Issue
Block a user