Files
cowork-local/tests/test_build_co4e_tab.py
T
f9f6bc01fd
CI / test (push) Canceled after 0s
Feature/delta team/epic r04 (#7)
## Summary

epic r04 - begin refactor

## Change Type

- [x] Cowork feature
- [ ] Bug fix
- [ ] Core AI contribution
- [ ] Test / hardening
- [ ] Performance
- [ ] Documentation

## Related Work

Cowork Task:

Core Repo: http://34.143.229.138/gitea-admin/fsg-ai-core-assets

Core AI Issue:

Core Task:

Related PR:

## Scope

What is intentionally included?

What is intentionally NOT included?

## Validation

- [ ] Unit tests
- [ ] Integration tests
- [ ] Manual verification
- [ ] Regression check

Commands / evidence:

## Security Impact

Permission / credential / network / customer data impact:

## Compatibility

- [ ] No breaking change
- [ ] Breaking change documented

## Reviewer Notes

Anything Cowork reviewers should pay attention to.

---------

Co-authored-by: Anh Tran Nguyen Minh <anhtnm1@fpt.com>
Co-authored-by: Huong Le Thi Thien <huongltt35@fpt.com>
Co-authored-by: Nam Pham Dinh Thanh <nampdt@fpt.com>
Co-authored-by: Vu Dam Tuan <vudt15@fpt.com>
Co-authored-by: Hiep Ha Van <hiephv3@fpt.com>
Co-authored-by: Lam Hoang Van <lamhv7@fpt.com>
Reviewed-on: #7
Co-authored-by: Duy Le Huu <duylh19@fpt.com>
2026-08-31 05:15:13 +00:00

103 lines
4.4 KiB
Python

"""Smoke test cho ``presentation.co4e.co4e_tab.build_co4e_tab`` — gọi thật
factory, dựng thật ``Co4ETab``, xác nhận nó không vỡ.
Vì sao chạy trong tiến trình con thay vì import thẳng trong tiến trình pytest
chính: ``CONFIG_DIR`` (config.py) và ``CO4E_DIR`` (core/co4e.py) đều là hằng số
module tính MỘT LẦN lúc import từ ``Path.home()``. Nhiều file test khác trong
bộ này (chạy trước theo thứ tự collect) đã import ``cowork_local.config``/
``cowork_local.core.co4e`` với HOME thật rồi — monkeypatch thuộc tính module
(cách ``tests/characterization/test_co4e_run_manager_behavior.py`` dùng cho
``CO4E_DIR``) chỉ vá được đúng chỗ đó, còn ``AppConfig.load()`` có thêm một bẫy
riêng: tham số mặc định ``path: Path = CONFIG_PATH`` được gán MỘT LẦN lúc định
nghĩa hàm, nên monkeypatch ``CONFIG_PATH`` sau đó không đổi được giá trị mặc
định đã đóng băng — gọi ``AppConfig.load()`` không tham số vẫn đọc file thật
dù đã vá module. Dựng ``Co4ETab`` thật kéo theo cả hai đường trên (và có thể
còn đường khác chưa biết, vì lớp này 2000+ dòng). Cô lập bằng biến môi trường
``HOME``/``USERPROFILE`` TRƯỚC bất kỳ import nào, trong một tiến trình con
sạch hoàn toàn, né được toàn bộ lớp bẫy này một lần — không cần biết hết mọi
hằng số tính lúc import ở đâu trong file 2000+ dòng đó.
Bắt được gì: đổi sai độ sâu dấu chấm ở import tương đối trong
``presentation/co4e/co4e_tab.py`` (``from ...ui.co4e_tab import Co4ETab``),
đổi chữ ký ``Co4ETab.__init__`` mà quên sửa lệnh gọi trong factory, hoặc
factory trả sai kiểu/sai ``ctx`` — không có test nào khác trong bộ này gọi
``build_co4e_tab()``, nên đây là lưới an toàn DUY NHẤT cho hàm này.
KHÔNG chạm dữ liệu thật: sandbox trống hoàn toàn, không copy
``~/.cowork_local`` thật (khác ``tools/capture_screens.py::_isolate_home()`` —
ở đó cố tình copy để chụp ảnh có dữ liệu mẫu; ở đây không cần, càng sạch càng
tốt cho một smoke test).
"""
from __future__ import annotations
import os
import subprocess
import sys
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
REPO_PARENT = REPO_ROOT.parent
_SMOKE_SCRIPT = """
import sys
sys.path.insert(0, {repo_parent!r})
from PySide6.QtWidgets import QApplication, QWidget
from cowork_local.config import AppConfig, CONFIG_DIR
from cowork_local.state import AppContext
from cowork_local.presentation.co4e.co4e_tab import build_co4e_tab
sandbox = sys.argv[1]
assert str(CONFIG_DIR).startswith(sandbox), "khong co lap: CONFIG_DIR=" + str(CONFIG_DIR)
app = QApplication([])
ctx = AppContext(AppConfig.load())
class _FakeWorkflowService:
\"\"\"Chua dung toi trong than ham build_co4e_tab hien tai (xem docstring
cua factory) - chi can mot doi tuong bat ky de kiem factory nhan dung
tham so bat buoc thu hai.\"\"\"
widget = build_co4e_tab(ctx, _FakeWorkflowService())
assert isinstance(widget, QWidget), "khong phai QWidget: " + repr(type(widget))
assert widget.ctx is ctx, "factory khong gan dung ctx cho widget tra ve"
print("SMOKE_OK")
"""
def test_build_co4e_tab_dung_that_va_gan_dung_ctx(tmp_path):
sandbox = tmp_path / "home"
sandbox.mkdir()
env = dict(os.environ)
env["HOME"] = str(sandbox)
env["USERPROFILE"] = str(sandbox)
env["QT_QPA_PLATFORM"] = "offscreen"
env.pop("HOMEDRIVE", None)
env.pop("HOMEPATH", None)
script = _SMOKE_SCRIPT.format(repo_parent=str(REPO_PARENT))
result = subprocess.run(
[sys.executable, "-c", script, str(sandbox)],
cwd=str(REPO_ROOT),
env=env,
capture_output=True,
text=True,
timeout=60,
)
assert result.returncode == 0, (
f"smoke build_co4e_tab that bai (exit {result.returncode}):\n"
f"--- stdout ---\n{result.stdout}\n--- stderr ---\n{result.stderr}"
)
assert "SMOKE_OK" in result.stdout, result.stdout
# Sandbox khong duoc dung: chua co gi ghi vao no truoc khi tien trinh con
# chay (con AppConfig.load() khong ghi gi ca - chi save() moi ghi).
assert not (sandbox / ".cowork_local").exists(), (
"AppConfig.load() khong duoc tu tao thu muc config that trong sandbox"
)