Skip to content

Commit 75c445b

Browse files
committed
test: strengthen Content-Disposition header assertions
- v2/test_files.py: expected_rfc5987 now includes the file extension so a regression that strips the extension from the RFC 5987 value is detected - test_database.py: strengthen the dual-flow download assertion to verify both filename= and filename*= params are present, not just the prefix - test_database.py: rename test_download_flows_non_ascii_content_disposition to test_download_flows_content_disposition_dual_param and update the docstring to accurately reflect that the ZIP filename is always ASCII (timestamp-based); the test now verifies the dual-param format
1 parent d08caa2 commit 75c445b

2 files changed

Lines changed: 23 additions & 11 deletions

File tree

src/backend/tests/unit/api/v2/test_files.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -625,11 +625,11 @@ async def test_unique_filename_path_storage(files_client, files_created_api_key)
625625
@pytest.mark.parametrize(
626626
("filename", "expected_rfc5987"),
627627
[
628-
("龙.txt", "%E9%BE%99"),
629-
("测试文件.txt", "%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6"),
630-
("日本語ファイル.txt", "%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB"),
631-
("arquivo_com_acentuação.txt", "arquivo_com_acentua%C3%A7%C3%A3o"),
632-
("normal_file.txt", "normal_file"),
628+
("龙.txt", "%E9%BE%99.txt"),
629+
("测试文件.txt", "%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6.txt"),
630+
("日本語ファイル.txt", "%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB.txt"),
631+
("arquivo_com_acentuação.txt", "arquivo_com_acentua%C3%A7%C3%A3o.txt"),
632+
("normal_file.txt", "normal_file.txt"),
633633
],
634634
)
635635
async def test_download_file_non_ascii_content_disposition(
@@ -657,8 +657,9 @@ async def test_download_file_non_ascii_content_disposition(
657657
assert expected_rfc5987 in content_disposition
658658
rfc5987_value = content_disposition.split("filename*=UTF-8''")[-1].split(";")[0].strip()
659659
decoded = unquote(rfc5987_value)
660-
# The original filename stem must appear in the server-returned decoded name
660+
# The decoded RFC 5987 value must contain both the stem and the extension
661661
assert filename.rsplit(".", 1)[0] in decoded
662+
assert decoded.endswith(".txt")
662663

663664

664665
async def test_batch_download_files_non_ascii_content_disposition(files_client, files_created_api_key):

src/backend/tests/unit/test_database.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -562,15 +562,24 @@ async def test_download_file(
562562
# Check response data
563563
# Since the endpoint now returns a zip file, we need to check the content type and the filename in the headers
564564
assert response.headers["Content-Type"] == "application/x-zip-compressed"
565-
assert "attachment; filename=" in response.headers["Content-Disposition"]
565+
content_disposition = response.headers["Content-Disposition"]
566+
assert "attachment" in content_disposition
567+
assert 'filename="' in content_disposition
568+
assert "filename*=UTF-8''" in content_disposition
566569

567570

568571
@pytest.mark.usefixtures("session")
569-
async def test_download_flows_non_ascii_content_disposition(client: AsyncClient, logged_in_headers):
570-
"""Downloading multiple flows must produce RFC 5987-encoded Content-Disposition for non-ASCII flow names."""
572+
async def test_download_flows_content_disposition_dual_param(client: AsyncClient, logged_in_headers):
573+
"""Downloading multiple flows must produce a dual-param RFC 5987 Content-Disposition header.
574+
575+
The ZIP filename is always timestamp-based (pure ASCII). This test verifies
576+
that both the legacy 'filename=' param and the RFC 5987 'filename*=' param
577+
are present and well-formed, as required for compatibility with both old
578+
and new HTTP clients.
579+
"""
571580
from urllib.parse import unquote
572581

573-
# Create two flows with Chinese names
582+
# Create two flows (names don't affect the ZIP filename, which is timestamp-based)
574583
chinese_names = ["龙流程", "测试下载"]
575584
flow_ids = []
576585
for name in chinese_names:
@@ -591,9 +600,11 @@ async def test_download_flows_non_ascii_content_disposition(client: AsyncClient,
591600
assert download_response.headers["Content-Type"] == "application/x-zip-compressed"
592601

593602
content_disposition = download_response.headers["Content-Disposition"]
603+
# Must include both params: ASCII fallback and RFC 5987
594604
assert "attachment" in content_disposition
605+
assert 'filename="' in content_disposition
595606
assert "filename*=UTF-8''" in content_disposition
596-
# The RFC 5987 value must be decodable and produce a valid filename
607+
# The RFC 5987 value must decode to a .zip filename
597608
rfc5987_value = content_disposition.split("filename*=UTF-8''")[-1].split(";")[0].strip()
598609
decoded = unquote(rfc5987_value)
599610
assert decoded.endswith(".zip")

0 commit comments

Comments
 (0)