Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions tests/source/recorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,19 +229,32 @@ def first_sync_config(owner: str, name: str) -> TrackingConfig:


async def record_first_sync(
token: str, owner: str, name: str, *, inner: httpx.AsyncBaseTransport | None = None
token: str,
owner: str,
name: str,
*,
inner: httpx.AsyncBaseTransport | None = None,
clock: Clock | None = None,
) -> list[Unit]:
"""Run a first sync of ``owner/name`` into a scratch database through the recording
transport; every unit it asked for. A private repository is refused after the sync's resolve
(its label pages included) and before any other request; a failed item or a run that does not
exit 0 stops it too."""
exit 0 stops it too.

``clock`` is the run's clock, the system clock by default. A replay of recorded units passes a
fixed one: the sync's 24-hour refresh measures each account from its recorded ``Date``, so on
the system clock a replay asks for lookups the recording does not hold once a day has
passed."""
_refuse_listed(owner, name)
run_clock = clock or SystemClock()
recorded_at = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
recording = RecordingTransport(inner or httpx.AsyncHTTPTransport(), recorded_at)
opened: list[PublicOnlySource] = []

def open_source(deadline: datetime | None) -> PublicOnlySource:
opened.append(PublicOnlySource(token, http_transport=recording, deadline=deadline))
opened.append(
PublicOnlySource(token, http_transport=recording, clock=run_clock, deadline=deadline)
)
return opened[-1]

config = first_sync_config(owner, name)
Expand All @@ -256,7 +269,7 @@ def open_source(deadline: datetime | None) -> PublicOnlySource:
code_version="recorder",
),
open_source=open_source,
clock=SystemClock(),
clock=run_clock,
)
# The engine fails the run on the refusal, before the index.
refused = [source.refused for source in opened if source.refused is not None]
Expand Down
28 changes: 21 additions & 7 deletions tests/source/test_recorder.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ async def test_a_listed_private_repository_is_never_requested(owner: str, name:
with pytest.raises(PrivateRepository):
await record("test-token", inner=replay.transport(), scenarios=scenarios)
with pytest.raises(PrivateRepository):
await record_first_sync("test-token", owner, name, inner=replay.transport())
await record_first_sync(
"test-token", owner, name, inner=replay.transport(), clock=FakeClock()
)
assert replay.seen == []


Expand Down Expand Up @@ -278,7 +280,9 @@ async def test_recording_a_first_sync_of_its_recordings_gives_them_back() -> Non
"""The first sync asks for exactly the recorded units, and records each as it was."""
replay = Replay.from_directory(FIRST_SYNC)
owner, name = FIRST_SYNC_REPOSITORY
units = await record_first_sync("test-token", owner, name, inner=replay.transport())
units = await record_first_sync(
"test-token", owner, name, inner=replay.transport(), clock=FakeClock()
)
assert replay.problems == []
# One resolve, the sync's own: the resolution the privacy check reads is the one it uses.
assert [seen.operation for seen in replay.seen] == [
Expand Down Expand Up @@ -306,7 +310,9 @@ async def test_a_private_repository_stops_a_first_sync_after_its_resolve() -> No
unit.data["isPrivate"] = True
replay.add(unit)
with pytest.raises(PrivateRepository, match=f"{owner}/{name}"):
await record_first_sync("test-token", owner, name, inner=replay.transport())
await record_first_sync(
"test-token", owner, name, inner=replay.transport(), clock=FakeClock()
)
assert [seen.operation for seen in replay.seen] == ["Resolve"]


Expand All @@ -318,7 +324,9 @@ async def test_a_retried_item_records_one_unit_per_file(first_sync: bool) -> Non
replay.modify(_batch_alias_error, when=lambda seen: seen.operation == "PullRequestBatch")
if first_sync:
owner, name = FIRST_SYNC_REPOSITORY
units = await record_first_sync("test-token", owner, name, inner=replay.transport())
units = await record_first_sync(
"test-token", owner, name, inner=replay.transport(), clock=FakeClock()
)
else:
units = await record("test-token", inner=replay.transport())
batches = [seen.numbers for seen in replay.seen if seen.operation == "PullRequestBatch"]
Expand Down Expand Up @@ -371,7 +379,9 @@ async def test_a_first_sync_that_fails_names_why(
change(replay)
owner, name = FIRST_SYNC_REPOSITORY
with pytest.raises(RecordingFailed) as raised:
await record_first_sync("test-token", owner, name, inner=replay.transport())
await record_first_sync(
"test-token", owner, name, inner=replay.transport(), clock=FakeClock()
)
assert str(raised.value) == message
assert [seen.operation for seen in replay.seen] == ["Resolve"]

Expand All @@ -383,13 +393,17 @@ async def test_a_first_sync_that_does_not_exit_0_stops_the_recording() -> None:
)
owner, name = FIRST_SYNC_REPOSITORY
with pytest.raises(RecordingFailed, match="first sync exited 2"):
await record_first_sync("test-token", owner, name, inner=replay.transport())
await record_first_sync(
"test-token", owner, name, inner=replay.transport(), clock=FakeClock()
)


def _first_sync_units() -> list[Any]:
owner, name = FIRST_SYNC_REPOSITORY
replay = Replay.from_directory(FIRST_SYNC)
return asyncio.run(record_first_sync("test-token", owner, name, inner=replay.transport()))
return asyncio.run(
record_first_sync("test-token", owner, name, inner=replay.transport(), clock=FakeClock())
)


@pytest.mark.parametrize("oversized", [False, True])
Expand Down