clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

feat/ui-updates
tinyrelay / internal / daemon / backup_restart_acceptance_test.go
backup_restart_acceptance_test.go 3.3K
1package daemon23import (4 "context"5 "os"6 "strings"7 "testing"8 "time"910 "github.com/FelineStateMachine/tinyrelay/internal/event"11 "github.com/FelineStateMachine/tinyrelay/internal/replication"12)1314func TestDaemonBackupJobResumesAfterRestart(t *testing.T) {15 ctx := context.Background()16 dir := t.TempDir()17 secret := strings.Repeat("0", 63) + "1"18 owner, err := event.PublicKey(secret)19 if err != nil {20 t.Fatal(err)21 }22 config := Config{DataDir: dir, DefaultTenant: "main"}23 app, err := New(ctx, config)24 if err != nil {25 t.Fatal(err)26 }27 meta, err := app.Create(ctx, CreateOptions{Name: "main", Owner: owner, Template: "default"})28 if err != nil {29 t.Fatal(err)30 }31 if err := app.Start(ctx, "http://relay.test"); err != nil {32 t.Fatal(err)33 }34 tenant := app.tenants[meta.ID]35 tenant.workCancel()36 tenant.workWG.Wait()37 if err := tenant.replication.AddJob(ctx, replication.JobSpec{ID: "restart-backup", Kind: replication.JobBackup, Relays: []string{"restart.backup.json"}}); err != nil {38 t.Fatal(err)39 }40 if err := app.Close(ctx); err != nil {41 t.Fatal(err)42 }4344 app, err = New(ctx, config)45 if err != nil {46 t.Fatal(err)47 }48 defer app.Close(ctx)49 if err := app.Start(ctx, "http://relay.test"); err != nil {50 t.Fatal(err)51 }52 reloaded := app.tenants[meta.ID]53 if !waitFor(t, 8*time.Second, func() bool {54 statuses, statusErr := reloaded.replication.ListJobStatus(ctx)55 return statusErr == nil && len(statuses) == 1 && statuses[0].Phase == "complete"56 }) {57 statuses, _ := reloaded.replication.ListJobStatus(ctx)58 t.Fatalf("backup job did not resume: %#v", statuses)59 }60 if _, err := os.Stat(meta.Paths.Root + "/restart.backup.json"); err != nil {61 t.Fatalf("backup artifact missing after restart: %v", err)62 }63}6465func TestDaemonFailedJobStatusSurvivesRestart(t *testing.T) {66 ctx := context.Background()67 dir := t.TempDir()68 secret := strings.Repeat("0", 63) + "1"69 owner, err := event.PublicKey(secret)70 if err != nil {71 t.Fatal(err)72 }73 config := Config{DataDir: dir, DefaultTenant: "main", AllowPrivateRelays: true}74 app, err := New(ctx, config)75 if err != nil {76 t.Fatal(err)77 }78 meta, err := app.Create(ctx, CreateOptions{Name: "main", Owner: owner, Template: "default"})79 if err != nil {80 t.Fatal(err)81 }82 if err := app.Start(ctx, "http://relay.test"); err != nil {83 t.Fatal(err)84 }85 tenant := app.tenants[meta.ID]86 tenant.workCancel()87 tenant.workWG.Wait()88 if err := tenant.replication.AddJob(ctx, replication.JobSpec{ID: "restart-failure", Kind: replication.JobPull, Relays: []string{"ws://127.0.0.1:1"}}); err != nil {89 t.Fatal(err)90 }91 if err := app.Close(ctx); err != nil {92 t.Fatal(err)93 }9495 app, err = New(ctx, config)96 if err != nil {97 t.Fatal(err)98 }99 defer app.Close(ctx)100 if err := app.Start(ctx, "http://relay.test"); err != nil {101 t.Fatal(err)102 }103 reloaded := app.tenants[meta.ID]104 if !waitFor(t, 8*time.Second, func() bool {105 statuses, statusErr := reloaded.replication.ListJobStatus(ctx)106 return statusErr == nil && len(statuses) == 1 && statuses[0].Phase == "failed" && statuses[0].Error != ""107 }) {108 statuses, _ := reloaded.replication.ListJobStatus(ctx)109 t.Fatalf("failed job status was not recorded after restart: %#v", statuses)110 }111 pending, err := reloaded.replication.Queue().Pending(ctx, "job")112 if err != nil {113 t.Fatal(err)114 }115 if len(pending) != 1 || pending[0].Attempts == 0 {116 t.Fatalf("failed job lost retry state: %#v", pending)117 }118}