Files
bot-bottle/tests/test_manifest_runtime.py
T
didericis 1f36d53f7b
test / run tests/run_tests.py (pull_request) Successful in 14s
refactor(manifest): convert TypedDict to frozen dataclasses
Replace the TypedDict + 14 manifest_* free functions with frozen
dataclasses (SshEntry, BottleEgress, Bottle, Agent, Manifest) carrying
their own validators and constructors. Call sites import Manifest and
chain attribute access; the manifest_* helpers and manifest_validate
are gone.

Behavior changes worth flagging:
- Agent.bottle is now required (was optional with a "(none)" fallback).
  Manifest.from_json_obj dies if any agent lacks a 'bottle' field or
  references an undefined bottle, where previously start.py raised the
  error lazily for the specific agent being launched.
- ssh.py now takes SshEntry instances; Host/IdentityFile shape checks
  moved upstream into Manifest construction, leaving only the IdentityFile
  filesystem-existence check in ssh_validate_entries.
- pipelock_bottle_allowlist's per-element string check is dropped — the
  Manifest validator enforces it at load.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-10 21:20:15 -04:00

53 lines
1.6 KiB
Python

"""Unit: bottle runtime — Manifest.from_json_obj defaults runtime to runc,
accepts runsc, and rejects unknown values, non-strings, and empty strings."""
import unittest
from claude_bottle.log import Die
from claude_bottle.manifest import Manifest
_ABSENT = object()
def _bottle(runtime_value: object) -> dict:
"""Build a minimal manifest JSON shape with one bottle whose runtime
field is set (or absent if `runtime_value is _ABSENT`)."""
bottle: dict = {}
if runtime_value is not _ABSENT:
bottle["runtime"] = runtime_value
return {
"bottles": {"dev": bottle},
"agents": {"demo": {"skills": [], "prompt": "", "bottle": "dev"}},
}
class TestManifestBottleRuntime(unittest.TestCase):
def test_default_runc_when_absent(self):
m = Manifest.from_json_obj(_bottle(_ABSENT))
self.assertEqual("runc", m.bottles["dev"].runtime)
def test_explicit_runc(self):
m = Manifest.from_json_obj(_bottle("runc"))
self.assertEqual("runc", m.bottles["dev"].runtime)
def test_explicit_runsc(self):
m = Manifest.from_json_obj(_bottle("runsc"))
self.assertEqual("runsc", m.bottles["dev"].runtime)
def test_rejects_unknown_runtime(self):
with self.assertRaises(Die):
Manifest.from_json_obj(_bottle("kata-runtime"))
def test_rejects_non_string(self):
with self.assertRaises(Die):
Manifest.from_json_obj(_bottle(42))
def test_rejects_empty_string(self):
with self.assertRaises(Die):
Manifest.from_json_obj(_bottle(""))
if __name__ == "__main__":
unittest.main()