package host import ( "context" "regexp" "testing" "github.com/DATA-DOG/go-sqlmock" "hyapp/pkg/appcode" hostdomain "hyapp/services/user-service/internal/domain/host" ) func TestGetHostEngagementStatsAggregatesOwnedFacts(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("create sqlmock: %v", err) } defer db.Close() mock.ExpectQuery("FROM user_mic_daily_stats"). WithArgs(validMicDayThresholdMS, "fami", int64(42), "2026-07-06", "2026-07-12"). WillReturnRows(sqlmock.NewRows([]string{"mic_ms", "valid_days"}).AddRow(int64(5400000), int64(1))) mock.ExpectQuery(regexp.QuoteMeta(` SELECT COUNT(DISTINCT matched.sender_user_id) FROM ( SELECT sender_user_id FROM user_private_message_events FORCE INDEX (idx_private_message_target_time) WHERE app_code = ? AND target_user_id = ? AND occurred_at_ms >= ? AND occurred_at_ms < ? UNION ALL SELECT sender_user_id FROM user_private_message_events FORCE INDEX (idx_private_message_target_time) WHERE app_code = ? AND target_user_id = ? AND occurred_at_ms >= ? AND occurred_at_ms < ? ) matched INNER JOIN users sender ON sender.user_id = matched.sender_user_id AND sender.app_code = ?`)). WithArgs( "fami", int64(42), int64(1783296000000), int64(1783900800000), "lalu", int64(42), int64(1783296000000), int64(1783900800000), "fami", ). WillReturnRows(sqlmock.NewRows([]string{"senders"}).AddRow(int64(6))) mock.ExpectQuery("FROM user_follow_events"). WithArgs("fami", int64(42), int64(1783296000000), int64(1783900800000)). WillReturnRows(sqlmock.NewRows([]string{"followers"}).AddRow(int64(4))) mock.ExpectQuery(regexp.QuoteMeta(` SELECT created_at_ms, last_heartbeat_at_ms FROM auth_sessions WHERE app_code = ? AND user_id = ? AND last_heartbeat_at_ms >= ? AND created_at_ms < ?`)). WithArgs("fami", int64(42), int64(1783296000000), int64(1783900800000)). WillReturnRows(sqlmock.NewRows([]string{"created_at_ms", "last_heartbeat_at_ms"}). AddRow(int64(1783299600000), int64(1783303200000)). AddRow(int64(1783301400000), int64(1783306800000))) repo := New(db) stats, err := repo.GetHostEngagementStats(appcode.WithContext(context.Background(), "fami"), hostdomain.EngagementStatsQuery{ HostUserID: 42, StartAtMS: 1783296000000, EndAtMS: 1783900800000, }) if err != nil { t.Fatalf("GetHostEngagementStats failed: %v", err) } // 两个重叠 session 按当天最早开始到最晚心跳合并,不能相加成重复在线时长。 if stats.OnlineDurationMS != 7200000 || stats.ValidMicDurationMS != 5400000 || stats.ValidMicDays != 1 || stats.PrivateMessageSenders != 6 || stats.NewFollowers != 4 { t.Fatalf("unexpected engagement stats: %+v", stats) } if err := mock.ExpectationsWereMet(); err != nil { t.Fatalf("unmet SQL expectations: %v", err) } } func TestRecordPrivateMessageEventResolvesAppFromUsers(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("create sqlmock: %v", err) } defer db.Close() mock.ExpectExec(regexp.QuoteMeta(` INSERT IGNORE INTO user_private_message_events ( app_code, event_id, sender_user_id, target_user_id, occurred_at_ms, created_at_ms ) SELECT target.app_code, ?, sender.user_id, target.user_id, ?, ? FROM users target INNER JOIN users sender ON sender.user_id = ? AND sender.app_code = target.app_code WHERE target.user_id = ?`)). WithArgs("im-message-1", int64(1783296000000), sqlmock.AnyArg(), int64(41), int64(42)). WillReturnResult(sqlmock.NewResult(0, 1)) repo := New(db) created, err := repo.RecordPrivateMessageEvent(appcode.WithContext(context.Background(), "lalu"), hostdomain.PrivateMessageEvent{ EventID: "im-message-1", SenderUserID: 41, TargetUserID: 42, OccurredAtMS: 1783296000000, }) if err != nil { t.Fatalf("RecordPrivateMessageEvent failed: %v", err) } if !created { t.Fatal("event must be created for users in the same authoritative app") } if err := mock.ExpectationsWereMet(); err != nil { t.Fatalf("unmet SQL expectations: %v", err) } }