oncall-engine/engine/apps/api/tests
Joey Orlando fa071bcd6e
chore: add pytest-socket library + disable network calls in tests (#5315)
# What this PR does

Inspired by [this
discussion](https://github.com/grafana/oncall/pull/5307#discussion_r1862449480).
_tldr;_ ensures that if any of our tests try making an external network
call, they will fail.

Setup an example test:

```python
def test_external_network_call():
    import requests

    response = requests.get('https://www.example.com')
    assert response.status_code == 200
```

and it worked (failed; [example CI test
run](https://github.com/grafana/oncall/actions/runs/12106416991/job/33752144727?pr=5315#step:6:389))
as expected:

```bash
__________________________ test_external_network_call __________________________
    def test_external_network_call():
        import requests
    
>       response = requests.get('https://www.example.com')
requests   = <module 'requests' from '/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/requests/__init__.py'>
apps/test_joey.py:4: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/requests/api.py:73: in get
    return request("get", url, params=params, **kwargs)
        kwargs     = {}
        params     = None
        url        = 'https://www.example.com'
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/requests/api.py:59: in request
    return session.request(method=method, url=url, **kwargs)
        kwargs     = {'params': None}
        method     = 'get'
        session    = <requests.sessions.Session object at 0x7f10ebaada90>
        url        = 'https://www.example.com'
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
        allow_redirects = True
        auth       = None
        cert       = None
        cookies    = None
        data       = None
        files      = None
        headers    = None
        hooks      = None
        json       = None
        method     = 'get'
        params     = None
        prep       = <PreparedRequest [GET]>
        proxies    = {}
        req        = <Request [GET]>
        self       = <requests.sessions.Session object at 0x7f10ebaada90>
        send_kwargs = {'allow_redirects': True, 'cert': None, 'proxies': OrderedDict(), 'stream': False, ...}
        settings   = {'cert': None, 'proxies': OrderedDict(), 'stream': False, 'verify': True}
        stream     = None
        timeout    = None
        url        = 'https://www.example.com'
        verify     = None
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
        adapter    = <requests.adapters.HTTPAdapter object at 0x7f10ebaada30>
        allow_redirects = True
        hooks      = {'response': []}
        kwargs     = {'cert': None, 'proxies': OrderedDict(), 'stream': False, 'timeout': None, ...}
        request    = <PreparedRequest [GET]>
        self       = <requests.sessions.Session object at 0x7f10ebaada90>
        start      = 1733064371.649901
        stream     = False
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/requests/adapters.py:667: in send
    resp = conn.urlopen(
        cert       = None
        chunked    = False
        conn       = <urllib3.connectionpool.HTTPSConnectionPool object at 0x7f10ebaadd30>
        proxies    = OrderedDict()
        request    = <PreparedRequest [GET]>
        self       = <requests.adapters.HTTPAdapter object at 0x7f10ebaada30>
        stream     = False
        timeout    = Timeout(connect=None, read=None, total=None)
        url        = '/'
        verify     = True
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:715: in urlopen
    httplib_response = self._make_request(
        assert_same_host = False
        body       = None
        body_pos   = None
        chunked    = False
        clean_exit = False
        conn       = None
        destination_scheme = None
        err        = None
        headers    = {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}
        http_tunnel_required = False
        is_new_proxy_conn = False
        method     = 'GET'
        parsed_url = Url(scheme=None, auth=None, host=None, port=None, path='/', query=None, fragment=None)
        pool_timeout = None
        redirect   = False
        release_conn = False
        release_this_conn = True
        response_kw = {'decode_content': False, 'preload_content': False}
        retries    = Retry(total=0, connect=None, read=False, redirect=None, status=None)
        self       = <urllib3.connectionpool.HTTPSConnectionPool object at 0x7f10ebaadd30>
        timeout    = Timeout(connect=None, read=None, total=None)
        timeout_obj = Timeout(connect=None, read=None, total=None)
        url        = '/'
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:404: in _make_request
    self._validate_conn(conn)
        chunked    = False
        conn       = <urllib3.connection.HTTPSConnection object at 0x7f10ebaadd60>
        httplib_request_kw = {'body': None, 'headers': {'User-Agent': 'python-requests/2.32.3', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive'}}
        method     = 'GET'
        self       = <urllib3.connectionpool.HTTPSConnectionPool object at 0x7f10ebaadd30>
        timeout    = Timeout(connect=None, read=None, total=None)
        timeout_obj = Timeout(connect=None, read=None, total=None)
        url        = '/'
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/urllib3/connectionpool.py:1060: in _validate_conn
    conn.connect()
        __class__  = <class 'urllib3.connectionpool.HTTPSConnectionPool'>
        conn       = <urllib3.connection.HTTPSConnection object at 0x7f10ebaadd60>
        self       = <urllib3.connectionpool.HTTPSConnectionPool object at 0x7f10ebaadd30>
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/urllib3/connection.py:363: in connect
    self.sock = conn = self._new_conn()
        self       = <urllib3.connection.HTTPSConnection object at 0x7f10ebaadd60>
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/urllib3/connection.py:174: in _new_conn
    conn = connection.create_connection(
        extra_kw   = {'socket_options': [(6, 1, 1)]}
        self       = <urllib3.connection.HTTPSConnection object at 0x7f10ebaadd60>
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/urllib3/util/connection.py:85: in create_connection
    sock.connect(sa)
        address    = ('www.example.com', 443)
        af         = <AddressFamily.AF_INET: 2>
        canonname  = ''
        err        = None
        family     = <AddressFamily.AF_UNSPEC: 0>
        host       = 'www.example.com'
        port       = 443
        proto      = 6
        res        = (<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('93.184.215.14', 443))
        sa         = ('93.184.215.14', 443)
        sock       = <socket.socket fd=12, family=2, type=1, proto=6, laddr=('0.0.0.0', 0)>
        socket_options = [(6, 1, 1)]
        socktype   = <SocketKind.SOCK_STREAM: 1>
        source_address = None
        timeout    = None
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
inst = <socket.socket fd=12, family=2, type=1, proto=6, laddr=('0.0.0.0', 0)>
args = (('93.184.215.14', 443),), host = '93.184.215.14'
    def guarded_connect(inst, *args):
        host = host_from_connect_args(args)
        if host in allowed_ip_hosts_and_hostnames or (
            _is_unix_socket(inst.family) and allow_unix_socket
        ):
            return _true_connect(inst, *args)
    
>       raise SocketConnectBlockedError(allowed_list, host)
E       pytest_socket.SocketConnectBlockedError: A test tried to use socket.socket.connect() with host "93.184.215.14" (allowed: "calendar.google.com (142.251.167.100,142.251.167.101,142.251.167.102,142.251.167.113,142.251.167.138,142.251.167.139,2607:f8b0:4004:c09::65,2607:f8b0:4004:c09::66,2607:f8b0:4004:c09::71,2607:f8b0:4004:c09::8b),localhost (127.0.0.1,::1),oncall-dev-mariadb ()").
allow_unix_socket = False
allowed_ip_hosts_and_hostnames = {'127.0.0.1', '142.251.167.100', '142.251.167.101', '142.251.167.102', '142.251.167.113', '142.251.167.138', ...}
allowed_list = ['calendar.google.com (142.251.167.100,142.251.167.101,142.251.167.102,142.251.167.113,142.251.167.138,142.251.167.139...8b0:4004:c09::66,2607:f8b0:4004:c09::71,2607:f8b0:4004:c09::8b)', 'localhost (127.0.0.1,::1)', 'oncall-dev-mariadb ()']
args       = (('93.184.215.14', 443),)
host       = '93.184.215.14'
inst       = <socket.socket fd=12, family=2, type=1, proto=6, laddr=('0.0.0.0', 0)>
/opt/hostedtoolcache/Python/3.12.3/x64/lib/python3.12/site-packages/pytest_socket.py:252: SocketConnectBlockedError
```

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
    show up in the autogenerated release notes.
2024-12-02 10:53:18 -05:00
..
__init__.py World, meet OnCall! 2022-06-03 08:09:47 -06:00
conftest.py chore: random slack code cleanup (#5307) 2024-11-29 13:21:29 +00:00
test_alert_group.py Reworked declare incident escalation step (#5130) 2024-10-07 19:26:10 +00:00
test_alert_group_escalation_snapshot.py cleanup CustomButton backend code + add ngrok/express outgoing webhook e2e test (#2544) 2024-03-28 15:37:22 +00:00
test_alert_group_table_settings.py Fix alert group columns validation (#3577) 2023-12-15 17:15:50 +00:00
test_alert_receive_channel.py chore: random slack code cleanup (#5307) 2024-11-29 13:21:29 +00:00
test_alert_receive_channel_template.py Adds new templates cheatsheats (#3643) 2024-01-17 13:49:36 +00:00
test_auth.py update URLs constructed by the backend to support IRM plugin (#5137) 2024-10-09 08:55:10 -04:00
test_channel_filter.py chore: fix some minor issues with recent slack_channel changes (#5228) 2024-11-05 04:51:04 -05:00
test_direct_paging.py add POST /escalation public API endpoint + add public API docs for teams/organization endpoints (#4815) 2024-08-15 18:31:35 +00:00
test_escalation_chain.py Fix team changing on PUT request if team is not in request data (#3530) 2023-12-07 14:44:52 +00:00
test_escalation_policy.py Add openAPI schema for some internal endpoints (#5037) 2024-10-24 09:24:36 +00:00
test_features.py Improve OpenAPI schema coverage (#3629) 2024-01-12 15:11:22 +00:00
test_integration_heartbeat.py Add reset button to disable integration heartbeat (#3959) 2024-03-04 19:20:00 +00:00
test_labels.py fix: update internal labels endpoints to work with RBAC (#5099) 2024-10-02 17:39:49 +00:00
test_live_settings.py Telegram long polling (#2250) 2023-08-24 09:12:24 +02:00
test_oncall_shift.py fix: Add rolling users validation for oncall shift API (#5050) 2024-09-20 21:06:33 +00:00
test_openapi_schema.py allow specifying more than one redis server URI in the REDIS_URI env var (#3368) 2023-11-16 10:48:36 -05:00
test_organization.py feat: add grafana_irm_enabled to GET /organization endpoint response (#5230) 2024-11-05 05:54:38 -05:00
test_permissions.py feat: update RBAC permissioning to support grafana-irm-app (#5149) 2024-10-10 19:02:21 +00:00
test_preview_template_options.py World, meet OnCall! 2022-06-03 08:09:47 -06:00
test_public_api_tokens.py Handle None role when syncing users from Grafana (#3147) 2023-10-19 17:39:08 +00:00
test_resolution_note.py Resolution note source mobile app (#3174) 2023-10-20 15:22:45 +01:00
test_route_regex_debugger.py World, meet OnCall! 2022-06-03 08:09:47 -06:00
test_schedule_export.py chore: add pytest-socket library + disable network calls in tests (#5315) 2024-12-02 10:53:18 -05:00
test_schedules.py chore: add pytest-socket library + disable network calls in tests (#5315) 2024-12-02 10:53:18 -05:00
test_set_org_default_slack_channel.py chore: fix some minor issues with recent slack_channel changes (#5228) 2024-11-05 04:51:04 -05:00
test_shift_swaps.py Speed up internal api endpoints (#4830) 2024-08-15 14:20:55 +00:00
test_slack_channels.py Handle None role when syncing users from Grafana (#3147) 2023-10-19 17:39:08 +00:00
test_slack_team_settings.py Handle None role when syncing users from Grafana (#3147) 2023-10-19 17:39:08 +00:00
test_team.py cleanup CustomButton backend code + add ngrok/express outgoing webhook e2e test (#2544) 2024-03-28 15:37:22 +00:00
test_telegram_channel.py Handle None role when syncing users from Grafana (#3147) 2023-10-19 17:39:08 +00:00
test_user.py feat: update RBAC permissioning to support grafana-irm-app (#5149) 2024-10-10 19:02:21 +00:00
test_user_groups.py Add endpoint to get a single user group (#4395) 2024-05-24 20:26:28 +00:00
test_user_notification_policy.py Allow custom wait delay (#4446) 2024-06-03 13:06:47 +00:00
test_user_schedule_export.py chore: add pytest-socket library + disable network calls in tests (#5315) 2024-12-02 10:53:18 -05:00
test_webhook_presets.py Migrate webhooks integration_filter to use a m2m field instead (#3946) 2024-02-23 11:55:44 +00:00
test_webhooks.py Add manual trigger support for webhooks (#4934) 2024-09-09 12:17:23 +00:00