92 lines
4.2 KiB
Go
92 lines
4.2 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"git.casaderoll.de/michael/urbm/internal/notify"
|
||
"git.casaderoll.de/michael/urbm/internal/platform"
|
||
"git.casaderoll.de/michael/urbm/internal/queue"
|
||
"git.casaderoll.de/michael/urbm/internal/restic"
|
||
"log/slog"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
|
||
"git.casaderoll.de/michael/urbm/internal/model"
|
||
)
|
||
|
||
func TestNotificationMessageIncludesBackupStatistics(t *testing.T) {
|
||
started := time.Date(2026, 6, 14, 12, 0, 0, 0, time.UTC)
|
||
finished := started.Add(2*time.Minute + 8*time.Second)
|
||
run := model.Run{TaskType: "backup", Status: "success", StartedAt: &started, FinishedAt: &finished, SnapshotID: "abc123456789abcdef", BytesAdded: 1536, FilesNew: 7, FilesChanged: 2, BytesProcessed: 5 * 1024 * 1024, FilesProcessed: 120, RetentionRemoved: 3, RetentionAfter: 14}
|
||
message := notificationMessage("Freigaben", "LV-426", run, finished)
|
||
for _, expected := range []string{"📊 Backup-Zusammenfassung", "📦 Repository: LV-426", "🗂️ Job: Freigaben", "📸 Snapshot: abc123456789", "⏱️ Dauer: 2 Min. 8 Sek.", "📂 Dateien: 120 verarbeitet", "💾 Verarbeitet: 5.0 MiB", "➕ Neu: 7 Dateien", "✏️ Geändert: 2 Dateien", "📤 Neu gespeichert: 1.5 KiB", "🧹 Aufbewahrung: 3 Snapshot(s) entfernt", "📸 Verbleibende Snapshots: 14", "🔐 Ziel: Restic Repository", "✅ Status: Erfolgreich"} {
|
||
if !strings.Contains(message, expected) {
|
||
t.Errorf("message %q does not contain %q", message, expected)
|
||
}
|
||
}
|
||
}
|
||
|
||
func TestNotificationTitleIncludesRepositoryAndStatus(t *testing.T) {
|
||
run := model.Run{TaskType: "backup", Status: "failed"}
|
||
title := notificationTitle("Freigaben", "LV-426", run)
|
||
if title != "❌ URBM Backup: LV-426" {
|
||
t.Fatalf("title = %q", title)
|
||
}
|
||
}
|
||
|
||
func TestNotificationMessageIncludesPruneSummary(t *testing.T) {
|
||
started := time.Date(2026, 6, 22, 3, 0, 0, 0, time.UTC)
|
||
finished := started.Add(42 * time.Second)
|
||
run := model.Run{TaskType: "prune", Status: "success", StartedAt: &started, FinishedAt: &finished, Message: "prune completed", RepositoryBefore: 100 * 1024 * 1024, RepositoryAfter: 75 * 1024 * 1024, RepositoryFreed: 25 * 1024 * 1024}
|
||
message := notificationMessage("Repository-Bereinigung", "LV-426", run, finished)
|
||
for _, expected := range []string{"🧹 Prune-Zusammenfassung", "📦 Repository: LV-426", "🗂️ Job: Repository-Bereinigung", "⏱️ Dauer: 42 Sekunden", "📦 Vorher: 100.0 MiB", "📦 Nachher: 75.0 MiB", "🧹 Freigegeben: 25.0 MiB", "🔐 Ziel: Restic Repository", "✅ Status: Erfolgreich"} {
|
||
if !strings.Contains(message, expected) {
|
||
t.Errorf("message %q does not contain %q", message, expected)
|
||
}
|
||
}
|
||
if strings.Contains(message, "⚠️ Details: prune completed") {
|
||
t.Fatalf("message contains redundant prune completion details: %q", message)
|
||
}
|
||
}
|
||
|
||
type checkSecrets struct{}
|
||
|
||
func (checkSecrets) Get(string) (string, error) { return "test", nil }
|
||
|
||
func TestCheckSendsSuccessAndFailureNotifications(t *testing.T) {
|
||
for _, code := range []int{0, 1} {
|
||
t.Run(fmt.Sprint(code), func(t *testing.T) {
|
||
dir := t.TempDir()
|
||
binary := filepath.Join(dir, "restic")
|
||
if err := os.WriteFile(binary, []byte(fmt.Sprintf("#!/bin/sh\necho check-result >&2\nexit %d\n", code)), 0700); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
var sent []string
|
||
s := &Service{
|
||
config: model.Config{Repositories: []model.Repository{{ID: "repo", Name: "test", Type: model.RepositoryLocal, Location: dir}}, Notifications: []model.NotificationTarget{{Type: "unraid", Enabled: true, Events: []string{"success", "failed"}}}},
|
||
repositoryLocks: map[string]chan struct{}{},
|
||
restic: &restic.Runner{Binary: binary, RuntimeDir: dir, Secrets: checkSecrets{}},
|
||
mounts: &platform.MountManager{}, queue: queue.New(nil, nil), log: slog.Default(),
|
||
notifier: ¬ify.Sender{RunCommand: func(_ context.Context, _ string, args ...string) error {
|
||
sent = append(sent, strings.Join(args, " "))
|
||
return nil
|
||
}},
|
||
}
|
||
result := s.execute(context.Background(), model.Run{ID: "run", JobID: "repo", TaskType: "check"})
|
||
want := "success"
|
||
if code != 0 {
|
||
want = "failed"
|
||
}
|
||
if result.Status != want || len(sent) != 1 {
|
||
t.Fatalf("status=%s messages=%v", result.Status, sent)
|
||
}
|
||
if !strings.Contains(sent[0], "URBM") {
|
||
t.Fatal(sent)
|
||
}
|
||
})
|
||
}
|
||
}
|