mirror of
https://github.com/HKUDS/OpenSpace.git
synced 2026-09-11 22:51:05 +00:00
Merge 2b0c8d4a99 into 4791133e11
This commit is contained in:
commit
42f50cc395
4 changed files with 187 additions and 0 deletions
|
|
@ -83,3 +83,7 @@ openspace = [
|
|||
"local_server/config.json",
|
||||
"local_server/README.md",
|
||||
]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
python_files = ["test_*.py"]
|
||||
|
|
|
|||
56
tests/cloud/test_client.py
Normal file
56
tests/cloud/test_client.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import importlib.util
|
||||
import io
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def _load_module():
|
||||
module_path = Path(__file__).resolve().parents[2] / "openspace" / "cloud" / "client.py"
|
||||
spec = importlib.util.spec_from_file_location("openspace_cloud_client_test", module_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
assert spec and spec.loader
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
_client = _load_module()
|
||||
CloudError = _client.CloudError
|
||||
OpenSpaceClient = _client.OpenSpaceClient
|
||||
|
||||
|
||||
def _zip_bytes(files: dict[str, str]) -> bytes:
|
||||
buffer = io.BytesIO()
|
||||
with zipfile.ZipFile(buffer, mode="w") as zf:
|
||||
for name, content in files.items():
|
||||
zf.writestr(name, content)
|
||||
return buffer.getvalue()
|
||||
|
||||
|
||||
def test_extract_zip_skips_path_traversal_entries(tmp_path: Path):
|
||||
zip_data = _zip_bytes(
|
||||
{
|
||||
"SKILL.md": "name: demo",
|
||||
"../escape.txt": "nope",
|
||||
"/absolute.txt": "nope",
|
||||
"nested/file.txt": "ok",
|
||||
}
|
||||
)
|
||||
|
||||
extracted = OpenSpaceClient._extract_zip(zip_data, tmp_path)
|
||||
|
||||
assert extracted == ["SKILL.md", "nested/file.txt"]
|
||||
assert (tmp_path / "SKILL.md").read_text(encoding="utf-8") == "name: demo"
|
||||
assert (tmp_path / "nested" / "file.txt").read_text(encoding="utf-8") == "ok"
|
||||
|
||||
|
||||
def test_validate_origin_parents_enforces_fixed_origin():
|
||||
with pytest.raises(CloudError, match="exactly 1 parent_skill_id"):
|
||||
OpenSpaceClient._validate_origin_parents("fixed", [])
|
||||
|
||||
OpenSpaceClient._validate_origin_parents("fixed", ["parent-1"])
|
||||
|
||||
|
||||
def test_unified_diff_returns_none_when_snapshots_match():
|
||||
assert OpenSpaceClient._unified_diff({"a.txt": "same\n"}, {"a.txt": "same\n"}) is None
|
||||
42
tests/config/test_utils.py
Normal file
42
tests/config/test_utils.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _load_module():
|
||||
module_path = Path(__file__).resolve().parents[2] / "openspace" / "config" / "utils.py"
|
||||
spec = importlib.util.spec_from_file_location("openspace_config_utils_test", module_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
assert spec and spec.loader
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
_utils = _load_module()
|
||||
get_config_value = _utils.get_config_value
|
||||
load_json_file = _utils.load_json_file
|
||||
save_json_file = _utils.save_json_file
|
||||
|
||||
|
||||
def test_pytest_scaffold_uses_tests_directory(pytestconfig):
|
||||
assert pytestconfig.getini("testpaths") == ["tests"]
|
||||
|
||||
|
||||
def test_get_config_value_supports_dict_and_object():
|
||||
config_dict = {"value": 42}
|
||||
|
||||
class ConfigObject:
|
||||
value = 42
|
||||
|
||||
assert get_config_value(config_dict, "value") == 42
|
||||
assert get_config_value(ConfigObject(), "value") == 42
|
||||
assert get_config_value(config_dict, "missing", "fallback") == "fallback"
|
||||
|
||||
|
||||
def test_save_and_load_json_round_trip(tmp_path: Path):
|
||||
payload = {"name": "openspace", "nested": {"enabled": True}}
|
||||
target = tmp_path / "nested" / "config.json"
|
||||
|
||||
save_json_file(payload, target)
|
||||
|
||||
assert target.exists()
|
||||
assert load_json_file(target) == payload
|
||||
85
tests/host_detection/test_nanobot.py
Normal file
85
tests/host_detection/test_nanobot.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _load_module():
|
||||
module_path = Path(__file__).resolve().parents[2] / "openspace" / "host_detection" / "nanobot.py"
|
||||
spec = importlib.util.spec_from_file_location("openspace_nanobot_test", module_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
assert spec and spec.loader
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
_nanobot = _load_module()
|
||||
match_provider = _nanobot.match_provider
|
||||
|
||||
|
||||
def test_match_provider_prefers_forced_provider():
|
||||
providers = {
|
||||
"openai": {"apiKey": "oa-key", "apiBase": "https://openai.example/v1"},
|
||||
"minimax": {"apiKey": "mini-key", "apiBase": "https://minimax.example/v1"},
|
||||
}
|
||||
|
||||
result = match_provider(providers, model="anything", forced_provider="minimax")
|
||||
|
||||
assert result == {
|
||||
"api_key": "mini-key",
|
||||
"api_base": "https://minimax.example/v1",
|
||||
}
|
||||
|
||||
|
||||
def test_read_nanobot_mcp_env_returns_openspace_env(tmp_path: Path, monkeypatch):
|
||||
config_path = tmp_path / "config.json"
|
||||
config_path.write_text(
|
||||
"""
|
||||
{
|
||||
"tools": {
|
||||
"mcpServers": {
|
||||
"openspace": {
|
||||
"env": {
|
||||
"OPENSPACE_MODEL": "openrouter/anthropic/claude"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".strip(),
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(_nanobot, "NANOBOT_CONFIG_PATH", config_path)
|
||||
|
||||
assert _nanobot.read_nanobot_mcp_env() == {"OPENSPACE_MODEL": "openrouter/anthropic/claude"}
|
||||
|
||||
|
||||
def test_try_read_nanobot_config_extracts_model_and_provider(tmp_path: Path, monkeypatch):
|
||||
config_path = tmp_path / "config.json"
|
||||
config_path.write_text(
|
||||
"""
|
||||
{
|
||||
"providers": {
|
||||
"minimax": {
|
||||
"apiKey": "mini-key",
|
||||
"apiBase": "https://minimax.example/v1"
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"model": "minimax/text-01",
|
||||
"provider": "minimax"
|
||||
}
|
||||
}
|
||||
}
|
||||
""".strip(),
|
||||
encoding="utf-8",
|
||||
)
|
||||
monkeypatch.setattr(_nanobot, "NANOBOT_CONFIG_PATH", config_path)
|
||||
|
||||
result = _nanobot.try_read_nanobot_config("")
|
||||
|
||||
assert result == {
|
||||
"api_key": "mini-key",
|
||||
"api_base": "https://minimax.example/v1",
|
||||
"_model": "minimax/text-01",
|
||||
"_forced_provider": "minimax",
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue