def test_should_not_return_current_request_for_older_python( self, mock_log): from fastapi import FastAPI from rollbar.contrib.fastapi import get_current_request from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to try: from fastapi import Request from fastapi.testclient import TestClient except ImportError: # Added in FastAPI v0.51.0+ from starlette.requests import Request from starlette.testclient import TestClient app = FastAPI() rollbar_add_to(app) @app.get('/') async def read_root(original_request: Request): request = get_current_request() self.assertIsNone(request) self.assertNotEqual(request, original_request) mock_log.assert_called_once_with( 'Python 3.7+ (or aiocontextvars package)' ' is required to receive current request.') client = TestClient(app) client.get('/')
def test_should_report_with_request_data(self, mock_report): from fastapi import FastAPI from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to try: from fastapi import Request from fastapi.testclient import TestClient except ImportError: # Added in FastAPI v0.51.0+ from starlette.requests import Request from starlette.testclient import TestClient app = FastAPI() rollbar_add_to(app) @app.get('/') def read_root(): 1 / 0 client = TestClient(app) with self.assertRaises(ZeroDivisionError): client.get('/') mock_report.assert_called_once() request = mock_report.call_args[0][1] self.assertIsInstance(request, Request)
def test_should_use_sync_report_exc_info_if_non_async_handlers( self, sync_report_exc_info, async_report_exc_info, mock_log): from fastapi import FastAPI import rollbar from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to try: from fastapi.testclient import TestClient except ImportError: # Added in FastAPI v0.51.0+ from starlette.testclient import TestClient rollbar.SETTINGS['handler'] = 'threading' app = FastAPI() rollbar_add_to(app) @app.get('/') async def root(): 1 / 0 client = TestClient(app) with self.assertRaises(ZeroDivisionError): client.get('/') sync_report_exc_info.assert_called_once() async_report_exc_info.assert_not_called() mock_log.assert_called_once_with( 'Failed to report asynchronously. Trying to report synchronously.')
def test_should_use_async_report_exc_info_if_any_async_handler( self, sync_report_exc_info, async_report_exc_info): from fastapi import FastAPI import rollbar from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to try: from fastapi.testclient import TestClient except ImportError: # Added in FastAPI v0.51.0+ from starlette.testclient import TestClient rollbar.SETTINGS['handler'] = 'httpx' app = FastAPI() rollbar_add_to(app) @app.get('/') async def root(): 1 / 0 client = TestClient(app) with self.assertRaises(ZeroDivisionError): client.get('/') async_report_exc_info.assert_called_once() sync_report_exc_info.assert_not_called()
def test_should_catch_and_report_errors(self, mock_report): from fastapi import FastAPI from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to try: from fastapi.testclient import TestClient except ImportError: # Added in FastAPI v0.51.0+ from starlette.testclient import TestClient app = FastAPI() rollbar_add_to(app) @app.get('/') async def read_root(): 1 / 0 client = TestClient(app) with self.assertRaises(ZeroDivisionError): client.get('/') mock_report.assert_called_once() args, kwargs = mock_report.call_args self.assertEqual(kwargs, {}) exc_type, exc_value, exc_tb = args[0] self.assertEqual(exc_type, ZeroDivisionError) self.assertIsInstance(exc_value, ZeroDivisionError)
def test_should_enable_loading_route_handler_for_multiple_routers(self): from fastapi import APIRouter, FastAPI from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to from rollbar.contrib.fastapi.routing import RollbarLoggingRoute app = FastAPI() router1 = APIRouter() router2 = APIRouter() router3 = APIRouter() old_app_route_class = app.router.route_class old_router1_route_class = router1.route_class old_router2_route_class = router2.route_class old_router3_route_class = router3.route_class self.assertEqual(len(app.routes), 4) self.assertEqual(len(router1.routes), 0) self.assertEqual(len(router2.routes), 0) self.assertEqual(len(router3.routes), 0) new_router1_route_class = rollbar_add_to(router1) new_router2_route_class = rollbar_add_to(router2) self.assertNotEqual(new_router1_route_class, old_router1_route_class) self.assertNotEqual(new_router2_route_class, old_router2_route_class) self.assertEqual(router1.route_class, RollbarLoggingRoute) self.assertEqual(router2.route_class, RollbarLoggingRoute) self.assertEqual(router1.route_class, new_router1_route_class) self.assertEqual(router2.route_class, new_router2_route_class) self.assertEqual(router3.route_class, old_router3_route_class) self.assertEqual(app.router.route_class, old_app_route_class) self.assertEqual(len(app.routes), 4) self.assertEqual(len(router1.routes), 0) self.assertEqual(len(router2.routes), 0) self.assertEqual(len(router3.routes), 0) @router1.get('/') async def read1(): ... @router2.get('/') async def read2(): ... @router3.get('/') async def read3(): ... app.include_router(router1) app.include_router(router2) app.include_router(router3) self.assertEqual(router1.route_class, new_router1_route_class) self.assertEqual(router2.route_class, new_router2_route_class) self.assertEqual(router3.route_class, old_router3_route_class) self.assertEqual(len(app.routes), 7)
def test_should_store_current_request(self, store_current_request): from fastapi import FastAPI from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to try: from fastapi.testclient import TestClient except ImportError: # Added in FastAPI v0.51.0+ from starlette.testclient import TestClient expected_scope = { 'client': ['testclient', 50000], 'headers': [ (b'host', b'testserver'), (b'user-agent', b'testclient'), (b'accept-encoding', b'gzip, deflate'), (b'accept', b'*/*'), (b'connection', b'keep-alive'), ], 'http_version': '1.1', 'method': 'GET', 'path': '/', 'query_string': b'', 'root_path': '', 'scheme': 'http', 'server': ['testserver', 80], 'type': 'http', } app = FastAPI() rollbar_add_to(app) @app.get('/') async def read_root(): ... client = TestClient(app) client.get('/') store_current_request.assert_called_once() scope = store_current_request.call_args[0][0] self.assertDictContainsSubset(expected_scope, scope)
def test_should_send_payload_with_request_body(self, mock_send_payload, *mocks): from fastapi import Body, FastAPI from pydantic import BaseModel from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to try: from fastapi.testclient import TestClient except ImportError: # Added in FastAPI v0.51.0+ from starlette.testclient import TestClient rollbar.SETTINGS['include_request_body'] = True expected_body = {'param1': 'value1', 'param2': 'value2'} app = FastAPI() rollbar_add_to(app) class TestBody(BaseModel): param1: str param2: str @app.post('/') def read_root(body: TestBody = Body(...)): 1 / 0 client = TestClient(app) with self.assertRaises(ZeroDivisionError): client.post('/', json=expected_body) mock_send_payload.assert_called_once() payload = mock_send_payload.call_args[0][0] payload_request = payload['data']['request'] self.assertEqual(payload_request['method'], 'POST') self.assertEqual(payload_request['user_ip'], 'testclient') self.assertEqual(payload_request['url'], 'http://testserver/') self.assertEqual(payload_request['body'], json.dumps(expected_body)) self.assertDictEqual( payload_request['headers'], { 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'content-length': str(len(json.dumps(expected_body))), 'content-type': 'application/json', 'host': 'testserver', 'user-agent': 'testclient', }, )
def test_should_send_payload_with_form_data(self, mock_send_payload, *mocks): from fastapi import FastAPI, Form from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to try: from fastapi.testclient import TestClient except ImportError: # Added in FastAPI v0.51.0+ from starlette.testclient import TestClient expected_form = {'param1': 'value1', 'param2': 'value2'} expected_body = b'param1=value1¶m2=value2' app = FastAPI() rollbar_add_to(app) @app.post('/') def read_root(param1: str = Form(...), param2: str = Form(...)): 1 / 0 client = TestClient(app) with self.assertRaises(ZeroDivisionError): r = client.post( '/', data=expected_body, headers={'Content-Type': 'application/x-www-form-urlencoded'}, ) mock_send_payload.assert_called_once() payload = mock_send_payload.call_args[0][0] payload_request = payload['data']['request'] self.assertEqual(payload_request['method'], 'POST') self.assertEqual(payload_request['user_ip'], 'testclient') self.assertEqual(payload_request['url'], 'http://testserver/') self.assertDictEqual(payload_request['POST'], expected_form) self.assertDictEqual( payload_request['headers'], { 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'content-length': str(len(expected_body)), 'content-type': 'application/x-www-form-urlencoded', 'host': 'testserver', 'user-agent': 'testclient', }, )
def test_should_enable_loading_route_handler_before_adding_routes_to_router( self): from fastapi import APIRouter, FastAPI from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to from rollbar.contrib.fastapi.routing import RollbarLoggingRoute app = FastAPI() router = APIRouter() old_app_route_class = app.router.route_class old_router_route_class = router.route_class self.assertEqual(len(app.routes), 4) self.assertEqual(len(router.routes), 0) new_route_class = rollbar_add_to(router) self.assertNotEqual(new_route_class, old_router_route_class) self.assertEqual(router.route_class, new_route_class) self.assertEqual(router.route_class, RollbarLoggingRoute) self.assertEqual(app.router.route_class, old_app_route_class) self.assertEqual(len(app.routes), 4) self.assertEqual(len(router.routes), 0) @router.get('/') async def read_root(): ... app.include_router(router) self.assertEqual(router.route_class, new_route_class) self.assertEqual(len(app.routes), 5)
def test_should_disable_loading_route_handler_after_adding_routes_to_router( self, mock_log): from fastapi import APIRouter, FastAPI from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to app = FastAPI() router = APIRouter() old_app_route_class = app.router.route_class old_router_route_class = router.route_class self.assertEqual(len(app.routes), 4) self.assertEqual(len(router.routes), 0) @router.get('/') async def read_root(): ... app.include_router(router) self.assertEqual(len(app.routes), 5) self.assertEqual(len(router.routes), 1) new_route_class = rollbar_add_to(app) self.assertEqual(len(app.routes), 5) self.assertEqual(len(router.routes), 1) self.assertIsNone(new_route_class) self.assertEqual(app.router.route_class, old_app_route_class) self.assertEqual(router.route_class, old_router_route_class) mock_log.assert_called_once_with( 'RollbarLoggingRoute must to be added to a bare router' ' (before adding routes). See docs for more details.')
def test_should_send_payload_with_request_data(self, mock_send_payload, *mocks): from fastapi import FastAPI from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to try: from fastapi.testclient import TestClient except ImportError: # Added in FastAPI v0.51.0+ from starlette.testclient import TestClient app = FastAPI() rollbar_add_to(app) @app.get('/{path}') def read_root(path): 1 / 0 client = TestClient(app) with self.assertRaises(ZeroDivisionError): client.get('/test?param1=value1¶m2=value2') mock_send_payload.assert_called_once() payload = mock_send_payload.call_args[0][0] payload_request = payload['data']['request'] self.assertEqual(payload_request['method'], 'GET') self.assertEqual(payload_request['user_ip'], 'testclient') self.assertEqual( payload_request['url'], 'http://testserver/test?param1=value1¶m2=value2', ) self.assertDictEqual(payload_request['params'], {'path': 'test'}) self.assertDictEqual(payload_request['GET'], { 'param1': 'value1', 'param2': 'value2' }) self.assertDictEqual( payload_request['headers'], { 'accept': '*/*', 'accept-encoding': 'gzip, deflate', 'connection': 'keep-alive', 'host': 'testserver', 'user-agent': 'testclient', }, )
def test_should_add_framework_version_to_payload(self, mock_send_payload, *mocks): import fastapi from fastapi import FastAPI import rollbar from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to self.assertIsNone(rollbar.BASE_DATA_HOOK) app = FastAPI() rollbar_add_to(app) rollbar.report_exc_info() mock_send_payload.assert_called_once() payload = mock_send_payload.call_args[0][0] self.assertIn('fastapi', payload['data']['framework']) self.assertIn(fastapi.__version__, payload['data']['framework'])
def test_should_warn_if_middleware_in_use(self): from fastapi import FastAPI from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to from rollbar.contrib.fastapi import ReporterMiddleware as FastAPIMiddleware from rollbar.contrib.starlette import ReporterMiddleware as StarletteMiddleware from rollbar.contrib.asgi import ReporterMiddleware as ASGIMiddleware for middleware in (FastAPIMiddleware, StarletteMiddleware, ASGIMiddleware): with mock.patch('logging.Logger.warning') as mock_log: app = FastAPI() app.add_middleware(middleware) rollbar_add_to(app) mock_log.assert_called_once_with( f'Detected middleware installed {[middleware]}' ' while loading Rollbar route handler.' ' This can cause in duplicate occurrences.')
def test_should_disable_loading_route_handler_if_fastapi_is_too_old(self): import logging import fastapi from fastapi import FastAPI from fastapi.routing import APIRoute from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to from rollbar.contrib.fastapi.utils import FastAPIVersionError logging.disable(logging.ERROR) # silent logger for tests fastapi_version = fastapi.__version__ app = FastAPI() old_route_class = app.router.route_class self.assertEqual(old_route_class, APIRoute) fastapi.__version__ = '0' with self.assertRaises(FastAPIVersionError): rollbar_add_to(app) fastapi.__version__ = '0.30.3' with self.assertRaises(FastAPIVersionError): rollbar_add_to(app) fastapi.__version__ = '0.40.10' with self.assertRaises(FastAPIVersionError): rollbar_add_to(app) self.assertEqual(app.router.route_class, old_route_class) logging.disable(logging.NOTSET) # make sure logger is re-enabled fastapi.__version__ = fastapi_version
def test_should_return_current_request(self): from fastapi import FastAPI from rollbar.contrib.fastapi import get_current_request from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to try: from fastapi import Request from fastapi.testclient import TestClient except ImportError: # Added in FastAPI v0.51.0+ from starlette.requests import Request from starlette.testclient import TestClient app = FastAPI() rollbar_add_to(app) @app.get('/') async def read_root(original_request: Request): request = get_current_request() self.assertEqual(request, original_request) client = TestClient(app) client.get('/')
def test_should_enable_loading_route_handler_for_fastapi_router(self): from fastapi import APIRouter from fastapi.routing import APIRoute from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to from rollbar.contrib.fastapi.routing import RollbarLoggingRoute router = APIRouter() old_route_class = router.route_class self.assertEqual(old_route_class, APIRoute) new_route_class = rollbar_add_to(router) self.assertNotEqual(new_route_class, old_route_class) self.assertEqual(router.route_class, RollbarLoggingRoute) self.assertEqual(router.route_class, new_route_class)
def test_should_disable_loading_route_handler_for_unknown_router( self, mock_log): from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to class UnknownRouter: routes = [] route_class = None router = UnknownRouter() old_route_class = router.route_class new_route_class = rollbar_add_to(router) self.assertIsNone(new_route_class) self.assertEqual(router.route_class, old_route_class) mock_log.assert_called_once_with( 'Error adding RollbarLoggingRoute to application.')
def test_should_enable_loading_route_handler_if_fastapi_version_is_sufficient( self): from fastapi import FastAPI from fastapi.routing import APIRoute from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to from rollbar.contrib.fastapi.routing import RollbarLoggingRoute self.assertTrue(ALLOWED_FASTAPI_VERSION) app = FastAPI() old_route_class = app.router.route_class self.assertEqual(old_route_class, APIRoute) new_route_class = rollbar_add_to(app) self.assertNotEqual(new_route_class, old_route_class) self.assertEqual(app.router.route_class, new_route_class) self.assertEqual(app.router.route_class, RollbarLoggingRoute)
def test_should_enable_loading_route_handler_before_adding_routes_to_app( self): from fastapi import FastAPI from rollbar.contrib.fastapi.routing import add_to as rollbar_add_to from rollbar.contrib.fastapi.routing import RollbarLoggingRoute app = FastAPI() old_route_class = app.router.route_class self.assertEqual(len(app.routes), 4) new_route_class = rollbar_add_to(app) self.assertNotEqual(new_route_class, old_route_class) self.assertEqual(app.router.route_class, new_route_class) self.assertEqual(len(app.routes), 4) @app.get('/') async def read_root(): ... self.assertEqual(app.router.route_class, new_route_class) self.assertEqual(app.router.route_class, RollbarLoggingRoute) self.assertEqual(len(app.routes), 5)