1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package usecase_test
4
5import (
6 "context"
7 "path/filepath"
8 "testing"
9
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12
13 "bnema.dev/ermite/internal/adapters/eventbus"
14 "bnema.dev/ermite/internal/adapters/kvstore"
15 "bnema.dev/ermite/internal/domain"
16 "bnema.dev/ermite/internal/ports"
17 "bnema.dev/ermite/internal/usecase"
18)
19
20// Issues over the real store: shared numbers with merge requests, the life of
21// an issue and its events.
22func TestIssuesOverTheStore(t *testing.T) {
23 ctx := context.Background()
24 store, err := kvstore.Open(ctx, filepath.Join(t.TempDir(), "kv"))
25 require.NoError(t, err)
26 t.Cleanup(func() { require.NoError(t, store.Close(context.Background())) })
27 bus := eventbus.NewWithBuffer(64)
28 events := bus.Subscribe(ctx)
29 n := name(t, "proj")
30 settings := domain.DefaultRepoSettings()
31 settings.Issues = domain.IssuesOwner
32 require.NoError(t, store.Create(ctx, domain.Repo{Name: n, Visibility: domain.VisibilityPublic, CreatedAt: now, Settings: settings}))
33
34 issues := usecase.NewIssues(usecase.IssuesConfig{Meta: store, Store: store.Issues(), MergeRequests: store.MergeRequests(), Bus: bus, Clock: fixedClock{}})
35 agent := domain.TokenPrincipal(domain.Token{ID: "t", Label: "bot", Scopes: []domain.Scope{domain.ScopeIssueWrite}, BranchPrefixes: []string{"x/"}})
36
37 mrTitle, err := domain.ParseMRTitle("Change")
38 require.NoError(t, err)
39 mr, err := store.MergeRequests().Create(ctx, domain.MergeRequest{
40 Repo: n, Title: mrTitle, State: domain.MRStateOpen, Source: "feat", Target: "main", Author: "a", CreatedAt: now, UpdatedAt: now,
41 })
42 require.NoError(t, err)
43 assert.EqualValues(t, 1, mr.Number)
44
45 issue, err := issues.Create(ctx, agent, n, ports.CreateIssueParams{Title: "Crash", Body: "details"})
46 require.NoError(t, err)
47 assert.EqualValues(t, 2, issue.Number, "the number follows the merge request")
48 assert.Equal(t, "bot", issue.Author)
49
50 kind, err := issues.Kind(ctx, domain.Anonymous(), n, 1)
51 require.NoError(t, err)
52 assert.Equal(t, domain.NumberMergeRequest, kind)
53 kind, err = issues.Kind(ctx, domain.Anonymous(), n, 2)
54 require.NoError(t, err)
55 assert.Equal(t, domain.NumberIssue, kind)
56 kind, err = issues.Kind(ctx, domain.Anonymous(), n, 3)
57 require.NoError(t, err)
58 assert.Equal(t, domain.NumberNone, kind)
59
60 _, err = issues.AddComment(ctx, agent, n, 2, "me too")
61 require.NoError(t, err)
62 _, err = issues.Close(ctx, agent, n, 2)
63 require.NoError(t, err)
64 _, err = issues.AddComment(ctx, agent, n, 2, "after close")
65 require.NoError(t, err)
66 _, err = issues.Close(ctx, agent, n, 2)
67 assert.ErrorIs(t, err, domain.ErrPreconditionFailed)
68 _, err = issues.Reopen(ctx, agent, n, 2)
69 require.NoError(t, err)
70
71 d, err := issues.Get(ctx, domain.Anonymous(), n, 2)
72 require.NoError(t, err)
73 assert.Equal(t, domain.IssueStateOpen, d.Issue.State)
74 require.Len(t, d.Comments, 2)
75 assert.Equal(t, "me too", d.Comments[0].Text.String())
76 assert.EqualValues(t, 2, d.Issue.CommentSeq)
77
78 page, err := issues.List(ctx, domain.Anonymous(), n, ports.ListIssuesParams{State: domain.IssueStateClosed})
79 require.NoError(t, err)
80 assert.Empty(t, page.Issues)
81
82 var kinds []string
83 for len(events) > 0 {
84 kinds = append(kinds, (<-events).EventKind())
85 }
86 assert.Equal(t, []string{"issue.opened", "issue.commented", "issue.closed", "issue.commented", "issue.reopened"}, kinds)
87}