Files
team-api/tests/integration/admin/notification_test.go
T

409 lines
11 KiB
Go

//go:build integration
package admin_test
import (
"encoding/json"
"fmt"
"testing"
"github.com/qianfree/team-api/tests/integration/admin/testinfra"
)
func TestTemplateList(t *testing.T) {
client := testinfra.GetAuthedClient(t)
resp := client.Get("/api/admin/notification/templates", map[string]string{
"page": "1",
"page_size": "10",
})
testinfra.AssertPaginatedList(t, resp, 0)
}
func TestTemplateGetAndUpdate(t *testing.T) {
client := testinfra.GetAuthedClient(t)
templateCode := getFirstTemplateCode(t, client)
if templateCode == "" {
return
}
// --- Get template detail ---
getResp := client.Get(fmt.Sprintf("/api/admin/notification/templates/%s", templateCode), nil)
getResp.AssertSuccess(t)
// Response has nested data: {"data": {...}}
var outerMap map[string]json.RawMessage
getResp.DecodeData(t, &outerMap)
var template struct {
Code string `json:"code"`
Subject string `json:"subject"`
BodyTemplate string `json:"body_template"`
Channel string `json:"channel"`
}
if innerData, ok := outerMap["data"]; ok {
json.Unmarshal(innerData, &template)
} else {
var raw json.RawMessage
raw, _ = json.Marshal(outerMap)
json.Unmarshal(raw, &template)
}
if template.Code != templateCode {
t.Fatalf("expected code=%q, got %q", templateCode, template.Code)
}
// --- Update with modified subject ---
testSubject := template.Subject + " [测试]"
updateResp := client.Put(fmt.Sprintf("/api/admin/notification/templates/%s", templateCode), map[string]any{
"subject": testSubject,
"body_template": template.BodyTemplate,
"channel": template.Channel,
})
updateResp.AssertSuccess(t)
// --- Verify update ---
verifyResp := client.Get(fmt.Sprintf("/api/admin/notification/templates/%s", templateCode), nil)
verifyResp.AssertSuccess(t)
var verifyOuter map[string]json.RawMessage
verifyResp.DecodeData(t, &verifyOuter)
var verifyData struct {
Subject string `json:"subject"`
}
if innerData, ok := verifyOuter["data"]; ok {
json.Unmarshal(innerData, &verifyData)
} else {
var raw json.RawMessage
raw, _ = json.Marshal(verifyOuter)
json.Unmarshal(raw, &verifyData)
}
if verifyData.Subject != testSubject {
t.Fatalf("expected subject=%q after update, got %q", testSubject, verifyData.Subject)
}
// --- Restore original ---
restoreResp := client.Put(fmt.Sprintf("/api/admin/notification/templates/%s", templateCode), map[string]any{
"subject": template.Subject,
"body_template": template.BodyTemplate,
"channel": template.Channel,
})
restoreResp.AssertSuccess(t)
}
func TestMessageList(t *testing.T) {
client := testinfra.GetAuthedClient(t)
resp := client.Get("/api/admin/notification/messages", map[string]string{
"page": "1",
"page_size": "10",
})
testinfra.AssertPaginatedList(t, resp, 0)
}
func TestMessageSendAndVerify(t *testing.T) {
client := testinfra.GetAuthedClient(t)
tenantID, cleanup := testinfra.CreateTestTenant(t, client)
defer cleanup()
// Count messages before sending
beforeResp := client.Get("/api/admin/notification/messages", map[string]string{
"tenant_id": fmt.Sprintf("%d", tenantID),
"page": "1",
"page_size": "10",
})
beforeResp.AssertSuccess(t)
beforeTotal := beforeResp.GetTotal(t)
// Send a message
msgTitle := fmt.Sprintf("验证测试消息 %s", randomSuffix())
msgContent := "这是一条用于验证发送成功的测试消息"
sendResp := client.Post("/api/admin/notification/messages/send", map[string]any{
"tenant_id": tenantID,
"title": msgTitle,
"content": msgContent,
"channel": "system",
})
sendResp.AssertSuccess(t)
// Verify the message appears in the list for this tenant
afterResp := client.Get("/api/admin/notification/messages", map[string]string{
"tenant_id": fmt.Sprintf("%d", tenantID),
"page": "1",
"page_size": "10",
})
afterResp.AssertSuccess(t)
afterTotal := afterResp.GetTotal(t)
if afterTotal <= beforeTotal {
t.Fatalf("expected message count to increase after send (before=%d, after=%d)", beforeTotal, afterTotal)
}
// Verify the message content
var msgList struct {
List []struct {
Title string `json:"title"`
Content string `json:"content"`
} `json:"list"`
}
afterResp.DecodeData(t, &msgList)
found := false
for _, msg := range msgList.List {
if msg.Title == msgTitle && msg.Content == msgContent {
found = true
break
}
}
if !found {
t.Fatalf("sent message with title=%q not found in message list", msgTitle)
}
t.Logf("Message send verified: tenant %d, before=%d, after=%d", tenantID, beforeTotal, afterTotal)
}
func TestMessageBroadcast(t *testing.T) {
client := testinfra.GetAuthedClient(t)
msgTitle := fmt.Sprintf("[集成测试] 广播消息 %s", randomSuffix())
resp := client.Post("/api/admin/notification/messages/broadcast", map[string]any{
"title": msgTitle,
"content": "这是一条集成测试广播消息",
"target_roles": []string{"owner", "admin"},
})
resp.AssertSuccess(t)
// Hard-delete broadcast messages from database
defer testinfra.HardDeleteMessagesByTitle(t, "[集成测试]")
}
func TestAnnouncementCRUD(t *testing.T) {
client := testinfra.GetAuthedClient(t)
suffix := randomSuffix()
originalTitle := fmt.Sprintf("CRUD测试公告 %s", suffix)
// --- Create ---
createResp := client.Post("/api/admin/announcements", map[string]any{
"title": originalTitle,
"type": "info",
"content": "这是一条集成测试公告内容",
"status": "draft",
"is_pinned": false,
"display_position": "console",
})
createResp.AssertSuccess(t)
announcementID := createResp.GetID(t)
defer func() {
testinfra.HardDeleteAnnouncement(t, announcementID)
}()
// --- Verify creation via list ---
listResp := client.Get("/api/admin/announcements", map[string]string{
"page": "1",
"page_size": "50",
"status": "draft",
})
testinfra.AssertPaginatedList(t, listResp, 1)
var listData struct {
List []struct {
Id int64 `json:"id"`
Title string `json:"title"`
Type string `json:"type"`
Status string `json:"status"`
IsPinned int `json:"is_pinned"`
DisplayPosition string `json:"display_position"`
} `json:"list"`
}
listResp.DecodeData(t, &listData)
var created *struct {
Id int64 `json:"id"`
Title string `json:"title"`
Type string `json:"type"`
Status string `json:"status"`
IsPinned int `json:"is_pinned"`
DisplayPosition string `json:"display_position"`
}
for i := range listData.List {
if listData.List[i].Id == announcementID {
created = &listData.List[i]
break
}
}
if created == nil {
t.Fatalf("announcement id=%d not found in draft list", announcementID)
}
if created.Title != originalTitle {
t.Fatalf("expected title=%q, got %q", originalTitle, created.Title)
}
if created.Status != "draft" {
t.Fatalf("new announcement should be draft, got %q", created.Status)
}
// --- Update ---
updatedTitle := fmt.Sprintf("更新公告 %s", suffix)
updateResp := client.Put(fmt.Sprintf("/api/admin/announcements/%d", announcementID), map[string]any{
"title": updatedTitle,
"type": "warning",
"content": "更新后的公告内容",
"status": "draft",
"is_pinned": 1,
"display_position": "both",
})
updateResp.AssertSuccess(t)
// --- Verify update via list ---
verifyResp := client.Get("/api/admin/announcements", map[string]string{
"page": "1",
"page_size": "50",
"status": "draft",
})
verifyResp.AssertSuccess(t)
var verifyData struct {
List []struct {
Id int64 `json:"id"`
Title string `json:"title"`
Type string `json:"type"`
IsPinned int `json:"is_pinned"`
DisplayPosition string `json:"display_position"`
} `json:"list"`
}
verifyResp.DecodeData(t, &verifyData)
var updated *struct {
Id int64 `json:"id"`
Title string `json:"title"`
Type string `json:"type"`
IsPinned int `json:"is_pinned"`
DisplayPosition string `json:"display_position"`
}
for i := range verifyData.List {
if verifyData.List[i].Id == announcementID {
updated = &verifyData.List[i]
break
}
}
if updated == nil {
t.Fatalf("announcement id=%d not found after update", announcementID)
}
if updated.Title != updatedTitle {
t.Fatalf("expected updated title=%q, got %q", updatedTitle, updated.Title)
}
if updated.Type != "warning" {
t.Fatalf("expected type=warning after update, got %q", updated.Type)
}
// --- Publish ---
publishResp := client.Put(fmt.Sprintf("/api/admin/announcements/%d/publish", announcementID), nil)
publishResp.AssertSuccess(t)
// --- Verify published status ---
pubListResp := client.Get("/api/admin/announcements", map[string]string{
"page": "1",
"page_size": "50",
"status": "published",
})
pubListResp.AssertSuccess(t)
var pubData struct {
List []struct {
Id int64 `json:"id"`
Status string `json:"status"`
} `json:"list"`
}
pubListResp.DecodeData(t, &pubData)
found := false
for _, item := range pubData.List {
if item.Id == announcementID {
found = true
if item.Status != "published" {
t.Fatalf("expected status=published after publish, got %q", item.Status)
}
}
}
if !found {
t.Fatal("published announcement not found in published list")
}
// --- Archive ---
archiveResp := client.Put(fmt.Sprintf("/api/admin/announcements/%d/archive", announcementID), nil)
archiveResp.AssertSuccess(t)
// --- Verify archived status ---
archListResp := client.Get("/api/admin/announcements", map[string]string{
"page": "1",
"page_size": "50",
"status": "archived",
})
archListResp.AssertSuccess(t)
var archData struct {
List []struct {
Id int64 `json:"id"`
Status string `json:"status"`
} `json:"list"`
}
archListResp.DecodeData(t, &archData)
foundArchived := false
for _, item := range archData.List {
if item.Id == announcementID {
foundArchived = true
if item.Status != "archived" {
t.Fatalf("expected status=archived after archive, got %q", item.Status)
}
}
}
if !foundArchived {
t.Fatal("archived announcement not found in archived list")
}
}
func TestAnnouncementNegative(t *testing.T) {
client := testinfra.GetAuthedClient(t)
// Create with missing title should fail
missingTitleResp := client.Post("/api/admin/announcements", map[string]any{
"content": "no title",
})
if missingTitleResp.Code == 0 {
t.Fatal("expected error for missing announcement title, got success")
}
// Publish non-existent announcement
publishNonExistResp := client.Put("/api/admin/announcements/999999999/publish", nil)
if publishNonExistResp.Code == 0 {
t.Fatal("expected error when publishing non-existent announcement, got success")
}
}
// getFirstTemplateCode returns the code of the first notification template, or empty string if none.
func getFirstTemplateCode(t *testing.T, client *testinfra.APIClient) string {
t.Helper()
listResp := client.Get("/api/admin/notification/templates", map[string]string{
"page": "1",
"page_size": "50",
})
listResp.AssertSuccess(t)
var listData struct {
List []struct {
Code string `json:"code"`
} `json:"list"`
}
listResp.DecodeData(t, &listData)
if len(listData.List) == 0 {
t.Skip("No notification templates found")
}
return listData.List[0].Code
}