tinyrelaycommit

Commit aa10e5ab5990

browse files at this commit | history

1diff --git a/tinygit/journal.go b/tinygit/journal.go
2index 52a3dda..f8f98d7 100644
3--- a/tinygit/journal.go
4+++ b/tinygit/journal.go
5@@ -96,15 +96,15 @@ func (g *GitRelay) recoverJournals() error {
6 keepJournal := false
7 if jr.Kind == 30618 {
8 current, found, err := g.store.Latest(context.Background(), 30618, owner, id)
9- if err != nil || !found || current.ID != jr.EventID {
10+ if err != nil {
11+ return err
12+ }
13+ if !found || current.ID != jr.EventID {
14 if removeErr := os.Remove(filepath.Join(g.journalDir(), entry.Name())); removeErr != nil && !errors.Is(removeErr, os.ErrNotExist) {
15 return removeErr
16 }
17 continue
18 }
19- if err != nil {
20- return err
21- }
22 if g.stateObjectsPresent(context.Background(), r) {
23 err = g.writeState(r)
24 } else {
25diff --git a/tinygit/journal_test.go b/tinygit/journal_test.go
26new file mode 100644
27index 0000000..b974e01
28--- /dev/null
29+++ b/tinygit/journal_test.go
30@@ -0,0 +1,63 @@
31+package tinygit
32+
33+import (
34+ "context"
35+ "errors"
36+ "os"
37+ "path/filepath"
38+ "strings"
39+ "testing"
40+
41+ "github.com/FelineStateMachine/tinyrelay/protocol/nostr"
42+)
43+
44+type unavailableMetadataStore struct {
45+ Store
46+ err error
47+}
48+
49+func (s unavailableMetadataStore) Latest(context.Context, int, string, string) (Event, bool, error) {
50+ return Event{}, false, s.err
51+}
52+
53+func TestJournalRecoveryPreservesIntentWhenStorageReadFails(t *testing.T) {
54+ ctx := context.Background()
55+ root := t.TempDir()
56+ store, err := OpenStore(ctx, filepath.Join(root, "events.db"))
57+ if err != nil {
58+ t.Fatal(err)
59+ }
60+ t.Cleanup(func() { _ = store.Close() })
61+ g, err := New(Config{Store: store, Root: filepath.Join(root, "git")})
62+ if err != nil {
63+ t.Fatal(err)
64+ }
65+ state := Event{Kind: 30618, CreatedAt: 1, Tags: [][]string{{"d", "demo"}, {"refs/heads/main", strings.Repeat("c", 40)}}}
66+ if err := nostr.Sign(&state, strings.Repeat("0", 63)+"1"); err != nil {
67+ t.Fatal(err)
68+ }
69+ if err := store.Save(ctx, state, 1); err != nil {
70+ t.Fatal(err)
71+ }
72+ repo := Repository{Owner: state.PubKey, Identifier: "demo", Refs: map[string]string{"refs/heads/main": strings.Repeat("c", 40)}}
73+ journal := journalRecord{Repository: key(repo.Owner, repo.Identifier), EventID: state.ID, Kind: 30618, Refs: repo.Refs}
74+ if err := g.writeJournal(repo, journal); err != nil {
75+ t.Fatal(err)
76+ }
77+ unavailable := errors.New("metadata temporarily unavailable")
78+ g.store = unavailableMetadataStore{Store: store, err: unavailable}
79+ if err := g.recoverJournals(); !errors.Is(err, unavailable) {
80+ t.Errorf("recovery error=%v; want storage failure", err)
81+ }
82+ if _, err := os.Stat(g.journalPath(journal)); err != nil {
83+ t.Fatalf("recovery discarded the journal after a read failure: %v", err)
84+ }
85+ g.store = store
86+ if err := g.recoverJournals(); err != nil {
87+ t.Fatal(err)
88+ }
89+ pending, err := os.ReadFile(filepath.Join(g.repoPath(repo), "tinyrelay.pending"))
90+ if err != nil || !strings.Contains(string(pending), "refs/heads/main "+strings.Repeat("c", 40)) {
91+ t.Fatalf("retry did not recover pending state: %q, %v", pending, err)
92+ }
93+}

About

ownerc01503e8035f
visibilitypublic
headaa10e5ab5990

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

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

Refs