mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-05-11 18:10:23 +08:00
110 lines
4.6 KiB
Go
110 lines
4.6 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"backupx/server/internal/config"
|
|
"backupx/server/internal/database"
|
|
"backupx/server/internal/logger"
|
|
"backupx/server/internal/model"
|
|
"backupx/server/internal/notify"
|
|
"backupx/server/internal/repository"
|
|
"backupx/server/internal/storage/codec"
|
|
)
|
|
|
|
type fakeNotifier struct {
|
|
typeName string
|
|
messages []notify.Message
|
|
lastConfig map[string]any
|
|
}
|
|
|
|
func (n *fakeNotifier) Type() string { return n.typeName }
|
|
func (n *fakeNotifier) SensitiveFields() []string { return []string{"secret"} }
|
|
func (n *fakeNotifier) Validate(config map[string]any) error {
|
|
if config["url"] == nil {
|
|
return nil
|
|
}
|
|
return nil
|
|
}
|
|
func (n *fakeNotifier) Send(_ context.Context, config map[string]any, message notify.Message) error {
|
|
n.lastConfig = config
|
|
n.messages = append(n.messages, message)
|
|
return nil
|
|
}
|
|
|
|
func newDashboardNotificationTestDeps(t *testing.T) (*DashboardService, *NotificationService, *fakeNotifier, repository.BackupTaskRepository, repository.BackupRecordRepository, repository.NotificationRepository) {
|
|
t.Helper()
|
|
log, err := logger.New(config.LogConfig{Level: "error"})
|
|
if err != nil {
|
|
t.Fatalf("logger.New returned error: %v", err)
|
|
}
|
|
db, err := database.Open(config.DatabaseConfig{Path: filepath.Join(t.TempDir(), "backupx.db")}, log)
|
|
if err != nil {
|
|
t.Fatalf("database.Open returned error: %v", err)
|
|
}
|
|
tasks := repository.NewBackupTaskRepository(db)
|
|
records := repository.NewBackupRecordRepository(db)
|
|
targets := repository.NewStorageTargetRepository(db)
|
|
notifications := repository.NewNotificationRepository(db)
|
|
if err := targets.Create(context.Background(), &model.StorageTarget{Name: "local", Type: "local_disk", Enabled: true, ConfigCiphertext: "ciphertext", ConfigVersion: 1, LastTestStatus: "unknown"}); err != nil {
|
|
t.Fatalf("Create storage target returned error: %v", err)
|
|
}
|
|
fake := &fakeNotifier{typeName: "webhook"}
|
|
registry := notify.NewRegistry(fake)
|
|
cipher := codec.NewConfigCipher("notify-secret")
|
|
dashboardService := NewDashboardService(tasks, records, targets)
|
|
notificationService := NewNotificationService(notifications, registry, cipher)
|
|
return dashboardService, notificationService, fake, tasks, records, notifications
|
|
}
|
|
|
|
func TestDashboardServiceStats(t *testing.T) {
|
|
dashboardService, _, _, tasks, records, _ := newDashboardNotificationTestDeps(t)
|
|
ctx := context.Background()
|
|
if err := tasks.Create(ctx, &model.BackupTask{Name: "site", Type: "file", Enabled: true, SourcePath: "/srv/site", StorageTargetID: 1, RetentionDays: 30, Compression: "gzip", MaxBackups: 10, LastStatus: "success"}); err != nil {
|
|
t.Fatalf("Create task returned error: %v", err)
|
|
}
|
|
startedAt := time.Now().UTC().Add(-time.Hour)
|
|
completedAt := time.Now().UTC()
|
|
if err := records.Create(ctx, &model.BackupRecord{TaskID: 1, StorageTargetID: 1, Status: "success", FileName: "site.tar.gz", FileSize: 2048, StoragePath: "site/2026/03/07/site.tar.gz", DurationSeconds: 30, StartedAt: startedAt, CompletedAt: &completedAt}); err != nil {
|
|
t.Fatalf("Create record returned error: %v", err)
|
|
}
|
|
stats, err := dashboardService.Stats(ctx)
|
|
if err != nil {
|
|
t.Fatalf("Stats returned error: %v", err)
|
|
}
|
|
if stats.TotalTasks != 1 || stats.TotalRecords != 1 || stats.TotalBackupBytes != 2048 {
|
|
t.Fatalf("unexpected stats: %#v", stats)
|
|
}
|
|
if len(stats.RecentRecords) != 1 || len(stats.StorageUsage) != 1 {
|
|
t.Fatalf("expected recent records and storage usage, got %#v", stats)
|
|
}
|
|
}
|
|
|
|
func TestNotificationServiceCreateAndDispatch(t *testing.T) {
|
|
_, notificationService, fake, _, _, notifications := newDashboardNotificationTestDeps(t)
|
|
ctx := context.Background()
|
|
created, err := notificationService.Create(ctx, NotificationUpsertInput{Name: "ops", Type: "webhook", Enabled: true, OnSuccess: true, OnFailure: true, Config: map[string]any{"url": "https://example.invalid", "secret": "top-secret"}})
|
|
if err != nil {
|
|
t.Fatalf("Create returned error: %v", err)
|
|
}
|
|
if len(created.MaskedFields) != 1 || created.MaskedFields[0] != "secret" {
|
|
t.Fatalf("unexpected masked fields: %#v", created.MaskedFields)
|
|
}
|
|
item, err := notifications.FindByID(ctx, created.ID)
|
|
if err != nil {
|
|
t.Fatalf("FindByID returned error: %v", err)
|
|
}
|
|
if item == nil || item.ConfigCiphertext == "" {
|
|
t.Fatalf("expected encrypted notification config")
|
|
}
|
|
if err := notificationService.NotifyBackupResult(ctx, BackupExecutionNotification{Task: &model.BackupTask{Name: "site"}, Record: &model.BackupRecord{ID: 1, Status: "success", StartedAt: time.Now().UTC()}, Error: nil}); err != nil {
|
|
t.Fatalf("NotifyBackupResult returned error: %v", err)
|
|
}
|
|
if len(fake.messages) != 1 {
|
|
t.Fatalf("expected one notification message, got %d", len(fake.messages))
|
|
}
|
|
}
|