fix(fx-list): MASTERING PANEL khong hien thi VST FX da scan trong Plugin Manager (cache _fx_scan_all ket [] vinh vien)
- vst_engine: list_scan_all cache co TTL 300s (FX_SCAN_TTL) + chi cache khi find_fx_bridge_exe() co exe (thieu bridge -> tra [] NHUNG khong cache de lan sau thu lai) — truoc day ket [] vi mui gio, MASTERING PANEL rong. - vst_engine: them invalidate_fx_scan() clear cache scan VST. - plugins.py: POST /scan (Plugin Manager Scan) goi _invalidate_fx_scan_cache() -> MASTERING PANEL lan mo ke tiep quet lai voi dirs moi; response them fx_cache_invalidated. - app.jsx: MasteringModal/FXRackModal load listFx() lai moi lan mo modal (deps [isOpen]/[track.id]) + loading state; VstPluginPicker nhan prop loading -> hien 'Dang quet VST FX...' thay vi 'Khong co VST FX'. - precompiled rebuild (LF) + index.html ?v=202608220330; dist sync. - tests: +4 test cache TTL/invalidate/no-bridge (TestFxScanCache).
This commit is contained in:
@@ -54,6 +54,72 @@ class TestPluginManager:
|
||||
assert PluginManager.validate_sf2_header(b'RIFF') is False
|
||||
|
||||
|
||||
class TestFxScanCache:
|
||||
"""list_scan_all cache TTL + invalidate — fix MASTERING PANEL không hiển thị
|
||||
VST FX đã scan trong Plugin Manager (cache kẹt [] vĩnh viễn)."""
|
||||
|
||||
SCAN_JSON = json.dumps({"plugins": [
|
||||
{"path": "C:\\VST3\\Ozone Pro.vst3", "name": "Ozone Pro",
|
||||
"type": "VST3", "is_fx": True, "is_instrument": False},
|
||||
]})
|
||||
|
||||
def _pm(self, tmp_path):
|
||||
d = str(tmp_path)
|
||||
return PluginManager(vst_dir=d, sf_dir=d, extra_vst_dirs=[])
|
||||
|
||||
def test_scan_caches_with_bridge(self, tmp_path):
|
||||
pm = self._pm(tmp_path)
|
||||
with patch("app.core.native_render.find_fx_bridge_exe", return_value="fx_bridge.exe"), \
|
||||
patch("subprocess.run", return_value=MagicMock(
|
||||
returncode=0, stdout=self.SCAN_JSON, stderr="")) as mrun:
|
||||
r1 = pm.list_scan_all()
|
||||
assert len(r1) == 1 and r1[0]["name"] == "Ozone Pro"
|
||||
assert pm._fx_scan_all is not None and len(pm._fx_scan_all) == 1
|
||||
# Lần 2 trong TTL → KHÔNG chạy lại bridge
|
||||
mrun.reset_mock()
|
||||
r2 = pm.list_scan_all()
|
||||
assert r2 == r1
|
||||
mrun.assert_not_called()
|
||||
|
||||
def test_scan_no_bridge_does_not_cache_empty(self, tmp_path):
|
||||
"""Bridge chưa tồn tại → trả [] nhưng KHÔNG cache → lần sau thử lại
|
||||
(trước đây cache [] vĩnh viễn → MASTERING PANEL trống)."""
|
||||
pm = self._pm(tmp_path)
|
||||
with patch("app.core.native_render.find_fx_bridge_exe", return_value=""):
|
||||
assert pm.list_scan_all() == []
|
||||
assert pm._fx_scan_all is None # KHÔNG cache rỗng
|
||||
# Có bridge → scan thật chạy
|
||||
with patch("app.core.native_render.find_fx_bridge_exe", return_value="fx_bridge.exe"), \
|
||||
patch("subprocess.run", return_value=MagicMock(
|
||||
returncode=0, stdout=self.SCAN_JSON, stderr="")):
|
||||
r = pm.list_scan_all()
|
||||
assert len(r) == 1
|
||||
|
||||
def test_scan_ttl_expiry_rescans(self, tmp_path):
|
||||
pm = self._pm(tmp_path)
|
||||
with patch("app.core.native_render.find_fx_bridge_exe", return_value="fx_bridge.exe"), \
|
||||
patch("subprocess.run", return_value=MagicMock(
|
||||
returncode=0, stdout=self.SCAN_JSON, stderr="")) as mrun:
|
||||
pm.list_scan_all()
|
||||
mrun.assert_called_once()
|
||||
# Giả TTL đã hết hạn → gọi lại phải scan
|
||||
pm._fx_scan_all_ts -= (pm.FX_SCAN_TTL + 1)
|
||||
pm.list_scan_all()
|
||||
assert mrun.call_count == 2
|
||||
|
||||
def test_invalidate_fx_scan(self, tmp_path):
|
||||
pm = self._pm(tmp_path)
|
||||
with patch("app.core.native_render.find_fx_bridge_exe", return_value="fx_bridge.exe"), \
|
||||
patch("subprocess.run", return_value=MagicMock(
|
||||
returncode=0, stdout=self.SCAN_JSON, stderr="")):
|
||||
pm.list_scan_all()
|
||||
assert pm._fx_scan_all is not None
|
||||
pm.invalidate_fx_scan()
|
||||
assert pm._fx_scan_all is None
|
||||
assert pm._fx_scan_all_ts == 0.0
|
||||
assert pm._fx_scan_cache is None
|
||||
|
||||
|
||||
class TestMidiNoteToFreq:
|
||||
def test_a4_440(self):
|
||||
assert midi_note_to_freq(69) == 440.0
|
||||
|
||||
Reference in New Issue
Block a user