~james/core

core/spindle/record_marks_test.go -rw-r--r-- 3.8 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 16 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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package spindle

import (
	"context"
	"testing"
	"time"

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

func ticketEvent(rkey string) tapc.Event {
	return recordEvent(testRepoDid, org_tangled.TrackTicketNSID, rkey, tapc.RecordCreateAction, map[string]string{})
}

func dueRecords(t *testing.T, env *ensureEnv) []db.RecordRetry {
	t.Helper()
	due, err := env.s.db.DueRecordRetries(time.Now())
	if err != nil {
		t.Fatal(err)
	}
	return due
}

func TestAPullRecordUnderMarkOnlyCostsNoReadsAndWaitsForItsJob(t *testing.T) {
	env := newEnsureEnv(t)
	env.serve("repo")
	env.ensure(t)
	ctx := withMarkOnly(context.Background())

	before := env.knot.count()
	if err := env.s.processEvent(ctx, ticketEvent("3kticket00001")); err != nil {
		t.Fatal(err)
	}
	if got := env.knot.count(); got != before {
		t.Fatalf("marking a pull record cost %d knot requests", got-before)
	}
	if got := dueRecords(t, env); len(got) != 1 || got[0].Rkey != "3kticket00001" {
		t.Fatalf("record marks = %+v, want the ticket", got)
	}

	env.s.runRepoJob(context.Background(), testRepoDid)
	if env.knot.count() == before {
		t.Fatal("the job never read the ticket from the knot")
	}
	if got := dueRecords(t, env); len(got) != 0 {
		t.Fatalf("a finished job left record marks %+v", got)
	}
}

func TestAPullRecordWaitsForItsReposPendingRefresh(t *testing.T) {
	env := newEnsureEnv(t)
	env.serve("repo")
	ctx := withMarkOnly(context.Background())

	if err := env.s.processEvent(ctx, markEvent(testRepoDid, env.spindleDid(), testOwner)); err != nil {
		t.Fatal(err)
	}
	if err := env.s.processEvent(ctx, ticketEvent("3kticket00001")); err != nil {
		t.Fatal(err)
	}
	if got := dueRecords(t, env); len(got) != 1 {
		t.Fatalf("a record for a repo that is about to be served was dropped, marks = %+v", got)
	}

	env.s.runRepoJob(context.Background(), testRepoDid)
	if rows := env.rows(t); len(rows) != 1 {
		t.Fatalf("the job didn't serve the repo, rows = %+v", rows)
	}
	if got := dueRecords(t, env); len(got) != 0 {
		t.Fatalf("the record mark outlived the repo's job: %+v", got)
	}
}

func TestAPullRecordForAnUnknownRepoLeavesNoMark(t *testing.T) {
	env := newEnsureEnv(t)
	if err := env.s.processEvent(withMarkOnly(context.Background()), ticketEvent("3kticket00001")); err != nil {
		t.Fatal(err)
	}
	if got := dueRecords(t, env); len(got) != 0 {
		t.Fatalf("an unknown repo's record left marks %+v", got)
	}
}

func TestAFailingRecordIsBackedOffInsteadOfSpinningTheJob(t *testing.T) {
	env := newEnsureEnv(t)
	env.serve("repo")
	env.ensure(t)
	rec := ticketEvent("3kticket00001").Record
	if err := env.s.markRecord(rec); err != nil {
		t.Fatal(err)
	}

	env.knot.failing = true
	env.s.runRecordMarks(context.Background(), testRepoDid)

	r := db.RecordRetry{RepoDid: testRepoDid, Collection: org_tangled.TrackTicketNSID, Rkey: "3kticket00001"}
	if attempts, err := env.s.db.RecordRetryAttempts(r); err != nil || attempts != 1 {
		t.Fatalf("attempts = %d, %v, want one failure on the mark", attempts, err)
	}
	if got := dueRecords(t, env); len(got) != 0 {
		t.Fatalf("a failed record is due again at once: %+v", got)
	}
}

func TestAFloodOfRecordsForAnotherRepoLeavesAServedReposMarkAlone(t *testing.T) {
	env := newEnsureEnv(t)
	env.serve("repo")
	env.ensure(t)
	if _, err := env.s.db.Exec(`insert into record_retries (repo_did, collection, rkey, attempts, due, epoch)
		with recursive n(i) as (select 0 union all select i + 1 from n where i < 30000)
		select 'did:plc:flood' || (i % 40), 'c', 'k' || i, 0, 0, 1 from n`); err != nil {
		t.Fatal(err)
	}

	if err := env.s.processEvent(withMarkOnly(context.Background()), ticketEvent("3kticket00001")); err != nil {
		t.Fatal(err)
	}
	if marks, err := env.s.db.DueRecordMarksOf(testRepoDid, time.Now()); err != nil || len(marks) != 1 {
		t.Fatalf("marks = %+v, %v, want the served repo's event kept while other repos fill the table", marks, err)
	}
}