feat: skip incomplete apply tasks before update
This commit is contained in:
@@ -6647,6 +6647,158 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_apply_tab_partitions_missing_content_by_update_mode(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
tab = ApplyTab(config=self.make_config(temp_dir))
|
||||
self.addCleanup(tab.close)
|
||||
tasks = [
|
||||
SimpleNamespace(id=1, item_id="51100639510", new_title="新标题", new_cover_path="new.jpg"),
|
||||
SimpleNamespace(id=2, item_id="51100639511", new_title="新标题", new_cover_path=None),
|
||||
SimpleNamespace(id=3, item_id="51100639512", new_title=None, new_cover_path="new.jpg"),
|
||||
SimpleNamespace(id=4, item_id="51100639513", new_title=None, new_cover_path=None),
|
||||
]
|
||||
|
||||
title_plan = tab._partition_update_content_tasks(tasks, "title")
|
||||
self.assertEqual([1, 2], [task.id for task in title_plan["executable"]])
|
||||
self.assertEqual([3, 4], [task.id for task in title_plan["missing_title"]])
|
||||
self.assertEqual([], title_plan["missing_cover"])
|
||||
|
||||
cover_plan = tab._partition_update_content_tasks(tasks, "cover")
|
||||
self.assertEqual([1, 3], [task.id for task in cover_plan["executable"]])
|
||||
self.assertEqual([], cover_plan["missing_title"])
|
||||
self.assertEqual([2, 4], [task.id for task in cover_plan["missing_cover"]])
|
||||
|
||||
title_cover_plan = tab._partition_update_content_tasks(tasks, "title_cover")
|
||||
self.assertEqual([1], [task.id for task in title_cover_plan["executable"]])
|
||||
self.assertEqual([3, 4], [task.id for task in title_cover_plan["missing_title"]])
|
||||
self.assertEqual([2, 4], [task.id for task in title_cover_plan["missing_cover"]])
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_apply_tab_skips_missing_content_but_starts_eligible_update(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
accounts.create_account("主店", "alias-a", debug_port=9222, config=cfg)
|
||||
batch_id = db.create_batch(["input.xlsx"], path=cfg["db_path"])
|
||||
db.insert_tasks(
|
||||
batch_id,
|
||||
[
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 2,
|
||||
"account_name": "Excel主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": "51100639510",
|
||||
},
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 3,
|
||||
"account_name": "Excel主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": "51100639511",
|
||||
},
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 4,
|
||||
"account_name": "Excel主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": "51100639512",
|
||||
},
|
||||
],
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
tasks = db.list_tasks(batch_id=batch_id, path=cfg["db_path"])
|
||||
for task in tasks:
|
||||
db.set_collected(task.id, "旧标题", "old.jpg", path=cfg["db_path"])
|
||||
db.set_generated(tasks[0].id, "新标题", "new.jpg", path=cfg["db_path"])
|
||||
db.set_generated(tasks[1].id, "新标题", None, path=cfg["db_path"])
|
||||
db.set_generated(tasks[2].id, None, "new.jpg", path=cfg["db_path"])
|
||||
statuses = []
|
||||
tab = ApplyTab(config=cfg, status_callback=statuses.append)
|
||||
self.addCleanup(tab.close)
|
||||
tab.update_mode_combo.setCurrentIndex(tab.update_mode_combo.findData("title_cover"))
|
||||
thread = FakeThread()
|
||||
|
||||
with mock.patch("app.gui.QMessageBox.question", return_value=gui.QMessageBox.Yes) as question, \
|
||||
mock.patch("app.gui.QMessageBox.warning") as warning, \
|
||||
mock.patch("app.gui.run_worker", return_value=thread):
|
||||
tab.start_update()
|
||||
|
||||
warning.assert_not_called()
|
||||
message = question.call_args[0][2]
|
||||
self.assertIn("任务数:1", message)
|
||||
self.assertIn("本轮将跳过 2 条缺少所选更新内容的记录", message)
|
||||
self.assertIn("缺少新标题:1 条(示例商品ID:51100639512)", message)
|
||||
self.assertIn("缺少新封面:1 条(示例商品ID:51100639511)", message)
|
||||
self.assertEqual([tasks[0].id], [task.id for task in tab.apply_worker.tasks])
|
||||
self.assertTrue(thread.started)
|
||||
self.assertIn("跳过 2 条(缺标题 1 / 缺封面 1)", statuses[-1])
|
||||
self.assertIn("缺失记录未进入本轮执行", tab.run_log_view.toPlainText())
|
||||
unchanged = db.list_tasks(batch_id=batch_id, path=cfg["db_path"])
|
||||
self.assertTrue(all(task.stage == "generated" for task in unchanged))
|
||||
self.assertTrue(all(task.status == "success" for task in unchanged))
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_apply_tab_preview_uses_same_missing_content_skip_rule(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
accounts.create_account("主店", "alias-a", debug_port=9222, config=cfg)
|
||||
batch_id = db.create_batch(["input.xlsx"], path=cfg["db_path"])
|
||||
db.insert_tasks(
|
||||
batch_id,
|
||||
[
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 2,
|
||||
"account_name": "Excel主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": "51100639510",
|
||||
},
|
||||
{
|
||||
"source_file_abs": os.path.join(temp_dir, "input.xlsx"),
|
||||
"source_sheet": "商品",
|
||||
"source_row": 3,
|
||||
"account_name": "Excel主店",
|
||||
"alias": "alias-a",
|
||||
"item_id": "51100639511",
|
||||
},
|
||||
],
|
||||
path=cfg["db_path"],
|
||||
)
|
||||
tasks = db.list_tasks(batch_id=batch_id, path=cfg["db_path"])
|
||||
for task in tasks:
|
||||
db.set_collected(task.id, "旧标题", "old.jpg", path=cfg["db_path"])
|
||||
db.set_generated(tasks[0].id, "新标题", "new.jpg", path=cfg["db_path"])
|
||||
db.set_generated(tasks[1].id, None, "new.jpg", path=cfg["db_path"])
|
||||
statuses = []
|
||||
tab = ApplyTab(config=cfg, status_callback=statuses.append)
|
||||
self.addCleanup(tab.close)
|
||||
tab.update_mode_combo.setCurrentIndex(tab.update_mode_combo.findData("title"))
|
||||
thread = FakeThread()
|
||||
|
||||
with mock.patch("app.gui.QMessageBox.question", return_value=gui.QMessageBox.Yes) as question, \
|
||||
mock.patch("app.gui.QMessageBox.warning") as warning, \
|
||||
mock.patch("app.gui.run_worker", return_value=thread):
|
||||
tab.preview_update()
|
||||
|
||||
warning.assert_not_called()
|
||||
message = question.call_args[0][2]
|
||||
self.assertIn("本轮将跳过 1 条缺少所选更新内容的记录", message)
|
||||
self.assertIn("缺少新标题:1 条(示例商品ID:51100639511)", message)
|
||||
self.assertEqual([tasks[0].id], [task.id for task in tab.apply_worker.tasks])
|
||||
self.assertTrue(tab.apply_worker.dry_run)
|
||||
self.assertIn("开始检查本轮更新:1 条,跳过 1 条(缺标题 1 / 缺封面 0)", statuses[-1])
|
||||
unchanged = db.list_tasks(batch_id=batch_id, path=cfg["db_path"])
|
||||
self.assertTrue(all(task.stage == "generated" for task in unchanged))
|
||||
self.assertTrue(all(task.status == "success" for task in unchanged))
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_apply_tab_allows_cover_only_result_but_blocks_modes_that_need_title(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
|
||||
Reference in New Issue
Block a user