"""test_backend.py —— 后端路径解析三形态 + 远程握手失败拒绝。""" from __future__ import annotations import httpx import pytest from vstore.backend import ( BackendError, LocalBackend, RemoteBackend, handshake, is_remote_spec, parse_backend, ) def test_parse_backend_bare_paths(): backend = parse_backend("/tmp/vault", "/tmp/index") assert isinstance(backend, LocalBackend) assert str(backend.vault_path) == "/tmp/vault" def test_parse_backend_file_url(): backend = parse_backend("file:///tmp/vault", "file:///tmp/index") assert isinstance(backend, LocalBackend) assert str(backend.vault_path) == "/tmp/vault" # file:// 前缀剥掉 assert str(backend.index_path) == "/tmp/index" def test_parse_backend_http_urls(): backend = parse_backend("http://h1:1/vault", "https://h2:2/index") assert isinstance(backend, RemoteBackend) assert backend.vault_url == "http://h1:1/vault" assert backend.index_url == "https://h2:2/index" def test_parse_backend_mixed_rejected(): with pytest.raises(BackendError): parse_backend("/tmp/vault", "http://h:1/index") def test_is_remote_spec(): assert is_remote_spec("http://x") assert is_remote_spec("https://x") assert not is_remote_spec("file:///x") assert not is_remote_spec("/tmp/x") assert not is_remote_spec("ftp://x") # 仅 http/https 视为远程 def test_local_handshake_ok(tmp_path): backend = LocalBackend(str(tmp_path / "vault"), str(tmp_path / "index")) handshake(backend) # 不抛 assert (tmp_path / "vault").exists() def test_remote_health_ok(monkeypatch): def fake_get(url, timeout=None): assert url.endswith("/health") return httpx.Response(200, json={"ok": True, "count": 0}, request=httpx.Request("GET", url)) monkeypatch.setattr("vstore.backend.httpx.get", fake_get) backend = RemoteBackend("http://h:1/v", "http://h:2/i") assert backend.health()["ok"] is True def test_remote_handshake_failure_rejected(monkeypatch): def fake_get(url, timeout=None): raise httpx.ConnectError("down", request=None) monkeypatch.setattr("vstore.backend.httpx.get", fake_get) backend = RemoteBackend("http://h:1/v", "http://h:2/i") with pytest.raises(BackendError): handshake(backend) def test_remote_search_empty_handshake(monkeypatch): def fake_get(url, timeout=None, params=None): return httpx.Response(200, json={"ok": True, "mode": "latest", "items": []}, request=httpx.Request("GET", url)) monkeypatch.setattr("vstore.backend.httpx.get", fake_get) backend = RemoteBackend("http://h:1/v", "http://h:2/i") assert backend.search_empty()["ok"] is True