~james/core

core/spindle/pull_versions_test.go -rw-r--r-- 2.6 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 14 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package spindle

import (
	"context"
	"slices"
	"testing"
	"time"

	"github.com/bluesky-social/indigo/atproto/syntax"

	"tangled.org/core/api/org_tangled"
	"tangled.org/core/spindle/db"
	"tangled.org/core/spindle/models"
)

func ticketRecord(state string) map[string]any {
	return map[string]any{
		"$type":        org_tangled.TrackTicketNSID,
		"state":        state,
		"title":        map[string]any{"$type": "org.tangled.markup.markdown#inline", "text": "fix the thing"},
		"createdAt":    "2026-02-01T00:00:00Z",
		"targetBranch": "main",
	}
}

const syncedTicket = "3kticket00001"

type ticketSync struct {
	t    *testing.T
	env  *ensureEnv
	repo *db.Repo
}

func newTicketSync(t *testing.T) *ticketSync {
	env := newEnsureEnv(t)
	env.serve("repo")
	return &ticketSync{t: t, env: env, repo: env.ensure(t)}
}

func (s *ticketSync) put(state string, editor syntax.DID) {
	s.env.knot.putVersion(testRepoDid, org_tangled.TrackTicketNSID, syncedTicket, editor, ticketRecord(state))
}

func (s *ticketSync) sync() error {
	_, _, err := s.env.s.syncPullTicket(context.Background(), s.env.k, s.repo, syncedTicket)
	return err
}

func (s *ticketSync) mustSync() {
	s.t.Helper()
	if err := s.sync(); err != nil {
		s.t.Fatal(err)
	}
}

func (s *ticketSync) events() []string {
	s.t.Helper()
	due, err := s.env.s.db.DuePullEvents(testRepoDid, time.Now(), 100)
	if err != nil {
		s.t.Fatal(err)
	}
	var out []string
	for _, ev := range due {
		out = append(out, string(ev.Event)+" by "+ev.Sender.String())
	}
	return out
}

func TestEveryStateChangeBetweenTwoSyncsFiresInOrder(t *testing.T) {
	s := newTicketSync(t)
	s.put("open", testBob)
	s.mustSync()

	s.put("closed", testCarol)
	s.put("open", testBob)
	s.mustSync()

	want := []string{
		string(models.WebhookEventPullRequestClosed) + " by " + testCarol.String(),
		string(models.WebhookEventPullRequestReopened) + " by " + testBob.String(),
	}
	if got := s.events(); !slices.Equal(got, want) {
		t.Fatalf("pull events = %v, want %v", got, want)
	}

	s.mustSync()
	if got := s.events(); len(got) != 2 {
		t.Fatalf("a sync with nothing new left events %v, want the same two", got)
	}
}

func TestAFailedVersionListDoesNotSkipTheStatesInBetween(t *testing.T) {
	s := newTicketSync(t)
	s.put("open", testBob)
	s.mustSync()

	s.put("closed", testCarol)
	s.put("open", testBob)
	s.env.knot.failVersions = true
	if err := s.sync(); err == nil {
		t.Fatal("a sync whose version list failed reported success, so its mark would be dropped")
	}

	s.env.knot.failVersions = false
	s.mustSync()
	if got := s.events(); len(got) != 2 {
		t.Fatalf("pull events = %v, want the closed and the reopened that the failed sync must not skip", got)
	}
}