Files
teng-lin--notebooklm-py/tests/_fixtures/chain.py
T
wehub-resource-sync 09e9f3545f
Test / Code Quality (push) Has been cancelled
Test / Test (macos-latest, Python 3.10) (push) Has been cancelled
Test / Test (macos-latest, Python 3.11) (push) Has been cancelled
Test / Test (macos-latest, Python 3.12) (push) Has been cancelled
Test / Test (macos-latest, Python 3.13) (push) Has been cancelled
Test / Test (macos-latest, Python 3.14) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.10) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.11) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.12) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.13) (push) Has been cancelled
Test / Test (ubuntu-latest, Python 3.14) (push) Has been cancelled
Test / Test (windows-latest, Python 3.10) (push) Has been cancelled
Test / Test (windows-latest, Python 3.11) (push) Has been cancelled
Test / Test (windows-latest, Python 3.12) (push) Has been cancelled
Test / Test (windows-latest, Python 3.13) (push) Has been cancelled
Test / Test (windows-latest, Python 3.14) (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
dependency-audit / pip-audit (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:30:13 +08:00

127 lines
4.1 KiB
Python

"""Test fixtures for the Tier-12 middleware chain.
These helpers let middleware tests build a chain with
``[middleware_under_test, ...]``, call it with a benign ``RpcRequest``, and
assert behavior without opening a real client/runtime HTTP stack.
Three helpers live here:
- :class:`FakeChainTerminal` — programmable terminal stub matching the
``NextCall`` shape: ``RpcRequest -> RpcResponse``.
- :func:`make_request` — factory for :class:`notebooklm._middleware.core.RpcRequest`
instances with benign defaults. Tests override only the fields they care
about via keyword arguments.
- :func:`chain_calls_through_to_terminal` — assertion helper that builds a
chain over a :class:`FakeChainTerminal`, invokes it once, and returns
whether the terminal was reached.
"""
from __future__ import annotations
import asyncio
from collections.abc import Callable, Sequence
from typing import Any
import httpx
from notebooklm._middleware.core import (
Middleware,
RpcRequest,
RpcResponse,
build_chain,
)
class FakeChainTerminal:
"""Programmable stub for the middleware chain terminal."""
def __init__(
self,
*,
response: httpx.Response | None = None,
response_factory: Callable[[], httpx.Response] | None = None,
raises: BaseException | None = None,
) -> None:
self.response: httpx.Response | None = response
self.response_factory: Callable[[], httpx.Response] | None = response_factory
self.raises: BaseException | None = raises
self.calls: list[dict[str, Any]] = []
@property
def was_called(self) -> bool:
"""``True`` if the terminal was called at least once."""
return bool(self.calls)
@property
def call_count(self) -> int:
"""Number of times the terminal was called."""
return len(self.calls)
async def __call__(self, request: RpcRequest) -> RpcResponse:
"""Record the request and return the configured response envelope."""
self.calls.append({"request": request, "context": request.context})
# Resolution priority: raises → response_factory → response →
# built-in 200/empty default. The call is recorded before any
# configured exception so tests can still assert call_count.
if self.raises is not None:
raise self.raises
if self.response_factory is not None:
response = self.response_factory()
elif self.response is not None:
response = self.response
else:
response = httpx.Response(status_code=200, content=b"")
return RpcResponse(response=response, context=request.context)
def make_request(**overrides: Any) -> RpcRequest:
"""Build an :class:`RpcRequest` with benign defaults plus overrides.
Passing an unknown keyword raises ``TypeError`` early so test typos
don't silently no-op.
"""
defaults: dict[str, Any] = {
"url": "https://notebooklm.google.com/_/LabsTailwindUi/data/batchexecute?authuser=0&_reqid=100000",
"headers": {"X-Goog-AuthUser": "0"},
"body": b"",
"context": {},
}
unknown = set(overrides) - set(defaults)
if unknown:
raise TypeError(
"make_request() got unexpected keyword(s): "
f"{sorted(unknown)!r}. Known fields: {sorted(defaults)!r}"
)
defaults.update(overrides)
return RpcRequest(**defaults)
def chain_calls_through_to_terminal(
terminal: FakeChainTerminal,
middlewares: Sequence[Middleware],
) -> bool:
"""Return ``True`` iff invoking the chain reaches the terminal."""
chain = build_chain(middlewares, terminal)
async def driver() -> RpcResponse:
return await chain(make_request())
# ``asyncio.run`` raises if there's already a running loop. The fixture
# is meant to be called from synchronous test bodies; tests that need
# to invoke the chain from an async context should compose
# ``build_chain`` + ``make_request`` directly.
asyncio.run(driver())
return terminal.was_called
__all__ = [
"FakeChainTerminal",
"chain_calls_through_to_terminal",
"make_request",
]