tinyrelayfile
tinyrelay/internal/daemon/backup_restart_acceptance_test.go/

internal/daemon/backup_restart_acceptance_test.go raw
1package daemon
2
3import (
4 "context"
5 "os"
6 "strings"
7 "testing"
8 "time"
9
10 "github.com/FelineStateMachine/tinyrelay/internal/event"
11 "github.com/FelineStateMachine/tinyrelay/internal/replication"
12)
13
14func 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 }
43
44 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}
64
65func 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 }
94
95 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}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs