Files
MailUI4Agents/server/internal/scheduler/calendar_test.go

112 lines
3.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package scheduler
import (
"strings"
"testing"
"time"
"github.com/agentmail/gateway/internal/models"
)
func TestRenderReminder(t *testing.T) {
at := time.Date(2026, 9, 4, 9, 30, 0, 0, time.Local)
e := models.CalendarEvent{
Title: "每日站会",
Description: "同步昨天进展与今天计划",
EventTime: at,
}
t.Run("三个变量都替换", func(t *testing.T) {
got := RenderReminder("日程提醒:{title}\n时间{time}\n{description}", e)
for _, want := range []string{"每日站会", "2026-09-04 09:30", "同步昨天进展与今天计划"} {
if !strings.Contains(got, want) {
t.Errorf("渲染结果缺 %q\n%s", want, got)
}
}
if strings.Contains(got, "{") {
t.Errorf("仍有未替换的占位符:\n%s", got)
}
})
t.Run("同一变量出现多次全部替换", func(t *testing.T) {
// ReplaceAll 而非 Replace模板里写两遍 {title} 时
// 只替换第一处会让 Agent 收到一封半成品邮件。
got := RenderReminder("{title} —— 请开始 {title}", e)
if strings.Contains(got, "{title}") {
t.Errorf("第二处 {title} 未替换:%s", got)
}
})
t.Run("空模板不产生占位符残留", func(t *testing.T) {
if got := RenderReminder("", e); got != "" {
t.Errorf("空模板应渲染成空串,得到 %q", got)
}
})
t.Run("没有变量的模板原样返回", func(t *testing.T) {
const plain = "该跑测试了"
if got := RenderReminder(plain, e); got != plain {
t.Errorf("纯文本模板应原样返回,得到 %q", got)
}
})
t.Run("描述为空时不留下空行以外的痕迹", func(t *testing.T) {
e2 := e
e2.Description = ""
got := RenderReminder("{title}|{description}|", e2)
if got != "每日站会||" {
t.Errorf("空描述应替换成空串,得到 %q", got)
}
})
// {time} 必须是本地时间。DSN 带 _timezone=UTC从库里读回的 EventTime
// 是 UTC不转本地就会把人在 +0800 输入的 14:30 写成 06:30
// 而前端预览用的是本地时间 —— 两边差 8 小时且都不报错。
t.Run("time 用本地时区而非 UTC", func(t *testing.T) {
// 刻意构造一个 UTC 时刻(模拟从库里 Scan 出来的样子)
utcEvent := models.CalendarEvent{
Title: "跨时区检查",
EventTime: time.Date(2026, 9, 3, 6, 30, 0, 0, time.UTC),
}
got := RenderReminder("{time}", utcEvent)
want := time.Date(2026, 9, 3, 6, 30, 0, 0, time.UTC).Local().Format("2006-01-02 15:04")
if got != want {
t.Errorf("{time} = %q期望本地时间 %q", got, want)
}
})
// 同一时刻无论以哪个时区的 Location 传进来,渲染结果必须一致 ——
// 它代表的是「墙上时钟的那一刻」,与 Location 的表示方式无关。
t.Run("同一时刻不同 Location 渲染一致", func(t *testing.T) {
base := time.Date(2026, 9, 3, 6, 30, 0, 0, time.UTC)
a := RenderReminder("{time}", models.CalendarEvent{EventTime: base})
b := RenderReminder("{time}", models.CalendarEvent{EventTime: base.Local()})
if a != b {
t.Errorf("UTC 与 Local 表示同一时刻却渲染出不同结果:%q vs %q", a, b)
}
})
}
func TestShort(t *testing.T) {
// 日志里截前 8 位;短 id测试里可能出现不能 panic
if got := short("0123456789abcdef"); got != "01234567" {
t.Errorf("长 id 应截断成 8 位,得到 %q", got)
}
if got := short("abc"); got != "abc" {
t.Errorf("短 id 应原样返回,得到 %q", got)
}
if got := short(""); got != "" {
t.Errorf("空串应原样返回,得到 %q", got)
}
}
func TestStartStopIdempotent(t *testing.T) {
// Stop 在没启动时被调defer 里必然发生)不该 panic
// Start 两次也不该泄漏 goroutine第二次先停旧的
Stop()
Start()
Start()
Stop()
Stop()
}