You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
90 lines
3.0 KiB
90 lines
3.0 KiB
|
2 months ago
|
# -*- coding: utf-8 -*-
|
||
|
|
"""Integration tests for system configuration API endpoints."""
|
||
|
|
|
||
|
|
import os
|
||
|
|
import tempfile
|
||
|
|
import unittest
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
from fastapi.testclient import TestClient
|
||
|
|
|
||
|
|
from api.app import create_app
|
||
|
|
from src.config import Config
|
||
|
|
|
||
|
|
|
||
|
|
class SystemConfigApiTestCase(unittest.TestCase):
|
||
|
|
def setUp(self) -> None:
|
||
|
|
self.temp_dir = tempfile.TemporaryDirectory()
|
||
|
|
self.env_path = Path(self.temp_dir.name) / ".env"
|
||
|
|
self.env_path.write_text(
|
||
|
|
"\n".join(
|
||
|
|
[
|
||
|
|
"STOCK_LIST=600519,000001",
|
||
|
|
"GEMINI_API_KEY=secret-key-value",
|
||
|
|
"SCHEDULE_TIME=18:00",
|
||
|
|
"LOG_LEVEL=INFO",
|
||
|
|
]
|
||
|
|
)
|
||
|
|
+ "\n",
|
||
|
|
encoding="utf-8",
|
||
|
|
)
|
||
|
|
os.environ["ENV_FILE"] = str(self.env_path)
|
||
|
|
Config.reset_instance()
|
||
|
|
|
||
|
|
app = create_app(static_dir=Path(self.temp_dir.name) / "empty-static")
|
||
|
|
self.client = TestClient(app)
|
||
|
|
|
||
|
|
def tearDown(self) -> None:
|
||
|
|
Config.reset_instance()
|
||
|
|
os.environ.pop("ENV_FILE", None)
|
||
|
|
self.temp_dir.cleanup()
|
||
|
|
|
||
|
|
def test_get_config_returns_raw_secret_value(self) -> None:
|
||
|
|
response = self.client.get("/api/v1/system/config")
|
||
|
|
self.assertEqual(response.status_code, 200)
|
||
|
|
|
||
|
|
payload = response.json()
|
||
|
|
item_map = {item["key"]: item for item in payload["items"]}
|
||
|
|
self.assertEqual(item_map["GEMINI_API_KEY"]["value"], "secret-key-value")
|
||
|
|
self.assertFalse(item_map["GEMINI_API_KEY"]["is_masked"])
|
||
|
|
|
||
|
|
def test_put_config_updates_secret_and_plain_field(self) -> None:
|
||
|
|
current = self.client.get("/api/v1/system/config").json()
|
||
|
|
|
||
|
|
response = self.client.put(
|
||
|
|
"/api/v1/system/config",
|
||
|
|
json={
|
||
|
|
"config_version": current["config_version"],
|
||
|
|
"mask_token": "******",
|
||
|
|
"reload_now": False,
|
||
|
|
"items": [
|
||
|
|
{"key": "GEMINI_API_KEY", "value": "new-secret-value"},
|
||
|
|
{"key": "STOCK_LIST", "value": "600519,300750"},
|
||
|
|
],
|
||
|
|
},
|
||
|
|
)
|
||
|
|
self.assertEqual(response.status_code, 200)
|
||
|
|
payload = response.json()
|
||
|
|
self.assertEqual(payload["applied_count"], 2)
|
||
|
|
self.assertEqual(payload["skipped_masked_count"], 0)
|
||
|
|
|
||
|
|
env_content = self.env_path.read_text(encoding="utf-8")
|
||
|
|
self.assertIn("STOCK_LIST=600519,300750", env_content)
|
||
|
|
self.assertIn("GEMINI_API_KEY=new-secret-value", env_content)
|
||
|
|
|
||
|
|
def test_put_config_returns_conflict_when_version_is_stale(self) -> None:
|
||
|
|
response = self.client.put(
|
||
|
|
"/api/v1/system/config",
|
||
|
|
json={
|
||
|
|
"config_version": "stale-version",
|
||
|
|
"items": [{"key": "STOCK_LIST", "value": "600519"}],
|
||
|
|
},
|
||
|
|
)
|
||
|
|
self.assertEqual(response.status_code, 409)
|
||
|
|
payload = response.json()
|
||
|
|
self.assertEqual(payload["error"], "config_version_conflict")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
unittest.main()
|