def test_repr(self): self.assertEqual('Request()', repr(Request())) self.assertEqual('Request({})', repr(Request({}))) self.assertEqual('Request({})', repr(Request([{}]))) self.assertEqual('Request(flags=4)', repr(Request(flags=4))) self.assertEqual('OpQuery({})', repr(OpQuery())) self.assertEqual('OpQuery({})', repr(OpQuery({}))) self.assertEqual('OpQuery({})', repr(OpQuery([{}]))) self.assertEqual('OpQuery({}, flags=SlaveOkay)', repr(OpQuery(flags=4))) self.assertEqual('OpQuery({}, flags=SlaveOkay)', repr(OpQuery({}, flags=4))) self.assertEqual('OpQuery({}, flags=TailableCursor|AwaitData)', repr(OpQuery({}, flags=34))) self.assertEqual('Command({})', repr(Command())) self.assertEqual('Command({"foo": 1})', repr(Command('foo'))) son = SON([('b', 1), ('a', 1), ('c', 1)]) self.assertEqual('Command({"b": 1, "a": 1, "c": 1})', repr(Command(son))) self.assertEqual('Command({}, flags=SlaveOkay)', repr(Command(flags=4))) self.assertEqual('OpInsert({}, {})', repr(OpInsert([{}, {}]))) self.assertEqual('OpInsert({}, {})', repr(OpInsert({}, {})))
def test_bson_classes(self): _id = '5a918f9fa08bff9c7688d3e1' for a, b in [ (Binary(b'foo'), mockup_bson.Binary(b'foo')), (Code('foo'), mockup_bson.Code('foo')), (Code('foo', {'x': 1}), mockup_bson.Code('foo', {'x': 1})), (DBRef('coll', 1), mockup_bson.DBRef('coll', 1)), (DBRef('coll', 1, 'db'), mockup_bson.DBRef('coll', 1, 'db')), (Decimal128('1'), mockup_bson.Decimal128('1')), (MaxKey(), mockup_bson.MaxKey()), (MinKey(), mockup_bson.MinKey()), (ObjectId(_id), mockup_bson.ObjectId(_id)), (Regex('foo', 'i'), mockup_bson.Regex('foo', 'i')), (Timestamp(1, 2), mockup_bson.Timestamp(1, 2)), ]: # Basic case. self.assertTrue( Matcher(Command(y=b)).matches(Command(y=b)), "MockupDB %r doesn't equal itself" % (b, )) # First Command argument is special, try comparing the second also. self.assertTrue( Matcher(Command('x', y=b)).matches(Command('x', y=b)), "MockupDB %r doesn't equal itself" % (b, )) # In practice, users pass PyMongo classes in message specs. self.assertTrue( Matcher(Command(y=b)).matches(Command(y=a)), "PyMongo %r != MockupDB %r" % (a, b)) self.assertTrue( Matcher(Command('x', y=b)).matches(Command('x', y=a)), "PyMongo %r != MockupDB %r" % (a, b))
def test_projection(self): q = {} fields = {'foo': True} # OP_QUERY, server = MockupDB(auto_ismaster=True, min_wire_version=0, max_wire_version=3) server.run() self.addCleanup(server.stop) client = MongoClient(server.uri) cursor = client.test.collection.find(q, fields) with going(next, cursor): request = server.receives(OpQuery(q, fields=fields)) request.reply([], cursor_id=0) # "find" command. server = MockupDB(auto_ismaster=True, min_wire_version=0, max_wire_version=4) server.run() self.addCleanup(server.stop) client = MongoClient(server.uri) cursor = client.test.collection.find(q, fields) cmd = Command( SON([('find', 'collection'), ('filter', q), ('projection', fields)])) with going(next, cursor): request = server.receives(cmd) request.ok(cursor={'id': 0, 'firstBatch': []})
def test_getDataSource(self): # arrange id = 1 future = go(self.app.get, f'/add_icecream_id/{id}') request = self.server.receives( Command( { 'find': 'dataSources', 'filter': { '_id': id }, 'limit': 1, 'singleBatch': True }, flags=4, namespace='app')) request.ok( cursor={ 'id': 0, 'firstBatch': [{ "icecream_name": "Rassberry", "icecream_flavour": "Rassberry", "Icecream_type": "Bar", "Icecream_price": "30/-", "description": "Nice" }] }) # act http_response = future() # assert self.assertIn('http://google.com/rest/api', http_response.get_data(as_text=True))
def test_getDataSource(self): # arrange future = go(self.app.get, f'/Login-Page/{username}') request = self.server.receives( Command( { 'find': 'dataSources', 'filter': { 'username': username }, 'limit': 1, 'singleBatch': True }, flags=4, namespace='app')) request.ok( cursor={ 'firstBatch': [{ "username": "******", "password": "******"["http://http://0.0.0.0:5000/"] }] }) # act http_response = future()
def test_autoresponds_case_insensitive(self): server = MockupDB(auto_ismaster=True) # Little M. Note this is only case-insensitive because it's a Command. server.autoresponds(Command('fooBar'), foo='bar') server.run() response = MongoClient(server.uri).admin.command('Foobar') self.assertEqual('bar', response['foo'])
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_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_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_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_insert_command_manipulate_false(self): # Test same three aspects as test_op_insert_manipulate_false does, # with the "insert" command. server = MockupDB(auto_ismaster={'maxWireVersion': 2}) 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: r = server.receives(Command("insert", "coll", documents=[{}])) # MockupDB doesn't understand "absent" in subdocuments yet. self.assertFalse('_id' in r.doc['documents'][0]) r.ok() 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: r = server.receives(Command("insert", "coll", documents=[{}])) self.assertFalse('_id' in r.doc['documents'][0]) r.ok() self.assertFalse('_id' in docs[0]) self.assertEqual(future(), [None]) docs = [{}, {}] # Two docs. with going(client.db.coll.insert, docs, manipulate=False) as future: r = server.receives(Command("insert", "coll", documents=[{}, {}])) self.assertFalse('_id' in r.doc['documents'][0]) self.assertFalse('_id' in r.doc['documents'][1]) r.ok() self.assertFalse('_id' in docs[0]) self.assertFalse('_id' in docs[1]) self.assertEqual(future(), [None, None])
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 setUp(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) self.server = MockupDB(auto_ismaster={"maxWireVersion": 6}) self.server.run() self.server.autoresponds( Command("find", "switch_collection", namespace="topology_database"), { "cursor": { "id": 0, "firstBatch": [{ **d, "_id": i } for i, d in enumerate(TOPOLOGY_DATABASE_DATA)], } }, ) self._stack = AsyncExitStack() td = self._stack.enter_context(tempfile.TemporaryDirectory()) self.rpc_unix_sock = os.path.join(td, "l.sock") self._stack.enter_context( patch.object(settings, "REMOTE_DATABASE_MONGO_URI", self.server.uri)) self._stack.enter_context( patch.object(settings, "NEGOTIATOR_RPC_UNIX_SOCK_PATH", self.rpc_unix_sock)) self._stack.enter_context( patch("agile_mesh_network.ryu.amn_manager.OVSManager", DummyOVSManager)) self._stack.enter_context( # To avoid automatic connection to a relay. patch.object(settings, "IS_RELAY", True)) self._stack.enter_context( patch.object(events_scheduler, "RyuAppEventLoopScheduler")) self.ryu_ev_loop_scheduler = events_scheduler.RyuAppEventLoopScheduler( ) self._stack.enter_context(self.ryu_ev_loop_scheduler) async def command_cb(session, msg): assert isinstance(msg, RPCCommand) await self._rpc_command_cb(msg) self.rpc_server = self.loop.run_until_complete( self._stack.enter_async_context( RPCUnixServer(self.rpc_unix_sock, command_cb)))
def test_find_command(self): server = MockupDB(auto_ismaster={'maxWireVersion': 4}) server.run() self.addCleanup(server.stop) client = MongoClient(server.uri) with going(list, client.test.collection.find()) as docs: server.receives(Command).reply({'cursor': { 'id': 123, 'firstBatch': [{'a': 1}]}}) request = server.receives(Command("getMore", 123)) request.reply({'cursor': { 'id': 0, 'nextBatch': [{'a': 2}]}}, starting_from=-3) self.assertEqual([{'a': 1}, {'a': 2}], docs())
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_command_fields(self): self.assertTrue(Matcher(Command('a', b=1)).matches(Command('a', b=1))) self.assertFalse(Matcher(Command('a', b=1)).matches(Command('a', b=2)))
def test_command_first_arg(self): self.assertFalse( Matcher(Command(ismaster=1)).matches(Command(ismaster=2)))
def test_command_name_case_insensitive(self): self.assertTrue( Matcher(Command('ismaster')).matches(Command('IsMaster')))
def test_assert_matches(self): request = OpQuery({'x': 17}, flags=QUERY_FLAGS['SlaveOkay']) request.assert_matches(request) with self.assertRaises(AssertionError): request.assert_matches(Command('foo'))
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
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