116 lines
3.6 KiB
Go
116 lines
3.6 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"os"
|
||
"testing"
|
||
|
||
assetPb "github.com/topfans/backend/pkg/proto/asset"
|
||
"github.com/topfans/backend/pkg/logger"
|
||
"github.com/topfans/backend/services/socialService/client"
|
||
"github.com/stretchr/testify/assert"
|
||
)
|
||
|
||
// TestMain 在测试启动时初始化 logger(service 代码内部使用 logger.Logger)
|
||
func TestMain(m *testing.M) {
|
||
_ = logger.Init(logger.Config{ServiceName: "social-service-test", Environment: "test"})
|
||
os.Exit(m.Run())
|
||
}
|
||
|
||
// TestFireLikeNotification_OwnerUidZero_Skips
|
||
// 验证 owner_uid <= 0 时直接跳过,不调用 mock client
|
||
func TestFireLikeNotification_OwnerUidZero_Skips(t *testing.T) {
|
||
mock := &client.MockNotificationClient{}
|
||
svc := &AssetLikeService{notificationClient: mock}
|
||
ctx := context.Background()
|
||
|
||
asset := &assetPb.GetAssetForRPCResponse{
|
||
AssetId: 1,
|
||
OwnerUid: 0,
|
||
Name: "some-asset",
|
||
CoverUrl: "https://example.com/cover.png",
|
||
}
|
||
|
||
svc.fireLikeNotification(ctx, asset, 1, 2, 1)
|
||
|
||
assert.Equal(t, int32(0), mock.CreateCallCount, "notification client should NOT be called when owner_uid is invalid")
|
||
}
|
||
|
||
// TestFireLikeNotification_NilAsset_Skips
|
||
// 防御 nil asset 入参
|
||
func TestFireLikeNotification_NilAsset_Skips(t *testing.T) {
|
||
mock := &client.MockNotificationClient{}
|
||
svc := &AssetLikeService{notificationClient: mock}
|
||
ctx := context.Background()
|
||
|
||
svc.fireLikeNotification(ctx, nil, 1, 2, 1)
|
||
|
||
assert.Equal(t, int32(0), mock.CreateCallCount, "notification client should NOT be called when asset is nil")
|
||
}
|
||
|
||
// TestFireLikeNotification_NilClient_Skips
|
||
// 防御 nil notificationClient 配置
|
||
func TestFireLikeNotification_NilClient_Skips(t *testing.T) {
|
||
svc := &AssetLikeService{notificationClient: nil}
|
||
ctx := context.Background()
|
||
asset := &assetPb.GetAssetForRPCResponse{
|
||
AssetId: 1,
|
||
OwnerUid: 100,
|
||
Name: "x",
|
||
CoverUrl: "y",
|
||
}
|
||
|
||
// 应直接 return,不 panic
|
||
svc.fireLikeNotification(ctx, asset, 1, 2, 1)
|
||
}
|
||
|
||
// TestFireLikeNotification_ClientErr_JustLogs
|
||
// 验证 notification client 报错时不 panic,不影响主路径
|
||
// 这是核心需求:"通知调用失败不能影响点赞主路径"
|
||
func TestFireLikeNotification_ClientErr_JustLogs(t *testing.T) {
|
||
mock := &client.MockNotificationClient{CreateErr: errors.New("rpc down")}
|
||
svc := &AssetLikeService{notificationClient: mock}
|
||
ctx := context.Background()
|
||
|
||
asset := &assetPb.GetAssetForRPCResponse{
|
||
AssetId: 1,
|
||
OwnerUid: 100,
|
||
Name: "藏品A",
|
||
CoverUrl: "https://cdn.example.com/a.png",
|
||
}
|
||
|
||
// 不应 panic
|
||
svc.fireLikeNotification(ctx, asset, 1, 2, 1)
|
||
|
||
assert.Equal(t, int32(1), mock.CreateCallCount, "notification client should be called exactly once")
|
||
assert.NotNil(t, mock.LastRequest, "LastRequest should be recorded")
|
||
}
|
||
|
||
// TestFireLikeNotification_Success_BuildsCorrectRequest
|
||
// 验证 happy path:构造的 request 字段全部正确
|
||
func TestFireLikeNotification_Success_BuildsCorrectRequest(t *testing.T) {
|
||
mock := &client.MockNotificationClient{}
|
||
svc := &AssetLikeService{notificationClient: mock}
|
||
ctx := context.Background()
|
||
|
||
asset := &assetPb.GetAssetForRPCResponse{
|
||
AssetId: 42,
|
||
OwnerUid: 100,
|
||
Name: "藏品X",
|
||
CoverUrl: "https://cdn.example.com/x.png",
|
||
}
|
||
|
||
svc.fireLikeNotification(ctx, asset, 42, 7, 3)
|
||
|
||
assert.Equal(t, int32(1), mock.CreateCallCount)
|
||
req := mock.LastRequest
|
||
if assert.NotNil(t, req) {
|
||
assert.Equal(t, int64(100), req.UserId, "通知收件人应为资产 owner")
|
||
assert.Equal(t, int64(3), req.StarId)
|
||
assert.Equal(t, "like", req.Type)
|
||
assert.Equal(t, "新点赞", req.Title)
|
||
assert.Contains(t, req.Content, "7", "Content 应包含 actor userID")
|
||
assert.NotNil(t, req.Data, "Data 结构体不能为空")
|
||
}
|
||
} |