|
| 1 | +"""Tests for comfy.deploy_environment.""" |
| 2 | + |
| 3 | +import os |
| 4 | + |
| 5 | +import pytest |
| 6 | + |
| 7 | +from comfy import deploy_environment |
| 8 | +from comfy.deploy_environment import get_deploy_environment |
| 9 | + |
| 10 | + |
| 11 | +@pytest.fixture(autouse=True) |
| 12 | +def _reset_cache_and_install_dir(tmp_path, monkeypatch): |
| 13 | + """Reset the functools cache and point the ComfyUI install dir at a tmp dir for each test.""" |
| 14 | + get_deploy_environment.cache_clear() |
| 15 | + monkeypatch.setattr(deploy_environment, "_COMFY_INSTALL_DIR", str(tmp_path)) |
| 16 | + yield |
| 17 | + get_deploy_environment.cache_clear() |
| 18 | + |
| 19 | + |
| 20 | +def _write_env_file(tmp_path, content: str) -> str: |
| 21 | + """Write the env file with exact content (no newline translation). |
| 22 | +
|
| 23 | + `newline=""` disables Python's text-mode newline translation so the bytes |
| 24 | + on disk match the literal string passed in, regardless of host OS. |
| 25 | + Newline-style tests (CRLF, lone CR) rely on this. |
| 26 | + """ |
| 27 | + path = os.path.join(str(tmp_path), ".comfy_environment") |
| 28 | + with open(path, "w", encoding="utf-8", newline="") as f: |
| 29 | + f.write(content) |
| 30 | + return path |
| 31 | + |
| 32 | + |
| 33 | +class TestGetDeployEnvironment: |
| 34 | + def test_returns_local_git_when_file_missing(self): |
| 35 | + assert get_deploy_environment() == "local-git" |
| 36 | + |
| 37 | + def test_reads_value_from_file(self, tmp_path): |
| 38 | + _write_env_file(tmp_path, "local-desktop2-standalone\n") |
| 39 | + assert get_deploy_environment() == "local-desktop2-standalone" |
| 40 | + |
| 41 | + def test_strips_trailing_whitespace_and_newline(self, tmp_path): |
| 42 | + _write_env_file(tmp_path, " local-desktop2-standalone \n") |
| 43 | + assert get_deploy_environment() == "local-desktop2-standalone" |
| 44 | + |
| 45 | + def test_only_first_line_is_used(self, tmp_path): |
| 46 | + _write_env_file(tmp_path, "first-line\nsecond-line\n") |
| 47 | + assert get_deploy_environment() == "first-line" |
| 48 | + |
| 49 | + def test_crlf_line_ending(self, tmp_path): |
| 50 | + # Windows editors often save text files with CRLF line endings. |
| 51 | + # The CR must not end up in the returned value. |
| 52 | + _write_env_file(tmp_path, "local-desktop2-standalone\r\n") |
| 53 | + assert get_deploy_environment() == "local-desktop2-standalone" |
| 54 | + |
| 55 | + def test_crlf_multiline_only_first_line_used(self, tmp_path): |
| 56 | + _write_env_file(tmp_path, "first-line\r\nsecond-line\r\n") |
| 57 | + assert get_deploy_environment() == "first-line" |
| 58 | + |
| 59 | + def test_crlf_with_surrounding_whitespace(self, tmp_path): |
| 60 | + _write_env_file(tmp_path, " local-desktop2-standalone \r\n") |
| 61 | + assert get_deploy_environment() == "local-desktop2-standalone" |
| 62 | + |
| 63 | + def test_lone_cr_line_ending(self, tmp_path): |
| 64 | + # Classic-Mac / some legacy editors use a bare CR. |
| 65 | + # Universal-newlines decoding treats it as a line terminator too. |
| 66 | + _write_env_file(tmp_path, "local-desktop2-standalone\r") |
| 67 | + assert get_deploy_environment() == "local-desktop2-standalone" |
| 68 | + |
| 69 | + def test_empty_file_falls_back_to_default(self, tmp_path): |
| 70 | + _write_env_file(tmp_path, "") |
| 71 | + assert get_deploy_environment() == "local-git" |
| 72 | + |
| 73 | + def test_empty_after_whitespace_strip_falls_back_to_default(self, tmp_path): |
| 74 | + _write_env_file(tmp_path, " \n") |
| 75 | + assert get_deploy_environment() == "local-git" |
| 76 | + |
| 77 | + def test_strips_control_chars_within_first_line(self, tmp_path): |
| 78 | + # Embedded NUL/control chars in the value should be stripped |
| 79 | + # (header-injection / smuggling protection). |
| 80 | + _write_env_file(tmp_path, "abc\x00\x07xyz\n") |
| 81 | + assert get_deploy_environment() == "abcxyz" |
| 82 | + |
| 83 | + def test_strips_non_ascii_characters(self, tmp_path): |
| 84 | + _write_env_file(tmp_path, "café-é\n") |
| 85 | + assert get_deploy_environment() == "caf-" |
| 86 | + |
| 87 | + def test_caps_read_at_128_bytes(self, tmp_path): |
| 88 | + # A single huge line with no newline must not be fully read into memory. |
| 89 | + huge = "x" * 10_000 |
| 90 | + _write_env_file(tmp_path, huge) |
| 91 | + result = get_deploy_environment() |
| 92 | + assert result == "x" * 128 |
| 93 | + |
| 94 | + def test_result_is_cached_across_calls(self, tmp_path): |
| 95 | + path = _write_env_file(tmp_path, "first_value\n") |
| 96 | + assert get_deploy_environment() == "first_value" |
| 97 | + # Overwrite the file — cached value should still be returned. |
| 98 | + with open(path, "w", encoding="utf-8") as f: |
| 99 | + f.write("second_value\n") |
| 100 | + assert get_deploy_environment() == "first_value" |
| 101 | + |
| 102 | + def test_unreadable_file_falls_back_to_default(self, tmp_path, monkeypatch): |
| 103 | + _write_env_file(tmp_path, "should_not_be_used\n") |
| 104 | + |
| 105 | + def _boom(*args, **kwargs): |
| 106 | + raise OSError("simulated read failure") |
| 107 | + |
| 108 | + monkeypatch.setattr("builtins.open", _boom) |
| 109 | + assert get_deploy_environment() == "local-git" |
0 commit comments