chore: 并入 iotlcm-worker-svr 历史到 worker-svr/(原提交 96f0f4e)

This commit is contained in:
MiFaZhan
2026-11-02 13:28:03 +08:00
422 changed files with 80993 additions and 0 deletions
@@ -0,0 +1,244 @@
package workorder
import (
"context"
"io"
"os"
"path/filepath"
"testing"
"time"
_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/model"
)
func TestMain(m *testing.M) {
g.Log().SetWriter(io.Discard)
code := m.Run()
_ = os.RemoveAll("resource")
os.Exit(code)
}
func TestAutoCloseResolved(t *testing.T) {
ctx := context.Background()
if err := gdb.SetConfig(gdb.Config{
"default": gdb.ConfigGroup{
{
Type: "sqlite",
Name: filepath.Join(t.TempDir(), "workorder.db"),
},
},
}); err != nil {
t.Fatalf("configure test database: %v", err)
}
defer g.DB().Close(ctx)
createWorkOrderTables(t, ctx)
service := New()
t.Run("resolved order is closed once", func(t *testing.T) {
insertWorkOrder(t, ctx, "WO-RESOLVED", statusResolved)
message := model.WorkOrderAutoCloseMessage{WoNo: "WO-RESOLVED"}
if err := service.AutoCloseResolved(ctx, message); err != nil {
t.Fatalf("AutoCloseResolved returned error: %v", err)
}
if status := workOrderStatus(t, ctx, message.WoNo); status != statusClosed {
t.Fatalf("expected closed status, got %d", status)
}
if count := workOrderRecordCount(t, ctx, message.WoNo); count != 1 {
t.Fatalf("expected one close record, got %d", count)
}
if err := service.AutoCloseResolved(ctx, message); err != nil {
t.Fatalf("duplicate AutoCloseResolved returned error: %v", err)
}
if count := workOrderRecordCount(t, ctx, message.WoNo); count != 1 {
t.Fatalf("duplicate message added records, got %d", count)
}
})
t.Run("non-resolved order is ignored", func(t *testing.T) {
insertWorkOrder(t, ctx, "WO-PROCESSING", 2)
if err := service.AutoCloseResolved(ctx, model.WorkOrderAutoCloseMessage{WoNo: "WO-PROCESSING"}); err != nil {
t.Fatalf("AutoCloseResolved returned error: %v", err)
}
if status := workOrderStatus(t, ctx, "WO-PROCESSING"); status != 2 {
t.Fatalf("non-resolved order changed status to %d", status)
}
if count := workOrderRecordCount(t, ctx, "WO-PROCESSING"); count != 0 {
t.Fatalf("non-resolved order added %d records", count)
}
})
t.Run("stale resolve message is ignored", func(t *testing.T) {
const woNo = "WO-STALE-MESSAGE"
insertWorkOrder(t, ctx, woNo, statusResolved)
resolveTime := gtime.Now().Add(-73 * time.Hour)
if _, err := g.DB().Model("t_wo_main").Ctx(ctx).Where("wo_no", woNo).Data(g.Map{"resolve_time": resolveTime}).Update(); err != nil {
t.Fatalf("set resolve time: %v", err)
}
if err := service.AutoCloseResolved(ctx, model.WorkOrderAutoCloseMessage{WoNo: woNo, ResolveTimeTs: resolveTime.Timestamp() - 1}); err != nil {
t.Fatalf("AutoCloseResolved returned error: %v", err)
}
if status := workOrderStatus(t, ctx, woNo); status != statusResolved {
t.Fatalf("stale message changed status to %d", status)
}
if count := workOrderRecordCount(t, ctx, woNo); count != 0 {
t.Fatalf("stale message added %d records", count)
}
})
t.Run("record failure rolls back status update", func(t *testing.T) {
for _, statement := range []string{
`CREATE TABLE t_message_log (message_log_id INTEGER PRIMARY KEY AUTOINCREMENT, message_type INTEGER, send_user_type INTEGER, user_ids TEXT, message_title TEXT, message_content TEXT, message_link TEXT, send_time DATETIME, is_recall INTEGER, tenant_id TEXT, created_dept INTEGER, created_by INTEGER, created_at DATETIME, updated_at DATETIME)`,
`CREATE TABLE t_user_message (message_id INTEGER PRIMARY KEY AUTOINCREMENT, message_log_id INTEGER, user_id INTEGER, is_read INTEGER, tenant_id TEXT, created_dept INTEGER, created_by INTEGER, created_at DATETIME, updated_at DATETIME)`,
} {
if _, err := g.DB().Exec(ctx, statement); err != nil {
t.Fatal(err)
}
}
insertWorkOrder(t, ctx, "WO-NOTICE", statusResolved)
if _, err := g.DB().Exec(ctx, `UPDATE t_wo_main SET creator_user_id = 88, creator_dept_id = 30, creator_type = 1 WHERE wo_no = ?`, "WO-NOTICE"); err != nil {
t.Fatal(err)
}
for attempt := 0; attempt < 2; attempt++ {
if err := service.AutoCloseResolved(ctx, model.WorkOrderAutoCloseMessage{WoNo: "WO-NOTICE"}); err != nil {
t.Fatal(err)
}
}
count, err := g.DB().Model("t_user_message").Ctx(ctx).Where("user_id", 88).Where("tenant_id", "tenant").Count()
if err != nil || count != 1 {
t.Fatalf("expected one tenant-scoped notice, count=%d err=%v", count, err)
}
insertWorkOrder(t, ctx, "WO-NOTICE-ROLLBACK", statusResolved)
if _, err := g.DB().Exec(ctx, `UPDATE t_wo_main SET creator_user_id = 88 WHERE wo_no = ?`, "WO-NOTICE-ROLLBACK"); err != nil {
t.Fatal(err)
}
if _, err := g.DB().Exec(ctx, `DROP TABLE t_user_message`); err != nil {
t.Fatal(err)
}
if err := service.AutoCloseResolved(ctx, model.WorkOrderAutoCloseMessage{WoNo: "WO-NOTICE-ROLLBACK"}); err == nil {
t.Fatal("expected notice failure")
}
if status := workOrderStatus(t, ctx, "WO-NOTICE-ROLLBACK"); status != statusResolved {
t.Fatalf("notice failure did not roll back: %d", status)
}
if _, err := g.DB().Exec(ctx, `UPDATE t_wo_main SET creator_user_id = 0 WHERE wo_no = ?`, "WO-NOTICE-ROLLBACK"); err != nil {
t.Fatal(err)
}
for _, name := range []string{"WO-NO-TIME", "WO-EARLY"} {
insertWorkOrder(t, ctx, name, statusResolved)
var resolveTime *gtime.Time
if name == "WO-EARLY" {
resolveTime = gtime.Now()
}
if _, err := g.DB().Exec(ctx, `UPDATE t_wo_main SET resolve_time = ? WHERE wo_no = ?`, resolveTime, name); err != nil {
t.Fatal(err)
}
if err := service.AutoCloseResolved(ctx, model.WorkOrderAutoCloseMessage{WoNo: name}); err != nil {
t.Fatal(err)
}
if status := workOrderStatus(t, ctx, name); status != statusResolved {
t.Fatalf("premature close: %s status=%d", name, status)
}
}
insertWorkOrder(t, ctx, "WO-SCAN", statusResolved)
if err := service.CloseOverdue(ctx); err != nil {
t.Fatal(err)
}
if status := workOrderStatus(t, ctx, "WO-SCAN"); status != statusClosed {
t.Fatalf("overdue scan did not close order: %d", status)
}
insertWorkOrder(t, ctx, "WO-ROLLBACK", statusResolved)
if _, err := g.DB().Exec(ctx, `DROP TABLE t_wo_record`); err != nil {
t.Fatalf("drop record table: %v", err)
}
if err := service.AutoCloseResolved(ctx, model.WorkOrderAutoCloseMessage{WoNo: "WO-ROLLBACK"}); err == nil {
t.Fatal("expected record insert error")
}
if status := workOrderStatus(t, ctx, "WO-ROLLBACK"); status != statusResolved {
t.Fatalf("transaction did not roll back, status=%d", status)
}
})
}
func createWorkOrderTables(t *testing.T, ctx context.Context) {
t.Helper()
statements := []string{
`CREATE TABLE t_wo_main (
id INTEGER PRIMARY KEY AUTOINCREMENT,
wo_no TEXT NOT NULL UNIQUE,
creator_user_id INTEGER,
creator_dept_id INTEGER,
creator_type INTEGER,
current_status INTEGER NOT NULL,
resolve_time DATETIME,
handler_dept_id INTEGER,
handler_user_id INTEGER,
tenant_id TEXT,
created_dept INTEGER,
created_by INTEGER,
updated_by INTEGER,
close_time DATETIME,
created_at DATETIME,
updated_at DATETIME
)`,
`CREATE TABLE t_wo_record (
id INTEGER PRIMARY KEY AUTOINCREMENT,
wo_no TEXT NOT NULL,
operation_type INTEGER,
operation_dept_id INTEGER,
operation_user_id INTEGER,
before_status INTEGER,
after_status INTEGER,
tenant_id TEXT,
created_dept INTEGER,
created_by INTEGER,
created_at DATETIME,
updated_at DATETIME
)`,
}
for _, statement := range statements {
if _, err := g.DB().Exec(ctx, statement); err != nil {
t.Fatalf("create test table: %v", err)
}
}
}
func insertWorkOrder(t *testing.T, ctx context.Context, woNo string, status int) {
t.Helper()
_, err := g.DB().Exec(ctx, `
INSERT INTO t_wo_main (
wo_no, current_status, handler_dept_id, handler_user_id,
tenant_id, created_dept, created_by, updated_by
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`, woNo, status, 10, 20, "tenant", 30, 40, 50)
if err != nil {
t.Fatalf("insert work order: %v", err)
}
if _, err := g.DB().Exec(ctx, `UPDATE t_wo_main SET resolve_time = ? WHERE wo_no = ?`, gtime.Now().Add(-73*time.Hour), woNo); err != nil {
t.Fatal(err)
}
}
func workOrderStatus(t *testing.T, ctx context.Context, woNo string) int {
t.Helper()
value, err := g.DB().Model("t_wo_main").Ctx(ctx).Where("wo_no", woNo).Value("current_status")
if err != nil {
t.Fatalf("query work order status: %v", err)
}
return value.Int()
}
func workOrderRecordCount(t *testing.T, ctx context.Context, woNo string) int {
t.Helper()
count, err := g.DB().Model("t_wo_record").Ctx(ctx).Where("wo_no", woNo).Count()
if err != nil {
t.Fatalf("count work order records: %v", err)
}
return count
}