Files
truf-server/tests/test_api_deadline_plumbing.py
2026-09-30 20:30:56 +03:00

77 lines
3.5 KiB
Python

from pathlib import Path
import sys
import time
import unittest
from unittest import mock
ROOT = Path(__file__).resolve().parents[1]
APP_DIR = ROOT / 'app'
sys.path.insert(0, str(APP_DIR))
import scanner
class ApiDeadlinePlumbingTests(unittest.TestCase):
def test_deadline_is_consumed_internally_not_forwarded_to_requests(self):
response = mock.Mock(status_code=200)
with mock.patch.object(scanner.requests, 'request', return_value=response) as request:
result = scanner.api_request(
'GET', 'https://example.invalid', timeout=10,
deadline=time.monotonic() + 1,
)
self.assertIs(result, response)
self.assertNotIn('deadline', request.call_args.kwargs)
self.assertGreater(request.call_args.kwargs['timeout'], 0)
self.assertLessEqual(request.call_args.kwargs['timeout'], 1)
def test_expired_deadline_never_reaches_requests(self):
with mock.patch.object(scanner.requests, 'request') as request:
with self.assertRaisesRegex(scanner.ApiRequestError, 'deadline expired'):
scanner.api_request('GET', 'https://example.invalid', deadline=time.monotonic() - 1)
request.assert_not_called()
def test_deadline_bounds_unset_timeouts(self):
for timeout in (None, (None, 30), (2, None), (None, None)):
with self.subTest(timeout=timeout):
response = mock.Mock(status_code=200)
with mock.patch.object(scanner.scan_config, 'api_proxy_enabled', False), \
mock.patch.object(scanner.requests, 'request', return_value=response) as request:
self.assertIs(scanner.api_request(
'GET', 'https://example.invalid', timeout=timeout,
deadline=time.monotonic() + 1,
), response)
effective = request.call_args.kwargs['timeout']
for value in effective if isinstance(effective, tuple) else (effective,):
self.assertGreater(value, 0)
self.assertLessEqual(value, 1)
def test_response_after_deadline_is_closed_not_returned_or_retried(self):
for stream in (False, True):
for status in (200, 503):
with self.subTest(stream=stream, status=status):
clock = [0.0]
response = mock.Mock(status_code=status)
def late_response(*args, **kwargs):
clock[0] = 11.0
return response
with mock.patch.object(scanner.time, 'monotonic', side_effect=lambda: clock[0]), \
mock.patch.object(scanner.scan_config, 'api_proxy_enabled', False), \
mock.patch.object(scanner.requests, 'request', side_effect=late_response) as request, \
mock.patch.object(scanner, '_wait_or_raise_scan_slot_fatal') as wait:
with self.assertRaisesRegex(scanner.ApiRequestError, 'deadline expired after response'):
scanner.api_request(
'GET', 'https://example.invalid', timeout=30,
deadline=10, max_retries=3, stream=stream,
)
request.assert_called_once()
response.close.assert_called_once()
wait.assert_not_called()
if __name__ == '__main__':
unittest.main()