Files
gochat/internal/service/push_delivery_service_test.go.bak
T
2026-06-04 15:44:48 +08:00

182 lines
5.7 KiB
Plaintext

package service
import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"sync"
"testing"
"github.com/gochat/gochat/internal/model"
"github.com/gochat/gochat/internal/repository"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
)
// setupPushDeliveryService 创建 PushTokenRepo + PushDeliveryService 测试实例。
func setupPushDeliveryService(t *testing.T) (*gorm.DB, *repository.PushTokenRepo, *PushDeliveryService) {
t.Helper()
db := setupServiceTestDB(t)
repo := repository.NewPushTokenRepo(db)
svc := NewPushDeliveryService(repo, "test-vapid-public", "test-vapid-private", "mailto:test@example.com")
return db, repo, svc
}
// setupWebhookDeliveryService 创建 WebhookSubscriptionRepo + WebhookDeliveryService 测试实例。
func setupWebhookDeliveryService(t *testing.T) (*gorm.DB, *repository.WebhookSubscriptionRepo, *WebhookDeliveryService) {
t.Helper()
db := setupServiceTestDB(t)
repo := repository.NewWebhookSubscriptionRepo(db)
svc := NewWebhookDeliveryService(repo)
return db, repo, svc
}
// ========== PushDeliveryService.SendPushNotification ==========
func TestPushDeliveryService_SendPushNotification_成功(t *testing.T) {
db, _, svc := setupPushDeliveryService(t)
account := createTestAccount(t, db)
user := createTestUser(t, db, account.ID)
// 创建推送令牌
createTestPushToken(t, db, user.ID, "push-token-ios-001", "ios")
createTestPushToken(t, db, user.ID, "push-token-android-002", "android")
payload := PushPayload{
Title: "测试推送",
Body: "这是一条测试推送消息",
Data: map[string]interface{}{"conversation_id": 123},
}
err := svc.SendPushNotification(context.Background(), user.ID, payload)
require.NoError(t, err)
// 当前实现仅记录日志,不返回错误
}
func TestPushDeliveryService_SendPushNotification_无令牌(t *testing.T) {
db, _, svc := setupPushDeliveryService(t)
account := createTestAccount(t, db)
user := createTestUser(t, db, account.ID)
payload := PushPayload{
Title: "测试推送",
Body: "无令牌推送",
}
err := svc.SendPushNotification(context.Background(), user.ID, payload)
require.NoError(t, err)
// 无令牌时跳过推送,不返回错误
}
// ========== WebhookDeliveryService.DeliverEvent ==========
func TestWebhookDeliveryService_DeliverEvent_成功(t *testing.T) {
db, _, svc := setupWebhookDeliveryService(t)
account := createTestAccount(t, db)
// 使用 httptest 创建模拟 webhook 端点
var receivedRequest struct {
body []byte
signature string
event string
deliveryID string
mu sync.Mutex
}
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
receivedRequest.mu.Lock()
defer receivedRequest.mu.Unlock()
bodyBytes, _ := io.ReadAll(r.Body)
receivedRequest.body = bodyBytes
receivedRequest.signature = r.Header.Get("X-Webhook-Signature")
receivedRequest.event = r.Header.Get("X-Webhook-Event")
receivedRequest.deliveryID = r.Header.Get("X-Webhook-Delivery-ID")
w.WriteHeader(http.StatusOK)
}))
t.Cleanup(func() { testServer.Close() })
// 创建 webhook 订阅指向测试服务器
eventsJSON, _ := json.Marshal([]string{"message_created"})
sub := &model.WebhookSubscription{
AccountID: account.ID,
URL: testServer.URL,
Events: eventsJSON,
Secret: "test-webhook-secret-key",
Active: true,
}
require.NoError(t, db.Create(sub).Error)
payload := map[string]interface{}{
"conversation_id": 42,
"message_id": 100,
"content": "Hello webhook",
}
err := svc.DeliverEvent(context.Background(), account.ID, "message_created", payload)
require.NoError(t, err)
// 验证测试服务器收到了正确的请求
receivedRequest.mu.Lock()
defer receivedRequest.mu.Unlock()
assert.NotEmpty(t, receivedRequest.body, "webhook 端点应收到请求体")
// 验证 X-Webhook-Signature 头
expectedSig := SignPayload(receivedRequest.body, "test-webhook-secret-key")
assert.Equal(t, expectedSig, receivedRequest.signature, "X-Webhook-Signature 应匹配 HMAC-SHA256 签名")
// 验证 X-Webhook-Event 头
assert.Equal(t, "message_created", receivedRequest.event, "X-Webhook-Event 应为 message_created")
// 验证 X-Webhook-Delivery-ID 头
assert.NotEmpty(t, receivedRequest.deliveryID, "X-Webhook-Delivery-ID 不应为空")
}
func TestWebhookDeliveryService_DeliverEvent_无订阅(t *testing.T) {
db, _, svc := setupWebhookDeliveryService(t)
account := createTestAccount(t, db)
payload := map[string]interface{}{"id": 1}
err := svc.DeliverEvent(context.Background(), account.ID, "message_created", payload)
require.NoError(t, err)
// 无匹配订阅时不发送,不返回错误
}
// ========== SignPayload ==========
func TestSignPayload_正确计算HMACSHA256(t *testing.T) {
payload := []byte(`{"event":"message_created","data":{"id":1}}`)
secret := "my-secret-key"
// 手动计算 HMAC-SHA256 用于比对
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(payload)
expectedHex := hex.EncodeToString(mac.Sum(nil))
result := SignPayload(payload, secret)
assert.Equal(t, expectedHex, result)
}
func TestSignPayload_不同密钥产生不同签名(t *testing.T) {
payload := []byte(`{"event":"test"}`)
sig1 := SignPayload(payload, "secret-one")
sig2 := SignPayload(payload, "secret-two")
assert.NotEqual(t, sig1, sig2, "不同密钥应产生不同签名")
}
func TestSignPayload_相同密钥和载荷产生相同签名(t *testing.T) {
payload := []byte(`{"event":"consistent"}`)
secret := "same-secret"
sig1 := SignPayload(payload, secret)
sig2 := SignPayload(payload, secret)
assert.Equal(t, sig1, sig2, "相同密钥和载荷应产生相同签名")
}