def test_ok(self): server = MockupDB(auto_ismaster={'maxWireVersion': 3}) server.run() self.addCleanup(server.stop) client = MongoClient(server.uri) with going(client.test.command, {'foo': 1}) as future: server.receives().ok(3) response = future() self.assertEqual(3, response['ok'])
class TestLegacyWrites(unittest.TestCase): def setUp(self): self.server = MockupDB(auto_ismaster=True) self.server.run() self.addCleanup(self.server.stop) self.client = MongoClient(self.server.uri) self.collection = self.client.db.get_collection( 'collection', write_concern=WriteConcern(w=0)) def test_insert_one(self): with going(self.collection.insert_one, {'_id': 1}): self.server.receives(OpInsert({'_id': 1}, flags=0)) def test_insert_many(self): collection = self.collection.with_options( write_concern=WriteConcern(0)) flags = INSERT_FLAGS['ContinueOnError'] docs = [{'_id': 1}, {'_id': 2}] with going(collection.insert_many, docs, ordered=False): self.server.receives(OpInsert(docs, flags=flags)) def test_replace_one(self): with going(self.collection.replace_one, {}, {}): self.server.receives(OpUpdate({}, {}, flags=0)) def test_update_many(self): flags = UPDATE_FLAGS['MultiUpdate'] with going(self.collection.update_many, {}, {'$unset': 'a'}): update = self.server.receives(OpUpdate({}, {}, flags=flags)) self.assertEqual(2, update.flags) def test_delete_one(self): flags = DELETE_FLAGS['SingleRemove'] with going(self.collection.delete_one, {}): delete = self.server.receives(OpDelete({}, flags=flags)) self.assertEqual(1, delete.flags) def test_delete_many(self): with going(self.collection.delete_many, {}): delete = self.server.receives(OpDelete({}, flags=0)) self.assertEqual(0, delete.flags)
class TestProductController(unittest.TestCase): @classmethod def setUpClass(self) -> None: self.server = MockupDB(auto_ismaster=True, verbose=True) self.server.run() Config.MONGO_URI = self.server.uri app = create_app() self.app = app.test_client() @classmethod def tearDownClass(self) -> None: self.server.stop() def test_create_product(self): to_insert = { "title": "First Aid kit", "description": "Your helper in journey", "params": { 'price': 350, 'class': 'B' } } headers = [('Content-Type', 'application/json')] go(self.app.post, '/api/product', data=dumps(to_insert), headers=headers) rv = self.server.receives() new_object_id = str(rv.docs[0]['documents'][0]['_id']) go(self.app.get, f'/api/product/{new_object_id}', headers=headers) request = self.server.receives() request_status = request.ok(cursor={'id': new_object_id, 'firstBatch': [ to_insert ]}) self.assertTrue(request_status)
def test_query_and_read_mode_sharded_op_msg(self): """Test OP_MSG sends non-primary $readPreference and never $query.""" server = MockupDB() server.autoresponds('ismaster', ismaster=True, msg='isdbgrid', minWireVersion=2, maxWireVersion=6) server.run() self.addCleanup(server.stop) client = MongoClient(server.uri) self.addCleanup(client.close) read_prefs = ( Primary(), SecondaryPreferred(), PrimaryPreferred(), Secondary(), Nearest(), SecondaryPreferred([{ 'tag': 'value' }]), ) for query in ( { 'a': 1 }, { '$query': { 'a': 1 } }, ): for mode in read_prefs: collection = client.db.get_collection('test', read_preference=mode) cursor = collection.find(query.copy()) with going(next, cursor): request = server.receives() # Command is not nested in $query. request.assert_matches( OpMsg( SON([('find', 'test'), ('filter', { 'a': 1 }), ('$readPreference', mode.document)]))) request.replies({'cursor': {'id': 0, 'firstBatch': [{}]}})
class BaseTestCase(unittest.TestCase): server = None @classmethod def setUpClass(self): self.server = MockupDB(auto_ismaster=True, verbose=True) self.server.run() # create mongo connection to mock server app.app.testing = True app.app.config['MONGO_URI'] = self.server.uri self.app = app.app.test_client() @classmethod def tearDownClass(self): self.server.stop() def test_getDataSources(self): # arrange future = go(self.app.get, '/dataSources') request = self.server.receives( Command({ 'find': 'dataSources', 'filter': {} }, flags=4, namespace='app')) request.ok( cursor={ 'id': 0, 'firstBatch': [{ 'name': 'Google', 'url': 'http://google.com/rest/api' }, { 'name': 'Rest', 'url': 'http://rest.com/rest/api' }] }) # act http_response = future() # assert data = http_response.get_data(as_text=True) self.assertIn('http://google.com/rest/api', data) self.assertIn('http://rest.com/rest/api', data)
def test_client_handshake_saslSupportedMechs(self): server = MockupDB() server.run() self.addCleanup(server.stop) primary_response = OpReply('ismaster', True, minWireVersion=2, maxWireVersion=6) client = MongoClient(server.uri, username='******', password='******') self.addCleanup(client.close) # New monitoring sockets send data during handshake. heartbeat = server.receives('ismaster') heartbeat.ok(primary_response) future = go(client.db.command, 'whatever') for request in server: if request.matches('ismaster'): if request.client_port == heartbeat.client_port: # This is the monitor again, keep going. request.ok(primary_response) else: # Handshaking a new application socket should send # saslSupportedMechs and speculativeAuthenticate. self.assertEqual(request['saslSupportedMechs'], 'admin.username') self.assertIn( 'saslStart', request['speculativeAuthenticate']) auth = {'conversationId': 1, 'done': False, 'payload': b'r=wPleNM8S5p8gMaffMDF7Py4ru9bnmmoqb0' b'1WNPsil6o=pAvr6B1garhlwc6MKNQ93ZfFky' b'tXdF9r,s=4dcxugMJq2P4hQaDbGXZR8uR3ei' b'PHrSmh4uhkg==,i=15000'} request.ok('ismaster', True, saslSupportedMechs=['SCRAM-SHA-256'], speculativeAuthenticate=auth, minWireVersion=2, maxWireVersion=6) # Authentication should immediately fail with: # OperationFailure: Server returned an invalid nonce. with self.assertRaises(OperationFailure): future() return
class MockupDBFlaskTest(unittest.TestCase): def setUp(self): self.server = MockupDB(3000, 'mongodb://localhost') self.server.run() # print('11111111111',self.server.uri) self.app = make_app(self.server.uri).test_client() print('000000000', self.app.get) def tearDown(self): self.server.stop() def test(self): future = go(self.app.get, "/pages/my_page_name") print('11111111', future) request = self.server.receives() print('22222', request) request.reply({"contents": "foo"}) http_response = future() print('333333333', http_response.get_data(as_text=True)) self.assertEqual("foo", http_response.get_data(as_text=True))
def test_query_and_read_mode_sharded_op_query(self): server = MockupDB() server.autoresponds('ismaster', ismaster=True, msg='isdbgrid', minWireVersion=2, maxWireVersion=5) server.run() self.addCleanup(server.stop) client = MongoClient(server.uri) self.addCleanup(client.close) modes_without_query = ( Primary(), SecondaryPreferred(),) modes_with_query = ( PrimaryPreferred(), Secondary(), Nearest(), SecondaryPreferred([{'tag': 'value'}]),) find_command = SON([('find', 'test'), ('filter', {'a': 1})]) for query in ({'a': 1}, {'$query': {'a': 1}},): for mode in modes_with_query + modes_without_query: collection = client.db.get_collection('test', read_preference=mode) cursor = collection.find(query.copy()) with going(next, cursor): request = server.receives() if mode in modes_without_query: # Filter is hoisted out of $query. request.assert_matches(Command(find_command)) self.assertFalse('$readPreference' in request) else: # Command is nested in $query. request.assert_matches(Command( SON([('$query', find_command), ('$readPreference', mode.document)]))) request.replies({'cursor': {'id': 0, 'firstBatch': [{}]}})
def test_query_and_read_mode_sharded(self): server = MockupDB() server.autoresponds('ismaster', ismaster=True, msg='isdbgrid') server.run() self.addCleanup(server.stop) client = MongoClient(server.uri) self.addCleanup(client.close) modes_without_query = ( Primary(), SecondaryPreferred(),) modes_with_query = ( PrimaryPreferred(), Secondary(), Nearest(), SecondaryPreferred([{'tag': 'value'}]),) for query in ({'a': 1}, {'$query': {'a': 1}},): for mode in modes_with_query + modes_without_query: collection = client.db.get_collection('test', read_preference=mode) cursor = collection.find(query.copy()) with going(next, cursor): request = server.receives(OpQuery) if mode in modes_without_query: # Query is not edited: {'a': 1} is not nested in $query, # {'$query': {'a': 1}} is not hoisted. request.assert_matches(query) self.assertFalse('$readPreference' in request) else: # {'a': 1} is *always* nested in $query. request.assert_matches({ '$query': {'a': 1}, '$readPreference': mode.document }) request.replies({})
class MockupDBFlaskTest(unittest.TestCase): def setUp(self): self.server = MockupDB(auto_ismaster=True) self.server.run() self.app = create_app(self.server.uri).test_client() def tearDown(self): self.server.stop() def mock_db_get(self, url=None): # dateStr = "2018-11-11T00:00:00.000Z" # date = dateutil.parser.parse(dateStr) request = self.server.receives( OpMsg('find', 'urls', filter={'shorturl': url})) request.ok(cursor={'id': 0, 'firstBatch': [mapping_dict[url]]}) def mock_db_update(self): request = self.server.pop().reply({"modified_count": 1}) def mock_db_get_many(self, url=None): request = self.server.pop() # request = self.server.receives( # OpMsg({"count": "urls", "query": {"shorturl": url}})) request.ok(cursor={ 'id': 0, 'firstBatch': [mapping_dict[url]], 'count': 1 }) def test_get_url_not_empty(self): future = go(self.app.get, "/urls/e5a53874fbde55") self.mock_db_get(url="e5a53874fbde55") self.mock_db_update() http_response = future() # print http_response.status # print http_response.mimetype # print http_response.response # print http_response.get_data() self.assertEqual(("Long url is : newlonnnn44\n"), http_response.get_data()) def test_get_url_not_found(self): future = go(self.app.get, "/urls/fggg874fbde55") self.mock_db_get(url="fggg874fbde55") http_response = future() self.assertEqual( "No long url found for this short url fggg874fbde55\n", http_response.get_data()) def test_get_access_time_all(self): future = go(self.app.get, "/urls/alltime_access/e5a53874fbde55") self.mock_db_get_many(url="e5a53874fbde55") http_response = future() self.assertEqual( "Access times for url: 'e5a53874fbde55'; for time duration: ' all' is: 1\n", http_response.get_data())
def test_client_handshake_data(self): primary, secondary = MockupDB(), MockupDB() for server in primary, secondary: server.run() self.addCleanup(server.stop) hosts = [server.address_string for server in primary, secondary] primary_response = OpReply('ismaster', True, setName='rs', hosts=hosts) secondary_response = OpReply('ismaster', False, setName='rs', hosts=hosts, secondary=True) client = MongoClient(primary.uri, replicaSet='rs', appname='my app', heartbeatFrequencyMS=500) # Speed up the test. self.addCleanup(client.close) # New monitoring sockets send data during handshake. heartbeat = primary.receives('ismaster') _check_handshake_data(heartbeat) heartbeat.ok(primary_response) heartbeat = secondary.receives('ismaster') _check_handshake_data(heartbeat) heartbeat.ok(secondary_response) # Subsequent heartbeats have no client data. primary.receives('ismaster', 1, client=absent).ok(primary_response) secondary.receives('ismaster', 1, client=absent).ok(secondary_response) # After a disconnect, next ismaster has client data again. primary.receives('ismaster', 1, client=absent).hangup() heartbeat = primary.receives('ismaster') _check_handshake_data(heartbeat) heartbeat.ok(primary_response) secondary.autoresponds('ismaster', secondary_response) # Start a command, so the client opens an application socket. future = go(client.db.command, 'whatever') for request in primary: if request.matches(Command('ismaster')): if request.client_port == heartbeat.client_port: # This is the monitor again, keep going. request.ok(primary_response) else: # Handshaking a new application socket. _check_handshake_data(heartbeat) request.ok(primary_response) else: # Command succeeds. request.assert_matches(Command('whatever')) request.ok() assert future() return
class TestResetAndRequestCheck(unittest.TestCase): def __init__(self, *args, **kwargs): super(TestResetAndRequestCheck, self).__init__(*args, **kwargs) self.ismaster_time = 0 self.client = None self.server = None def setup_server(self): self.server = MockupDB() def responder(request): self.ismaster_time = time.time() return request.ok(ismaster=True, minWireVersion=2, maxWireVersion=6) self.server.autoresponds('ismaster', responder) self.server.run() self.addCleanup(self.server.stop) kwargs = {'socketTimeoutMS': 100} # Disable retryable reads when pymongo supports it. kwargs['retryReads'] = False self.client = MongoClient(self.server.uri, **kwargs) wait_until(lambda: self.client.nodes, 'connect to standalone') def tearDown(self): if hasattr(self, 'client') and self.client: self.client.close() def _test_disconnect(self, operation): # Application operation fails. Test that client resets server # description and does *not* schedule immediate check. self.setup_server() # Network error on application operation. with self.assertRaises(ConnectionFailure): with going(operation.function, self.client): self.server.receives().hangup() # Server is Unknown. topology = self.client._topology with self.assertRaises(ConnectionFailure): topology.select_server_by_address(self.server.address, 0) time.sleep(0.5) after = time.time() # Demand a reconnect. with going(self.client.db.command, 'buildinfo'): self.server.receives('buildinfo').ok() last = self.ismaster_time self.assertGreaterEqual(last, after, 'called ismaster before needed') def _test_timeout(self, operation): # Application operation times out. Test that client does *not* reset # server description and does *not* schedule immediate check. self.setup_server() with self.assertRaises(ConnectionFailure): with going(operation.function, self.client): self.server.receives() before = self.ismaster_time time.sleep(0.5) # Server is *not* Unknown. topology = self.client._topology server = topology.select_server_by_address(self.server.address, 0) self.assertEqual(SERVER_TYPE.Standalone, server.description.server_type) after = self.ismaster_time self.assertEqual(after, before, 'unneeded ismaster call') def _test_not_master(self, operation): # Application operation gets a "not master" error. self.setup_server() with self.assertRaises(ConnectionFailure): with going(operation.function, self.client): request = self.server.receives() before = self.ismaster_time request.replies(operation.not_master) time.sleep(1) # Server is rediscovered. topology = self.client._topology server = topology.select_server_by_address(self.server.address, 0) self.assertEqual(SERVER_TYPE.Standalone, server.description.server_type) after = self.ismaster_time self.assertGreater(after, before, 'ismaster not called')
class functionsTest(unittest.TestCase): def setUp(self): self.server = MockupDB(auto_ismaster={"maxWireVersion": 3}) self.server.run() #self.testConf['mongo_url'] = self.testConf = { "mongo_url" : self.server.uri, "host_url": "https://lmp.nupursjsu.net", "host" : "127.0.0.1", "port" : 8080 } def tearDown(self): self.server.stop() def test_display_userdetails(self): user_details = {'userId': 'user1', 'firstName': 'myFirstName', 'lastName': 'myLastName', 'age': 20} userId = "user1" details = go(display_userdetails, userId, self.testConf) query = OpQuery({"userId": "user1"}, namespace="Books.myapp_user", fields={"_id": False}) request = self.server.receives(query) request.reply(user_details) output = details() for key in output: if key in user_details: self.assertEqual(user_details[key], output[key]) def test_display_bookdetails(self): book_details = {'userId': 'user1', 'firstName': 'myFirstName', 'lastName': 'myLastName', 'age': 20} userId = "user1" details = go(display_userdetails, userId, self.testConf) query = OpQuery({"userId": "user1"}, namespace="Books.myapp_user", fields={"_id": False}) request = self.server.receives(query) request.reply(book_details) output = details() for key in output: if key in book_details: self.assertEqual(book_details[key], output[key]) def test_update_bookdetails(self): book_details = {'userId': 'user1', 'firstName': 'myFirstName', 'lastName': 'myLastName', 'age': 20} userId = "user1" details = go(display_userdetails, userId, self.testConf) query = OpQuery({"userId": "user1"}, namespace="Books.myapp_user", fields={"_id": False}) request = self.server.receives(query) request.reply(book_details) output = details() for key in output: if key in book_details: self.assertEqual(book_details[key], output[key]) def test_update_userdetails(self): user_details = {'userId': 'user1', 'firstName': 'myFirstName', 'lastName': 'myLastName', 'age': 20} userId = "user1" details = go(display_userdetails, userId, self.testConf) query = OpQuery({"userId": "user1"}, namespace="Books.myapp_user", fields={"_id": False}) request = self.server.receives(query) request.reply(user_details) output = details() for key in output: if key in user_details: self.assertEqual(user_details[key], output[key])
class GetDataSourceTestCase(unittest.TestCase): @classmethod def setUpClass(self): self.server = MockupDB(auto_ismaster=True, verbose=True) self.server.run() # create mongo connection to mock server app.testing = True app.config['MONGO_URI'] = self.server.uri self.app = app.test_client() @classmethod def tearDownClass(self): self.server.stop() def test_getDataSource(self): # arrange id = '5a8f1e368f7936badfbb0cfa' future = go(self.app.get, f'/dataSource/{id}') request = self.server.receives( Command( { 'find': 'dataSources', 'filter': { '_id': mockup_oid(id) }, 'limit': 1, 'singleBatch': True }, flags=4, namespace='app')) request.ok( cursor={ 'id': 0, 'firstBatch': [{ 'name': 'bla', 'url': 'http://google.com/rest/api' }] }) # act http_response = future() # assert self.assertIn('http://google.com/rest/api', http_response.get_data(as_text=True)) def test_getDataSource_404(self): id = '5a8f1e368f7936badfbb0cfb' future = go(self.app.get, f'/dataSource/{id}') request = self.server.receives( Command( { 'find': 'dataSources', 'filter': { '_id': mockup_oid(id) }, 'limit': 1, 'singleBatch': True }, flags=4, namespace='app')) request.ok(cursor={'id': 0, 'firstBatch': []}) # act http_response = future() # assert self.assertEqual(http_response.status_code, 404) def test_getDataSources(self): # arrange future = go(self.app.get, '/dataSources') request = self.server.receives( Command({ 'find': 'dataSources', 'filter': {} }, flags=4, namespace='app')) request.ok( cursor={ 'id': 0, 'firstBatch': [{ 'name': 'Google', 'url': 'http://google.com/rest/api' }, { 'name': 'Rest', 'url': 'http://rest.com/rest/api' }] }) # act http_response = future() # assert data = http_response.get_data(as_text=True) self.assertIn('http://google.com/rest/api', data) self.assertIn('http://rest.com/rest/api', data) def test_addDataSource(self): # arrange id = '5a924d7a29a6e5484dcf68be' headers = [('Content-Type', 'application/json')] # need to pass _id because pymongo creates one so it's impossible to match insert request without _ids toInsert = {'name': 'new', 'url': 'http://google.com', '_id': id} future = go(self.app.put, '/dataSource', data=dumps(toInsert), headers=headers) request = self.server.receives( Command( { 'insert': 'dataSources', 'ordered': True, 'documents': [{ 'name': 'new', 'url': 'http://google.com', '_id': mockup_oid(id) }] }, namespace='app')) request.ok(cursor={'inserted_id': id}) # act http_response = future() # assert data = http_response.get_data(as_text=True) self.assertIn(id, data) self.assertEqual(http_response.status_code, 201) def test_deleteDataSource(self): # arrange id = '5a8f1e368f7936badfbb0cfa' future = go(self.app.delete, f'/dataSource/{id}') request = self.server.receives( Command( { 'delete': 'dataSources', 'ordered': True, 'deletes': [{ 'q': { '_id': mockup_oid(id) }, 'limit': 1 }] }, namespace='app')) request.ok({'acknowledged': True, 'n': 1}) # act http_response = future() # assert self.assertIn(f'deleted {id}', http_response.get_data(as_text=True)) self.assertEqual(http_response.status_code, 202) def test_deleteDataSource_notFound(self): # arrange id = '5a8f1e368f7936badfbb0000' future = go(self.app.delete, f'/dataSource/{id}') request = self.server.receives( Command( { 'delete': 'dataSources', 'ordered': True, 'deletes': [{ 'q': { '_id': mockup_oid(id) }, 'limit': 1 }] }, namespace='app')) request.ok({'acknowledged': True, 'n': 0}) # act http_response = future() # assert self.assertIn(f'{id} not found', http_response.get_data(as_text=True)) self.assertEqual(http_response.status_code, 404)
def test_monitor(self): cluster_time = Timestamp(0, 0) reply = { 'minWireVersion': 0, 'maxWireVersion': 6, '$clusterTime': { 'clusterTime': cluster_time } } server = MockupDB() server.run() self.addCleanup(server.stop) client = MongoClient(server.uri, heartbeatFrequencyMS=500) self.addCleanup(client.close) request = server.receives('ismaster') # No $clusterTime in first ismaster, only in subsequent ones self.assertNotIn('$clusterTime', request) request.ok(reply) # Next exchange: client returns first clusterTime, we send the second. request = server.receives('ismaster') self.assertIn('$clusterTime', request) self.assertEqual(request['$clusterTime']['clusterTime'], cluster_time) cluster_time = Timestamp(cluster_time.time, cluster_time.inc + 1) reply['$clusterTime'] = {'clusterTime': cluster_time} request.reply(reply) # Third exchange: client returns second clusterTime. request = server.receives('ismaster') self.assertEqual(request['$clusterTime']['clusterTime'], cluster_time) # Return command error with a new clusterTime. cluster_time = Timestamp(cluster_time.time, cluster_time.inc + 1) error = { 'ok': 0, 'code': 211, 'errmsg': 'Cache Reader No keys found for HMAC ...', '$clusterTime': { 'clusterTime': cluster_time } } request.reply(error) # Fourth exchange: the Monitor retry attempt uses the clusterTime from # the previous isMaster error. request = server.receives('ismaster') self.assertEqual(request['$clusterTime']['clusterTime'], cluster_time) cluster_time = Timestamp(cluster_time.time, cluster_time.inc + 1) error['$clusterTime'] = {'clusterTime': cluster_time} request.reply(error) # Fifth exchange: the Monitor attempt uses the clusterTime from # the previous isMaster error. request = server.receives('ismaster') self.assertEqual(request['$clusterTime']['clusterTime'], cluster_time) request.reply(reply) client.close()
class TestShop(unittest.TestCase): def setUp(self): """ Prepare the test envirement. start the server to mockup the database """ self.server = MockupDB(auto_ismaster=True, verbose=True) self.server.run() app.testing = True app.config['MONGO_URI'] = self.server.uri self.app = app.test_client() self.token = mock_access_token()['access_token'] self.auth_header = {'Authorization': 'Bearer {}'.format(self.token)} def tearDown(self): self.server.stop() def test_notoken(self): future = go(self.app.get, '/shops/5b3a7297d2e5ce5bbd3d0121') self.assertEqual(future().status_code, 401) future = go(self.app.put, '/shops/5b3a7297d2e5ce5bbd3d0121') self.assertEqual(future().status_code, 401) future = go(self.app.delete, '/shops/5b3a7297d2e5ce5bbd3d0121') self.assertEqual(future().status_code, 401) future = go(self.app.get, '/shops') self.assertEqual(future().status_code, 401) future = go(self.app.post, '/shops') self.assertEqual(future().status_code, 401) def test_invalid_token(self): headers = {'Authorization': 'Bearer invalid_token'} future = go(self.app.get, '/shops/5b3a7297d2e5ce5bbd3d0121', headers=headers) self.assertEqual(future().status_code, 400) future = go(self.app.put, '/shops/5b3a7297d2e5ce5bbd3d0121', headers=headers) self.assertEqual(future().status_code, 400) future = go(self.app.delete, '/shops/5b3a7297d2e5ce5bbd3d0121', headers=headers) self.assertEqual(future().status_code, 400) future = go(self.app.get, '/shops', headers=headers) self.assertEqual(future().status_code, 400) future = go(self.app.post, '/shops', headers=headers) self.assertEqual(future().status_code, 400) def test_shop_notfound(self): future = go(self.app.get, '/shops/5b3a7297d2e5ce5bbd3d0121', headers=self.auth_header) request = self.server.receives() request.ok(cursor={'id': 0, 'firstBatch': []}) self.assertEqual(future().status_code, 400) future = go(self.app.put, '/shops/5b3a7297d2e5ce5bbd3d0121', headers=self.auth_header, json=SHOP_REQ) request = self.server.receives() request.ok(cursor={'id': 0, 'firstBatch': []}) self.assertEqual(future().status_code, 400) future = go(self.app.delete, '/shops/5b3a7297d2e5ce5bbd3d0121', headers=self.auth_header) request = self.server.receives() request.ok(cursor={'id': 0, 'firstBatch': []}) self.assertEqual(future().status_code, 400) def test_invalid_shop_id(self): future = go(self.app.get, '/shops/invalidid', headers=self.auth_header) self.assertEqual(future().status_code, 400) future = go(self.app.put, '/shops/invalidid', headers=self.auth_header) self.assertEqual(future().status_code, 400) future = go(self.app.delete, '/shops/invalidid', headers=self.auth_header) self.assertEqual(future().status_code, 400)
def test_op_insert_manipulate_false(self): # Test three aspects of legacy insert with manipulate=False: # 1. The return value is None, [None], or [None, None] as appropriate. # 2. _id is not set on the passed-in document object. # 3. _id is not sent to server. server = MockupDB(auto_ismaster=True) server.run() self.addCleanup(server.stop) client = MongoClient(server.uri) self.addCleanup(client.close) doc = {} with going(client.db.coll.insert, doc, manipulate=False) as future: server.receives(OpInsert({'_id': absent})) server.receives('getlasterror').replies_to_gle() self.assertFalse('_id' in doc) self.assertIsNone(future()) docs = [{}] # One doc in a list. with going(client.db.coll.insert, docs, manipulate=False) as future: server.receives(OpInsert({'_id': absent})) server.receives('getlasterror').replies_to_gle() self.assertFalse('_id' in docs[0]) self.assertEqual(future(), [None]) docs = [{}, {}] # Two docs. with going(client.db.coll.insert, docs, manipulate=False) as future: server.receives(OpInsert({'_id': absent}, {'_id': absent})) server.receives('getlasterror').replies_to_gle() self.assertFalse('_id' in docs[0]) self.assertFalse('_id' in docs[1]) self.assertEqual(future(), [None, None])
class TestUnacknowledgedWrites(unittest.TestCase): def setUp(self): self.server = MockupDB(auto_ismaster=True) self.server.run() self.addCleanup(self.server.stop) self.client = MongoClient(self.server.uri) self.collection = self.client.db.get_collection( 'collection', write_concern=WriteConcern(w=0)) def test_insert_one(self): with going(self.collection.insert_one, {'_id': 1}): # The moreToCome flag = 2. self.server.receives( OpMsg('insert', 'collection', writeConcern={'w': 0}, flags=2)) def test_insert_many(self): collection = self.collection.with_options( write_concern=WriteConcern(0)) docs = [{'_id': 1}, {'_id': 2}] with going(collection.insert_many, docs, ordered=False): self.server.receives( OpMsg(SON([('insert', 'collection'), ('ordered', False), ('writeConcern', { 'w': 0 })]), flags=2)) def test_replace_one(self): with going(self.collection.replace_one, {}, {}): self.server.receives( OpMsg(SON([('update', 'collection'), ('writeConcern', { 'w': 0 })]), flags=2)) def test_update_many(self): with going(self.collection.update_many, {}, {'$unset': 'a'}): self.server.receives( OpMsg(SON([('update', 'collection'), ('ordered', True), ('writeConcern', { 'w': 0 })]), flags=2)) def test_delete_one(self): with going(self.collection.delete_one, {}): self.server.receives( OpMsg(SON([('delete', 'collection'), ('writeConcern', { 'w': 0 })]), flags=2)) def test_delete_many(self): with going(self.collection.delete_many, {}): self.server.receives( OpMsg(SON([('delete', 'collection'), ('writeConcern', { 'w': 0 })]), flags=2))
class SignInTest(unittest.TestCase): def setUp(self): """ Prepare the test envirement. start the server to mockup the database """ self.server = MockupDB(auto_ismaster=True, verbose=True) self.server.run() app.testing = True app.config['MONGO_URI'] = self.server.uri self.app = app.test_client() def tearDown(self): """shuts down the mockupDB server""" self.server.stop() def test_signin_invalid_client(self): USER_REQ = OpMsg({ "find": "users", "filter": {"login": "******", "password": "******"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") CLIENT_REQ = OpMsg({ "find": "clients", "filter": {"client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") future = go(self.app.post, '/auth/signin', json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) request = self.server.receives(USER_REQ) request.ok(cursor={'id': 0, 'firstBatch': [USER]}) request = self.server.receives(CLIENT_REQ) request.ok(cursor={'id': 0, 'firstBatch': []}) self.assertEqual(future().status_code, 400) def test_signin_invalid_user(self): USER_REQ = OpMsg({ "find": "users", "filter": {"login": "******", "password": "******"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") future = go(self.app.post, '/auth/signin', json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) request = self.server.receives(USER_REQ) request.ok(cursor={'id': 0, 'firstBatch': []}) self.assertEqual(future().status_code, 400) def test_signin_valid_user(self): USER_REQ = OpMsg({ "find": "users", "filter": {"login": "******", "password": "******"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") CLIENT_REQ = OpMsg({ "find": "clients", "filter": {"client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") future = go(self.app.post,'/auth/signin', json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) request = self.server.receives(USER_REQ) request.ok(cursor={'id': 0, 'firstBatch': [USER]}) request = self.server.receives(CLIENT_REQ) request.ok(cursor={'id': 0, 'firstBatch': [CLIENT]}) self.assertEqual(future().status_code, 200) def test_signin_get_users(self): USER_REQ = OpMsg({ "find": "users", "filter": {}, "projection": {"password": 0}, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") user = { "_id": "5b37fff8bbf300b7ef185042", "login": "******", "password": "******", "role": "admin" } access_token = generate_access_token( user=user, pivate_key=app.config['PRIVATE_KEY'], auth_host=app.config['AUTH_HOST'], token_ttl=app.config['TOKEN_TTL'], auth_algo=app.config['AUTH_ALGO'] ) headers = {'Authorization': 'Bearer {}'.format(access_token['access_token'])} future = go(self.app.get, '/auth/signin', headers=headers) request = self.server.receives(USER_REQ, timeout=60) request.ok(cursor={'id': 0, 'firstBatch': [USER]})
class TestLegacyWrites(unittest.TestCase): def setUp(self): self.server = MockupDB(auto_ismaster=True) self.server.run() self.addCleanup(self.server.stop) self.client = MongoClient(self.server.uri) self.collection = self.client.db.collection def test_insert_one(self): with going(self.collection.insert_one, {'_id': 1}) as future: self.server.receives(OpInsert({'_id': 1}, flags=0)) self.server.receives(Command('getlasterror')).replies_to_gle() self.assertEqual(1, future().inserted_id) def test_insert_many(self): collection = self.collection.with_options( write_concern=WriteConcern(0)) flags = INSERT_FLAGS['ContinueOnError'] docs = [{'_id': 1}, {'_id': 2}] with going(collection.insert_many, docs, ordered=False) as future: self.server.receives(OpInsert(docs, flags=flags)) self.assertEqual([1, 2], future().inserted_ids) def test_replace_one(self): with going(self.collection.replace_one, {}, {}) as future: self.server.receives(OpUpdate({}, {}, flags=0)) request = self.server.receives(Command('getlasterror')) request.replies_to_gle(upserted=1) self.assertEqual(1, future().upserted_id) def test_update_many(self): flags = UPDATE_FLAGS['MultiUpdate'] with going(self.collection.update_many, {}, {'$unset': 'a'}) as future: update = self.server.receives(OpUpdate({}, {}, flags=flags)) self.assertEqual(2, update.flags) gle = self.server.receives(Command('getlasterror')) gle.replies_to_gle(upserted=1) self.assertEqual(1, future().upserted_id) def test_delete_one(self): flags = DELETE_FLAGS['SingleRemove'] with going(self.collection.delete_one, {}) as future: delete = self.server.receives(OpDelete({}, flags=flags)) self.assertEqual(1, delete.flags) gle = self.server.receives(Command('getlasterror')) gle.replies_to_gle(n=1) self.assertEqual(1, future().deleted_count) def test_delete_many(self): with going(self.collection.delete_many, {}) as future: delete = self.server.receives(OpDelete({}, flags=0)) self.assertEqual(0, delete.flags) gle = self.server.receives(Command('getlasterror')) gle.replies_to_gle(n=2) self.assertEqual(2, future().deleted_count)
class TestLikedDislikedShop(unittest.TestCase): def setUp(self): """ Prepare the test envirement. start the server to mockup the database """ self.server = MockupDB(auto_ismaster=True, verbose=True) self.server.run() app.testing = True app.config['MONGO_URI'] = self.server.uri self.app = app.test_client() self.token = mock_access_token()['access_token'] self.auth_header = {'Authorization': 'Bearer {}'.format(self.token)} def tearDown(self): self.server.stop() def test_get_liked_disliked_shops(self): future = go(self.app.get, '/shops/liked', headers=self.auth_header, json=SHOP_REQ) request = self.server.receives() request.ok(cursor={'id': 0, 'firstBatch': [SHOP_RESULT]}) self.assertEqual(future().status_code, 200) future = go(self.app.get, '/shops/disliked', headers=self.auth_header, json=SHOP_REQ) request = self.server.receives() request.ok(cursor={'id': 0, 'firstBatch': [DISLIKER]}) request = self.server.receives() request.ok(cursor={'id': 0, 'firstBatch': [SHOP_RESULT]}) self.assertEqual(future().status_code, 200) def test_post_like_dislike_shops(self): future = go(self.app.post, '/shops/liked', headers=self.auth_header, json=SHOP_REQ) request = self.server.receives() request.ok(cursor={'id': 0, 'firstBatch': []}) request = self.server.receives() request.ok(cursor={'id': 0, 'firstBatch': []}) request = self.server.receives() request.ok({ 'n': 1, 'nModified': 1, 'ok': 1.0, 'updatedExisting': True }) self.assertEqual(future().status_code, 201) def test_delete_like_dislike_shop_valid(self): future = go(self.app.delete, '/shops/5b3a7297d2e5ce5bbd3d0121', headers=self.auth_header) request = self.server.receives() request.ok(cursor={'id': 0, 'firstBatch': [SHOP_RESULT]}) request = self.server.receives() request.ok() request = self.server.receives() request.ok(cursor={'id': 0, 'firstBatch': []}) self.assertEqual(future().status_code, 204)
def test_client_handshake_data(self): primary, secondary = MockupDB(), MockupDB() for server in primary, secondary: server.run() self.addCleanup(server.stop) hosts = [server.address_string for server in (primary, secondary)] primary_response = OpReply('ismaster', True, setName='rs', hosts=hosts, minWireVersion=2, maxWireVersion=6) error_response = OpReply( 0, errmsg='Cache Reader No keys found for HMAC ...', code=211) secondary_response = OpReply('ismaster', False, setName='rs', hosts=hosts, secondary=True, minWireVersion=2, maxWireVersion=6) client = MongoClient(primary.uri, replicaSet='rs', appname='my app', heartbeatFrequencyMS=500) # Speed up the test. self.addCleanup(client.close) # New monitoring sockets send data during handshake. heartbeat = primary.receives('ismaster') _check_handshake_data(heartbeat) heartbeat.ok(primary_response) heartbeat = secondary.receives('ismaster') _check_handshake_data(heartbeat) heartbeat.ok(secondary_response) # Subsequent heartbeats have no client data. primary.receives('ismaster', 1, client=absent).ok(error_response) secondary.receives('ismaster', 1, client=absent).ok(error_response) # The heartbeat retry has no client data after a command failure. primary.receives('ismaster', 1, client=absent).ok(error_response) secondary.receives('ismaster', 1, client=absent).ok(error_response) # Still no client data. primary.receives('ismaster', 1, client=absent).ok(primary_response) secondary.receives('ismaster', 1, client=absent).ok(secondary_response) # After a disconnect, next ismaster has client data again. primary.receives('ismaster', 1, client=absent).hangup() heartbeat = primary.receives('ismaster') _check_handshake_data(heartbeat) heartbeat.ok(primary_response) secondary.autoresponds('ismaster', secondary_response) # Start a command, so the client opens an application socket. future = go(client.db.command, 'whatever') for request in primary: if request.matches(Command('ismaster')): if request.client_port == heartbeat.client_port: # This is the monitor again, keep going. request.ok(primary_response) else: # Handshaking a new application socket. _check_handshake_data(request) request.ok(primary_response) else: # Command succeeds. if version_tuple >= (3, 7): request.assert_matches(OpMsg('whatever')) else: request.assert_matches(Command('whatever')) request.ok() assert future() return
class SignInTest(unittest.TestCase): def setUp(self): self.server = MockupDB(auto_ismaster=True, verbose=True) self.server.run() app.testing = True app.config['MONGO_URI'] = self.server.uri self.app = app.test_client() def tearDown(self): self.server.stop() def test_delete_user(self): USER_REQ = OpMsg({ "find": "users", "filter": {"login": "******"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") user = { "_id": "5b37fff8bbf300b7ef185042", "login": "******", "password": "******", "role": "admin" } access_token = generate_access_token( user=user, pivate_key=app.config['PRIVATE_KEY'], auth_host=app.config['AUTH_HOST'], token_ttl=app.config['TOKEN_TTL'], auth_algo=app.config['AUTH_ALGO'] ) headers = {'Authorization': 'Bearer {}'.format(access_token['access_token'])} future = go(self.app.delete, '/auth/signup', headers=headers, json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) request = self.server.receives(USER_REQ) request.ok(cursor={'id': 0, 'firstBatch': [USER]}) self.server.receives().ok() request = self.server.receives(USER_REQ) request.ok(cursor={'id': 0, 'firstBatch': []}) self.assertEqual(future().status_code, 204) def test_nonadmin_delete(self): user = { "_id": "5b37fff8bbf300b7ef185042", "login": "******", "password": "******", "role": "regular" } access_token = generate_access_token( user=user, pivate_key=app.config['PRIVATE_KEY'], auth_host=app.config['AUTH_HOST'], token_ttl=app.config['TOKEN_TTL'], auth_algo=app.config['AUTH_ALGO'] ) headers = {'Authorization': 'Bearer {}'.format(access_token['access_token'])} future = go(self.app.delete, '/auth/signup', headers=headers, json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) self.assertEqual(future().status_code, 401) def test_delete_nonexisting_user(self): USER_REQ = OpMsg({ "find": "users", "filter": {"login": "******"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") user = { "_id": "5b37fff8bbf300b7ef185042", "login": "******", "password": "******", "role": "admin" } access_token = generate_access_token( user=user, pivate_key=app.config['PRIVATE_KEY'], auth_host=app.config['AUTH_HOST'], token_ttl=app.config['TOKEN_TTL'], auth_algo=app.config['AUTH_ALGO'] ) headers = {'Authorization': 'Bearer {}'.format(access_token['access_token'])} future = go(self.app.delete, '/auth/signup', headers=headers, json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) request = self.server.receives(USER_REQ) request.ok(cursor={'id': 0, 'firstBatch': []}) self.assertEqual(future().status_code, 400) def test_signup_valid_client_success(self): USER_REQ = OpMsg({ "find": "users", "filter": {"login": "******"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") CLIENT_REQ = OpMsg({ "find": "clients", "filter": {"client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice" ) future = go(self.app.post, '/auth/signup', json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) request = self.server.receives(CLIENT_REQ) request.ok(cursor={'id': 0, 'firstBatch': [CLIENT]}) request = self.server.receives(USER_REQ) request.ok(cursor={'id': 0, 'firstBatch': []}) self.server.receives().ok({"_id":USER["_id"]}) self.assertEqual(future().status_code, 201) def test_signup_create_existing_user(self): USER_REQ = OpMsg({ "find": "users", "filter": {"login": "******"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") CLIENT_REQ = OpMsg({ "find": "clients", "filter": {"client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice" ) future = go(self.app.post, '/auth/signup', json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) request = self.server.receives(CLIENT_REQ) request.ok(cursor={'id': 0, 'firstBatch': [CLIENT]}) request = self.server.receives(USER_REQ) request.ok(cursor={'id': 0, 'firstBatch': [USER]}) def test_signup_with_invalid_client(self): CLIENT_REQ = OpMsg({ "find": "clients", "filter": {"client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice" ) future = go(self.app.post, '/auth/signup', json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) request = self.server.receives(CLIENT_REQ) request.ok(cursor={'id': 0, 'firstBatch': []}) self.assertEqual(future().status_code, 400) def test_signup_with_invalid_email(self): USER_REQ = OpMsg({ "find": "users", "filter": {"login": "******"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") CLIENT_REQ = OpMsg({ "find": "clients", "filter": {"client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice" ) future = go(self.app.post, '/auth/signup', json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) self.assertEqual(future().status_code, 400) def test_update_invalid_email(self): user = { "_id": "5b37fff8bbf300b7ef185042", "login": "******", "password": "******", "role": "admin" } access_token = generate_access_token( user=user, pivate_key=app.config['PRIVATE_KEY'], auth_host=app.config['AUTH_HOST'], token_ttl=app.config['TOKEN_TTL'], auth_algo=app.config['AUTH_ALGO'] ) headers = {'Authorization': 'Bearer {}'.format(access_token['access_token'])} future = go(self.app.put, '/auth/signup', headers=headers, json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) self.assertEqual(future().status_code, 400) def test_update_invalid_user(self): user = { "_id": "5b37fff8bbf300b7ef185042", "login": "******", "password": "******", "role": "admin" } access_token = generate_access_token( user=user, pivate_key=app.config['PRIVATE_KEY'], auth_host=app.config['AUTH_HOST'], token_ttl=app.config['TOKEN_TTL'], auth_algo=app.config['AUTH_ALGO'] ) headers = {'Authorization': 'Bearer {}'.format(access_token['access_token'])} future = go(self.app.put, '/auth/signup', headers=headers, json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) self.server.receives().ok(cursor={'id': 0, 'firstBatch': []}) self.assertEqual(future().status_code, 400) def test_update_valid(self): USER_REQ = OpMsg({ "find": "users", "filter": {"login": "******"}, "limit": 1, "singleBatch": True, "$db": "authservice", "$readPreference": {"mode": "primaryPreferred"}}, namespace="authservice") user = { "_id": "5b37fff8bbf300b7ef185042", "login": "******", "password": "******", "role": "admin" } access_token = generate_access_token( user=user, pivate_key=app.config['PRIVATE_KEY'], auth_host=app.config['AUTH_HOST'], token_ttl=app.config['TOKEN_TTL'], auth_algo=app.config['AUTH_ALGO'] ) headers = {'Authorization': 'Bearer {}'.format(access_token['access_token'])} future = go(self.app.put, '/auth/signup', headers=headers, json={ "userID": '', "login": "******", "password": "******", "client_id": "midleware1", "client_secret": "1sfg135df1d32fsdf489d7q6sdq6s4d" }) request = self.server.receives(USER_REQ) request.ok(cursor={'id': 0, 'firstBatch': [USER]}) self.server.receives().ok() self.assertEqual(future().status_code, 400)
def test_op_insert_manipulate_false(self): # Test three aspects of legacy insert with manipulate=False: # 1. The return value is None, [None], or [None, None] as appropriate. # 2. _id is not set on the passed-in document object. # 3. _id is not sent to server. server = MockupDB(auto_ismaster=True) server.run() self.addCleanup(server.stop) client = MongoClient(server.uri) self.addCleanup(client.close) coll = client.db.get_collection('coll', write_concern=WriteConcern(w=0)) doc = {} with going(coll.insert, doc, manipulate=False) as future: if version_tuple >= (3, 7): server.receives( OpMsg(SON([("insert", coll.name), ("ordered", True), ("writeConcern", { "w": 0 }), ("documents", [{}])]), flags=OP_MSG_FLAGS['moreToCome'])) else: server.receives(OpInsert({'_id': absent})) self.assertFalse('_id' in doc) self.assertIsNone(future()) docs = [{}] # One doc in a list. with going(coll.insert, docs, manipulate=False) as future: if version_tuple >= (3, 7): # PyMongo 3.7 ordered bulk w:0 writes use implicit w:1. request = server.receives() request.assert_matches( OpMsg(SON([("insert", coll.name), ("ordered", True), ("documents", [{}])]), flags=0)) request.reply({"n": 1}) else: server.receives(OpInsert({'_id': absent})) self.assertFalse('_id' in docs[0]) self.assertEqual(future(), [None]) docs = [{}, {}] # Two docs. with going(coll.insert, docs, manipulate=False) as future: if version_tuple >= (3, 7): # PyMongo 3.7 ordered bulk w:0 writes use implicit w:1. request = server.receives() request.assert_matches( OpMsg(SON([("insert", coll.name), ("ordered", True), ("documents", [{}, {}])]), flags=0)) request.reply({"n": 2}) else: server.receives(OpInsert({'_id': absent}, {'_id': absent})) self.assertFalse('_id' in docs[0]) self.assertFalse('_id' in docs[1]) self.assertEqual(future(), [None, None])