def test_alive(self): primary = ha_tools.get_primary() secondary = ha_tools.get_random_secondary() primary_cx = connected( MongoClient( primary, serverSelectionTimeoutMS=self.server_selection_timeout)), secondary_cx = connected( MongoClient( secondary, serverSelectionTimeoutMS=self.server_selection_timeout)) rsc = connected( MongoClient( self.seed, replicaSet=self.name, serverSelectionTimeoutMS=self.server_selection_timeout)) self.assertTrue(primary_cx.alive()) self.assertTrue(secondary_cx.alive()) self.assertTrue(rsc.alive()) ha_tools.kill_primary() time.sleep(0.5) self.assertFalse(primary_cx.alive()) self.assertTrue(secondary_cx.alive()) self.assertFalse(rsc.alive()) ha_tools.kill_members([secondary], 2) time.sleep(0.5) self.assertFalse(primary_cx.alive()) self.assertFalse(secondary_cx.alive()) self.assertFalse(rsc.alive())
def test_mongo_client(self): pair = client_context.pair m = rs_or_single_client(w=0) coll = m.pymongo_test.write_concern_test coll.drop() doc = {"_id": ObjectId()} coll.insert_one(doc) self.assertTrue(coll.insert_one(doc)) coll = coll.with_options(write_concern=WriteConcern(w=1)) self.assertRaises(OperationFailure, coll.insert_one, doc) m = rs_or_single_client() coll = m.pymongo_test.write_concern_test new_coll = coll.with_options(write_concern=WriteConcern(w=0)) self.assertTrue(new_coll.insert_one(doc)) self.assertRaises(OperationFailure, coll.insert_one, doc) m = rs_or_single_client("mongodb://%s/" % (pair,), replicaSet=client_context.replica_set_name) coll = m.pymongo_test.write_concern_test self.assertRaises(OperationFailure, coll.insert_one, doc) m = rs_or_single_client("mongodb://%s/?w=0" % (pair,), replicaSet=client_context.replica_set_name) coll = m.pymongo_test.write_concern_test coll.insert_one(doc) # Equality tests direct = connected(single_client(w=0)) direct2 = connected(single_client("mongodb://%s/?w=0" % (pair,), **self.credentials)) self.assertEqual(direct, direct2) self.assertFalse(direct != direct2)
def test_mongo_client(self): pair = client_context.pair m = rs_or_single_client(w=0) coll = m.pymongo_test.write_concern_test coll.drop() doc = {"_id": ObjectId()} coll.insert_one(doc) self.assertTrue(coll.insert_one(doc)) coll = coll.with_options(write_concern=WriteConcern(w=1)) self.assertRaises(OperationFailure, coll.insert_one, doc) m = rs_or_single_client() coll = m.pymongo_test.write_concern_test new_coll = coll.with_options(write_concern=WriteConcern(w=0)) self.assertTrue(new_coll.insert_one(doc)) self.assertRaises(OperationFailure, coll.insert_one, doc) m = rs_or_single_client("mongodb://%s/" % (pair, ), replicaSet=client_context.replica_set_name) coll = m.pymongo_test.write_concern_test self.assertRaises(OperationFailure, coll.insert_one, doc) m = rs_or_single_client("mongodb://%s/?w=0" % (pair, ), replicaSet=client_context.replica_set_name) coll = m.pymongo_test.write_concern_test coll.insert_one(doc) # Equality tests direct = connected(single_client(w=0)) direct2 = connected( single_client("mongodb://%s/?w=0" % (pair, ), **self.credentials)) self.assertEqual(direct, direct2) self.assertFalse(direct != direct2)
def test_ssl_pem_passphrase(self): # Expects the server to be running with server.pem and ca.pem # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem vi = sys.version_info if vi[0] == 2 and vi < (2, 7, 9) or vi[0] == 3 and vi < (3, 3): self.assertRaises( ConfigurationError, MongoClient, 'localhost', ssl=True, ssl_certfile=CLIENT_ENCRYPTED_PEM, ssl_pem_passphrase="clientpassword", ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100) else: connected(MongoClient('localhost', ssl=True, ssl_certfile=CLIENT_ENCRYPTED_PEM, ssl_pem_passphrase="clientpassword", ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100, **self.credentials)) uri_fmt = ("mongodb://localhost/?ssl=true" "&ssl_certfile=%s&ssl_pem_passphrase=clientpassword" "&ssl_ca_certs=%s&serverSelectionTimeoutMS=100") connected(MongoClient(uri_fmt % (CLIENT_ENCRYPTED_PEM, CA_PEM), **self.credentials))
def test_local_threshold(self): client = connected(self.mock_client(localThresholdMS=30)) self.assertEqual(30, client.local_threshold_ms) wait_until(lambda: len(client.nodes) == 3, 'connect to all mongoses') topology = client._topology # All are within a 30-ms latency window, see self.mock_client(). self.assertEqual(set([('a', 1), ('b', 2), ('c', 3)]), writable_addresses(topology)) # No error client.admin.command('ismaster') client = connected(self.mock_client(localThresholdMS=0)) self.assertEqual(0, client.local_threshold_ms) # No error client.db.command('ismaster') # Our chosen mongos goes down. client.kill_host('%s:%s' % next(iter(client.nodes))) try: client.db.command('ismaster') except: pass # We eventually connect to a new mongos. def connect_to_new_mongos(): try: return client.db.command('ismaster') except AutoReconnect: pass wait_until(connect_to_new_mongos, 'connect to a new mongos')
def test_ssl_pem_passphrase(self): # Expects the server to be running with server.pem and ca.pem # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem if not hasattr(ssl, 'SSLContext') and not _ssl.IS_PYOPENSSL: self.assertRaises(ConfigurationError, MongoClient, 'localhost', ssl=True, ssl_certfile=CLIENT_ENCRYPTED_PEM, ssl_pem_passphrase="qwerty", ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100) else: connected( MongoClient('localhost', ssl=True, ssl_certfile=CLIENT_ENCRYPTED_PEM, ssl_pem_passphrase="qwerty", ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=5000, **self.credentials)) uri_fmt = ("mongodb://localhost/?ssl=true" "&ssl_certfile=%s&ssl_pem_passphrase=qwerty" "&ssl_ca_certs=%s&serverSelectionTimeoutMS=5000") connected( MongoClient(uri_fmt % (CLIENT_ENCRYPTED_PEM, CA_PEM), **self.credentials))
def test_local_threshold(self): client = connected(self.mock_client(localThresholdMS=30)) self.assertEqual(30, client.local_threshold_ms) wait_until(lambda: len(client.nodes) == 3, 'connect to all mongoses') topology = client._topology # All are within a 30-ms latency window, see self.mock_client(). self.assertEqual(set([('a', 1), ('b', 2), ('c', 3)]), writable_addresses(topology)) # No error client.db.collection.find_one() client = connected(self.mock_client(localThresholdMS=0)) self.assertEqual(0, client.local_threshold_ms) # No error client.db.collection.find_one() # Our chosen mongos goes down. client.kill_host('%s:%s' % next(iter(client.nodes))) try: client.db.collection.find_one() except: pass # No error client.db.collection.find_one()
def test_ssl_pem_passphrase(self): # Expects the server to be running with server.pem and ca.pem # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem if not CERT_SSL: raise SkipTest("No mongod available over SSL with certs") vi = sys.version_info if vi[0] == 2 and vi < (2, 7, 9) or vi[0] == 3 and vi < (3, 3): self.assertRaises(ConfigurationError, MongoClient, 'server', ssl=True, ssl_certfile=CLIENT_ENCRYPTED_PEM, ssl_pem_passphrase="clientpassword", ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100) else: connected( MongoClient('server', ssl=True, ssl_certfile=CLIENT_ENCRYPTED_PEM, ssl_pem_passphrase="clientpassword", ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100)) uri_fmt = ("mongodb://server/?ssl=true" "&ssl_certfile=%s&ssl_pem_passphrase=clientpassword" "&ssl_ca_certs=%s&serverSelectionTimeoutMS=100") connected(MongoClient(uri_fmt % (CLIENT_ENCRYPTED_PEM, CA_PEM)))
def test_ssl_pem_passphrase(self): # Expects the server to be running with server.pem and ca.pem # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem if not CERT_SSL: raise SkipTest("No mongod available over SSL with certs") vi = sys.version_info if vi[0] == 2 and vi < (2, 7, 9) or vi[0] == 3 and vi < (3, 3): self.assertRaises( ConfigurationError, MongoClient, 'server', ssl=True, ssl_certfile=CLIENT_ENCRYPTED_PEM, ssl_pem_passphrase="clientpassword", ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100) else: connected(MongoClient('server', ssl=True, ssl_certfile=CLIENT_ENCRYPTED_PEM, ssl_pem_passphrase="clientpassword", ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100)) uri_fmt = ("mongodb://server/?ssl=true" "&ssl_certfile=%s&ssl_pem_passphrase=clientpassword" "&ssl_ca_certs=%s&serverSelectionTimeoutMS=100") connected(MongoClient(uri_fmt % (CLIENT_ENCRYPTED_PEM, CA_PEM)))
def test_atexit_hook(self): client = single_client(client_context.host, client_context.port) executor = one(client._topology._servers.values())._monitor._executor connected(client) # The executor stores a weakref to itself in _EXECUTORS. ref = one([r for r in _EXECUTORS.copy() if r() is executor]) del executor del client wait_until(partial(unregistered, ref), 'unregister executor', timeout=5)
def test_ssl_crlfile_support(self): if not hasattr(ssl, 'VERIFY_CRL_CHECK_LEAF'): self.assertRaises( ConfigurationError, MongoClient, 'localhost', ssl=True, ssl_ca_certs=CA_PEM, ssl_crlfile=CRL_PEM, serverSelectionTimeoutMS=100) else: connected(MongoClient('localhost', ssl=True, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100, **self.credentials)) with self.assertRaises(ConnectionFailure): connected(MongoClient('localhost', ssl=True, ssl_ca_certs=CA_PEM, ssl_crlfile=CRL_PEM, serverSelectionTimeoutMS=100, **self.credentials)) uri_fmt = ("mongodb://localhost/?ssl=true&" "ssl_ca_certs=%s&serverSelectionTimeoutMS=100") connected(MongoClient(uri_fmt % (CA_PEM,), **self.credentials)) uri_fmt = ("mongodb://localhost/?ssl=true&ssl_crlfile=%s" "&ssl_ca_certs=%s&serverSelectionTimeoutMS=100") with self.assertRaises(ConnectionFailure): connected(MongoClient(uri_fmt % (CRL_PEM, CA_PEM), **self.credentials))
def test_auth_from_uri(self): self.client.admin.add_user("admin", "pass", roles=["root"]) self.addCleanup(self.client.admin.remove_user, "admin") self.addCleanup(remove_all_users, self.client.pymongo_test) self.client.pymongo_test.add_user("user", "pass", roles=["userAdmin", "readWrite"]) with self.assertRaises(OperationFailure): connected(rs_or_single_client("mongodb://*****:*****@%s:%d" % (host, port))) # No error. connected(rs_or_single_client_noauth("mongodb://*****:*****@%s:%d" % (host, port))) # Wrong database. uri = "mongodb://*****:*****@%s:%d/pymongo_test" % (host, port) with self.assertRaises(OperationFailure): connected(rs_or_single_client(uri)) # No error. connected(rs_or_single_client_noauth("mongodb://*****:*****@%s:%d/pymongo_test" % (host, port))) # Auth with lazy connection. rs_or_single_client( "mongodb://*****:*****@%s:%d/pymongo_test" % (host, port), connect=False ).pymongo_test.test.find_one() # Wrong password. bad_client = rs_or_single_client("mongodb://*****:*****@%s:%d/pymongo_test" % (host, port), connect=False) self.assertRaises(OperationFailure, bad_client.pymongo_test.test.find_one)
def test_auth_network_error(self): # Make sure there's no semaphore leak if we get a network error # when authenticating a new socket with cached credentials. # Get a client with one socket so we detect if it's leaked. c = connected(rs_or_single_client(maxPoolSize=1, waitQueueTimeoutMS=1)) # Simulate an authenticate() call on a different socket. credentials = auth._build_credentials_tuple( 'DEFAULT', 'admin', db_user, db_pwd, {}) c._cache_credentials('test', credentials, connect=False) # Cause a network error on the actual socket. pool = get_pool(c) socket_info = one(pool.sockets) socket_info.sock.close() # SocketInfo.check_auth logs in with the new credential, but gets a # socket.error. Should be reraised as AutoReconnect. self.assertRaises(AutoReconnect, c.test.collection.find_one) # No semaphore leak, the pool is allowed to make a new socket. c.test.collection.find_one()
def test_failover(self): nthreads = 10 client = connected(self.mock_client(localThresholdMS=0.001)) wait_until(lambda: len(client.nodes) == 3, 'connect to all mongoses') # Our chosen mongos goes down. client.kill_host('a:1') # Trigger failover to higher-latency nodes. AutoReconnect should be # raised at most once in each thread. passed = [] def f(): try: client.db.command('ismaster') except AutoReconnect: # Second attempt succeeds. client.db.command('ismaster') passed.append(True) threads = [threading.Thread(target=f) for _ in range(nthreads)] for t in threads: t.start() for t in threads: t.join() self.assertEqual(nthreads, len(passed)) # Down host removed from list. self.assertEqual(2, len(client.nodes))
def test_load_balancing(self): # Although the server selection JSON tests already prove that # select_servers works for sharded topologies, here we do an end-to-end # test of discovering servers' round trip times and configuring # localThresholdMS. client = connected(self.mock_client()) wait_until(lambda: len(client.nodes) == 3, 'connect to all mongoses') # Prohibited for topology type Sharded. with self.assertRaises(InvalidOperation): client.address topology = client._topology self.assertEqual(TOPOLOGY_TYPE.Sharded, topology.description.topology_type) # a and b are within the 15-ms latency window, see self.mock_client(). self.assertEqual(set([('a', 1), ('b', 2)]), writable_addresses(topology)) client.mock_rtts['a:1'] = 0.040 # Discover only b is within latency window. wait_until(lambda: set([('b', 2)]) == writable_addresses(topology), 'discover server "a" is too far')
def test_load_balancing(self): # Although the server selection JSON tests already prove that # select_servers works for sharded topologies, here we do an end-to-end # test of discovering servers' round trip times and configuring # localThresholdMS. client = connected(self.mock_client()) wait_until(lambda: len(client.nodes) == 3, 'connect to all mongoses') # Prohibited for topology type Sharded. with self.assertRaises(InvalidOperation): client.address topology = client._topology self.assertEqual(TOPOLOGY_TYPE.Sharded, topology.description.topology_type) # a and b are within the 15-ms latency window, see self.mock_client(). self.assertEqual(set([('a', 1), ('b', 2)]), writable_addresses(topology)) client.mock_rtts['a:1'] = 0.045 # Discover only b is within latency window. wait_until(lambda: set([('b', 2)]) == writable_addresses(topology), 'discover server "a" is too far')
def test_local_threshold(self): client = connected(self.mock_client(localThresholdMS=30)) wait_until(lambda: len(client.nodes) == 3, 'connect to all mongoses') topology = client._topology # All are within a 30-ms latency window, see self.mock_client(). self.assertEqual(set([('a', 1), ('b', 2), ('c', 3)]), writable_addresses(topology))
def test_connect_with_internal_ips(self): # Client is passed an IP it can reach, 'a:1', but the RS config # only contains unreachable IPs like 'internal-ip'. PYTHON-608. with self.assertRaises(AutoReconnect) as context: connected( MockClient(standalones=[], members=['a:1'], mongoses=[], ismaster_hosts=['internal-ip:27017'], host='a:1', replicaSet='rs', serverSelectionTimeoutMS=100)) self.assertEqual( "Could not reach any servers in [('internal-ip', 27017)]." " Replica set is configured with internal hostnames or IPs?", str(context.exception))
def test_connect_with_internal_ips(self): # Client is passed an IP it can reach, 'a:1', but the RS config # only contains unreachable IPs like 'internal-ip'. PYTHON-608. with self.assertRaises(AutoReconnect) as context: connected(MockClient( standalones=[], members=['a:1'], mongoses=[], ismaster_hosts=['internal-ip:27017'], host='a:1', replicaSet='rs', serverSelectionTimeoutMS=100)) self.assertEqual( "Could not reach any servers in [('internal-ip', 27017)]." " Replica set is configured with internal hostnames or IPs?", str(context.exception))
def test_validation_with_system_ca_certs(self): # Expects the server to be running with server.pem and ca.pem. # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # --sslWeakCertificateValidation # if sys.platform == "win32": raise SkipTest("Can't test system ca certs on Windows.") if sys.version_info < (2, 7, 9): raise SkipTest("Can't load system CA certificates.") if (ssl.OPENSSL_VERSION.lower().startswith('libressl') and sys.platform == 'darwin' and not _ssl.IS_PYOPENSSL): raise SkipTest( "LibreSSL on OSX doesn't support setting CA certificates " "using SSL_CERT_FILE environment variable.") # Tell OpenSSL where CA certificates live. os.environ['SSL_CERT_FILE'] = CA_PEM try: with self.assertRaises(ConnectionFailure): # Server cert is verified but hostname matching fails connected( MongoClient('server', ssl=True, serverSelectionTimeoutMS=100, **self.credentials)) # Server cert is verified. Disable hostname matching. connected( MongoClient('server', ssl=True, ssl_match_hostname=False, serverSelectionTimeoutMS=100, **self.credentials)) # Server cert and hostname are verified. connected( MongoClient('localhost', ssl=True, serverSelectionTimeoutMS=100, **self.credentials)) # Server cert and hostname are verified. connected( MongoClient( 'mongodb://localhost/?ssl=true&serverSelectionTimeoutMS=100', **self.credentials)) finally: os.environ.pop('SSL_CERT_FILE')
def get_client(): # Attempt a direct connection to each node until one succeeds. Using a # non-PRIMARY read preference allows us to use the node even if it's a # secondary. for i, node in enumerate(nodes.keys()): try: return connected( pymongo.MongoClient( node, read_preference=ReadPreference.PRIMARY_PREFERRED)) except pymongo.errors.ConnectionFailure: if i == len(nodes) - 1: raise
def test_cert_ssl_validation_hostname_matching(self): # Expects the server to be running with server.pem and ca.pem # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # response = self.client.admin.command('ismaster') with self.assertRaises(ConnectionFailure): connected( MongoClient('server', ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100, **self.credentials)) connected( MongoClient('server', ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=100, **self.credentials)) if 'setName' in response: with self.assertRaises(ConnectionFailure): connected( MongoClient('server', replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100, **self.credentials)) connected( MongoClient('server', replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=100, **self.credentials))
def test_validation_with_system_ca_certs(self): # Expects the server to be running with the server.pem, ca.pem # and crl.pem provided in mongodb and the server tests eg: # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # --sslCRLFile=/path/to/pymongo/test/certificates/crl.pem # --sslWeakCertificateValidation # # Also requires an /etc/hosts entry where "server" is resolvable if not CERT_SSL: raise SkipTest("No mongod available over SSL with certs") if not SERVER_IS_RESOLVABLE: raise SkipTest("No hosts entry for 'server'. Cannot validate " "hostname in the certificate") if sys.platform == "win32": raise SkipTest("Can't test system ca certs on Windows.") if sys.version_info < (2, 7, 9): raise SkipTest("Can't load system CA certificates.") # Tell OpenSSL where CA certificates live. os.environ['SSL_CERT_FILE'] = CA_PEM try: with self.assertRaises(ConnectionFailure): # Server cert is verified but hostname matching fails connected(MongoClient(pair, ssl=True, serverSelectionTimeoutMS=100)) # Server cert is verified. Disable hostname matching. connected(MongoClient(pair, ssl=True, ssl_match_hostname=False, serverSelectionTimeoutMS=100)) # Server cert and hostname are verified. connected(MongoClient('server', ssl=True, serverSelectionTimeoutMS=100)) # Server cert and hostname are verified. connected( MongoClient( 'mongodb://server/?ssl=true&serverSelectionTimeoutMS=100')) finally: os.environ.pop('SSL_CERT_FILE')
def test_cert_ssl_validation_hostname_matching(self): # Expects the server to be running with the server.pem, ca.pem # and crl.pem provided in mongodb and the server tests eg: # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # --sslCRLFile=/path/to/pymongo/test/certificates/crl.pem if not CERT_SSL: raise SkipTest("No mongod available over SSL with certs") response = ssl_client.admin.command('ismaster') with self.assertRaises(ConnectionFailure): connected( MongoClient(pair, ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100)) connected( MongoClient(pair, ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=100)) if 'setName' in response: with self.assertRaises(ConnectionFailure): connected( MongoClient(pair, replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100)) connected( MongoClient(pair, replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=100))
def test_exhaust_network_error(self): # When doing an exhaust query, the socket stays checked out on success # but must be checked in on error to avoid semaphore leaks. client = rs_or_single_client(maxPoolSize=1) collection = client.pymongo_test.test pool = get_pool(client) pool._check_interval_seconds = None # Never check. # Ensure a socket. connected(client) # Cause a network error. sock_info = one(pool.sockets) sock_info.sock.close() cursor = collection.find(cursor_type=CursorType.EXHAUST) with self.assertRaises(ConnectionFailure): next(cursor) self.assertTrue(sock_info.closed) # The semaphore was decremented despite the error. self.assertTrue(pool._socket_semaphore.acquire(blocking=False))
def test_reconnect(self): nthreads = 10 client = connected(self.mock_client()) # connected() ensures we've contacted at least one mongos. Wait for # all of them. wait_until(lambda: len(client.nodes) == 3, 'connect to all mongoses') # Trigger reconnect. client.close() do_simple_op(client, nthreads) wait_until(lambda: len(client.nodes) == 3, 'reconnect to all mongoses')
def test_validation_with_system_ca_certs(self): # Expects the server to be running with the server.pem, ca.pem # and crl.pem provided in mongodb and the server tests eg: # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # --sslCRLFile=/path/to/pymongo/test/certificates/crl.pem # --sslWeakCertificateValidation # # Also requires an /etc/hosts entry where "server" is resolvable if not CERT_SSL: raise SkipTest("No mongod available over SSL with certs") if not SERVER_IS_RESOLVABLE: raise SkipTest("No hosts entry for 'server'. Cannot validate " "hostname in the certificate") if sys.platform == "win32": raise SkipTest("Can't test system ca certs on Windows.") if sys.version_info < (2, 7, 9): raise SkipTest("Can't load system CA certificates.") # Tell OpenSSL where CA certificates live. os.environ['SSL_CERT_FILE'] = CA_PEM try: with self.assertRaises(ConnectionFailure): # Server cert is verified but hostname matching fails connected( MongoClient(pair, ssl=True, serverSelectionTimeoutMS=100)) # Server cert is verified. Disable hostname matching. connected( MongoClient(pair, ssl=True, ssl_match_hostname=False, serverSelectionTimeoutMS=100)) # Server cert and hostname are verified. connected( MongoClient('server', ssl=True, serverSelectionTimeoutMS=100)) # Server cert and hostname are verified. connected( MongoClient( 'mongodb://server/?ssl=true&serverSelectionTimeoutMS=100')) finally: os.environ.pop('SSL_CERT_FILE')
def test_socket_timeout_ms_validation(self): c = rs_or_single_client(socketTimeoutMS=10 * 1000) self.assertEqual(10, get_pool(c).opts.socket_timeout) c = connected(rs_or_single_client(socketTimeoutMS=None)) self.assertEqual(None, get_pool(c).opts.socket_timeout) self.assertRaises(ValueError, rs_or_single_client, socketTimeoutMS=0) self.assertRaises(ValueError, rs_or_single_client, socketTimeoutMS=-1) self.assertRaises(ValueError, rs_or_single_client, socketTimeoutMS=1e10) self.assertRaises(ValueError, rs_or_single_client, socketTimeoutMS="foo")
def test_cert_ssl_validation_hostname_matching(self): # Expects the server to be running with the server.pem, ca.pem # and crl.pem provided in mongodb and the server tests eg: # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # --sslCRLFile=/path/to/pymongo/test/certificates/crl.pem if not CERT_SSL: raise SkipTest("No mongod available over SSL with certs") response = ssl_client.admin.command('ismaster') with self.assertRaises(ConnectionFailure): connected(MongoClient(pair, ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100)) connected(MongoClient(pair, ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=100)) if 'setName' in response: with self.assertRaises(ConnectionFailure): connected(MongoClient(pair, replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100)) connected(MongoClient(pair, replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=100))
def test_zero_latency(self): ping_times = set() # Generate unique ping times. while len(ping_times) < len(self.client.nodes): ping_times.add(random.random()) for ping_time, host in zip(ping_times, self.client.nodes): ServerDescription._host_to_round_trip_time[host] = ping_time try: client = connected( rs_client(readPreference='nearest', localThresholdMS=0)) wait_until(lambda: client.nodes == self.client.nodes, "discovered all nodes") host = self.read_from_which_host(client) for _ in range(5): self.assertEqual(host, self.read_from_which_host(client)) finally: ServerDescription._host_to_round_trip_time.clear()
def test_validation_with_system_ca_certs(self): # Expects the server to be running with server.pem and ca.pem. # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # --sslWeakCertificateValidation # if sys.platform == "win32": raise SkipTest("Can't test system ca certs on Windows.") if sys.version_info < (2, 7, 9): raise SkipTest("Can't load system CA certificates.") # Tell OpenSSL where CA certificates live. os.environ['SSL_CERT_FILE'] = CA_PEM try: with self.assertRaises(ConnectionFailure): # Server cert is verified but hostname matching fails connected(MongoClient('server', ssl=True, serverSelectionTimeoutMS=100, **self.credentials)) # Server cert is verified. Disable hostname matching. connected(MongoClient('server', ssl=True, ssl_match_hostname=False, serverSelectionTimeoutMS=100, **self.credentials)) # Server cert and hostname are verified. connected(MongoClient('localhost', ssl=True, serverSelectionTimeoutMS=100, **self.credentials)) # Server cert and hostname are verified. connected( MongoClient( 'mongodb://localhost/?ssl=true&serverSelectionTimeoutMS=100', **self.credentials)) finally: os.environ.pop('SSL_CERT_FILE')
def test_validation_with_system_ca_certs(self): # Expects the server to be running with server.pem and ca.pem. # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # --sslWeakCertificateValidation # if sys.platform == "win32": raise SkipTest("Can't test system ca certs on Windows.") if sys.version_info < (2, 7, 9): raise SkipTest("Can't load system CA certificates.") # Tell OpenSSL where CA certificates live. os.environ['SSL_CERT_FILE'] = CA_PEM try: with self.assertRaises(ConnectionFailure): # Server cert is verified but hostname matching fails connected( MongoClient('server', ssl=True, serverSelectionTimeoutMS=100)) # Server cert is verified. Disable hostname matching. connected( MongoClient('server', ssl=True, ssl_match_hostname=False, serverSelectionTimeoutMS=100)) # Server cert and hostname are verified. connected( MongoClient('localhost', ssl=True, serverSelectionTimeoutMS=100)) # Server cert and hostname are verified. connected( MongoClient( 'mongodb://localhost/?ssl=true&serverSelectionTimeoutMS=100' )) finally: os.environ.pop('SSL_CERT_FILE')
def test_zero_latency(self): ping_times = set() # Generate unique ping times. while len(ping_times) < len(self.client.nodes): ping_times.add(random.random()) for ping_time, host in zip(ping_times, self.client.nodes): ServerDescription._host_to_round_trip_time[host] = ping_time try: client = connected( rs_client(readPreference='nearest', localThresholdMS=0)) wait_until( lambda: client.nodes == self.client.nodes, "discovered all nodes") host = self.read_from_which_host(client) for _ in range(5): self.assertEqual(host, self.read_from_which_host(client)) finally: ServerDescription._host_to_round_trip_time.clear()
def test_cert_ssl_validation_hostname_matching(self): # Expects the server to be running with server.pem and ca.pem # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # response = self.client.admin.command('ismaster') with self.assertRaises(ConnectionFailure): connected(MongoClient('server', ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100)) connected(MongoClient('server', ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=100)) if 'setName' in response: with self.assertRaises(ConnectionFailure): connected(MongoClient('server', replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100)) connected(MongoClient('server', replicaSet=response['setName'], ssl=True, ssl_certfile=CLIENT_PEM, ssl_cert_reqs=ssl.CERT_REQUIRED, ssl_ca_certs=CA_PEM, ssl_match_hostname=False, serverSelectionTimeoutMS=100))
def test_socket_timeout_ms_validation(self): c = rs_or_single_client(socketTimeoutMS=10 * 1000) self.assertEqual(10, get_pool(c).opts.socket_timeout) c = connected(rs_or_single_client(socketTimeoutMS=None)) self.assertEqual(None, get_pool(c).opts.socket_timeout) self.assertRaises(ValueError, rs_or_single_client, socketTimeoutMS=0) self.assertRaises(ValueError, rs_or_single_client, socketTimeoutMS=-1) self.assertRaises(ValueError, rs_or_single_client, socketTimeoutMS=1e10) self.assertRaises(ValueError, rs_or_single_client, socketTimeoutMS='foo')
def test_exhaust_query_server_error(self): # When doing an exhaust query, the socket stays checked out on success # but must be checked in on error to avoid semaphore leaks. client = connected(rs_or_single_client(maxPoolSize=1)) collection = client.pymongo_test.test pool = get_pool(client) sock_info = one(pool.sockets) # This will cause OperationFailure in all mongo versions since # the value for $orderby must be a document. cursor = collection.find(SON([("$query", {}), ("$orderby", True)]), cursor_type=CursorType.EXHAUST) self.assertRaises(OperationFailure, cursor.next) self.assertFalse(sock_info.closed) # The socket was checked in and the semaphore was decremented. self.assertIn(sock_info, pool.sockets) self.assertTrue(pool._socket_semaphore.acquire(blocking=False))
def test_auth_from_uri(self): self.client.admin.add_user("admin", "pass", roles=["root"]) self.addCleanup(self.client.admin.remove_user, 'admin') self.addCleanup(remove_all_users, self.client.pymongo_test) self.client.pymongo_test.add_user("user", "pass", roles=['userAdmin', 'readWrite']) with self.assertRaises(OperationFailure): connected(rs_or_single_client("mongodb://*****:*****@%s:%d" % (host, port))) # No error. connected( rs_or_single_client_noauth("mongodb://*****:*****@%s:%d" % (host, port))) # Wrong database. uri = "mongodb://*****:*****@%s:%d/pymongo_test" % (host, port) with self.assertRaises(OperationFailure): connected(rs_or_single_client(uri)) # No error. connected( rs_or_single_client_noauth( "mongodb://*****:*****@%s:%d/pymongo_test" % (host, port))) # Auth with lazy connection. rs_or_single_client("mongodb://*****:*****@%s:%d/pymongo_test" % (host, port), connect=False).pymongo_test.test.find_one() # Wrong password. bad_client = rs_or_single_client( "mongodb://*****:*****@%s:%d/pymongo_test" % (host, port), connect=False) self.assertRaises(OperationFailure, bad_client.pymongo_test.test.find_one)
def test_ssl_crlfile_support(self): # Expects the server to be running with server.pem and ca.pem # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem if not CERT_SSL: raise SkipTest("No mongod available over SSL with certs") if not hasattr(ssl, 'VERIFY_CRL_CHECK_LEAF'): self.assertRaises(ConfigurationError, MongoClient, 'server', ssl=True, ssl_ca_certs=CA_PEM, ssl_crlfile=CRL_PEM, serverSelectionTimeoutMS=100) else: connected( MongoClient('server', ssl=True, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100)) with self.assertRaises(ConnectionFailure): connected( MongoClient('server', ssl=True, ssl_ca_certs=CA_PEM, ssl_crlfile=CRL_PEM, serverSelectionTimeoutMS=100)) uri_fmt = ("mongodb://server/?ssl=true&" "ssl_ca_certs=%s&serverSelectionTimeoutMS=100") connected(MongoClient(uri_fmt % (CA_PEM, ))) uri_fmt = ("mongodb://server/?ssl=true&ssl_crlfile=%s" "&ssl_ca_certs=%s&serverSelectionTimeoutMS=100") with self.assertRaises(ConnectionFailure): connected(MongoClient(uri_fmt % (CRL_PEM, CA_PEM)))
def test_zero_latency(self): if (client_context.version >= (3, 7, 2) and client_context.auth_enabled and client_context.is_rs): raise SkipTest("Disabled due to SERVER-32845") ping_times = set() # Generate unique ping times. while len(ping_times) < len(self.client.nodes): ping_times.add(random.random()) for ping_time, host in zip(ping_times, self.client.nodes): ServerDescription._host_to_round_trip_time[host] = ping_time try: client = connected( rs_client(readPreference='nearest', localThresholdMS=0)) wait_until(lambda: client.nodes == self.client.nodes, "discovered all nodes") host = self.read_from_which_host(client) for _ in range(5): self.assertEqual(host, self.read_from_which_host(client)) finally: ServerDescription._host_to_round_trip_time.clear()
def test_exhaust_query_server_error(self): # When doing an exhaust query, the socket stays checked out on success # but must be checked in on error to avoid semaphore leaks. client = connected(rs_or_single_client(maxPoolSize=1)) collection = client.pymongo_test.test pool = get_pool(client) sock_info = one(pool.sockets) # This will cause OperationFailure in all mongo versions since # the value for $orderby must be a document. cursor = collection.find(SON([('$query', {}), ('$orderby', True)]), cursor_type=CursorType.EXHAUST) self.assertRaises(OperationFailure, cursor.next) self.assertFalse(sock_info.closed) # The socket was checked in and the semaphore was decremented. self.assertIn(sock_info, pool.sockets) self.assertTrue(pool._socket_semaphore.acquire(blocking=False))
def test_ssl_crlfile_support(self): # Expects the server to be running with server.pem and ca.pem # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem if not CERT_SSL: raise SkipTest("No mongod available over SSL with certs") if not hasattr(ssl, 'VERIFY_CRL_CHECK_LEAF'): self.assertRaises( ConfigurationError, MongoClient, 'server', ssl=True, ssl_ca_certs=CA_PEM, ssl_crlfile=CRL_PEM, serverSelectionTimeoutMS=100) else: connected(MongoClient('server', ssl=True, ssl_ca_certs=CA_PEM, serverSelectionTimeoutMS=100)) with self.assertRaises(ConnectionFailure): connected(MongoClient('server', ssl=True, ssl_ca_certs=CA_PEM, ssl_crlfile=CRL_PEM, serverSelectionTimeoutMS=100)) uri_fmt = ("mongodb://server/?ssl=true&" "ssl_ca_certs=%s&serverSelectionTimeoutMS=100") connected(MongoClient(uri_fmt % (CA_PEM,))) uri_fmt = ("mongodb://server/?ssl=true&ssl_crlfile=%s" "&ssl_ca_certs=%s&serverSelectionTimeoutMS=100") with self.assertRaises(ConnectionFailure): connected(MongoClient(uri_fmt % (CRL_PEM, CA_PEM)))
def test_constants(self): # Set bad defaults. MongoClient.HOST = "somedomainthatdoesntexist.org" MongoClient.PORT = 123456789 with self.assertRaises(AutoReconnect): connected(MongoClient(serverSelectionTimeoutMS=10)) # Override the defaults. No error. connected(MongoClient(host, port)) # Set good defaults. MongoClient.HOST = host MongoClient.PORT = port # No error. connected(MongoClient())
def test_validation_with_system_ca_certs(self): # Expects the server to be running with server.pem and ca.pem. # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # --sslWeakCertificateValidation # self.patch_system_certs(CA_PEM) with self.assertRaises(ConnectionFailure): # Server cert is verified but hostname matching fails connected( MongoClient('server', ssl=True, serverSelectionTimeoutMS=100, **self.credentials)) # Server cert is verified. Disable hostname matching. connected( MongoClient('server', ssl=True, tlsAllowInvalidHostnames=True, serverSelectionTimeoutMS=100, **self.credentials)) # Server cert and hostname are verified. connected( MongoClient('localhost', ssl=True, serverSelectionTimeoutMS=100, **self.credentials)) # Server cert and hostname are verified. connected( MongoClient( 'mongodb://localhost/?ssl=true&serverSelectionTimeoutMS=100', **self.credentials))
def test_mongodb_x509_auth(self): # Expects the server to be running with the server.pem, ca.pem # and crl.pem provided in mongodb and the server tests as well as # --auth # # --sslPEMKeyFile=/path/to/pymongo/test/certificates/server.pem # --sslCAFile=/path/to/pymongo/test/certificates/ca.pem # --sslCRLFile=/path/to/pymongo/test/certificates/crl.pem # --auth if not CERT_SSL: raise SkipTest("No mongod available over SSL with certs") if not Version.from_client(ssl_client).at_least(2, 5, 3, -1): raise SkipTest("MONGODB-X509 tests require MongoDB 2.5.3 or newer") if not server_started_with_auth(ssl_client): raise SkipTest('Authentication is not enabled on server') self.addCleanup(ssl_client['$external'].logout) self.addCleanup(remove_all_users, ssl_client['$external']) # Give admin all necessary privileges. ssl_client['$external'].add_user(MONGODB_X509_USERNAME, roles=[ {'role': 'readWriteAnyDatabase', 'db': 'admin'}, {'role': 'userAdminAnyDatabase', 'db': 'admin'}]) coll = ssl_client.pymongo_test.test self.assertRaises(OperationFailure, coll.count) self.assertTrue(ssl_client.admin.authenticate( MONGODB_X509_USERNAME, mechanism='MONGODB-X509')) coll.drop() uri = ('mongodb://%s@%s:%d/?authMechanism=' 'MONGODB-X509' % ( quote_plus(MONGODB_X509_USERNAME), host, port)) # SSL options aren't supported in the URI... self.assertTrue(MongoClient(uri, ssl=True, ssl_certfile=CLIENT_PEM)) # Should require a username uri = ('mongodb://%s:%d/?authMechanism=MONGODB-X509' % (host, port)) client_bad = MongoClient(uri, ssl=True, ssl_certfile=CLIENT_PEM) self.assertRaises(OperationFailure, client_bad.pymongo_test.test.delete_one, {}) # Auth should fail if username and certificate do not match uri = ('mongodb://%s@%s:%d/?authMechanism=' 'MONGODB-X509' % ( quote_plus("not the username"), host, port)) bad_client = MongoClient(uri, ssl=True, ssl_certfile=CLIENT_PEM) with self.assertRaises(OperationFailure): bad_client.pymongo_test.test.find_one() self.assertRaises(OperationFailure, ssl_client.admin.authenticate, "not the username", mechanism="MONGODB-X509") # Invalid certificate (using CA certificate as client certificate) uri = ('mongodb://%s@%s:%d/?authMechanism=' 'MONGODB-X509' % ( quote_plus(MONGODB_X509_USERNAME), host, port)) # These tests will raise SSLError (>= 3.2) or ConnectionFailure # (2.x) depending on where OpenSSL first sees the PEM file. try: connected(MongoClient(uri, ssl=True, ssl_certfile=CA_PEM, serverSelectionTimeoutMS=100)) except (ssl.SSLError, ConnectionFailure): pass else: self.fail("Invalid certificate accepted.") try: connected(MongoClient(pair, ssl=True, ssl_certfile=CA_PEM, serverSelectionTimeoutMS=100)) except (ssl.SSLError, ConnectionFailure): pass else: self.fail("Invalid certificate accepted.")
except socket.error: return False finally: socket.setdefaulttimeout(socket_timeout) # Shared ssl-enabled client for the tests ssl_client = None if HAVE_SSL: import ssl # Check this all once instead of before every test method below. # Is MongoDB configured for SSL? try: connected(MongoClient(host, port, ssl=True, serverSelectionTimeoutMS=100)) SIMPLE_SSL = True except ConnectionFailure: pass # Is MongoDB configured with server.pem, ca.pem, and crl.pem from # mongodb jstests/lib? try: ssl_client = connected(MongoClient( host, port, ssl=True, ssl_certfile=CLIENT_PEM, serverSelectionTimeoutMS=100)) CERT_SSL = True except ConnectionFailure: pass
def test_equality(self): c = connected(rs_or_single_client()) self.assertEqual(client_context.rs_or_standalone_client, c) # Explicitly test inequality self.assertFalse(client_context.rs_or_standalone_client != c)
def test_host_w_port(self): with self.assertRaises(ValueError): connected(MongoClient("%s:1234567" % host, connectTimeoutMS=1, serverSelectionTimeoutMS=10))