deepseek-cursor-proxy/tests/test_config.py

243 lines
9.1 KiB
Python

from __future__ import annotations
import os
from pathlib import Path
import stat
from tempfile import TemporaryDirectory
import unittest
from unittest.mock import patch
from deepseek_cursor_proxy.config import (
DEFAULT_MISSING_REASONING_STRATEGY,
DEFAULT_NGROK,
DEFAULT_PORT,
DEFAULT_REASONING_CACHE_MAX_AGE_SECONDS,
DEFAULT_REASONING_CACHE_MAX_ROWS,
DEFAULT_THINKING,
DEFAULT_UPSTREAM_MODEL,
DEFAULT_VERBOSE,
ProxyConfig,
default_config_path,
default_reasoning_content_path,
)
class ConfigTests(unittest.TestCase):
def test_default_paths_live_in_visible_user_app_directory(self) -> None:
home = Path("/tmp/home")
with patch("deepseek_cursor_proxy.config.Path.home", return_value=home):
self.assertEqual(
default_config_path(), home / ".deepseek-cursor-proxy" / "config.yaml"
)
self.assertEqual(
default_reasoning_content_path(),
home / ".deepseek-cursor-proxy" / "reasoning_content.sqlite3",
)
self.assertEqual(
ProxyConfig().reasoning_content_path,
home / ".deepseek-cursor-proxy" / "reasoning_content.sqlite3",
)
self.assertEqual(ProxyConfig().ngrok, DEFAULT_NGROK)
def test_missing_default_config_file_is_populated(self) -> None:
with TemporaryDirectory() as temp_dir:
home = Path(temp_dir)
with patch("deepseek_cursor_proxy.config.Path.home", return_value=home):
config = ProxyConfig.from_file(config_path=None)
config_path = default_config_path()
config_text = config_path.read_text(encoding="utf-8")
self.assertTrue(config_path.exists())
self.assertIn(f"model: {DEFAULT_UPSTREAM_MODEL}", config_text)
self.assertIn(
f"missing_reasoning_strategy: {DEFAULT_MISSING_REASONING_STRATEGY}",
config_text,
)
self.assertIn(
"reasoning_cache_max_age_seconds: "
f"{DEFAULT_REASONING_CACHE_MAX_AGE_SECONDS}",
config_text,
)
self.assertIn(
f"reasoning_cache_max_rows: {DEFAULT_REASONING_CACHE_MAX_ROWS}",
config_text,
)
self.assertIn(f"ngrok: {str(DEFAULT_NGROK).lower()}", config_text)
self.assertEqual(stat.S_IMODE(config_path.stat().st_mode), 0o600)
self.assertEqual(config.upstream_model, DEFAULT_UPSTREAM_MODEL)
self.assertEqual(config.ngrok, DEFAULT_NGROK)
self.assertEqual(
config.missing_reasoning_strategy, DEFAULT_MISSING_REASONING_STRATEGY
)
self.assertEqual(
config.reasoning_cache_max_age_seconds,
DEFAULT_REASONING_CACHE_MAX_AGE_SECONDS,
)
self.assertEqual(
config.reasoning_cache_max_rows, DEFAULT_REASONING_CACHE_MAX_ROWS
)
def test_missing_explicit_config_file_is_not_populated(self) -> None:
with TemporaryDirectory() as temp_dir:
config_path = Path(temp_dir) / "missing.yaml"
config = ProxyConfig.from_file(config_path=config_path)
self.assertFalse(config_path.exists())
self.assertEqual(config.upstream_model, DEFAULT_UPSTREAM_MODEL)
self.assertEqual(config.ngrok, DEFAULT_NGROK)
self.assertEqual(
config.reasoning_cache_max_age_seconds,
DEFAULT_REASONING_CACHE_MAX_AGE_SECONDS,
)
self.assertEqual(
config.reasoning_cache_max_rows, DEFAULT_REASONING_CACHE_MAX_ROWS
)
def test_loads_config_from_user_yaml_file(self) -> None:
with TemporaryDirectory() as temp_dir:
config_path = Path(temp_dir) / "config.yaml"
reasoning_content_path = Path(temp_dir) / "reasoning_content.sqlite3"
config_path.write_text(
"\n".join(
[
"base_url: https://example.com/v1/",
"model: deepseek-v4-flash",
"thinking: pass_through",
"reasoning_effort: max",
"port: 9100",
"host: 0.0.0.0",
"ngrok: true",
"verbose: true",
"request_timeout: 123.5",
"max_request_body_bytes: 1234",
"cors: true",
"display_reasoning: false",
f"reasoning_content_path: {reasoning_content_path}",
"missing_reasoning_strategy: reject",
"reasoning_cache_max_age_seconds: 60",
"reasoning_cache_max_rows: 50",
]
),
encoding="utf-8",
)
config = ProxyConfig.from_file(config_path=config_path)
self.assertEqual(config.upstream_base_url, "https://example.com/v1")
self.assertEqual(config.upstream_model, "deepseek-v4-flash")
self.assertEqual(config.thinking, "pass-through")
self.assertEqual(config.reasoning_effort, "max")
self.assertEqual(config.host, "0.0.0.0")
self.assertEqual(config.port, 9100)
self.assertTrue(config.ngrok)
self.assertTrue(config.verbose)
self.assertEqual(config.request_timeout, 123.5)
self.assertEqual(config.max_request_body_bytes, 1234)
self.assertTrue(config.cors)
self.assertFalse(config.cursor_display_reasoning)
self.assertEqual(config.reasoning_content_path, reasoning_content_path)
self.assertEqual(config.missing_reasoning_strategy, "reject")
self.assertEqual(config.reasoning_cache_max_age_seconds, 60)
self.assertEqual(config.reasoning_cache_max_rows, 50)
def test_invalid_config_values_fall_back_to_defaults(self) -> None:
with TemporaryDirectory() as temp_dir:
config_path = Path(temp_dir) / "config.yaml"
config_path.write_text(
"\n".join(
[
"thinking: maybe",
"missing_reasoning_strategy: maybe",
"port: nope",
"verbose: maybe",
]
),
encoding="utf-8",
)
config = ProxyConfig.from_file(config_path=config_path)
self.assertEqual(config.thinking, DEFAULT_THINKING)
self.assertEqual(
config.missing_reasoning_strategy, DEFAULT_MISSING_REASONING_STRATEGY
)
self.assertEqual(config.port, DEFAULT_PORT)
self.assertEqual(config.ngrok, DEFAULT_NGROK)
self.assertEqual(config.verbose, DEFAULT_VERBOSE)
def test_relative_reasoning_content_path_in_config_is_relative_to_config_file(
self,
) -> None:
with TemporaryDirectory() as temp_dir:
config_path = Path(temp_dir) / "config.yaml"
config_path.write_text(
"\n".join(
[
"reasoning_content_path: custom.sqlite3",
]
),
encoding="utf-8",
)
config = ProxyConfig.from_file(config_path=config_path)
self.assertEqual(
config.reasoning_content_path, Path(temp_dir) / "custom.sqlite3"
)
def test_cursor_reasoning_display_can_be_disabled_from_config(self) -> None:
with TemporaryDirectory() as temp_dir:
config_path = Path(temp_dir) / "config.yaml"
config_path.write_text(
"\n".join(
[
"display_reasoning: false",
]
),
encoding="utf-8",
)
config = ProxyConfig.from_file(config_path=config_path)
self.assertFalse(config.cursor_display_reasoning)
def test_invalid_yaml_config_raises_value_error(self) -> None:
with TemporaryDirectory() as temp_dir:
config_path = Path(temp_dir) / "config.yaml"
config_path.write_text("- not\n- a\n- mapping\n", encoding="utf-8")
with self.assertRaises(ValueError):
ProxyConfig.from_file(config_path=config_path)
def test_process_environment_does_not_override_config(self) -> None:
with TemporaryDirectory() as temp_dir:
config_path = Path(temp_dir) / "config.yaml"
config_path.write_text("verbose: false\n", encoding="utf-8")
with patch.dict(
"os.environ",
{
"PROXY_VERBOSE": "true",
"DEEPSEEK_CURSOR_PROXY_CONFIG_PATH": "/ignored.yaml",
},
clear=True,
):
config = ProxyConfig.from_file(config_path=config_path)
self.assertEqual(
dict(os.environ),
{
"PROXY_VERBOSE": "true",
"DEEPSEEK_CURSOR_PROXY_CONFIG_PATH": "/ignored.yaml",
},
)
self.assertFalse(config.verbose)
if __name__ == "__main__":
unittest.main()