1// SPDX-License-Identifier: AGPL-3.0-or-later
2package kvstore_test
3
4import (
5 "bnema.dev/ermite/internal/adapters/kvstore"
6 "bnema.dev/ermite/internal/domain"
7 "bnema.dev/ermite/internal/ports"
8 "context"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/require"
11 "slices"
12 "testing"
13 "time"
14)
15
16func TestIssueLinksReplace(t *testing.T) {
17 ctx := context.Background()
18 s, _, repo := repoWithMRs(t)
19 links := s.IssueLinks()
20 added, removed, err := links.ReplaceLinks(ctx, repo, 9, []int64{3, 2, 3}, []int64{2}, ports.ReferenceEvent{})
21 require.NoError(t, err)
22 assert.Equal(t, []domain.IssueLink{{Issue: 2, MergeRequest: 9, Closes: true}, {Issue: 3, MergeRequest: 9}}, added)
23 assert.Empty(t, removed)
24 got, err := links.LinksOfMergeRequest(ctx, repo, 9)
25 require.NoError(t, err)
26 assert.Equal(t, added, got)
27 added, removed, err = links.ReplaceLinks(ctx, repo, 9, []int64{2, 3}, []int64{2}, ports.ReferenceEvent{})
28 require.NoError(t, err)
29 assert.Empty(t, added)
30 assert.Empty(t, removed)
31 added, removed, err = links.ReplaceLinks(ctx, repo, 9, []int64{3, 4}, []int64{3}, ports.ReferenceEvent{})
32 require.NoError(t, err)
33 assert.Equal(t, []domain.IssueLink{{Issue: 3, MergeRequest: 9, Closes: true}, {Issue: 4, MergeRequest: 9}}, added)
34 assert.Equal(t, []domain.IssueLink{{Issue: 2, MergeRequest: 9, Closes: true}}, removed)
35 got, err = links.LinksOfIssue(ctx, repo, 2, 100)
36 require.NoError(t, err)
37 assert.Empty(t, got)
38 added, removed, err = links.ReplaceLinks(ctx, repo, 9, []int64{3}, nil, ports.ReferenceEvent{})
39 require.NoError(t, err)
40 assert.Empty(t, added)
41 assert.Equal(t, []domain.IssueLink{{Issue: 3, MergeRequest: 9, Closes: true}, {Issue: 4, MergeRequest: 9}}, removed)
42 for _, mr := range []int64{12, 1, 5} {
43 _, _, err = links.ReplaceLinks(ctx, repo, mr, []int64{3}, nil, ports.ReferenceEvent{})
44 require.NoError(t, err)
45 }
46 got, err = links.LinksOfIssue(ctx, repo, 3, 2)
47 require.NoError(t, err)
48 assert.Equal(t, []domain.IssueLink{{Issue: 3, MergeRequest: 1}, {Issue: 3, MergeRequest: 5}}, got)
49 require.NoError(t, s.Delete(ctx, repo))
50 assert.Zero(t, countKeys(t, s, "isref/"+repo.String()+"/"))
51 assert.Zero(t, countKeys(t, s, "mrref/"+repo.String()+"/"))
52 _, _, err = links.ReplaceLinks(ctx, repo, 9, []int64{2}, nil, ports.ReferenceEvent{})
53 assert.ErrorIs(t, err, domain.ErrNotFound)
54}
55
56func TestIssueClosedByRoundTrip(t *testing.T) {
57 ctx := context.Background()
58 s, _, repo := repoWithMRs(t)
59 issue := newIssue(t, repo, "closed by merge")
60 issue.State = domain.IssueStateClosed
61 issue.ClosedByMergeRequest = 17
62 stored, err := s.Issues().Create(ctx, issue)
63 require.NoError(t, err)
64 assert.Equal(t, int64(17), stored.ClosedByMergeRequest)
65 stored.ClosedByMergeRequest = 0
66 require.NoError(t, s.Issues().Update(ctx, stored))
67 stored, err = s.Issues().Get(ctx, repo, stored.Number)
68 require.NoError(t, err)
69 assert.Zero(t, stored.ClosedByMergeRequest)
70}
71
72func TestMRHistoryKeepsEarliestEvents(t *testing.T) {
73 ctx := context.Background()
74 s, _, repo := repoWithMRs(t)
75 var want []domain.IssueEvent
76 // Issue keys and insertion order both differ from timestamp order. Equal
77 // timestamps across issues also exercise the issue/sequence tie breakers.
78 for i := 0; i < 3; i++ {
79 issue, err := s.Issues().Create(ctx, newIssue(t, repo, "history"))
80 require.NoError(t, err)
81 var events []domain.IssueEvent
82 for j := 0; j < 240; j++ {
83 events = append(events, domain.IssueEvent{Kind: domain.IssueEventReferenced, MergeRequest: 9, CreatedAt: time.Unix(int64(240-j), 0)})
84 }
85 require.NoError(t, s.Issues().Update(ctx, issue, events...))
86 stored, err := s.Issues().ListEvents(ctx, repo, issue.Number)
87 require.NoError(t, err)
88 want = append(want, stored...)
89 }
90 slices.SortFunc(want, domain.CompareIssueEvents)
91 require.Greater(t, len(want), kvstore.MaxIssueEvents)
92 got, err := s.IssueLinks().EventsOfMergeRequest(ctx, repo, 9)
93 require.NoError(t, err)
94 assert.Equal(t, want[:kvstore.MaxIssueEvents], got)
95 assert.Equal(t, kvstore.MaxIssueEvents, cap(got))
96}