# Path: bugsnag/asgi.py
# class BugsnagMiddleware:
#     """
#     Sends unhandled exceptions to Bugsnag which happen while processing
#     requests.
# 
#     >>> async def app(scope, receive, send):
#     ...     await send({
#     ...         "type": "http.request",
#     ...         "body": b"Hello World",
#     ...         "more_body": False,
#     ...     })
#     >>> app = BugsnagMiddleware(app)
#     """
#     def __init__(self, app):
#         self.app = app
#         stack = bugsnag.configure().internal_middleware
# 
#         def add_request_info(event):
#             if not hasattr(event.request_config, 'asgi_scope'):
#                 return
# 
#             scope = event.request_config.asgi_scope
#             request = dict()
#             server = []
# 
#             client = scope.get('client')
#             if client is not None and len(client) > 0:
#                 request['clientIp'] = scope['client'][0]
# 
#             if 'server' in scope and type(scope['server']) in [list, tuple]:
#                 server = scope['server']
#             if 'headers' in scope:
#                 request['headers'] = dict(
#                         [i for i in scope['headers'] if len(i) == 2])
#             for prop in RequestMetadata:
#                 for item in prop.scope_keys:
#                     if item in scope:
#                         request[prop.metadata_key] = scope[item]
#                         break
# 
#             request['url'] = parse_url(request, server)
# 
#             event.add_tab("request", request)
#             if bugsnag.configure().send_environment:
#                 event.add_tab("environment", scope)
# 
#         stack.before_notify(add_request_info)
# 
#     async def __call__(self, scope, receive, send):
#         bugsnag.configure()._breadcrumbs.create_copy_for_context()
#         bugsnag.configure_request(asgi_scope=scope)
#         try:
#             if bugsnag.configuration.auto_capture_sessions:
#                 bugsnag.start_session()
# 
#             # only HTTP and Websocket requests have headers
#             if scope['type'] in ('http', 'websocket'):
#                 _auto_leave_breadcrumb(
#                     '{} request'.format(scope['type']),
#                     _get_breadcrumb_metadata(scope),
#                     BreadcrumbType.NAVIGATION
#                 )
# 
#             await self.app(scope, receive, send)
#         except Exception as e:
#             bugsnag.auto_notify(e, severity_reason=SEVERITY_REASON)
#             raise
# 
# Path: bugsnag/breadcrumbs.py
# class BreadcrumbType(Enum):
#     NAVIGATION = 'navigation'
#     REQUEST = 'request'
#     PROCESS = 'process'
#     LOG = 'log'
#     USER = 'user'
#     STATE = 'state'
#     ERROR = 'error'
#     MANUAL = 'manual'
# 
# Path: tests/utils.py
# class IntegrationTest(unittest.TestCase):
# 
#     @classmethod
#     def setUpClass(cls):
#         cls.server = FakeBugsnagServer()
# 
#     def setUp(self):
#         self.server.received = []
# 
#     def tearDown(self):
#         bugsnag.legacy.default_client.uninstall_sys_hook()
#         client = bugsnag.Client()
#         client.configuration.api_key = 'some key'
#         bugsnag.legacy.default_client = client
#         bugsnag.legacy.configuration = client.configuration
# 
#     @classmethod
#     def tearDownClass(cls):
#         cls.server.shutdown()
# 
#     def assertSentReportCount(self, count):
#         self.assertEqual(len(self.server.received), count)
# 
#     def assertExceptionName(self, received_index, event_index, name):
#         json_body = self.server.received[received_index]['json_body']
#         event = json_body['events'][event_index]
#         exception = event['exceptions'][0]
#         self.assertEqual(exception['errorClass'], name)
# 
#     @property
#     def sent_report_count(self) -> int:
#         return len(self.server.received)
# 
# class ScaryException(Exception):
#     pass


from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
from starlette.testclient import TestClient
from starlette.websockets import WebSocket
from bugsnag.asgi import BugsnagMiddleware
from bugsnag.breadcrumbs import BreadcrumbType
from tests.utils import IntegrationTest, ScaryException
import bugsnag
import pytest

        payload = self.server.received[0]['json_body']
        metadata = payload['events'][0]['metaData']
        request = metadata['request']
        self.assertEqual('/', request['path'])
        self.assertEqual('GET', request['httpMethod'])
        self.assertEqual('http', request['type'])
        self.assertEqual('http://testserver/', request['url'])
        self.assertEqual('35b', metadata['wave']['size'])

        exception = payload['events'][0]['exceptions'][0]
        self.assertEqual('tests.utils.ScaryException', exception['errorClass'])
        self.assertEqual('fell winds!', exception['message'])
        self.assertEqual('next_func', exception['stacktrace'][0]['method'])
        self.assertEqual('index', exception['stacktrace'][1]['method'])

        breadcrumbs = payload['events'][0]['breadcrumbs']

        assert len(breadcrumbs) == 1
        assert breadcrumbs[0]['name'] == 'http request'
        assert breadcrumbs[0]['metaData'] == {'to': '/'}
        assert breadcrumbs[0]['type'] == BreadcrumbType.NAVIGATION.value

    def test_websocket_crash(self):
        async def app(scope, receive, send):
            websocket = WebSocket(scope, receive=receive, send=send)
            await websocket.accept()
            raise ScaryException('invalid inputs')
            await websocket.close()


