test_profile_runtime_repair.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import importlib.util
  2. import tempfile
  3. import unittest
  4. from pathlib import Path
  5. spec = importlib.util.spec_from_file_location('profile_repair', Path(__file__).parents[1] / 'profile_runtime_repair.py')
  6. repair = importlib.util.module_from_spec(spec)
  7. spec.loader.exec_module(repair)
  8. SERVER = '''
  9. def _resolve_model() -> str:
  10. if env := _env_model_seed():
  11. return env
  12. m = _load_cfg().get("model", "")
  13. if isinstance(m, dict):
  14. return str(m.get("default", "") or "").strip()
  15. if isinstance(m, str) and m:
  16. return m.strip()
  17. # No env seed / config preference: native fallback.
  18. return "fallback"
  19. def _resolve_startup_runtime():
  20. model = _resolve_model()
  21. return model, "launch-provider"
  22. '''
  23. METHODS = '''
  24. @method("session.create")
  25. def create(rid, params):
  26. return _resolve_model()
  27. @method("session.resume")
  28. def resume(rid, params):
  29. return _resolve_model()
  30. '''
  31. class ProfileRepairTests(unittest.TestCase):
  32. def setUp(self):
  33. self.temp = tempfile.TemporaryDirectory()
  34. self.root = Path(self.temp.name)
  35. gateway = self.root / 'tui_gateway'
  36. gateway.mkdir()
  37. (gateway / 'server.py').write_text(SERVER)
  38. (gateway / 'methods_session.py').write_text(METHODS)
  39. def tearDown(self):
  40. self.temp.cleanup()
  41. def test_configured_profile_model_and_provider_win_over_launch_environment(self):
  42. prepared = repair.prepare(self.root)
  43. namespace = {'_env_model_seed': lambda: 'gpt-5.6-terra',
  44. '_load_cfg': lambda: {'model': {'default': 'grok-4.6'}},
  45. '_config_model_target': lambda: ('grok-4.6', 'custom:yaoer')}
  46. exec(prepared[0][2], namespace)
  47. self.assertEqual(namespace['_resolve_model'](), 'grok-4.6')
  48. self.assertEqual(namespace['_resolve_startup_runtime'](), ('grok-4.6', 'custom:yaoer'))
  49. namespace['_load_cfg'] = lambda: {}
  50. self.assertEqual(namespace['_resolve_model'](), 'gpt-5.6-terra')
  51. namespace['_load_cfg'] = lambda: {'model': {'default': ''}}
  52. self.assertEqual(namespace['_resolve_model'](), 'gpt-5.6-terra')
  53. # Preparation is read-only; activation belongs to the transactional installer.
  54. self.assertEqual(prepared[0][0].read_text(), SERVER)
  55. def test_create_and_resume_metadata_run_in_requested_profile_and_restore_context(self):
  56. profile = ['default']
  57. methods = {}
  58. def method(name):
  59. def register(handler):
  60. methods[name] = handler
  61. return handler
  62. return register
  63. def scoped(handler):
  64. def wrapped(rid, params):
  65. old = profile[0]
  66. profile[0] = params['profile']
  67. try:
  68. return handler(rid, params)
  69. finally:
  70. profile[0] = old
  71. return wrapped
  72. namespace = {'method': method, '_profile_scoped': scoped,
  73. '_resolve_model': lambda: {'default': 'gpt-5.6-terra', 'yaoer': 'grok-4.6'}[profile[0]]}
  74. exec(repair.prepare(self.root)[1][2], namespace)
  75. for handler in methods.values():
  76. self.assertEqual(handler('id', {'profile': 'yaoer'}), 'grok-4.6')
  77. self.assertEqual(profile[0], 'default')
  78. def test_idempotent_repair_and_unknown_source_is_rejected_without_writes(self):
  79. for path, _, updated in repair.prepare(self.root):
  80. path.write_bytes(updated)
  81. self.assertTrue(all(before == after for _, before, after in repair.prepare(self.root)))
  82. server = self.root / 'tui_gateway' / 'server.py'
  83. server.write_text('def incompatible(): pass\n')
  84. with self.assertRaises(ValueError):
  85. repair.prepare(self.root)
  86. self.assertEqual(server.read_text(), 'def incompatible(): pass\n')