async def test_store(app, client, store, client_mock): await store.startup(app) assert store.active assert not store.volatile assert store.rev is None default_length = len(datastore.SYS_OBJECTS) read_length = default_length + len( read_objects()) - 1 # overlapping item is merged assert len(store.items()) == default_length await datastore.check_remote(app) await store.read('doc') assert len(store.items()) == read_length assert store.rev == 'rev_read' # Defaults were added to read objects, so those were flushed await asyncio.sleep(0.05) assert client_mock.write.call_count == 1 assert store.rev == 'rev_write' # write on add store['inserted', 9001] = 'val' await asyncio.sleep(0.05) assert client_mock.write.call_count == 2 assert len(store.items()) == read_length + 1 # write on delete del store['inserted', 9001] assert len(store.items()) == read_length await asyncio.sleep(0.05) assert client_mock.write.call_count == 3 # handle read error client_mock.read.side_effect = return_once(RuntimeError, then=('rev_read', read_objects())) with pytest.warns(UserWarning, match='read error'): await store.read('doc') assert store.rev is None assert store.document is None with pytest.warns(UserWarning, match='flush error'): await asyncio.sleep(0.05) # reset to normal await store.read('doc') # continue on write error with pytest.warns(UserWarning, match='flush error'): client_mock.write.side_effect = return_once(RuntimeError, then='rev_write') store['inserted2', 9002] = 'val' await asyncio.sleep(0.05) assert client_mock.write.call_count == 5 # write on shutdown store['inserted3', 9003] = 'val' await store.shutdown(app) assert client_mock.write.call_count == 6
async def test_config(app, client, config, client_mock): def vals(): return {'k1': 1, 'k2': 2} client_mock.read.return_value = ('rev_read', vals()) await config.startup(app) assert config.active assert config.rev is None cb = Mock() config.subscribe(cb) with config.open() as cfg: cfg['key'] = 'val' with config.open() as cfg: assert 'key' in cfg # values are cleared when reading await config.read('doc') cb.assert_called_once_with(vals()) assert config.rev == 'rev_read' assert client_mock.write.call_count == 0 with config.open() as cfg: assert cfg == vals() cfg['key'] = 'val' await asyncio.sleep(0.05) assert config.rev == 'rev_write' assert client_mock.write.call_count == 1 # handle read error client_mock.read.side_effect = return_once(RuntimeError, then=('rev_read', vals())) with pytest.warns(UserWarning, match='read error'): await config.read('doc') assert config.rev is None assert config.document is None with config.open() as cfg: assert cfg == {} cfg['key'] = 'val' with pytest.warns(UserWarning, match='flush error'): await asyncio.sleep(0.05) # reset to normal await config.read('doc') # continue on write error with pytest.warns(UserWarning, match='flush error'): client_mock.write.side_effect = return_once(RuntimeError, then='rev_write') with config.open() as cfg: cfg['insert'] = 'outsert' await asyncio.sleep(0.05) assert client_mock.write.call_count == 3
async def test_granular_poll_access(query_kind, app, access_token_builder, dummy_zmq_server): """ Test that tokens grant granular access to checking query status. """ client, db, log_dir = app token = access_token_builder({query_kind: {"permissions": {"poll": True}}}) expected_responses = dict.fromkeys(query_kinds, 401) expected_responses[query_kind] = 303 responses = {} for q_kind in query_kinds: dummy_zmq_server.side_effect = return_once( { "id": 10, "query_kind": q_kind }, then={ "id": 10, "status": "done" }) response = await client.get( f"/api/0/poll/0", headers={"Authorization": f"Bearer {token}"}, json={"query_kind": q_kind}, ) responses[q_kind] = response.status_code assert expected_responses == responses
async def test_poll_bad_query(app, access_token_builder, dummy_zmq_server): """ Test that correct status code and any redirect is returned when polling a running query """ client, db, log_dir, app = app token = access_token_builder({ "modal_location": { "permissions": { "poll": True }, "spatial_aggregation": ["DUMMY_AGGREGATION"], } }) dummy_zmq_server.side_effect = return_once( ZMQReply( status="error", msg=f"Unknown query id: 'DUMMY_QUERY_ID'", payload={ "query_id": "DUMMY_QUERY_ID", "query_state": "awol" }, ).as_json()) response = await client.get(f"/api/0/poll/DUMMY_QUERY_ID", headers={"Authorization": f"Bearer {token}"}) assert response.status_code == 404
async def test_poll_query_query_error(app, access_token_builder, dummy_zmq_server): """ Test that correct status code and any redirect is returned when polling a query that errored """ client, db, log_dir, app = app token = access_token_builder( {"modal_location": { "permissions": { "poll": True } }}) # TODO: Fix the logic that makes this necessary dummy_zmq_server.side_effect = return_once( ZMQReply( status="success", payload={ "query_id": "DUMMY_QUERY_ID", "query_kind": "modal_location" }, ).as_json(), then=ZMQReply( status="error", payload={ "query_id": "DUMMY_QUERY_ID", "query_state": "error" }, ).as_json(), ) response = await client.get(f"/api/0/poll/DUMMY_QUERY_ID", headers={"Authorization": f"Bearer {token}"}) assert response.status_code == 500
async def test_poll_query(status, http_code, app, dummy_zmq_server, access_token_builder): """ Test that correct status code and any redirect is returned when polling a running query """ client, db, log_dir = app token = access_token_builder( {"modal_location": { "permissions": { "poll": True } }}) dummy_zmq_server.side_effect = return_once( { "id": 0, "query_kind": "modal_location" }, then={ "status": status, "id": 0 }) response = await client.get(f"/api/0/poll/0", headers={"Authorization": f"Bearer {token}"}) assert response.status_code == http_code if status == "done": assert "/api/0/get/0" == response.headers["Location"]
async def test_method__poll_with_reconnect_when_droped(self): with patch('ethereumd.poller.Poller.poll'): poller = Poller(self.rpc_proxy) with patch.object(AsyncIOHTTPClient, '_call', side_effect=return_once( lambda: BadResponseError('test', code=-99999999), then=fake_call())): poller._pending = '0x6f4111062b3db311e6521781f4ef0046' await poller._poll_with_reconnect('pending')
async def test_poll_query(query_state, http_code, app, access_token_builder, dummy_zmq_server): """ Test that correct status code and any redirect is returned when polling a running query """ client, db, log_dir, app = app token = access_token_builder({ "modal_location": { "permissions": { "poll": True }, "spatial_aggregation": ["DUMMY_AGGREGATION"], } }) # The replies below are in response to the following messages: # - get_query_kind # - poll_query # # {'status': 'done', 'msg': '', 'payload': {'query_id': '5ffe4a96dbe33a117ae9550178b81836', 'query_kind': 'modal_location'}} # {'status': 'done', 'msg': '', 'payload': {'query_id': '5ffe4a96dbe33a117ae9550178b81836', 'query_kind': 'modal_location', 'query_state': 'completed'}} # dummy_zmq_server.side_effect = return_once( ZMQReply( status="success", payload={ "query_id": "DUMMY_QUERY_ID", "query_params": { "query_kind": "modal_location", "aggregation_unit": "DUMMY_AGGREGATION", }, }, ).as_json(), then=ZMQReply( status="success", payload={ "query_id": "DUMMY_QUERY_ID", "query_state": query_state }, ).as_json(), ) response = await client.get(f"/api/0/poll/DUMMY_QUERY_ID", headers={"Authorization": f"Bearer {token}"}) assert response.status_code == http_code if query_state == "success": assert "/api/0/get/DUMMY_QUERY_ID" == response.headers["Location"]
async def test_poll_query(action_right, query_state, http_code, app, access_token_builder, dummy_zmq_server): """ Test that correct status code and any redirect is returned when polling a running query """ token = access_token_builder( [f"{action_right}&modal_location.aggregation_unit.DUMMY_AGGREGATION"]) # The replies below are in response to the following messages: # - get_query_kind # - poll_query # # {'status': 'done', 'msg': '', 'payload': {'query_id': '5ffe4a96dbe33a117ae9550178b81836', 'query_kind': 'modal_location'}} # {'status': 'done', 'msg': '', 'payload': {'query_id': '5ffe4a96dbe33a117ae9550178b81836', 'query_kind': 'modal_location', 'query_state': 'completed'}} # dummy_zmq_server.side_effect = return_once( ZMQReply( status="success", payload={ "query_id": "DUMMY_QUERY_ID", "query_params": { "query_kind": "modal_location", "aggregation_unit": "DUMMY_AGGREGATION", }, }, ), then=ZMQReply( status="success", payload={ "query_id": "DUMMY_QUERY_ID", "query_state": query_state, "progress": { "eligible": 0, "queued": 0, "executing": 0 }, }, ), ) response = await app.client.get( f"/api/0/poll/DUMMY_QUERY_ID", headers={"Authorization": f"Bearer {token}"}) assert response.status_code == http_code if query_state == "success": assert "/api/0/get/DUMMY_QUERY_ID" == response.headers["Location"]
async def test_poll_bad_query(app, access_token_builder, dummy_zmq_server): """ Test that correct status code and any redirect is returned when polling a running query """ token = token = access_token_builder( [f"run&modal_location.aggregation_unit.DUMMY_AGGREGATION"]) dummy_zmq_server.side_effect = return_once( ZMQReply( status="error", msg=f"Unknown query id: 'DUMMY_QUERY_ID'", payload={ "query_id": "DUMMY_QUERY_ID", "query_state": "awol" }, )) response = await app.client.get( f"/api/0/poll/DUMMY_QUERY_ID", headers={"Authorization": f"Bearer {token}"}) assert response.status_code == 404