Files
welcome-to-codevalet-as-a-p…/tests/test_operator_env.py
Nathan Trudeau a866a498e7 Add test for TTY
2026-05-04 13:38:35 -04:00

105 lines
3.9 KiB
Python

from __future__ import annotations
import os
import stat
import sys
import tempfile
import unittest
from pathlib import Path
from unittest import mock
HERE = Path(__file__).resolve().parent
ROOT = HERE.parent
sys.path.insert(0, str(ROOT / "forge-stack-orchestrator" / "scripts"))
import operator_env as oe # noqa: E402
class UpdateEnvFileTests(unittest.TestCase):
def test_replaces_commented_placeholders_and_preserves_mode(self) -> None:
with tempfile.TemporaryDirectory() as tmpdir:
env_path = Path(tmpdir) / ".env"
env_path.write_text(
"FORGE_STACK_DEVPI_PASSWORD=change-me\n"
"# FORGE_STACK_DEVPI_GITHUB_TOKEN=\n"
"FORGE_STACK_DEVPI_PYARMOR_DEVICE_ID=1\n",
encoding="utf-8",
)
os.chmod(env_path, 0o600)
oe.update_env_file(
env_path,
{
"FORGE_STACK_DEVPI_PASSWORD": "secret-pass",
"FORGE_STACK_DEVPI_GITHUB_TOKEN": "ghp_test",
},
)
rendered = env_path.read_text(encoding="utf-8")
self.assertIn("FORGE_STACK_DEVPI_PASSWORD=secret-pass\n", rendered)
self.assertIn("FORGE_STACK_DEVPI_GITHUB_TOKEN=ghp_test\n", rendered)
self.assertEqual(stat.S_IMODE(env_path.stat().st_mode), 0o600)
class CollectUpdatesTests(unittest.TestCase):
def test_interactive_accepts_dev_tty_when_stdin_is_not_tty(self) -> None:
fake_tty = mock.mock_open()
with mock.patch.object(oe.sys.stdin, "isatty", return_value=False), mock.patch.object(
oe.sys.stderr,
"isatty",
return_value=True,
), mock.patch("builtins.open", fake_tty):
self.assertTrue(oe.interactive())
fake_tty.assert_called_once_with("/dev/tty", "r", encoding="utf-8")
def test_collects_password_github_and_pyarmor_when_missing(self) -> None:
env_values = {
oe.DEVPI_PASSWORD_KEY: "change-me",
oe.GITHUB_TOKEN_KEY: "",
oe.PYARMOR_ACTIVATION_KEY: "",
oe.PYARMOR_REGFILE_KEY: "",
oe.PYARMOR_DEVICE_KEY: "1",
}
with mock.patch.object(oe, "interactive", return_value=True), mock.patch.object(
oe,
"prompt_value",
side_effect=[
"backend-pass",
"ghp_123",
"/secure/license-email.txt",
"/secure/pyarmor-reg.zip",
"7",
],
), mock.patch.object(oe, "prompt_bool", return_value=True):
updates = oe.collect_updates(env_values, created_env=False)
self.assertEqual(updates[oe.DEVPI_PASSWORD_KEY], "backend-pass")
self.assertEqual(updates[oe.GITHUB_TOKEN_KEY], "ghp_123")
self.assertEqual(updates[oe.PYARMOR_ACTIVATION_KEY], "/secure/license-email.txt")
self.assertEqual(updates[oe.PYARMOR_REGFILE_KEY], "/secure/pyarmor-reg.zip")
self.assertEqual(updates[oe.PYARMOR_DEVICE_KEY], "7")
def test_skips_pyarmor_when_operator_declines_release_host_mode(self) -> None:
env_values = {
oe.DEVPI_PASSWORD_KEY: "backend-pass",
oe.GITHUB_TOKEN_KEY: "",
oe.PYARMOR_ACTIVATION_KEY: "",
oe.PYARMOR_REGFILE_KEY: "",
oe.PYARMOR_DEVICE_KEY: "1",
}
with mock.patch.object(oe, "interactive", return_value=True), mock.patch.object(
oe,
"prompt_value",
side_effect=[""],
), mock.patch.object(oe, "prompt_bool", return_value=False):
updates = oe.collect_updates(env_values, created_env=False)
self.assertNotIn(oe.GITHUB_TOKEN_KEY, updates)
self.assertNotIn(oe.PYARMOR_ACTIVATION_KEY, updates)
self.assertNotIn(oe.PYARMOR_REGFILE_KEY, updates)
self.assertNotIn(oe.PYARMOR_DEVICE_KEY, updates)
if __name__ == "__main__":
unittest.main()