BoxTrend 的回答那条 SQL 复用了 d.day(基于 created_at 的日期表达式)做 GROUP BY, 但 WHERE 过滤用的是 answered_at。于是「40 天前创建、昨天才回答」的提问被排除在 窗口外(created_at < from),昨天的回答数里不出现;「今天创建、明天回答」的又 被记到今天。趋势图里的「每日回答数」根本不是「某天被回答了多少」。 单独构造 answerDay(基于 COALESCE(answered_at, updated_at)),WHERE / GROUP BY / SELECT 三者口径一致。PG 用 to_char(... AT TIME ZONE INTERVAL ...),MySQL 用 CONVERT_TZ,与 analyticsDialectFor 对 created_at 的处理对称。 新增 box_analytics_test.go:构造「40 天前创建、昨天回答」的提问,断言计入昨天, 并做变异验证(改回 d.day → 测试失败)。
76 lines
2.4 KiB
Go
76 lines
2.4 KiB
Go
// Copyright 2026 tamakyi. All rights reserved.
|
|
// Use of this source code is governed by a MIT-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package db
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestBoxTrendAnswerByAnsweredDate 验证「每日回答数」按 answered_at 分组,
|
|
// 而不是按 created_at。
|
|
//
|
|
// 背景:BoxTrend 一度两条 SQL 都复用 created_at 的日期表达式,导致「40 天前创建、
|
|
// 昨天才回答」的提问被排除在窗口外(created_at < from),昨天/今天的回答数里
|
|
// 根本不出现;「今天创建、明天回答」的又会被记到今天。本测试构造一条
|
|
// 「创建日远早于窗口、回答日落在窗口内」的提问,断言它出现在回答日那天。
|
|
func TestBoxTrendAnswerByAnsweredDate(t *testing.T) {
|
|
db, cleanup := newTestDB(t)
|
|
ctx := context.Background()
|
|
store := NewBoxAnalyticsStore(db)
|
|
|
|
t.Cleanup(func() {
|
|
_ = cleanup("questions")
|
|
})
|
|
|
|
now := time.Now()
|
|
// 窗口 = 最近 7 天
|
|
from := now.AddDate(0, 0, -6)
|
|
to := now
|
|
|
|
// 一条 40 天前创建、昨天才回答的提问
|
|
answeredAt := now.AddDate(0, 0, -1)
|
|
createdAt := now.AddDate(0, 0, -40)
|
|
q := &Question{
|
|
UserID: 9,
|
|
Content: "很久以前问的,昨天才回答",
|
|
Answer: "这是回答",
|
|
AnsweredAt: &answeredAt,
|
|
}
|
|
// 直接写 created_at / answered_at,绕过 Create 的自动时间戳
|
|
require.NoError(t, db.Model(&Question{}).Create(q).Error)
|
|
require.NoError(t, db.Model(&Question{}).Where("id = ?", q.ID).
|
|
Updates(map[string]interface{}{
|
|
"created_at": createdAt,
|
|
"answered_at": answeredAt,
|
|
"updated_at": answeredAt,
|
|
}).Error)
|
|
|
|
trend, err := store.BoxTrend(ctx, 9, from, to)
|
|
require.NoError(t, err)
|
|
|
|
// 找到回答日那天(昨天)的计数,答案数应 >= 1
|
|
var found bool
|
|
for _, d := range trend {
|
|
if d.Day.Year() == answeredAt.Year() &&
|
|
d.Day.Month() == answeredAt.Month() &&
|
|
d.Day.Day() == answeredAt.Day() {
|
|
require.GreaterOrEqual(t, d.Answers, int64(1),
|
|
"回答应计入 answered_at 那一天,而不是按 created_at 被排除")
|
|
found = true
|
|
}
|
|
// 创建日(40 天前)不应出现在窗口内
|
|
if d.Day.Year() == createdAt.Year() &&
|
|
d.Day.Month() == createdAt.Month() &&
|
|
d.Day.Day() == createdAt.Day() {
|
|
t.Errorf("创建日在窗口外,不应出现在趋势里")
|
|
}
|
|
}
|
|
require.True(t, found, "回答日应出现在趋势结果里")
|
|
}
|