chore: import upstream snapshot with attribution
Sync docs with Docusaurus / sync (push) Waiting to run
Tests / Check if changed (push) Waiting to run
Tests / format (push) Blocked by required conditions
Tests / check-imports (push) Blocked by required conditions
Tests / Unit / macos-latest (push) Blocked by required conditions
Tests / Unit / ubuntu-latest (push) Blocked by required conditions
Tests / Unit / windows-latest (push) Blocked by required conditions
Tests / mypy (push) Blocked by required conditions
Tests / Integration / ubuntu-latest (push) Blocked by required conditions
Tests / Integration / macos-latest (push) Blocked by required conditions
Tests / Integration / windows-latest (push) Blocked by required conditions
Tests / notify-slack-on-failure (push) Blocked by required conditions
Tests / Mark tests as completed (push) Blocked by required conditions
Docker image release / Build base image (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:22:28 +08:00
commit c56bef871b
9296 changed files with 1854228 additions and 0 deletions
+87
View File
@@ -0,0 +1,87 @@
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
#
# SPDX-License-Identifier: Apache-2.0
import threading
import pytest
from haystack.components.agents.state import State
from haystack.hooks.invocation import _run_hooks, _run_hooks_async
class RecordingHook:
"""Sync-only hook (no `run_async`), to exercise the async fallback path."""
def __init__(self, label: str, log: list) -> None:
self.label = label
self.log = log
def run(self, state: State) -> None:
self.log.append(("run", self.label))
class ThreadRecordingHook:
def __init__(self) -> None:
self.thread_id: int | None = None
def run(self, state: State) -> None:
self.thread_id = threading.get_ident()
class AsyncRecordingHook:
def __init__(self, label: str, log: list) -> None:
self.label = label
self.log = log
def run(self, state: State) -> None:
self.log.append(("run", self.label))
async def run_async(self, state: State) -> None:
self.log.append(("run_async", self.label))
class TestRunHooks:
def test_runs_all_hooks_for_hook_point_in_order(self):
log: list = []
hooks = {"before_llm": [RecordingHook("a", log), RecordingHook("b", log)]}
_run_hooks(hooks, "before_llm", State(schema={}))
assert log == [("run", "a"), ("run", "b")]
def test_only_runs_the_given_hook_point(self):
log: list = []
hooks = {"before_llm": [RecordingHook("a", log)], "on_exit": [RecordingHook("b", log)]}
_run_hooks(hooks, "on_exit", State(schema={}))
assert log == [("run", "b")]
def test_no_hooks_for_hook_point_is_noop(self):
_run_hooks({}, "before_llm", State(schema={})) # does not raise
class TestRunHooksAsync:
@pytest.mark.asyncio
async def test_awaits_run_async_when_present(self):
log: list = []
await _run_hooks_async({"before_llm": [AsyncRecordingHook("a", log)]}, "before_llm", State(schema={}))
assert log == [("run_async", "a")]
@pytest.mark.asyncio
async def test_falls_back_to_run_when_no_run_async(self):
log: list = []
await _run_hooks_async({"before_llm": [RecordingHook("a", log)]}, "before_llm", State(schema={}))
assert log == [("run", "a")]
@pytest.mark.asyncio
async def test_falls_back_to_run_in_worker_thread(self):
hook = ThreadRecordingHook()
event_loop_thread_id = threading.get_ident()
await _run_hooks_async({"before_llm": [hook]}, "before_llm", State(schema={}))
assert hook.thread_id is not None
assert hook.thread_id != event_loop_thread_id
@pytest.mark.asyncio
async def test_runs_in_order_mixing_sync_and_async(self):
log: list = []
hooks = {"before_llm": [AsyncRecordingHook("a", log), RecordingHook("b", log)]}
await _run_hooks_async(hooks, "before_llm", State(schema={}))
assert log == [("run_async", "a"), ("run", "b")]