7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
92 lines
3.2 KiB
Python
92 lines
3.2 KiB
Python
"""Smoke tests for the run_parallel_searches helper.
|
|
|
|
These verify the contract documented in the module:
|
|
|
|
* empty input short-circuits to an empty list
|
|
* non-empty input returns one ``(query, payload)`` tuple per query
|
|
* ``search_fn`` may return any payload type (list, dict, etc.)
|
|
* ``context_factory=None`` path works (no Flask context required)
|
|
* ``context_factory`` is invoked once per query so each worker gets a
|
|
fresh Flask app context — sharing one context across concurrent workers
|
|
raises ``ValueError: <Token> was created in a different Context``
|
|
"""
|
|
|
|
import threading
|
|
|
|
from flask import Flask
|
|
|
|
from local_deep_research.advanced_search_system.parallel_search import (
|
|
run_parallel_searches,
|
|
)
|
|
|
|
|
|
def test_empty_queries_returns_empty_list():
|
|
assert run_parallel_searches([], lambda q: [q]) == []
|
|
|
|
|
|
def test_returns_one_tuple_per_query():
|
|
results = run_parallel_searches(["a", "b", "c"], lambda q: [q.upper()])
|
|
assert sorted(results) == [("a", ["A"]), ("b", ["B"]), ("c", ["C"])]
|
|
|
|
|
|
def test_payload_can_be_dict():
|
|
results = run_parallel_searches(
|
|
["x", "y"], lambda q: {"question": q, "results": [q]}
|
|
)
|
|
assert sorted(results) == [
|
|
("x", {"question": "x", "results": ["x"]}),
|
|
("y", {"question": "y", "results": ["y"]}),
|
|
]
|
|
|
|
|
|
def test_max_workers_passed_through():
|
|
# Smoke test: helper accepts max_workers without error.
|
|
results = run_parallel_searches(["a", "b", "c"], lambda q: q, max_workers=2)
|
|
assert sorted(results) == [("a", "a"), ("b", "b"), ("c", "c")]
|
|
|
|
|
|
def test_default_max_workers():
|
|
# When max_workers is None, defaults to len(queries). Smoke test only.
|
|
results = run_parallel_searches(["a"], lambda q: q)
|
|
assert results == [("a", "a")]
|
|
|
|
|
|
def test_context_factory_called_once_per_query():
|
|
"""The factory is invoked once per query (a fresh context per worker),
|
|
never a single shared instance."""
|
|
from unittest.mock import MagicMock
|
|
|
|
# side_effect returns a brand-new context-manager mock on every call.
|
|
factory = MagicMock(side_effect=lambda: MagicMock())
|
|
results = run_parallel_searches(
|
|
["a", "b", "c"], lambda q: q, context_factory=factory
|
|
)
|
|
assert factory.call_count == 3
|
|
assert sorted(results) == [("a", "a"), ("b", "b"), ("c", "c")]
|
|
|
|
|
|
def test_fresh_context_per_worker_survives_concurrency():
|
|
"""Regression for the shared-AppContext crash.
|
|
|
|
Each worker must receive its OWN Flask app context. We force every
|
|
worker to sit inside its pushed context simultaneously (via a barrier);
|
|
with a per-call factory this completes cleanly. The previous design
|
|
shared one AppContext across all workers, which raised
|
|
``ValueError: <Token ...> was created in a different Context`` once two
|
|
workers entered/left it concurrently.
|
|
"""
|
|
app = Flask(__name__)
|
|
queries = ["a", "b", "c", "d"]
|
|
barrier = threading.Barrier(len(queries), timeout=10)
|
|
|
|
def search_fn(q):
|
|
# Block until ALL workers are inside their context at once, forcing
|
|
# the concurrent push/pop that crashed the shared-context design.
|
|
barrier.wait()
|
|
return q
|
|
|
|
results = run_parallel_searches(
|
|
queries, search_fn, context_factory=app.app_context
|
|
)
|
|
assert sorted(results) == [("a", "a"), ("b", "b"), ("c", "c"), ("d", "d")]
|