Files
OpenViking/tests/conftest.py
T
Qin Haojie 7abd6ab249 refactor(client): remove Python embedded mode (#3712)
* refactor(client): remove Python embedded mode

Consolidate Python consumers on the HTTP SDK while keeping shared server and storage capabilities unchanged.

* refactor(client): remove obsolete embedded leftovers
2026-08-10 18:00:00 +08:00

179 lines
5.7 KiB
Python

# Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd.
# SPDX-License-Identifier: AGPL-3.0
"""Global test fixtures"""
import asyncio
import shutil
from pathlib import Path
from typing import AsyncGenerator, Generator
import pytest
import pytest_asyncio
from openviking.models.embedder.base import DenseEmbedderBase, EmbedResult
from openviking.server.identity import RequestContext, Role
from openviking.service.core import OpenVikingService
from openviking.service.task_tracker import set_task_tracker
from openviking.storage import viking_fs as viking_fs_module
from openviking_cli.session.user_id import UserIdentifier
from openviking_cli.utils.config.embedding_config import EmbeddingConfig
from openviking_cli.utils.config.open_viking_config import OpenVikingConfigSingleton
from tests.utils.mock_agfs import MockLocalAGFS
# ── Workaround: local .so may lack AGFS_Grep symbol (new in latest source) ──
def _patch_agfs_grep_if_missing():
"""Wrap _setup_functions to catch missing AGFS_Grep and skip its binding."""
try:
from openviking.pyagfs.binding_client import BindingLib
_orig_setup = BindingLib._setup_functions
def _safe_setup(self):
try:
_orig_setup(self)
except AttributeError as e:
if "AGFS_Grep" not in str(e):
raise
# Re-implement _setup_functions but skip AGFS_Grep lines.
# We do this by temporarily removing the Grep lines from the
# source, but since we can't edit .so, we monkey-patch the lib
# object's __getattr__ to not fail on AGFS_Grep.
import ctypes
class _GrepStub:
"""Fake ctypes function descriptor for AGFS_Grep."""
argtypes = [
ctypes.c_int64,
ctypes.c_char_p,
ctypes.c_char_p,
ctypes.c_int,
ctypes.c_int,
ctypes.c_int,
ctypes.c_int,
]
restype = ctypes.c_char_p
def __call__(self, *args):
return b'{"error":"AGFS_Grep not available in this .so version"}'
# Patch at the CDLL instance level by overriding __getattr__
orig_class = type(self.lib)
orig_getattr = orig_class.__getattr__
def patched_getattr(cdll_self, name):
if name == "AGFS_Grep":
return _GrepStub()
return orig_getattr(cdll_self, name)
orig_class.__getattr__ = patched_getattr
try:
_orig_setup(self)
finally:
orig_class.__getattr__ = orig_getattr
BindingLib._setup_functions = _safe_setup
except Exception:
pass
_patch_agfs_grep_if_missing()
# Test data root directory
PROJECT_ROOT = Path(__file__).parent.parent
TEST_TMP_DIR = PROJECT_ROOT / "test_data" / "tmp"
@pytest.fixture(scope="session")
def event_loop():
"""Create session-level event loop"""
loop = asyncio.new_event_loop()
yield loop
loop.close()
@pytest.fixture(scope="function")
def temp_dir() -> Generator[Path, None, None]:
"""Create temp directory, auto-cleanup before and after test"""
shutil.rmtree(TEST_TMP_DIR, ignore_errors=True)
TEST_TMP_DIR.mkdir(parents=True, exist_ok=True)
yield TEST_TMP_DIR
@pytest.fixture(scope="function")
def test_data_dir(temp_dir: Path) -> Path:
"""Create test data directory"""
data_dir = temp_dir / "data"
data_dir.mkdir(parents=True, exist_ok=True)
return data_dir
# ============ Service Fixtures ============
@pytest_asyncio.fixture(scope="function")
async def service(
test_data_dir: Path,
monkeypatch,
) -> AsyncGenerator[OpenVikingService, None]:
"""Create an initialized service for domain-level tests."""
previous_viking_fs = viking_fs_module._instance
class FakeEmbedder(DenseEmbedderBase):
def __init__(self):
super().__init__(model_name="test-fake-embedder")
def embed(self, text: str, is_query: bool = False) -> EmbedResult:
return EmbedResult(dense_vector=[0.1] * 1024)
def get_dimension(self) -> int:
return 1024
monkeypatch.setattr(EmbeddingConfig, "get_embedder", lambda self: FakeEmbedder())
mock_agfs = MockLocalAGFS(root_path=test_data_dir / "mock_agfs_root")
monkeypatch.setattr(
"openviking.utils.agfs_utils.create_agfs_client",
lambda *args, **kwargs: mock_agfs,
)
OpenVikingConfigSingleton.reset_instance()
OpenVikingConfigSingleton.initialize(
config_dict={
"storage": {
"workspace": str(test_data_dir),
"agfs": {"backend": "local"},
"vectordb": {"backend": "local"},
},
"embedding": {
"dense": {
"provider": "openai",
"model": "test-embedder",
"api_key": "test-key",
"dimension": 1024,
}
},
}
)
instance = OpenVikingService(
path=str(test_data_dir),
user=UserIdentifier.the_default_user(),
)
try:
await instance.initialize()
yield instance
finally:
await instance.close()
set_task_tracker(None)
viking_fs_module._instance = previous_viking_fs
OpenVikingConfigSingleton.reset_instance()
@pytest.fixture(scope="function")
def request_context() -> RequestContext:
return RequestContext(
user=UserIdentifier.the_default_user(),
role=Role.USER,
)