def test_file_context_mode_property(): handler = FilesHandler() file_path = files2_index_path context = handler.open(file_path) assert context.mode == "rb" assert context.loop is not None assert isinstance(context.loop, AbstractEventLoop)
async def test_file_context_raises_for_invalid_mode(): handler = FilesHandler() with pytest.raises(ValueError) as error_info: async with handler.open("foo.txt", mode="xx") as file_context: file_context.write("Foo") assert "invalid mode" in str(error_info.value)
async def test_read_file_with_open(files_folder: pathlib.Path, file_name: str): handler = FilesHandler() full_file_path = str(files_folder / file_name) async with handler.open(full_file_path) as file_context: contents = await file_context.read() with open(full_file_path, mode="rb") as file: expected_contents = file.read() assert contents == expected_contents
async def test_seek_and_read_chunk(files_folder: pathlib.Path, file_name: str, index: int, size: int): handler = FilesHandler() full_file_path = str(files_folder / file_name) async with handler.open(full_file_path) as file_context: await file_context.seek(index) chunk_read_async = await file_context.read(size) with open(full_file_path, mode="rb") as file: file.seek(index) chunk_read = file.read(size) assert chunk_read_async == chunk_read
async def test_text_file_range_request_single_part_if_range_handling( range_value, matches): file_path = get_file_path("example.txt") info = FileInfo.from_path(file_path) response = get_response_for_file( FilesHandler(), Request( "GET", b"/example", [ (b"Range", range_value), (b"If-Range", info.etag.encode() + (b"" if matches else b"xx")), ], ), file_path, 1200, ) expected_status = 206 if matches else 200 assert response.status == expected_status if not matches: body = await response.read() with open(file_path, mode="rb") as actual_file: assert body == actual_file.read()
async def test_get_range_file_getter_raises_for_invalid(): getter = get_range_file_getter(FilesHandler(), files2_index_path, 100, Range("bytes", [RangePart(None, None)])) with pytest.raises(BadRequest): async for chunk in getter(): ...
def __init__( self, *, router: Optional[Router] = None, services: Optional[Container] = None, debug: bool = False, show_error_details: Optional[bool] = None, ): if router is None: router = Router() if services is None: services = Container() if show_error_details is None: show_error_details = bool( os.environ.get("APP_SHOW_ERROR_DETAILS", False)) super().__init__(show_error_details, router) self.services: Container = services self._service_provider: Optional[Services] = None self.debug = debug self.middlewares: List[Callable[..., Awaitable[Response]]] = [] self._default_headers: Optional[Tuple[Tuple[str, str], ...]] = None self._middlewares_configured = False self._cors_strategy: Optional[CORSStrategy] = None self._authentication_strategy: Optional[AuthenticationStrategy] = None self._authorization_strategy: Optional[AuthorizationStrategy] = None self.on_start = ApplicationEvent(self) self.after_start = ApplicationEvent(self) self.on_stop = ApplicationEvent(self) self.started = False self.controllers_router: RoutesRegistry = controllers_router self.files_handler = FilesHandler() self.server_error_details_handler = ServerErrorDetailsHandler() self._session_middleware: Optional[SessionMiddleware] = None
def __init__( self, *, router: Optional[Router] = None, resources: Optional[Resources] = None, services: Optional[Container] = None, debug: bool = False, show_error_details: bool = False, ): if router is None: router = Router() if services is None: services = Container() super().__init__(show_error_details, router) if resources is None: resources = Resources(get_resource_file_content("error.html")) self.services: Container = services self._service_provider: Optional[Services] = None self.debug = debug self.middlewares: List[Callable[..., Awaitable[Response]]] = [] self.access_logger = None self.logger = None self._default_headers: Optional[Tuple[Tuple[str, str], ...]] = None self._middlewares_configured = False self.resources = resources self._authentication_strategy: Optional[AuthenticationStrategy] = None self._authorization_strategy: Optional[AuthorizationStrategy] = None self.on_start = ApplicationEvent(self) self.after_start = ApplicationEvent(self) self.on_stop = ApplicationEvent(self) self.started = False self.controllers_router: RoutesRegistry = controllers_router self.files_handler = FilesHandler()
async def test_invalid_range_request_range_not_satisfiable(range_value): file_path = get_file_path("example.txt") with pytest.raises(RangeNotSatisfiable): get_response_for_file( FilesHandler(), Request("GET", b"/example", [(b"Range", range_value)]), file_path, 1200, )
async def test_get_response_for_file_returns_cache_control_header(cache_time): response = get_response_for_file(FilesHandler(), Request("GET", b"/example", None), TEST_FILES[0], cache_time) assert response.status == 200 header = response.get_single_header(b"cache-control") assert header == f"max-age={cache_time}".encode()
async def test_get_response_for_file_with_head_method_returns_empty_body_with_info( file_path, ): response = get_response_for_file(FilesHandler(), Request("HEAD", b"/example", None), file_path, 1200) assert response.status == 200 data = await response.read() assert data is None
async def test_read_file_rt_mode(files_folder: pathlib.Path, file_name: str): handler = FilesHandler() full_file_path = str(files_folder / file_name) contents = await handler.read(full_file_path, mode="rt") with open(full_file_path, mode="rt") as f: expected_contents = f.read() assert contents == expected_contents
async def test_get_response_for_file_returns_file_contents(file_path): response = get_response_for_file(FilesHandler(), Request("GET", b"/example", None), file_path, 1200) assert response.status == 200 data = await response.read() with open(file_path, mode="rb") as test_file: contents = test_file.read() assert data == contents
async def test_write_file_text_mode(temp_files_folder: pathlib.Path): handler = FilesHandler() file_name = str(uuid4()) + ".txt" full_file_path = str(temp_files_folder / file_name) contents = "Lorem ipsum dolor sit" await handler.write(full_file_path, contents, mode="wt") with open(full_file_path, mode="rt") as f: expected_contents = f.read() assert contents == expected_contents
async def test_get_response_for_file_returns_not_modified_handling_if_none_match_header( file_path, method): info = FileInfo.from_path(file_path) response = get_response_for_file( FilesHandler(), Request(method, b"/example", [(b"If-None-Match", info.etag.encode())]), file_path, 1200, ) assert response.status == 304 data = await response.read() assert data is None
async def test_read_file_chunks(files_folder: pathlib.Path, file_name: str): handler = FilesHandler() full_file_path = str(files_folder / file_name) chunk: bytes chunk_size = 1024 contents = b"" expected_contents = b"" async with handler.open(full_file_path) as file_context: async for chunk in file_context.chunks(chunk_size): assert chunk is not None contents += chunk with open(full_file_path, mode="rb") as f: while True: chunk = f.read(chunk_size) if not chunk: break expected_contents += chunk assert contents == expected_contents
async def test_text_file_range_request_single_part(range_value, expected_bytes, expected_content_range): file_path = get_file_path("example.txt") response = get_response_for_file( FilesHandler(), Request("GET", b"/example", [(b"Range", range_value)]), file_path, 1200, ) assert response.status == 206 body = await response.read() assert body == expected_bytes assert response.get_single_header( b"content-range") == expected_content_range
async def test_write_file_with_iterable(temp_files_folder: pathlib.Path): handler = FilesHandler() file_name = str(uuid4()) + ".txt" full_file_path = str(temp_files_folder / file_name) async def provider(): yield b"Lorem " await asyncio.sleep(0.01) yield b"ipsum" await asyncio.sleep(0.01) yield b" dolor" yield b" sit" await handler.write(full_file_path, provider) with open(full_file_path, mode="rb") as f: expected_contents = f.read() assert b"Lorem ipsum dolor sit" == expected_contents
async def test_text_file_range_request_multi_part( range_value: bytes, expected_bytes_lines: List[bytes]): file_path = get_file_path("example.txt") response = get_response_for_file( FilesHandler(), Request("GET", b"/example", [(b"Range", range_value)]), file_path, 1200, ) assert response.status == 206 content_type = response.content.type boundary = content_type.split(b"=")[1] body = await response.read() expected_bytes_lines = [ line.replace(b"##BOUNDARY##", boundary) for line in expected_bytes_lines ] assert body.splitlines() == expected_bytes_lines
async def test_get_response_for_file_returns_headers(file_path, method): response = get_response_for_file( FilesHandler(), Request(method, b"/example", None), file_path, 1200 ) assert response.status == 200 info = FileInfo.from_path(file_path) expected_headers = { b"etag": info.etag.encode(), b"last-modified": str(info.modified_time).encode(), b"accept-ranges": b"bytes", b"cache-control": b"max-age=1200", } for expected_header_name, expected_header_value in expected_headers.items(): value = response.get_single_header(expected_header_name) assert value is not None assert value == expected_header_value
async def data_provider(): async for chunk in FilesHandler().chunks(file_path): yield chunk
async def test_get_response_for_file_raise_for_file_not_found(): with pytest.raises(FileNotFoundError): get_response_for_file(FilesHandler(), Request("GET", b"/example.txt", None), "example.txt", 1200)