siteinfosync_test.go 4.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package tools
  2. import (
  3. "testing"
  4. "time"
  5. "github.com/mark3labs/mcp-go/mcp"
  6. "go.mongodb.org/mongo-driver/bson/primitive"
  7. "fwh-toolbox-server/domain"
  8. )
  9. func syncRecord(p domain.Progress, created, completed time.Time) *domain.SiteInfoUpdateRecord {
  10. id := primitive.NewObjectID()
  11. return &domain.SiteInfoUpdateRecord{Id: &id, Progress: p, CreateTime: created, UpdateTime: completed, Total: 100}
  12. }
  13. func TestSiteInfoSyncDecide(t *testing.T) {
  14. now := time.Date(2026, 10, 29, 12, 0, 0, 0, time.UTC)
  15. ago := func(h float64) time.Time { return now.Add(-time.Duration(h * float64(time.Hour))) }
  16. freshDone := syncRecord(domain.ProgressComplete, ago(3), ago(1))
  17. oldDone := syncRecord(domain.ProgressComplete, ago(50), ago(48))
  18. cases := []struct {
  19. name string
  20. latest, last *domain.SiteInfoUpdateRecord
  21. force bool
  22. state string
  23. action string
  24. }{
  25. {"从未同步", nil, nil, false, syncStateNever, "triggered"},
  26. {"pending 刚请求", syncRecord(domain.ProgressPending, ago(0.1), ago(0.1)), oldDone, false, syncStateSyncing, "tracking"},
  27. {"running 2 小时仍在同步", syncRecord(domain.ProgressRunning, ago(2), ago(2)), oldDone, false, syncStateSyncing, "tracking"},
  28. {"同步中 force 也不重复触发", syncRecord(domain.ProgressRunning, ago(2), ago(2)), oldDone, true, syncStateSyncing, "tracking"},
  29. {"running 超过 6 小时疑似中断", syncRecord(domain.ProgressRunning, ago(7), ago(7)), oldDone, false, syncStateStale, "skipped_stale"},
  30. {"疑似中断 force 重新触发", syncRecord(domain.ProgressRunning, ago(7), ago(7)), oldDone, true, syncStateStale, "triggered"},
  31. {"24 小时内已成功", freshDone, freshDone, false, syncStateIdle, "skipped_fresh"},
  32. {"24 小时内已成功 force", freshDone, freshDone, true, syncStateIdle, "triggered"},
  33. {"成功已超过 24 小时", oldDone, oldDone, false, syncStateIdle, "triggered"},
  34. {"上次失败", syncRecord(domain.ProgressError, ago(1), ago(1)), freshDone, false, syncStateIdle, "triggered"},
  35. }
  36. for _, c := range cases {
  37. s := evalSiteInfoSync(c.latest, c.last, now)
  38. if s.State != c.state {
  39. t.Errorf("%s: state = %s,期望 %s", c.name, s.State, c.state)
  40. }
  41. if action, _ := s.decideRefresh(c.force); action != c.action {
  42. t.Errorf("%s: action = %s,期望 %s", c.name, action, c.action)
  43. }
  44. if _, ok := refreshMessages[c.action]; !ok {
  45. t.Errorf("%s: action %s 缺少提示文案", c.name, c.action)
  46. }
  47. if v := s.view(); v["advice"] == "" {
  48. t.Errorf("%s: advice 为空", c.name)
  49. }
  50. }
  51. }
  52. func TestSiteInfoTaskState(t *testing.T) {
  53. now := time.Date(2026, 10, 29, 12, 0, 0, 0, time.UTC)
  54. ago := func(h float64) time.Time { return now.Add(-time.Duration(h * float64(time.Hour))) }
  55. cases := []struct {
  56. name string
  57. flag string
  58. rec *domain.SiteInfoUpdateRecord
  59. status mcp.TaskStatus
  60. isError bool
  61. }{
  62. {"排队中", "triggered", syncRecord(domain.ProgressPending, ago(0.1), ago(0.1)), mcp.TaskStatusWorking, false},
  63. {"同步中", "tracking", syncRecord(domain.ProgressRunning, ago(1), ago(1)), mcp.TaskStatusWorking, false},
  64. {"超过 6 小时疑似中断", "triggered", syncRecord(domain.ProgressRunning, ago(7), ago(7)), mcp.TaskStatusFailed, true},
  65. {"完成", "triggered", syncRecord(domain.ProgressComplete, ago(2), ago(1)), mcp.TaskStatusCompleted, false},
  66. {"失败", "triggered", syncRecord(domain.ProgressError, ago(2), ago(2)), mcp.TaskStatusFailed, true},
  67. {"取消", "triggered", syncRecord(domain.ProgressCancelled, ago(2), ago(2)), mcp.TaskStatusCancelled, true},
  68. {"未触发:数据较新,立即完成", "skipped_fresh", syncRecord(domain.ProgressComplete, ago(3), ago(2)), mcp.TaskStatusCompleted, false},
  69. {"未触发:疑似中断,立即完成", "skipped_stale", syncRecord(domain.ProgressRunning, ago(7), ago(7)), mcp.TaskStatusCompleted, false},
  70. }
  71. for _, c := range cases {
  72. st := siteInfoTaskState(c.flag, c.rec, now)
  73. if st.Status != c.status {
  74. t.Errorf("%s: status = %s,期望 %s", c.name, st.Status, c.status)
  75. }
  76. if st.Status.IsTerminal() && (st.Result == nil || st.Result.IsError != c.isError) {
  77. t.Errorf("%s: 终态结果不符合预期(isError 期望 %v):%+v", c.name, c.isError, st.Result)
  78. }
  79. if !st.Status.IsTerminal() && st.Message == "" {
  80. t.Errorf("%s: 进行中应有进度说明", c.name)
  81. }
  82. }
  83. }