internal/store/mergequeue_test.go
136 lines · 4221 bytes
4 symbols in this file
1package store
2
3import (
4 "slices"
5 "testing"
6)
7
8// A queued merge rides on the merge request row, re-queueing replaces
9// the queuer and strategy and clears the reason, and dequeueing says
10// whether there was anything to take off.
11func TestMergeQueueRoundTrip(t *testing.T) {
12 s, repoID, uid := mrFixture(t)
13 mr, err := s.MRByNumber(repoID, 1)
14 if err != nil {
15 t.Fatal(err)
16 }
17 if mr.QueuedAt != "" {
18 t.Fatalf("fresh MR is queued: %+v", mr)
19 }
20 if err := s.QueueMerge(mr.ID, uid, "ff", 0, 0); err != nil {
21 t.Fatal(err)
22 }
23 if err := s.SetMergeQueueReason(mr.ID, "checks pending"); err != nil {
24 t.Fatal(err)
25 }
26 mr, _ = s.MRByNumber(repoID, 1)
27 if mr.QueuedAt == "" || mr.QueuedBy != "cmc" || mr.QueuedByID != uid || mr.QueueStrategy != "ff" || mr.QueueReason != "checks pending" {
28 t.Fatalf("queued MR: %+v", mr)
29 }
30 byID, err := s.MRByID(mr.ID)
31 if err != nil || byID.Number != 1 || byID.QueueStrategy != "ff" {
32 t.Fatalf("MRByID = %+v, %v", byID, err)
33 }
34
35 if err := s.QueueMerge(mr.ID, uid, "merge", 0, 0); err != nil {
36 t.Fatal(err)
37 }
38 mr, _ = s.MRByNumber(repoID, 1)
39 if mr.QueueStrategy != "merge" || mr.QueueReason != "" {
40 t.Fatalf("re-queued MR: %+v", mr)
41 }
42
43 ids, err := s.QueuedMRsAtHead(repoID, "abc123")
44 if err != nil || !slices.Equal(ids, []int64{mr.ID}) {
45 t.Fatalf("QueuedMRsAtHead = %v, %v", ids, err)
46 }
47 if ids, _ := s.QueuedMRsAtHead(repoID, "other"); len(ids) != 0 {
48 t.Fatalf("QueuedMRsAtHead(other) = %v", ids)
49 }
50
51 if ok, err := s.DequeueMerge(mr.ID); err != nil || !ok {
52 t.Fatalf("DequeueMerge = %v, %v", ok, err)
53 }
54 if ok, _ := s.DequeueMerge(mr.ID); ok {
55 t.Fatal("second DequeueMerge found a row")
56 }
57}
58
59// A merge request that leaves the open states leaves the queue with it,
60// whichever path merged or closed it.
61func TestMergeQueueLeftOnMergeOrClose(t *testing.T) {
62 s, repoID, uid := mrFixture(t)
63 mr, _ := s.MRByNumber(repoID, 1)
64 for _, mark := range []func() error{
65 func() error { return s.MarkMerged(mr.ID, "base", uid, "") },
66 func() error { return s.MarkClosed(mr.ID, uid, "") },
67 } {
68 if err := s.SetMRState(mr.ID, "open"); err != nil {
69 t.Fatal(err)
70 }
71 if err := s.QueueMerge(mr.ID, uid, "", 0, 0); err != nil {
72 t.Fatal(err)
73 }
74 if err := mark(); err != nil {
75 t.Fatal(err)
76 }
77 got, _ := s.MRByNumber(repoID, 1)
78 if got.QueuedAt != "" {
79 t.Fatalf("%s MR still queued: %+v", got.State, got)
80 }
81 }
82 // source_gone keeps it: the branch can come back.
83 if err := s.SetMRState(mr.ID, "open"); err != nil {
84 t.Fatal(err)
85 }
86 s.QueueMerge(mr.ID, uid, "", 0, 0)
87 s.SetMRState(mr.ID, "source_gone")
88 if got, _ := s.MRByNumber(repoID, 1); got.QueuedAt == "" {
89 t.Fatal("source_gone dropped the queued merge")
90 }
91}
92
93// A queued merge remembers the credential it was queued with, and a
94// removed key or revoked token reads back as gone rather than as some
95// later credential that reused the id.
96func TestMergeQueueCredential(t *testing.T) {
97 s, repoID, uid := mrFixture(t)
98 mr, _ := s.MRByNumber(repoID, 1)
99 if err := s.AddSSHKey(uid, "SHA256:k1", "ssh-ed25519", []byte("b1"), "full", ""); err != nil {
100 t.Fatal(err)
101 }
102 key, err := s.SSHKeyByFingerprint("SHA256:k1")
103 if err != nil {
104 t.Fatal(err)
105 }
106 if err := s.QueueMerge(mr.ID, uid, "", key.ID, 0); err != nil {
107 t.Fatal(err)
108 }
109 if q, err := s.MergeQueueCredential(mr.ID); err != nil || q.Kind != "key" || q.KeyID != key.ID {
110 t.Fatalf("credential = %+v, %v", q, err)
111 }
112 if err := s.RemoveSSHKey(uid, "SHA256:k1"); err != nil {
113 t.Fatal(err)
114 }
115 if q, _ := s.MergeQueueCredential(mr.ID); q.Kind != "key" || q.KeyID != 0 {
116 t.Fatalf("credential after key removal = %+v, want key with id 0", q)
117 }
118 if err := s.QueueMerge(mr.ID, uid, "", 0, 0); err != nil {
119 t.Fatal(err)
120 }
121 if q, _ := s.MergeQueueCredential(mr.ID); q.Kind != "" {
122 t.Fatalf("web-queued credential = %+v", q)
123 }
124}
125
126// A merge request whose source branch is gone is not one a status can
127// merge.
128func TestQueuedMRsAtHeadSkipsSourceGone(t *testing.T) {
129 s, repoID, uid := mrFixture(t)
130 mr, _ := s.MRByNumber(repoID, 1)
131 s.QueueMerge(mr.ID, uid, "", 0, 0)
132 s.SetMRState(mr.ID, "source_gone")
133 if ids, _ := s.QueuedMRsAtHead(repoID, "abc123"); len(ids) != 0 {
134 t.Fatalf("QueuedMRsAtHead = %v, want none", ids)
135 }
136}