f2891a1634
Address PR #395 review (two P1s): - Version hash covered only `bot_bottle/**.py`, but the image `COPY`s the whole package — non-Python inputs baked in (egress_entrypoint.sh, netpool.defaults.env) didn't change the version, so a launch host could boot a stale rootfs whose code differs from its checkout. Hash every regular file under bot_bottle/ (excluding __pycache__/.pyc). Regression tests: a shell-script change bumps the version; .pyc/__pycache__ don't. - publish_infra `_put` read the whole (hundreds-of-MB) gz into memory via read_bytes(). Stream it from disk with an explicit Content-Length; the tiny .sha256 stays in-memory. Test asserts the body is the file object, not bytes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoEZHDjv84ChoZbozQERhJ
63 lines
2.0 KiB
Python
63 lines
2.0 KiB
Python
"""Unit: the infra-artifact publisher's upload path (PRD 0069 Stage 2).
|
|
|
|
The rootfs is hundreds of MB, so `_put` must stream it from disk rather than
|
|
read it into memory. Network is mocked; no Docker, no real build.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import tempfile
|
|
import unittest
|
|
import urllib.request
|
|
from pathlib import Path
|
|
from unittest import mock
|
|
|
|
from bot_bottle.backend.firecracker import publish_infra as pub
|
|
|
|
|
|
class _Resp:
|
|
status = 201
|
|
|
|
def __enter__(self) -> "_Resp":
|
|
return self
|
|
|
|
def __exit__(self, *a: object) -> bool:
|
|
return False
|
|
|
|
|
|
class TestPut(unittest.TestCase):
|
|
def test_streams_file_body_with_content_length(self) -> None:
|
|
captured: list[urllib.request.Request] = []
|
|
|
|
def fake_urlopen(req: urllib.request.Request, *a: object, **k: object) -> _Resp:
|
|
captured.append(req)
|
|
return _Resp()
|
|
|
|
with tempfile.TemporaryDirectory() as d:
|
|
f = Path(d) / "rootfs.ext4.gz"
|
|
payload = b"x" * 4096
|
|
f.write_bytes(payload)
|
|
with mock.patch.object(pub.urllib.request, "urlopen", fake_urlopen):
|
|
pub._put("https://reg/pkg", f, token="t")
|
|
|
|
req = captured[0]
|
|
# Body is the open file object (streamed), never the bytes in memory.
|
|
self.assertTrue(hasattr(req.data, "read"))
|
|
self.assertNotIsInstance(req.data, (bytes, bytearray))
|
|
self.assertEqual(str(len(payload)), req.get_header("Content-length"))
|
|
|
|
def test_small_bytes_body_still_works(self) -> None:
|
|
captured: list[urllib.request.Request] = []
|
|
|
|
def fake_urlopen(req: urllib.request.Request, *a: object, **k: object) -> _Resp:
|
|
captured.append(req)
|
|
return _Resp()
|
|
|
|
with mock.patch.object(pub.urllib.request, "urlopen", fake_urlopen):
|
|
pub._put("https://reg/sha", b"abc123 rootfs\n", token="")
|
|
self.assertEqual(b"abc123 rootfs\n", captured[0].data)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|