New test files: - custom_field_repository_test.go: 10 tests for CustomFieldRepository & UserCustomFieldValueRepository - login_log_repository_test.go: 3 tests for ListCursor, ListByUserIDCursor, ListAllForExport - operation_log_repository_test.go: 1 test for ListCursor - role_repository_test.go: 2 tests for GetAncestorIDs, GetAncestors - social_account_repository_test.go: 8 CRUD tests - theme_repository_test.go: 10 tests for ThemeConfigRepository - user_role_repository_test.go: 1 test for DeleteByUserAndRole Modified test files: - device_repository_test.go: Added ListAllCursor tests - user_repository_test.go: Added AdvancedSearch tests - webhook_repository_test.go: Added ListByCreatorPaginated test Updated documentation with new coverage status.
228 lines
6.4 KiB
Go
228 lines
6.4 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/user-management-system/internal/domain"
|
|
)
|
|
|
|
func setupWebhookRepository(t *testing.T) *WebhookRepository {
|
|
t.Helper()
|
|
|
|
db := openTestDB(t)
|
|
if err := db.AutoMigrate(&domain.Webhook{}, &domain.WebhookDelivery{}); err != nil {
|
|
t.Fatalf("migrate webhook tables failed: %v", err)
|
|
}
|
|
|
|
return NewWebhookRepository(db)
|
|
}
|
|
|
|
func newWebhookFixture(name string, createdBy int64, status domain.WebhookStatus) *domain.Webhook {
|
|
return &domain.Webhook{
|
|
Name: name,
|
|
URL: "https://example.com/webhook",
|
|
Secret: "secret-demo",
|
|
Events: `["user.registered"]`,
|
|
Status: status,
|
|
MaxRetries: 3,
|
|
TimeoutSec: 10,
|
|
CreatedBy: createdBy,
|
|
}
|
|
}
|
|
|
|
func TestWebhookRepositoryCreateGetUpdateAndDelete(t *testing.T) {
|
|
repo := setupWebhookRepository(t)
|
|
ctx := context.Background()
|
|
|
|
webhook := newWebhookFixture("alpha", 101, domain.WebhookStatusActive)
|
|
if err := repo.Create(ctx, webhook); err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
if webhook.ID == 0 {
|
|
t.Fatal("expected webhook id to be assigned")
|
|
}
|
|
|
|
loaded, err := repo.GetByID(ctx, webhook.ID)
|
|
if err != nil {
|
|
t.Fatalf("GetByID failed: %v", err)
|
|
}
|
|
if loaded.Name != "alpha" {
|
|
t.Fatalf("expected loaded webhook name alpha, got %q", loaded.Name)
|
|
}
|
|
|
|
if err := repo.Update(ctx, webhook.ID, map[string]interface{}{
|
|
"name": "alpha-updated",
|
|
"status": domain.WebhookStatusInactive,
|
|
}); err != nil {
|
|
t.Fatalf("Update failed: %v", err)
|
|
}
|
|
|
|
updated, err := repo.GetByID(ctx, webhook.ID)
|
|
if err != nil {
|
|
t.Fatalf("GetByID after update failed: %v", err)
|
|
}
|
|
if updated.Name != "alpha-updated" {
|
|
t.Fatalf("expected updated name alpha-updated, got %q", updated.Name)
|
|
}
|
|
if updated.Status != domain.WebhookStatusInactive {
|
|
t.Fatalf("expected updated status inactive, got %d", updated.Status)
|
|
}
|
|
|
|
if err := repo.Delete(ctx, webhook.ID); err != nil {
|
|
t.Fatalf("Delete failed: %v", err)
|
|
}
|
|
|
|
if _, err := repo.GetByID(ctx, webhook.ID); err == nil {
|
|
t.Fatal("expected deleted webhook lookup to fail")
|
|
}
|
|
}
|
|
|
|
func TestWebhookRepositoryListsByCreatorAndActiveStatus(t *testing.T) {
|
|
repo := setupWebhookRepository(t)
|
|
ctx := context.Background()
|
|
|
|
fixtures := []*domain.Webhook{
|
|
newWebhookFixture("creator-1-active", 1, domain.WebhookStatusActive),
|
|
newWebhookFixture("creator-1-inactive", 1, domain.WebhookStatusInactive),
|
|
newWebhookFixture("creator-2-active", 2, domain.WebhookStatusActive),
|
|
}
|
|
|
|
for _, webhook := range fixtures {
|
|
if err := repo.Create(ctx, webhook); err != nil {
|
|
t.Fatalf("Create(%s) failed: %v", webhook.Name, err)
|
|
}
|
|
}
|
|
|
|
creatorOneHooks, err := repo.ListByCreator(ctx, 1)
|
|
if err != nil {
|
|
t.Fatalf("ListByCreator(1) failed: %v", err)
|
|
}
|
|
if len(creatorOneHooks) != 2 {
|
|
t.Fatalf("expected 2 hooks for creator 1, got %d", len(creatorOneHooks))
|
|
}
|
|
|
|
allHooks, err := repo.ListByCreator(ctx, 0)
|
|
if err != nil {
|
|
t.Fatalf("ListByCreator(0) failed: %v", err)
|
|
}
|
|
if len(allHooks) != 3 {
|
|
t.Fatalf("expected 3 hooks when listing all creators, got %d", len(allHooks))
|
|
}
|
|
|
|
activeHooks, err := repo.ListActive(ctx)
|
|
if err != nil {
|
|
t.Fatalf("ListActive failed: %v", err)
|
|
}
|
|
if len(activeHooks) != 2 {
|
|
t.Fatalf("expected 2 active hooks, got %d", len(activeHooks))
|
|
}
|
|
for _, hook := range activeHooks {
|
|
if hook.Status != domain.WebhookStatusActive {
|
|
t.Fatalf("expected active hook status, got %d", hook.Status)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWebhookRepositoryCreateAndListDeliveries(t *testing.T) {
|
|
repo := setupWebhookRepository(t)
|
|
ctx := context.Background()
|
|
|
|
webhook := newWebhookFixture("delivery-hook", 7, domain.WebhookStatusActive)
|
|
if err := repo.Create(ctx, webhook); err != nil {
|
|
t.Fatalf("Create webhook failed: %v", err)
|
|
}
|
|
|
|
olderTime := time.Now().Add(-time.Minute)
|
|
newerTime := time.Now()
|
|
|
|
firstDelivery := &domain.WebhookDelivery{
|
|
WebhookID: webhook.ID,
|
|
EventType: domain.EventUserRegistered,
|
|
Payload: `{"user":"older"}`,
|
|
StatusCode: 200,
|
|
ResponseBody: `{"ok":true}`,
|
|
Attempt: 1,
|
|
Success: true,
|
|
CreatedAt: olderTime,
|
|
}
|
|
secondDelivery := &domain.WebhookDelivery{
|
|
WebhookID: webhook.ID,
|
|
EventType: domain.EventUserLogin,
|
|
Payload: `{"user":"newer"}`,
|
|
StatusCode: 500,
|
|
ResponseBody: `{"ok":false}`,
|
|
Attempt: 2,
|
|
Success: false,
|
|
Error: "delivery failed",
|
|
CreatedAt: newerTime,
|
|
}
|
|
|
|
if err := repo.CreateDelivery(ctx, firstDelivery); err != nil {
|
|
t.Fatalf("CreateDelivery(first) failed: %v", err)
|
|
}
|
|
if err := repo.CreateDelivery(ctx, secondDelivery); err != nil {
|
|
t.Fatalf("CreateDelivery(second) failed: %v", err)
|
|
}
|
|
|
|
latestOnly, err := repo.ListDeliveries(ctx, webhook.ID, 1)
|
|
if err != nil {
|
|
t.Fatalf("ListDeliveries(limit=1) failed: %v", err)
|
|
}
|
|
if len(latestOnly) != 1 {
|
|
t.Fatalf("expected 1 latest delivery, got %d", len(latestOnly))
|
|
}
|
|
if latestOnly[0].ID != secondDelivery.ID {
|
|
t.Fatalf("expected latest delivery id %d, got %d", secondDelivery.ID, latestOnly[0].ID)
|
|
}
|
|
|
|
allDeliveries, err := repo.ListDeliveries(ctx, webhook.ID, 10)
|
|
if err != nil {
|
|
t.Fatalf("ListDeliveries(limit=10) failed: %v", err)
|
|
}
|
|
if len(allDeliveries) != 2 {
|
|
t.Fatalf("expected 2 deliveries, got %d", len(allDeliveries))
|
|
}
|
|
if allDeliveries[0].ID != secondDelivery.ID || allDeliveries[1].ID != firstDelivery.ID {
|
|
t.Fatal("expected deliveries to be returned in reverse created_at order")
|
|
}
|
|
}
|
|
|
|
func TestWebhookRepositoryListByCreatorPaginated(t *testing.T) {
|
|
repo := setupWebhookRepository(t)
|
|
ctx := context.Background()
|
|
|
|
// 创建多个webhook
|
|
for i := 0; i < 5; i++ {
|
|
if err := repo.Create(ctx, newWebhookFixture("wh-creator1-"+string(rune('a'+i)), 1, domain.WebhookStatusActive)); err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
}
|
|
// 另一个用户的webhook
|
|
if err := repo.Create(ctx, newWebhookFixture("wh-creator2", 2, domain.WebhookStatusActive)); err != nil {
|
|
t.Fatalf("Create failed: %v", err)
|
|
}
|
|
|
|
// 测试分页查询创建者1的webhook
|
|
webhooks, total, err := repo.ListByCreatorPaginated(ctx, 1, 0, 3)
|
|
if err != nil {
|
|
t.Fatalf("ListByCreatorPaginated failed: %v", err)
|
|
}
|
|
if len(webhooks) != 3 {
|
|
t.Errorf("len(webhooks) = %d, want 3", len(webhooks))
|
|
}
|
|
if total != 5 {
|
|
t.Errorf("total = %d, want 5", total)
|
|
}
|
|
|
|
// 测试第二页
|
|
webhooks2, _, err := repo.ListByCreatorPaginated(ctx, 1, 3, 3)
|
|
if err != nil {
|
|
t.Fatalf("ListByCreatorPaginated page 2 failed: %v", err)
|
|
}
|
|
if len(webhooks2) != 2 {
|
|
t.Errorf("len(webhooks2) = %d, want 2", len(webhooks2))
|
|
}
|
|
}
|