mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-28 13:01:38 +00:00
* merge branch develop with main * bump desktop version * fix the merge * sync Cargo.lock to desktop 2.0.0 * fix cli conftest.py --------- Co-authored-by: deeleeramone <>
191 lines
6.7 KiB
Python
191 lines
6.7 KiB
Python
"""Unit tests for the ``openbb-sec`` command-line interface."""
|
|
|
|
import asyncio
|
|
import json
|
|
import os
|
|
import sys
|
|
from types import SimpleNamespace
|
|
from unittest.mock import AsyncMock
|
|
|
|
import pytest
|
|
|
|
from openbb_sec import cli
|
|
from openbb_sec.utils import cache
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _isolate_cache_env(monkeypatch):
|
|
"""Track the cache-dir env var so writes inside ``main`` are restored."""
|
|
monkeypatch.setenv(cache.CACHE_DIR_ENV_VAR, "__placeholder__")
|
|
monkeypatch.delenv(cache.CACHE_DIR_ENV_VAR, raising=False)
|
|
|
|
|
|
class TestResolveCacheDirectory:
|
|
"""cli.resolve_cache_directory precedence."""
|
|
|
|
def test_explicit_argument_wins(self):
|
|
out = cli.resolve_cache_directory("~/x/sec", discover=False)
|
|
assert out.endswith(os.path.join("x", "sec"))
|
|
assert os.path.isabs(out)
|
|
|
|
def test_env_var_override(self, monkeypatch, tmp_path):
|
|
monkeypatch.setenv(cache.CACHE_DIR_ENV_VAR, str(tmp_path / "envcache"))
|
|
out = cli.resolve_cache_directory(discover=False)
|
|
assert out == str((tmp_path / "envcache").resolve())
|
|
|
|
def test_falls_back_to_preferences(self, monkeypatch):
|
|
monkeypatch.delenv(cache.CACHE_DIR_ENV_VAR, raising=False)
|
|
prefs = SimpleNamespace(cache_directory="/data/openbb")
|
|
settings = SimpleNamespace(preferences=prefs)
|
|
monkeypatch.setattr(
|
|
"openbb_core.app.service.user_service.UserService",
|
|
lambda: SimpleNamespace(default_user_settings=settings),
|
|
)
|
|
out = cli.resolve_cache_directory(discover=False)
|
|
assert out == os.path.join(cli._abs("/data/openbb"), "sec")
|
|
|
|
def test_discover_loads_layered_config(self, monkeypatch, tmp_path):
|
|
called = {}
|
|
monkeypatch.setattr(
|
|
"openbb_core.app.config.loader.load_layered_config",
|
|
lambda: called.setdefault("loaded", True),
|
|
)
|
|
monkeypatch.setenv(cache.CACHE_DIR_ENV_VAR, str(tmp_path / "c"))
|
|
out = cli.resolve_cache_directory(discover=True)
|
|
assert called["loaded"] is True
|
|
assert out == str((tmp_path / "c").resolve())
|
|
|
|
|
|
class TestCreateApp:
|
|
"""cli.create_app factory."""
|
|
|
|
def test_adds_root_endpoints(self, monkeypatch):
|
|
from fastapi import FastAPI
|
|
|
|
fresh = FastAPI()
|
|
monkeypatch.setattr("openbb_core.api.rest_api.app", fresh)
|
|
monkeypatch.setattr(
|
|
"openbb_sec.sec_router.get_widgets_json",
|
|
AsyncMock(return_value={"w": 1}),
|
|
)
|
|
monkeypatch.setattr(
|
|
"openbb_sec.sec_router.get_apps_json",
|
|
AsyncMock(return_value=[{"a": 1}]),
|
|
)
|
|
app = cli.create_app()
|
|
routes = {
|
|
r.path: r
|
|
for r in app.routes
|
|
if getattr(r, "path", "")
|
|
in (
|
|
"/widgets.json",
|
|
"/apps.json",
|
|
)
|
|
}
|
|
assert set(routes) == {"/widgets.json", "/apps.json"}
|
|
widgets = asyncio.run(routes["/widgets.json"].endpoint())
|
|
apps = asyncio.run(routes["/apps.json"].endpoint())
|
|
assert json.loads(bytes(widgets.body)) == {"w": 1}
|
|
assert json.loads(bytes(apps.body)) == [{"a": 1}]
|
|
|
|
def test_idempotent(self, monkeypatch):
|
|
from fastapi import FastAPI
|
|
|
|
fresh = FastAPI()
|
|
monkeypatch.setattr("openbb_core.api.rest_api.app", fresh)
|
|
cli.create_app()
|
|
cli.create_app()
|
|
count = len(
|
|
[r for r in fresh.routes if getattr(r, "path", "") == "/widgets.json"]
|
|
)
|
|
assert count == 1
|
|
|
|
|
|
class TestPrintInfo:
|
|
"""cli._print_info output."""
|
|
|
|
def test_not_created(self, capsys, tmp_path):
|
|
cli._print_info(str(tmp_path / "missing"))
|
|
out = capsys.readouterr().out
|
|
assert "not created yet" in out
|
|
|
|
def test_with_usage(self, capsys, tmp_path):
|
|
(tmp_path / "a.bin").write_bytes(b"hello")
|
|
cli._print_info(str(tmp_path))
|
|
out = capsys.readouterr().out
|
|
assert "Disk usage" in out
|
|
assert "5 bytes" in out
|
|
|
|
|
|
class TestServe:
|
|
"""cli.serve delegation to openbb-api."""
|
|
|
|
def test_invokes_openbb_api(self, monkeypatch):
|
|
captured = {}
|
|
|
|
def fake_run(command, check):
|
|
captured["command"] = command
|
|
captured["check"] = check
|
|
return SimpleNamespace(returncode=0)
|
|
|
|
monkeypatch.setattr("subprocess.run", fake_run)
|
|
monkeypatch.setattr("importlib.util.find_spec", lambda name: object())
|
|
rc = cli.serve(["--port", "7000"])
|
|
assert rc == 0
|
|
assert captured["command"][:3] == [
|
|
sys.executable,
|
|
"-m",
|
|
"openbb_platform_api.main",
|
|
]
|
|
assert "--app" in captured["command"]
|
|
assert cli._APP_FACTORY in captured["command"]
|
|
assert "--factory" in captured["command"]
|
|
assert captured["command"][-2:] == ["--port", "7000"]
|
|
|
|
def test_missing_openbb_api(self, monkeypatch, capsys):
|
|
monkeypatch.setattr("importlib.util.find_spec", lambda name: None)
|
|
rc = cli.serve([])
|
|
assert rc == 1
|
|
assert "openbb-api is required" in capsys.readouterr().out
|
|
|
|
|
|
class TestMain:
|
|
"""cli.main command dispatch."""
|
|
|
|
def test_path(self, monkeypatch, capsys):
|
|
monkeypatch.setattr(cli, "resolve_cache_directory", lambda c: "/tmp/x/sec")
|
|
assert cli.main(["path"]) == 0
|
|
assert capsys.readouterr().out.strip() == "/tmp/x/sec"
|
|
|
|
def test_info(self, monkeypatch, capsys):
|
|
monkeypatch.setattr(cli, "resolve_cache_directory", lambda c: "/tmp/x/sec")
|
|
monkeypatch.setattr(cli, "_print_info", lambda d: print(f"INFO {d}"))
|
|
assert cli.main(["info"]) == 0
|
|
assert "INFO /tmp/x/sec" in capsys.readouterr().out
|
|
|
|
def test_clear(self, monkeypatch, capsys):
|
|
monkeypatch.setattr(cli, "resolve_cache_directory", lambda c: "/tmp/x/sec")
|
|
monkeypatch.setattr(cache, "clear_cache", lambda: 7)
|
|
assert cli.main(["clear"]) == 0
|
|
assert "Cleared 7 cache entries" in capsys.readouterr().out
|
|
|
|
def test_serve_default_with_passthrough(self, monkeypatch):
|
|
monkeypatch.setattr(cli, "resolve_cache_directory", lambda c: "/tmp/x/sec")
|
|
captured = {}
|
|
|
|
def fake_serve(passthrough):
|
|
captured["p"] = passthrough
|
|
return 0
|
|
|
|
monkeypatch.setattr(cli, "serve", fake_serve)
|
|
host = "0.0.0.0" # noqa: S104
|
|
rc = cli.main(["--host", host, "--port", "8000", "--reload"])
|
|
assert rc == 0
|
|
assert captured["p"] == ["--host", host, "--port", "8000", "--reload", "true"]
|
|
|
|
def test_serve_sets_cache_env(self, monkeypatch):
|
|
monkeypatch.setattr(cli, "resolve_cache_directory", lambda c: "/tmp/resolved")
|
|
monkeypatch.setattr(cli, "serve", lambda p: 0)
|
|
cli.main([])
|
|
assert cli.os.environ[cache.CACHE_DIR_ENV_VAR] == "/tmp/resolved"
|