fix(db): migrate processed tasks with missing product status

This commit is contained in:
chengma
2026-07-27 18:15:51 +08:00
parent 82444412ab
commit 4d949751d1
6 changed files with 283 additions and 15 deletions
+163
View File
@@ -1,4 +1,5 @@
import os
import sqlite3
import sys
import unittest
from unittest import mock
@@ -259,6 +260,168 @@ class DbTests(TempDirMixin, unittest.TestCase):
self.assert_removed(temp_dir)
def test_init_db_defaults_processed_missing_status_and_creates_one_backup(self):
with self.make_temp_dir() as temp_dir:
db_path = os.path.join(temp_dir, "cmshopee.db")
db.init_db(db_path)
batch_id = db.create_batch(["processed.xlsx"], path=db_path)
deleted_batch_id = db.create_batch(["deleted.xlsx"], path=db_path)
item_ids = {
"stage": "51100639801",
"timestamp": "51100639802",
"content": "51100639803",
"unprocessed": "51100639804",
"unknown": "51100639805",
"deleted_task": "51100639806",
"deleted_batch": "51100639807",
}
rows = []
for source_row, item_id in enumerate(item_ids.values(), start=2):
rows.append(
{
"source_file_abs": os.path.join(temp_dir, f"{item_id}.xlsx"),
"source_sheet": "Sheet1",
"source_row": source_row,
"account_name": "店铺",
"alias": "alias",
"item_id": item_id,
}
)
db.insert_tasks(batch_id, rows[:-1], path=db_path)
db.insert_tasks(deleted_batch_id, rows[-1:], path=db_path)
conn = db.connect(db_path)
try:
tasks = {
task.item_id: task
for task in db.list_tasks(batch_id=batch_id, conn=conn)
}
deleted_batch_task = db.list_tasks(
batch_id=deleted_batch_id,
conn=conn,
)[0]
with conn:
conn.execute(
"UPDATE batches SET created_at = ? WHERE id IN (?, ?)",
("2026-07-27T12:00:00", batch_id, deleted_batch_id),
)
conn.execute(
"UPDATE tasks SET stage = 'generated', new_cover_path = ? WHERE id = ?",
(
os.path.join(temp_dir, "stage.jpg"),
tasks[item_ids["stage"]].id,
),
)
conn.execute(
"UPDATE tasks SET generated_at = ?, new_cover_path = ? WHERE id = ?",
(
"2026-07-27T12:01:00",
os.path.join(temp_dir, "timestamp.jpg"),
tasks[item_ids["timestamp"]].id,
),
)
conn.execute(
"UPDATE tasks SET new_title = ? WHERE id = ?",
("历史生成标题", tasks[item_ids["content"]].id),
)
conn.execute(
"""
UPDATE tasks
SET product_status = 'unknown',
product_status_note = '已有未知状态',
new_title = '不应覆盖'
WHERE id = ?
""",
(tasks[item_ids["unknown"]].id,),
)
conn.execute(
"UPDATE tasks SET stage = 'generated', deleted_at = ? WHERE id = ?",
("2026-07-27T12:02:00", tasks[item_ids["deleted_task"]].id),
)
conn.execute(
"UPDATE tasks SET stage = 'generated' WHERE id = ?",
(deleted_batch_task.id,),
)
conn.execute(
"UPDATE batches SET deleted_at = ? WHERE id = ?",
("2026-07-27T12:03:00", deleted_batch_id),
)
finally:
conn.close()
db.init_db(db_path)
migrated = {
task.item_id: task
for task in db.list_tasks(
batch_id=batch_id,
path=db_path,
include_deleted=True,
)
}
for key in ("stage", "timestamp", "content"):
task = migrated[item_ids[key]]
self.assertEqual("normal", task.product_status)
self.assertEqual(
db.LEGACY_PRODUCT_STATUS_DEFAULT_NOTE,
task.product_status_note,
)
self.assertIsNone(task.product_status_at)
self.assertIsNone(migrated[item_ids["unprocessed"]].product_status)
self.assertEqual("unknown", migrated[item_ids["unknown"]].product_status)
self.assertEqual(
"已有未知状态",
migrated[item_ids["unknown"]].product_status_note,
)
self.assertIsNone(migrated[item_ids["deleted_task"]].product_status)
deleted_batch_task = db.list_tasks(
batch_id=deleted_batch_id,
path=db_path,
include_deleted=True,
)[0]
self.assertIsNone(deleted_batch_task.product_status)
backup_dir = os.path.join(temp_dir, "backups")
backups = [
os.path.join(backup_dir, name)
for name in os.listdir(backup_dir)
if f"before-{db.LEGACY_STATUS_BACKUP_TASK_ID}" in name
]
self.assertEqual(1, len(backups))
backup_conn = sqlite3.connect(backups[0])
try:
row = backup_conn.execute(
"SELECT product_status FROM tasks WHERE item_id = ?",
(item_ids["stage"],),
).fetchone()
self.assertIsNone(row[0])
finally:
backup_conn.close()
content_task = migrated[item_ids["content"]]
plan = product_status.build_apply_plan([content_task], "title")
self.assertEqual([content_task.id], [task.id for task in plan["executable"]])
first_updated_at = content_task.updated_at
db.init_db(db_path)
self.assertEqual(
first_updated_at,
db.get_task(content_task.id, path=db_path).updated_at,
)
self.assertEqual(
1,
len(
[
name
for name in os.listdir(backup_dir)
if f"before-{db.LEGACY_STATUS_BACKUP_TASK_ID}" in name
]
),
)
self.assert_removed(temp_dir)
def test_init_db_repairs_only_legacy_promotion_status_misclassification(self):
with self.make_temp_dir() as temp_dir:
db_path = os.path.join(temp_dir, "cmshopee.db")
+3 -2
View File
@@ -7644,7 +7644,7 @@ class GuiTests(TempDirMixin, unittest.TestCase):
],
path=cfg["db_path"],
)
statuses = ["unlisted", "reviewing", None]
statuses = ["unlisted", "reviewing", "unknown"]
for task, status in zip(
db.list_tasks(batch_id=batch_id, path=cfg["db_path"]),
statuses,
@@ -8566,6 +8566,7 @@ class GuiTests(TempDirMixin, unittest.TestCase):
db.mark_failed(tasks_b[0].id, "generate", "生成失败", path=cfg["db_path"])
db.set_product_status(tasks_a[0].id, "normal", path=cfg["db_path"])
db.set_product_status(tasks_a[1].id, "unlisted", path=cfg["db_path"])
db.set_product_status(tasks_a[2].id, "reviewing", path=cfg["db_path"])
db.set_product_status(tasks_b[0].id, "unknown", path=cfg["db_path"])
tab = GenerateTab(config=cfg)
@@ -8628,7 +8629,7 @@ class GuiTests(TempDirMixin, unittest.TestCase):
self.assertEqual([], unlisted_plan["execution_tasks"])
tab.status_filter.setCurrentIndex(tab.status_filter.findData("all"))
tab.product_status_filter.setCurrentIndex(
tab.product_status_filter.findData("unchecked")
tab.product_status_filter.findData("reviewing")
)
self.assertEqual(1, tab.model.rowCount())
self.assertEqual("51100639512", tab.model.index(0, 1).data())