Monorepo for Tangled
tangled.org
1package db
2
3import (
4 "testing"
5
6 "tangled.org/core/orm"
7)
8
9func seedFollow(t *testing.T, d *DB, userDid, subjectDid, rkey, followedAt string) {
10 t.Helper()
11 if _, err := d.Exec(
12 `insert into follows (user_did, subject_did, rkey, followed_at) values (?, ?, ?, ?)`,
13 userDid, subjectDid, rkey, followedAt,
14 ); err != nil {
15 t.Fatalf("seedFollow %s -> %s: %v", userDid, subjectDid, err)
16 }
17}
18
19func seedStar(t *testing.T, d *DB, did, rkey, subject, created string) {
20 t.Helper()
21 if _, err := d.Exec(
22 `insert into stars (did, rkey, subject_type, subject, created) values (?, ?, 'repo', ?, ?)`,
23 did, rkey, subject, created,
24 ); err != nil {
25 t.Fatalf("seedStar %s -> %s: %v", did, subject, err)
26 }
27}
28
29func TestFilterInSubquery(t *testing.T) {
30 f := orm.FilterInSubquery("did", "select subject_did from follows where user_did = ?", "did:plc:viewer")
31 if got, want := f.Condition(), "did in (select subject_did from follows where user_did = ?)"; got != want {
32 t.Errorf("Condition() = %q, want %q", got, want)
33 }
34 if args := f.Arg(); len(args) != 1 || args[0] != "did:plc:viewer" {
35 t.Errorf("Arg() = %v, want [did:plc:viewer]", args)
36 }
37}
38
39func TestMakeTimeline_FollowingOnly(t *testing.T) {
40 d := newTestDB(t)
41
42 const (
43 viewer = "did:plc:viewer"
44 followed = "did:plc:followed"
45 stranger = "did:plc:stranger"
46 )
47
48 // viewer follows `followed` but not `stranger`
49 seedFollow(t, d, viewer, followed, "rkey-viewer-followed", "2024-01-01T00:00:00Z")
50
51 // both users create repos
52 seedRepo(t, d, followed, "knot.example.com", "followed-repo", "rkey-fr", "did:plc:repo-followed")
53 seedRepo(t, d, stranger, "knot.example.com", "stranger-repo", "rkey-sr", "did:plc:repo-stranger")
54
55 // both users star a repo
56 seedStar(t, d, followed, "rkey-fs", "did:plc:repo-stranger", "2024-02-01T00:00:00Z")
57 seedStar(t, d, stranger, "rkey-ss", "did:plc:repo-followed", "2024-02-01T00:00:00Z")
58
59 // both users follow someone else
60 seedFollow(t, d, followed, stranger, "rkey-ff", "2024-03-01T00:00:00Z")
61 seedFollow(t, d, stranger, viewer, "rkey-sf", "2024-03-01T00:00:00Z")
62
63 groups, err := MakeTimeline(d, 50, viewer, true)
64 if err != nil {
65 t.Fatalf("MakeTimeline(following): %v", err)
66 }
67
68 var nRepos, nStars, nFollows int
69 for _, g := range groups {
70 switch {
71 case g.Primary.Repo != nil:
72 nRepos++
73 if g.Primary.Repo.Did != followed {
74 t.Errorf("repo event from %q, want only %q", g.Primary.Repo.Did, followed)
75 }
76 case g.Primary.RepoStar != nil:
77 nStars++
78 if g.Primary.RepoStar.Star.Did != followed {
79 t.Errorf("star event from %q, want only %q", g.Primary.RepoStar.Star.Did, followed)
80 }
81 case g.Primary.Follow != nil:
82 nFollows++
83 if g.Primary.Follow.UserDid != followed {
84 t.Errorf("follow event from %q, want only %q", g.Primary.Follow.UserDid, followed)
85 }
86 }
87 }
88
89 if nRepos != 1 || nStars != 1 || nFollows != 1 {
90 t.Errorf("got %d repo, %d star, %d follow events; want 1 of each", nRepos, nStars, nFollows)
91 }
92}
93
94func TestMakeTimeline_FollowingNobody(t *testing.T) {
95 d := newTestDB(t)
96
97 // other users are active, but viewer follows nobody
98 seedRepo(t, d, "did:plc:stranger", "knot.example.com", "repo", "rkey-r", "did:plc:repo-1")
99 seedStar(t, d, "did:plc:stranger", "rkey-s", "did:plc:repo-1", "2024-02-01T00:00:00Z")
100 seedFollow(t, d, "did:plc:stranger", "did:plc:other", "rkey-f", "2024-03-01T00:00:00Z")
101
102 groups, err := MakeTimeline(d, 50, "did:plc:viewer", true)
103 if err != nil {
104 t.Fatalf("MakeTimeline(following nobody): %v", err)
105 }
106 if len(groups) != 0 {
107 t.Errorf("expected empty following timeline, got %d groups", len(groups))
108 }
109}
110
111func TestMakeTimeline_Global(t *testing.T) {
112 d := newTestDB(t)
113
114 seedRepo(t, d, "did:plc:a", "knot.example.com", "repo-a", "rkey-a", "did:plc:repo-a")
115 seedStar(t, d, "did:plc:b", "rkey-bs", "did:plc:repo-a", "2024-02-01T00:00:00Z")
116 seedFollow(t, d, "did:plc:b", "did:plc:a", "rkey-bf", "2024-03-01T00:00:00Z")
117
118 groups, err := MakeTimeline(d, 50, "", false)
119 if err != nil {
120 t.Fatalf("MakeTimeline(global): %v", err)
121 }
122 if len(groups) != 3 {
123 t.Errorf("expected 3 groups in global timeline, got %d", len(groups))
124 }
125}