feat(ai-studio): keep workspace usable during generation
This commit is contained in:
@@ -996,6 +996,132 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_image_studio_generation_keeps_current_project_workspace_available(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
db.init_db(cfg["db_path"])
|
||||
project = image_studio.create_or_get_project(
|
||||
account_alias="alias-a",
|
||||
account_slug="alias_a",
|
||||
item_id="51100639510",
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
source = image_studio.add_asset(
|
||||
project.id,
|
||||
"original",
|
||||
local_path=self.write_test_image(os.path.join(temp_dir, "source.jpg")),
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
tab = ImageStudioTab(config=cfg, db_path=cfg["db_path"])
|
||||
self.addCleanup(tab.close)
|
||||
tab._select_project(project.id)
|
||||
tab._select_source_asset(source)
|
||||
tab.prompt_edit.setPlainText("第一轮提示词")
|
||||
|
||||
class FakeStudioWorker:
|
||||
def __init__(self):
|
||||
self.progress = DummySignal()
|
||||
self.log = DummySignal()
|
||||
self.finished = DummySignal()
|
||||
self.failed = DummySignal()
|
||||
|
||||
def cancel(self):
|
||||
pass
|
||||
|
||||
fake_worker = FakeStudioWorker()
|
||||
fake_thread = FakeThread()
|
||||
with mock.patch(
|
||||
"app.gui.tabs.image_studio.ImageStudioGenerateJobsWorker",
|
||||
return_value=fake_worker,
|
||||
) as worker_factory, mock.patch(
|
||||
"app.gui.tabs.image_studio.run_worker", return_value=fake_thread
|
||||
):
|
||||
tab.start_generation()
|
||||
|
||||
self.assertEqual("generate", tab._operation_kind)
|
||||
self.assertTrue(tab.pool_grid.isEnabled())
|
||||
self.assertTrue(tab.main_selection_list.isEnabled())
|
||||
self.assertTrue(tab.detail_selection_list.isEnabled())
|
||||
self.assertTrue(tab.template_combo.isEnabled())
|
||||
self.assertTrue(tab.prompt_edit.isEnabled())
|
||||
self.assertTrue(tab.job_type_combo.isEnabled())
|
||||
self.assertTrue(tab.count_spin.isEnabled())
|
||||
self.assertTrue(tab.aspect_combo.isEnabled())
|
||||
self.assertTrue(tab.open_folder_button.isEnabled())
|
||||
self.assertFalse(tab.start_button.isEnabled())
|
||||
self.assertFalse(tab.resume_button.isEnabled())
|
||||
self.assertFalse(tab.pull_images_button.isEnabled())
|
||||
self.assertFalse(tab.project_table.isEnabled())
|
||||
self.assertFalse(tab.original_grid.isEnabled())
|
||||
self.assertFalse(tab.export_button.isEnabled())
|
||||
self.assertFalse(tab.delete_project_button.isEnabled())
|
||||
self.assertIn("下一轮生成", tab.generation_guard_label.text())
|
||||
|
||||
tab.prompt_edit.setPlainText("下一轮提示词")
|
||||
tab.count_spin.setValue(3)
|
||||
tab.job_type_combo.setCurrentIndex(tab.job_type_combo.findData("detail"))
|
||||
tab.aspect_combo.setCurrentIndex(tab.aspect_combo.findData("3:4"))
|
||||
args = worker_factory.call_args.args
|
||||
self.assertEqual("第一轮提示词", args[2])
|
||||
self.assertEqual(4, args[3])
|
||||
self.assertEqual("main", worker_factory.call_args.kwargs["job_type"])
|
||||
self.assertEqual("1:1", worker_factory.call_args.kwargs["aspect_ratio"])
|
||||
|
||||
tab._finish_worker()
|
||||
self.assertTrue(tab.start_button.isEnabled())
|
||||
self.assertEqual("", tab._operation_kind)
|
||||
self.assertIn("不会在失败后", tab.generation_guard_label.text())
|
||||
|
||||
fake_thread.finished.emit()
|
||||
self.assertIsNone(tab._running_worker)
|
||||
self.assertIsNone(tab._running_thread)
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_image_studio_worker_waits_for_thread_cleanup_before_next_start(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
tab = ImageStudioTab(config=cfg, db_path=cfg["db_path"])
|
||||
self.addCleanup(tab.close)
|
||||
first_worker = SimpleNamespace()
|
||||
second_worker = SimpleNamespace()
|
||||
first_thread = FakeThread()
|
||||
second_thread = FakeThread()
|
||||
|
||||
with mock.patch(
|
||||
"app.gui.tabs.image_studio.run_worker",
|
||||
side_effect=[first_thread, second_thread],
|
||||
) as run_worker:
|
||||
self.assertTrue(
|
||||
tab._start_worker(
|
||||
first_worker,
|
||||
"AI工场测试线程",
|
||||
operation_kind="generate",
|
||||
)
|
||||
)
|
||||
tab._finish_worker()
|
||||
self.assertFalse(
|
||||
tab._start_worker(
|
||||
second_worker,
|
||||
"AI工场测试线程",
|
||||
operation_kind="generate",
|
||||
)
|
||||
)
|
||||
self.assertEqual(1, run_worker.call_count)
|
||||
first_thread.finished.emit()
|
||||
self.assertTrue(
|
||||
tab._start_worker(
|
||||
second_worker,
|
||||
"AI工场测试线程",
|
||||
operation_kind="generate",
|
||||
)
|
||||
)
|
||||
|
||||
self.assertEqual(2, run_worker.call_count)
|
||||
second_thread.finished.emit()
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_image_studio_worker_thread_is_kept_until_thread_finished(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
|
||||
Reference in New Issue
Block a user