diff --git a/src/jianda_proxy/config.py b/src/jianda_proxy/config.py new file mode 100644 index 0000000..5f67fe5 --- /dev/null +++ b/src/jianda_proxy/config.py @@ -0,0 +1,70 @@ +import os +import configparser +from pathlib import Path + +SECTION = "proxy" +DEFAULTS = { + "remote_domain": "git.zz.com", + "upstream_host": "62.234.191.215", + "upstream_port": "3000", + "listen_port": "13000", + "listen_host": "127.0.0.1", +} + + +def get_config_dir(): + if os.name == "nt": + base = os.environ.get("APPDATA", os.path.expanduser("~")) + else: + base = os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")) + return os.path.join(base, "jianda-proxy") + + +def _ensure_dir(path): + os.makedirs(path, exist_ok=True) + + +def get_config_path(): + return os.path.join(get_config_dir(), "config.ini") + + +def get_pid_path(): + return os.path.join(get_config_dir(), "daemon.pid") + + +def get_log_path(): + return os.path.join(get_config_dir(), "proxy.log") + + +def load_config(): + path = get_config_path() + _ensure_dir(get_config_dir()) + parser = configparser.ConfigParser() + if not os.path.exists(path): + parser[SECTION] = dict(DEFAULTS) + with open(path, "w") as f: + parser.write(f) + else: + parser.read(path) + if SECTION not in parser: + parser[SECTION] = dict(DEFAULTS) + return parser + + +def set_config_value(key, value): + if key not in DEFAULTS: + raise ValueError(f"Unknown config key: {key}. Valid keys: {', '.join(DEFAULTS)}") + parser = load_config() + parser[SECTION][key] = value + with open(get_config_path(), "w") as f: + parser.write(f) + + +def get_config_value(key): + parser = load_config() + return parser.get(SECTION, key) + + +def list_config(): + parser = load_config() + return dict(parser[SECTION]) diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..89247f8 --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,82 @@ +import os +import tempfile +import pytest +from configparser import ConfigParser +from jianda_proxy.config import ( + get_config_dir, + get_config_path, + get_pid_path, + get_log_path, + load_config, + set_config_value, + get_config_value, + list_config, + DEFAULTS, +) + +FIXTURES = { + "remote_domain": "git.zz.com", + "upstream_host": "62.234.191.215", + "upstream_port": "3000", + "listen_port": "13000", + "listen_host": "127.0.0.1", +} + + +class TestConfigDir: + def test_returns_path_with_app_name(self, tmp_path, monkeypatch): + monkeypatch.setenv("HOME", str(tmp_path)) + result = get_config_dir() + assert "jianda-proxy" in result + + def test_windows_uses_appdata(self, tmp_path, monkeypatch): + monkeypatch.setenv("APPDATA", str(tmp_path)) + monkeypatch.delenv("HOME", raising=False) + monkeypatch.delenv("XDG_CONFIG_HOME", raising=False) + result = get_config_dir() + assert "jianda-proxy" in result + + +class TestConfigCRUD: + def test_load_creates_default_config(self, tmp_path, monkeypatch): + monkeypatch.setattr("jianda_proxy.config.get_config_dir", lambda: str(tmp_path)) + config = load_config() + for key, val in FIXTURES.items(): + assert config.get("proxy", key) == val + + def test_load_creates_config_file(self, tmp_path, monkeypatch): + monkeypatch.setattr("jianda_proxy.config.get_config_dir", lambda: str(tmp_path)) + load_config() + assert (tmp_path / "config.ini").exists() + + def test_set_and_get_value(self, tmp_path, monkeypatch): + monkeypatch.setattr("jianda_proxy.config.get_config_dir", lambda: str(tmp_path)) + set_config_value("listen_port", "8080") + assert get_config_value("listen_port") == "8080" + + def test_set_unknown_key_raises(self, tmp_path, monkeypatch): + monkeypatch.setattr("jianda_proxy.config.get_config_dir", lambda: str(tmp_path)) + with pytest.raises(ValueError, match="Unknown config key"): + set_config_value("nonexistent_key", "value") + + def test_list_config(self, tmp_path, monkeypatch): + monkeypatch.setattr("jianda_proxy.config.get_config_dir", lambda: str(tmp_path)) + load_config() + result = list_config() + assert isinstance(result, dict) + for key, val in FIXTURES.items(): + assert result[key] == val + + +class TestPaths: + def test_config_path(self, tmp_path, monkeypatch): + monkeypatch.setattr("jianda_proxy.config.get_config_dir", lambda: str(tmp_path)) + assert get_config_path().endswith("config.ini") + + def test_pid_path(self, tmp_path, monkeypatch): + monkeypatch.setattr("jianda_proxy.config.get_config_dir", lambda: str(tmp_path)) + assert get_pid_path().endswith("daemon.pid") + + def test_log_path(self, tmp_path, monkeypatch): + monkeypatch.setattr("jianda_proxy.config.get_config_dir", lambda: str(tmp_path)) + assert get_log_path().endswith("proxy.log")