#!/usr/bin/env python3 """ Tests for the `logging` section of cell_config (ConfigManager): - default schema present after first load - round-trip persistence of python + container levels - migration from the legacy config/api/log_levels.json side-file - invalid-level rejection - inclusion in the backed-up cell_config """ import sys import os import json import tempfile import shutil import unittest from pathlib import Path api_dir = Path(__file__).parent.parent / 'api' sys.path.insert(0, str(api_dir)) from config_manager import ConfigManager def _make_cm(tmp): config_file = os.path.join(tmp, 'cell_config.json') data_dir = os.path.join(tmp, 'data') os.makedirs(data_dir, exist_ok=True) return ConfigManager(config_file, data_dir) class TestLoggingSchema(unittest.TestCase): def setUp(self): self.tmp = tempfile.mkdtemp() def tearDown(self): shutil.rmtree(self.tmp, ignore_errors=True) def test_default_logging_config_present(self): cm = _make_cm(self.tmp) cfg = cm.get_logging_config() self.assertEqual(cfg['python']['root'], 'INFO') self.assertEqual(cfg['python']['services']['network'], 'INFO') self.assertEqual(cfg['containers']['caddy'], 'INFO') self.assertEqual(cfg['containers']['coredns'], 'INFO') def test_set_and_get_python_level_round_trip(self): cm = _make_cm(self.tmp) cm.set_python_log_level('network', 'DEBUG') cm.set_python_log_level('root', 'WARNING') # Re-load from disk to prove persistence. cm2 = _make_cm(self.tmp) cfg = cm2.get_logging_config() self.assertEqual(cfg['python']['services']['network'], 'DEBUG') self.assertEqual(cfg['python']['root'], 'WARNING') def test_set_and_get_container_level_round_trip(self): cm = _make_cm(self.tmp) cm.set_container_log_level('coredns', 'DEBUG') cm2 = _make_cm(self.tmp) self.assertEqual(cm2.get_logging_config()['containers']['coredns'], 'DEBUG') def test_invalid_python_level_rejected(self): cm = _make_cm(self.tmp) with self.assertRaises(ValueError): cm.set_python_log_level('network', 'LOUD') def test_invalid_container_level_rejected(self): cm = _make_cm(self.tmp) with self.assertRaises(ValueError): cm.set_container_log_level('caddy', 'chatty') def test_migration_from_legacy_log_levels_json(self): # Legacy side-file lived at config/api/log_levels.json (next to cell_config). api_cfg_dir = os.path.join(self.tmp, 'api') os.makedirs(api_cfg_dir, exist_ok=True) with open(os.path.join(api_cfg_dir, 'log_levels.json'), 'w') as f: json.dump({'network': 'DEBUG', 'email': 'WARNING', 'bogus': 'INFO'}, f) cm = _make_cm(self.tmp) cfg = cm.get_logging_config() self.assertEqual(cfg['python']['services']['network'], 'DEBUG') self.assertEqual(cfg['python']['services']['email'], 'WARNING') # Unknown service names from the legacy file are ignored. self.assertNotIn('bogus', cfg['python']['services']) def test_logging_section_is_part_of_persisted_config(self): """The logging section lives in cell_config (already in the backup set).""" cm = _make_cm(self.tmp) cm.set_python_log_level('vault', 'ERROR') with open(cm.config_file) as f: on_disk = json.load(f) self.assertIn('logging', on_disk) self.assertEqual(on_disk['logging']['python']['services']['vault'], 'ERROR') if __name__ == '__main__': unittest.main()