test(s3_v2): drop the libfaketime hour rollover cell and its dev dependency

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
yucheng 2026-09-30 22:30:19 +00:00
parent ee8d21604a
commit 79a71c8550
4 changed files with 0 additions and 129 deletions

View file

@ -236,7 +236,6 @@ dev = [
"pytest-timeout==2.4.0",
"vcrpy==8.2.1",
"pytest-recording==0.13.4",
"libfaketime==3.0.1",
]
e2e-dev = [
"playwright==1.61.0",

View file

@ -169,7 +169,6 @@ pygithub: >=2.8.1 # LGPL license
argon2-cffi: >=25.1.0 # MIT License
blockbuster: >=1.5.26 # Apache 2.0 license
pylint: >=3.3.9 # GPLv2 license
libfaketime: >=3.0.1 # GPLv2 license, dev-only LD_PRELOAD clock for tests/integration, https://github.com/simon-weber/python-libfaketime
httpx2: >=2.5.0 # BSD 3-Clause License
httpcore2: >=2.5.0 # BSD 3-Clause License
mcp-types: >=2.2.0 # MIT License

View file

@ -7,7 +7,6 @@ from concurrent.futures import ThreadPoolExecutor
from contextlib import contextmanager
from dataclasses import dataclass, field
from datetime import datetime, timedelta
from importlib.resources import files
from pathlib import Path
from typing import Final
from urllib.parse import quote, unquote
@ -37,7 +36,6 @@ from integration._support.wire import Reply, Request, wire_server
FLUSH: Final = {"DEFAULT_S3_FLUSH_INTERVAL_SECONDS": "1"}
HOUR: Final = {"s3_partition_granularity": "hour"}
FAKETIME_LIBRARY: Final = files("libfaketime").joinpath("vendor", "libfaketime", "src", "libfaketime.so.1")
ANTHROPIC_MODEL: Final = "anthropic/claude-sonnet-4-5-20250929"
WARNING: Final = "s3 logging: s3_partition_granularity="
SINK_CREDENTIALS: Final = {
@ -207,23 +205,6 @@ def _keys_on_fresh_connections(candidate: Gateway, aliases: tuple[str, ...]) ->
return tuple(pool.map(generate, aliases))
SETUP_AUDITS: Final = (
("created", "LiteLLM_ProxyModelTable"),
("created", "LiteLLM_ProxyModelTable"),
("created", "LiteLLM_VerificationToken"),
)
def _audit_changes(sink: RecordingS3Sink, audit_prefix: str) -> tuple[tuple[str, str], ...]:
bodies: Final = (body for target, body in sink.objects().items() if target.startswith(audit_prefix))
lines: Final = b"\n".join(bodies).splitlines()
return tuple(sorted((str(audit["action"]), str(audit["table_name"])) for audit in map(_audit_line, lines)))
def _audit_line(line: bytes) -> Mapping[str, JsonValue]:
return object_value(json.loads(line))
def _created_key_hashes(sink: RecordingS3Sink, audit_prefix: str) -> frozenset[str]:
created: Final = (
object_value(json.loads(body)) for target, body in sink.objects().items() if target.startswith(audit_prefix)
@ -1083,99 +1064,6 @@ def test_s3_v2_hour_coded_403_retries_reuse_the_same_hour_key(gateway: Gateway,
assert _outside_layout(objects, "hour") == ()
def test_s3_v2_hour_rollover_inside_one_batch_flush_splits_files_by_hour_folder(
gateway: Gateway, tmp_path: Path
) -> None:
assert FAKETIME_LIBRARY.is_file(), "the libfaketime dev dependency drives the proxy clock"
marker: Final = "s3hroll" + uuid.uuid4().hex[:8]
clock: Final = tmp_path / "proxy-clock"
clock.write_text("@2026-09-29 10:59:30\n")
upstream: Final = CountingUpstream()
sink: Final = RecordingS3Sink(delay_seconds=0.05)
audit_prefix: Final = f"/{BUCKET}/{PREFIX}/audit_logs/"
with (
wire_server(upstream.respond) as provider,
wire_server(sink.respond) as bucket,
_s3_proxy(
gateway,
tmp_path,
bucket.url,
{**HOUR, "s3_batch_file_upload": True},
{"store_audit_logs": True, "audit_log_callbacks": ["s3_v2"]},
environment={
"DEFAULT_S3_FLUSH_INTERVAL_SECONDS": "3600",
"DEFAULT_S3_BATCH_SIZE": "1",
"LD_PRELOAD": str(FAKETIME_LIBRARY),
"FAKETIME_TIMESTAMP_FILE": str(clock),
"FAKETIME_CACHE_DURATION": "1",
"FAKETIME_DONT_FAKE_MONOTONIC": "1",
},
workers=1,
) as owned,
owned.gateway.scenario() as scenario,
):
openai_model, _, key = _models(scenario, provider.url)
setup_audits: Final = eventually(
lambda: _audit_changes(sink, audit_prefix),
lambda changes: changes == SETUP_AUDITS,
seconds=30,
)
def advance(stamp: str, shown: str) -> None:
clock.write_text(f"@2026-09-29 {stamp}\n")
eventually(
lambda: owned.gateway.client.get("/health/liveliness").headers["date"],
lambda date: f" {shown}:" in date,
seconds=10,
)
advance("10:59:40", "10:59")
flushed_before: Final = frozenset(sink.objects())
before: Final = tuple(f"{marker}-before-{index}" for index in range(4))
after: Final = tuple(f"{marker}-after-{index}" for index in range(4))
answered_before: Final = _sdk_chats(owned.gateway, openai_model, key, before)
advance("11:00:05", "11:00")
answered_after: Final = _sdk_chats(owned.gateway, openai_model, key, after)
spent: Final = eventually(
lambda: read_rows(
'SELECT request_id FROM "LiteLLM_SpendLogs" WHERE request_id = ANY(%s)',
(list(answered_before + answered_after),),
),
lambda rows: len(rows) == len(before) + len(after),
seconds=70,
)
pending: Final = frozenset(sink.objects()) - flushed_before
scenario.key(models=[openai_model])
batches: Final = eventually(
lambda: {
target: body
for target, body in sink.objects().items()
if target not in flushed_before and not target.startswith(audit_prefix)
},
lambda landed: sum(len(body.splitlines()) for body in landed.values()) >= len(before) + len(after),
seconds=30,
)
batch_file: Final = re.compile(
rf"/{BUCKET}/{PREFIX}/2026-09-29/(\d{{2}})/batch_(\d{{2}}-\d{{2}}-\d{{2}})_[0-9a-f]{{32}}\.jsonl"
)
layout: Final = {
(match.group(1), match.group(2)): sorted(_prompt(object_value(json.loads(line))) for line in body.splitlines())
for target, body in batches.items()
if (match := batch_file.fullmatch(unquote(target)))
}
assert setup_audits == SETUP_AUDITS
assert answered_before == before and answered_after == after
assert sorted(str(row["request_id"]) for row in spent) == sorted(before + after)
assert sorted(upstream.received()) == sorted(before + after), "every prompt must reach the upstream exactly once"
assert pending == frozenset(), (
f"request logs must stay queued until the audit log fills the batch: {sorted(pending)}"
)
assert len(layout) == len(batches) == 2, tuple(batches)
assert sorted(hour for hour, _ in layout) == ["10", "11"], layout
assert len({stamp for _, stamp in layout}) == 1, f"both hour files must come from one flush: {layout}"
assert {hour: prompts for (hour, _), prompts in layout.items()} == {"10": sorted(before), "11": sorted(after)}
def test_s3_v2_hour_slow_sink_batches_never_duplicate_an_upload(gateway: Gateway, tmp_path: Path) -> None:
marker: Final = "s3hslow" + uuid.uuid4().hex[:8]
upstream: Final = CountingUpstream()

15
uv.lock generated
View file

@ -4399,19 +4399,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/41/a0/b91504515c1f9a299fc157967ffbd2f0321bce0516a3d5b89f6f4cad0355/lazy_object_proxy-1.12.0-pp39.pp310.pp311.graalpy311-none-any.whl", hash = "sha256:c3b2e0af1f7f77c4263759c4824316ce458fabe0fceadcd24ef8ca08b2d1e402", size = 15072, upload-time = "2025-08-22T13:50:05.498Z" },
]
[[package]]
name = "libfaketime"
version = "3.0.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "python-dateutil" },
{ name = "pytz" },
]
sdist = { url = "https://files.pythonhosted.org/packages/df/85/b46c502837430823420be8ba856479819acc5a5fa4e46de167b0188f4ba3/libfaketime-3.0.1.tar.gz", hash = "sha256:49c2b06250bd5a1206efe5ecfdc575850517081b50b42c6c58718be1a4a09fbd", size = 75878, upload-time = "2026-08-19T16:44:13.598Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/87/a3/af0d453324bff5ee0c1ae51be5604df56c5c6d1d5f61e430a1b96a80e2ac/libfaketime-3.0.1-py3-none-any.whl", hash = "sha256:5eed7c17f3d4ba0f6f828de4975f69a622b06b1e792674e6c1b069c0689fab79", size = 92987, upload-time = "2026-08-19T16:44:12.085Z" },
]
[[package]]
name = "librt"
version = "0.15.0"
@ -4700,7 +4687,6 @@ dev = [
{ name = "hypothesis" },
{ name = "keyring" },
{ name = "langfuse" },
{ name = "libfaketime" },
{ name = "mypy" },
{ name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
{ name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
@ -4916,7 +4902,6 @@ dev = [
{ name = "hypothesis", specifier = "==6.165.10" },
{ name = "keyring", specifier = "==25.7.0" },
{ name = "langfuse", specifier = ">=4.7,<5.0" },
{ name = "libfaketime", specifier = "==3.0.1" },
{ name = "mypy", specifier = "==1.20.1" },
{ name = "numpy", specifier = ">=1.26.0,<3.0" },
{ name = "openapi-core", specifier = "==0.22.0" },