from __future__ import annotations import os import unittest from contextlib import contextmanager from unittest.mock import patch from app.config import AgentConfig, load_config @contextmanager def temp_env(**overrides: str | None): originals: dict[str, str | None] = {} try: for key, value in overrides.items(): originals[key] = os.environ.get(key) if value is None: os.environ.pop(key, None) else: os.environ[key] = value yield finally: for key, original in originals.items(): if original is None: os.environ.pop(key, None) else: os.environ[key] = original class LoadConfigMetadataTests(unittest.TestCase): @patch("app.config.Path.mkdir") def test_metadata_from_environment_variables(self, mock_mkdir): with temp_env( MASTER_ENDPOINT="http://master.local", AGENT_HOSTNAME="dev-user-one-pod", AGENT_ENV="prod", AGENT_USER="ops", AGENT_INSTANCE="node-1", ): config = load_config() self.assertEqual(config.environment, "prod") self.assertEqual(config.user, "ops") self.assertEqual(config.instance, "node-1") mock_mkdir.assert_called() @patch("app.config.Path.mkdir") def test_metadata_falls_back_to_hostname(self, mock_mkdir): with temp_env( MASTER_ENDPOINT="http://master.local", AGENT_HOSTNAME="qa-team-abc-pod-2", AGENT_ENV=None, AGENT_USER=None, AGENT_INSTANCE=None, ): config = load_config() self.assertEqual(config.environment, "qa") self.assertEqual(config.user, "team") self.assertEqual(config.instance, "abc") mock_mkdir.assert_called() @patch("app.config._load_metadata_from_state", return_value=("prod", "ops", "node-1")) @patch("app.config.Path.mkdir") def test_metadata_from_node_state(self, mock_mkdir, mock_state): with temp_env( MASTER_ENDPOINT="http://master.local", AGENT_HOSTNAME="host_abc", AGENT_ENV=None, AGENT_USER=None, AGENT_INSTANCE=None, ): config = load_config() self.assertEqual(config.environment, "prod") self.assertEqual(config.user, "ops") self.assertEqual(config.instance, "node-1") mock_state.assert_called_once() mock_mkdir.assert_called() @patch("app.config.Path.mkdir") def test_partial_environment_variables_fallback(self, mock_mkdir): with temp_env( MASTER_ENDPOINT="http://master.local", AGENT_HOSTNAME="stage-ml-001-node", AGENT_ENV="prod", AGENT_USER=None, AGENT_INSTANCE=None, ): config = load_config() self.assertEqual(config.environment, "stage") self.assertEqual(config.user, "ml") self.assertEqual(config.instance, "001") mock_mkdir.assert_called() @patch("app.config.Path.mkdir") def test_invalid_hostname_raises_error(self, mock_mkdir): with temp_env( MASTER_ENDPOINT="http://master.local", AGENT_HOSTNAME="invalidhostname", AGENT_ENV=None, AGENT_USER=None, AGENT_INSTANCE=None, ): with self.assertRaises(ValueError): load_config() mock_mkdir.assert_not_called() class CollectMetadataTests(unittest.TestCase): @patch("app.collector._detect_ip_address", return_value="127.0.0.1") @patch("app.collector._detect_gpu_count", return_value=0) @patch("app.collector._detect_memory_bytes", return_value=1024) @patch("app.collector._detect_cpu_count", return_value=8) def test_collect_metadata_uses_config_fields( self, mock_cpu, mock_memory, mock_gpu, mock_ip, ): config = AgentConfig( hostname="dev-user-001-pod", environment="prod", user="ops", instance="node-1", node_file="/tmp/node.json", version="1.0.0", master_endpoint="http://master.local", report_interval_seconds=60, health_dir="/tmp/health", ) from app.collector import collect_metadata metadata = collect_metadata(config) self.assertEqual(metadata["env"], "prod") self.assertEqual(metadata["user"], "ops") self.assertEqual(metadata["instance"], "node-1") self.assertEqual(metadata["hostname"], "dev-user-001-pod") self.assertEqual(metadata["ip"], "127.0.0.1") self.assertEqual(metadata["cpu_number"], 8) self.assertEqual(metadata["memory_in_bytes"], 1024) self.assertEqual(metadata["gpu_number"], 0) if __name__ == "__main__": unittest.main()