internal/store/mrs_test.go
144 lines · 4453 bytes
1package store
2
3import "testing"
4
5func mrFixture(t *testing.T) (*Store, int64, int64) {
6 t.Helper()
7 s := open(t)
8 if err := s.MigrateUp(); err != nil {
9 t.Fatal(err)
10 }
11 uid, err := s.CreateUser("cmc", true)
12 if err != nil {
13 t.Fatal(err)
14 }
15 repoID, err := s.CreateRepo("user", uid, "lib", "public")
16 if err != nil {
17 t.Fatal(err)
18 }
19 if _, err := s.CreateMR(repoID, uid, repoID, "feature", "main", "t", "", "abc123", "md", false); err != nil {
20 t.Fatal(err)
21 }
22 return s, repoID, uid
23}
24
25// A merged or closed MR records who resolved it and when: the state alone
26// cannot say it, and updated_at moves for every edit.
27func TestResolutionStamps(t *testing.T) {
28 s, repoID, uid := mrFixture(t)
29 mr, err := s.MRByNumber(repoID, 1)
30 if err != nil {
31 t.Fatal(err)
32 }
33 if mr.MergedAt != "" || mr.ClosedAt != "" {
34 t.Fatalf("open MR carries a stamp: %+v", mr)
35 }
36 if err := s.MarkMerged(mr.ID, "base1", uid, ""); err != nil {
37 t.Fatal(err)
38 }
39 mr, _ = s.MRByNumber(repoID, 1)
40 if mr.State != "merged" || mr.MergedAt == "" || mr.MergedBy != "cmc" {
41 t.Fatalf("merge stamp: %+v", mr)
42 }
43
44 // Reopening — a source branch that came back — clears the stamp.
45 if err := s.SetMRState(mr.ID, "open"); err != nil {
46 t.Fatal(err)
47 }
48 mr, _ = s.MRByNumber(repoID, 1)
49 if mr.MergedAt != "" || mr.MergedBy != "" {
50 t.Fatalf("reopen kept the merge stamp: %+v", mr)
51 }
52
53 if err := s.MarkClosed(mr.ID, uid, ""); err != nil {
54 t.Fatal(err)
55 }
56 mr, _ = s.MRByNumber(repoID, 1)
57 if mr.State != "closed" || mr.ClosedAt == "" || mr.ClosedBy != "cmc" {
58 t.Fatalf("close stamp: %+v", mr)
59 }
60}
61
62// An import carries the upstream time but no local account for the actor.
63func TestResolutionStampImported(t *testing.T) {
64 s, repoID, _ := mrFixture(t)
65 mr, _ := s.MRByNumber(repoID, 1)
66 if err := s.MarkMerged(mr.ID, "base1", 0, "2024-03-02T10:00:00Z"); err != nil {
67 t.Fatal(err)
68 }
69 mr, _ = s.MRByNumber(repoID, 1)
70 if mr.MergedAt != "2024-03-02T10:00:00Z" || mr.MergedBy != "" {
71 t.Fatalf("imported merge stamp: %+v", mr)
72 }
73}
74
75// PreferredVerifiedEmail falls back to a verified secondary when the
76// primary is not verified, unlike PrimaryVerifiedEmail (#158).
77func TestPreferredVerifiedEmail(t *testing.T) {
78 s := open(t)
79 if err := s.MigrateUp(); err != nil {
80 t.Fatal(err)
81 }
82 uid, err := s.CreateUser("gus", false)
83 if err != nil {
84 t.Fatal(err)
85 }
86
87 if addr, err := s.PreferredVerifiedEmail(uid); err != nil || addr != "" {
88 t.Fatalf("no addresses at all: %q, %v", addr, err)
89 }
90
91 if err := s.AddEmail(uid, "primary@example.test", "", true); err != nil {
92 t.Fatal(err)
93 }
94 if addr, err := s.PreferredVerifiedEmail(uid); err != nil || addr != "" {
95 t.Fatalf("unverified primary only: %q, %v", addr, err)
96 }
97 if addr, err := s.PrimaryVerifiedEmail(uid); err != nil || addr != "" {
98 t.Fatalf("PrimaryVerifiedEmail on an unverified primary: %q, %v", addr, err)
99 }
100
101 if err := s.AddEmail(uid, "secondary@example.test", "smtp", false); err != nil {
102 t.Fatal(err)
103 }
104 if addr, err := s.PreferredVerifiedEmail(uid); err != nil || addr != "secondary@example.test" {
105 t.Fatalf("unverified primary, verified secondary: %q, %v", addr, err)
106 }
107 // PrimaryVerifiedEmail keeps meaning exactly what it says: still "",
108 // because the primary itself is still unverified.
109 if addr, err := s.PrimaryVerifiedEmail(uid); err != nil || addr != "" {
110 t.Fatalf("PrimaryVerifiedEmail with only the secondary verified: %q, %v", addr, err)
111 }
112
113 if err := s.VerifyEmail(uid, "primary@example.test", "admin"); err != nil {
114 t.Fatal(err)
115 }
116 if addr, err := s.PreferredVerifiedEmail(uid); err != nil || addr != "primary@example.test" {
117 t.Fatalf("both verified, primary should win: %q, %v", addr, err)
118 }
119}
120
121// With no verified primary, the choice among verified secondaries must not
122// depend on insertion or row order.
123func TestPreferredVerifiedEmailDeterministicTiebreak(t *testing.T) {
124 s := open(t)
125 if err := s.MigrateUp(); err != nil {
126 t.Fatal(err)
127 }
128 uid, err := s.CreateUser("gus", false)
129 if err != nil {
130 t.Fatal(err)
131 }
132 if err := s.AddEmail(uid, "primary@example.test", "", true); err != nil {
133 t.Fatal(err)
134 }
135 if err := s.AddEmail(uid, "zzz@example.test", "smtp", false); err != nil {
136 t.Fatal(err)
137 }
138 if err := s.AddEmail(uid, "aaa@example.test", "smtp", false); err != nil {
139 t.Fatal(err)
140 }
141 if addr, err := s.PreferredVerifiedEmail(uid); err != nil || addr != "aaa@example.test" {
142 t.Fatalf("tiebreak should be alphabetical: %q, %v", addr, err)
143 }
144}