# Path: bugsnag/asgi.py
# class BugsnagMiddleware:
#     """
#     Sends unhandled exceptions to Bugsnag which happen while processing
#     requests.
# 
#     >>> async def app(scope, receive, send):
#     ...     await send({
#     ...         "type": "http.request",
#     ...         "body": b"Hello World",
#     ...         "more_body": False,
#     ...     })
#     >>> app = BugsnagMiddleware(app)
#     """
#     def __init__(self, app):
#         self.app = app
#         stack = bugsnag.configure().internal_middleware
# 
#         def add_request_info(event):
#             if not hasattr(event.request_config, 'asgi_scope'):
#                 return
# 
#             scope = event.request_config.asgi_scope
#             request = dict()
#             server = []
# 
#             client = scope.get('client')
#             if client is not None and len(client) > 0:
#                 request['clientIp'] = scope['client'][0]
# 
#             if 'server' in scope and type(scope['server']) in [list, tuple]:
#                 server = scope['server']
#             if 'headers' in scope:
#                 request['headers'] = dict(
#                         [i for i in scope['headers'] if len(i) == 2])
#             for prop in RequestMetadata:
#                 for item in prop.scope_keys:
#                     if item in scope:
#                         request[prop.metadata_key] = scope[item]
#                         break
# 
#             request['url'] = parse_url(request, server)
# 
#             event.add_tab("request", request)
#             if bugsnag.configure().send_environment:
#                 event.add_tab("environment", scope)
# 
#         stack.before_notify(add_request_info)
# 
#     async def __call__(self, scope, receive, send):
#         bugsnag.configure()._breadcrumbs.create_copy_for_context()
#         bugsnag.configure_request(asgi_scope=scope)
#         try:
#             if bugsnag.configuration.auto_capture_sessions:
#                 bugsnag.start_session()
# 
#             # only HTTP and Websocket requests have headers
#             if scope['type'] in ('http', 'websocket'):
#                 _auto_leave_breadcrumb(
#                     '{} request'.format(scope['type']),
#                     _get_breadcrumb_metadata(scope),
#                     BreadcrumbType.NAVIGATION
#                 )
# 
#             await self.app(scope, receive, send)
#         except Exception as e:
#             bugsnag.auto_notify(e, severity_reason=SEVERITY_REASON)
#             raise
# 
# Path: bugsnag/breadcrumbs.py
# class BreadcrumbType(Enum):
#     NAVIGATION = 'navigation'
#     REQUEST = 'request'
#     PROCESS = 'process'
#     LOG = 'log'
#     USER = 'user'
#     STATE = 'state'
#     ERROR = 'error'
#     MANUAL = 'manual'
# 
# Path: tests/utils.py
# class IntegrationTest(unittest.TestCase):
# 
#     @classmethod
#     def setUpClass(cls):
#         cls.server = FakeBugsnagServer()
# 
#     def setUp(self):
#         self.server.received = []
# 
#     def tearDown(self):
#         bugsnag.legacy.default_client.uninstall_sys_hook()
#         client = bugsnag.Client()
#         client.configuration.api_key = 'some key'
#         bugsnag.legacy.default_client = client
#         bugsnag.legacy.configuration = client.configuration
# 
#     @classmethod
#     def tearDownClass(cls):
#         cls.server.shutdown()
# 
#     def assertSentReportCount(self, count):
#         self.assertEqual(len(self.server.received), count)
# 
#     def assertExceptionName(self, received_index, event_index, name):
#         json_body = self.server.received[received_index]['json_body']
#         event = json_body['events'][event_index]
#         exception = event['exceptions'][0]
#         self.assertEqual(exception['errorClass'], name)
# 
#     @property
#     def sent_report_count(self) -> int:
#         return len(self.server.received)
# 
# class ScaryException(Exception):
#     pass


# Path: tests/integrations/test_asgi.py
from starlette.applications import Starlette
from starlette.responses import PlainTextResponse
from starlette.testclient import TestClient
from starlette.websockets import WebSocket
from bugsnag.asgi import BugsnagMiddleware
from bugsnag.breadcrumbs import BreadcrumbType
from tests.utils import IntegrationTest, ScaryException
import bugsnag
import pytest


        payload = self.server.received[0]['json_body']
        metadata = payload['events'][0]['metaData']
        request = metadata['request']
        self.assertEqual('/', request['path'])
        self.assertEqual('GET', request['httpMethod'])
        self.assertEqual('http', request['type'])
        self.assertEqual('http://testserver/', request['url'])
        self.assertEqual('35b', metadata['wave']['size'])

        exception = payload['events'][0]['exceptions'][0]
        self.assertEqual('tests.utils.ScaryException', exception['errorClass'])
        self.assertEqual('fell winds!', exception['message'])
        self.assertEqual('next_func', exception['stacktrace'][0]['method'])
        self.assertEqual('index', exception['stacktrace'][1]['method'])

        breadcrumbs = payload['events'][0]['breadcrumbs']

        assert len(breadcrumbs) == 1
        assert breadcrumbs[0]['name'] == 'http request'
        assert breadcrumbs[0]['metaData'] == {'to': '/'}
        assert breadcrumbs[0]['type'] == BreadcrumbType.NAVIGATION.value

    def test_websocket_crash(self):
        async def app(scope, receive, send):
            websocket = WebSocket(scope, receive=receive, send=send)
            await websocket.accept()
            raise ScaryException('invalid inputs')
            await websocket.close()


        app = TestClient(BugsnagMiddleware(app))