## 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>
This commit was merged in pull request #7.
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
"""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"
|
||||
)
|
||||
Reference in New Issue
Block a user