|
|
@@ -5,14 +5,12 @@ package issues |
|
|
|
|
|
|
|
import ( |
|
|
|
"context" |
|
|
|
"fmt" |
|
|
|
"path" |
|
|
|
"path/filepath" |
|
|
|
"testing" |
|
|
|
"time" |
|
|
|
|
|
|
|
"code.gitea.io/gitea/models/db" |
|
|
|
"code.gitea.io/gitea/models/unittest" |
|
|
|
"code.gitea.io/gitea/modules/indexer/issues/bleve" |
|
|
|
"code.gitea.io/gitea/modules/indexer/issues/internal" |
|
|
|
"code.gitea.io/gitea/modules/setting" |
|
|
|
"code.gitea.io/gitea/modules/util" |
|
|
|
|
|
|
@@ -29,186 +27,381 @@ func TestMain(m *testing.M) { |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
func TestBleveSearchIssues(t *testing.T) { |
|
|
|
assert.NoError(t, unittest.PrepareTestDatabase()) |
|
|
|
setting.CfgProvider, _ = setting.NewConfigProviderFromData("") |
|
|
|
|
|
|
|
tmpIndexerDir := t.TempDir() |
|
|
|
|
|
|
|
setting.CfgProvider.Section("queue.issue_indexer").Key("DATADIR").MustString(path.Join(tmpIndexerDir, "issues.queue")) |
|
|
|
|
|
|
|
oldIssuePath := setting.Indexer.IssuePath |
|
|
|
setting.Indexer.IssuePath = path.Join(tmpIndexerDir, "issues.queue") |
|
|
|
defer func() { |
|
|
|
setting.Indexer.IssuePath = oldIssuePath |
|
|
|
}() |
|
|
|
|
|
|
|
setting.Indexer.IssueType = "bleve" |
|
|
|
setting.LoadQueueSettings() |
|
|
|
InitIssueIndexer(true) |
|
|
|
defer func() { |
|
|
|
if bleveIndexer, ok := (*globalIndexer.Load()).(*bleve.Indexer); ok { |
|
|
|
bleveIndexer.Close() |
|
|
|
} |
|
|
|
}() |
|
|
|
|
|
|
|
time.Sleep(5 * time.Second) |
|
|
|
|
|
|
|
t.Run("issue2", func(t *testing.T) { |
|
|
|
ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ |
|
|
|
Keyword: "issue2", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}) |
|
|
|
assert.NoError(t, err) |
|
|
|
assert.EqualValues(t, []int64{2}, ids) |
|
|
|
}) |
|
|
|
|
|
|
|
t.Run("first", func(t *testing.T) { |
|
|
|
ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ |
|
|
|
Keyword: "first", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}) |
|
|
|
assert.NoError(t, err) |
|
|
|
assert.EqualValues(t, []int64{1}, ids) |
|
|
|
}) |
|
|
|
|
|
|
|
t.Run("for", func(t *testing.T) { |
|
|
|
ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ |
|
|
|
Keyword: "for", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}) |
|
|
|
assert.NoError(t, err) |
|
|
|
assert.ElementsMatch(t, []int64{1, 2, 3, 5, 11}, ids) |
|
|
|
}) |
|
|
|
|
|
|
|
t.Run("good", func(t *testing.T) { |
|
|
|
ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ |
|
|
|
Keyword: "good", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}) |
|
|
|
assert.NoError(t, err) |
|
|
|
assert.EqualValues(t, []int64{1}, ids) |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
func TestDBSearchIssuesWithKeyword(t *testing.T) { |
|
|
|
func TestDBSearchIssues(t *testing.T) { |
|
|
|
assert.NoError(t, unittest.PrepareTestDatabase()) |
|
|
|
|
|
|
|
setting.Indexer.IssueType = "db" |
|
|
|
InitIssueIndexer(true) |
|
|
|
|
|
|
|
t.Run("issue2", func(t *testing.T) { |
|
|
|
ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ |
|
|
|
Keyword: "issue2", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}) |
|
|
|
assert.NoError(t, err) |
|
|
|
assert.EqualValues(t, []int64{2}, ids) |
|
|
|
}) |
|
|
|
|
|
|
|
t.Run("first", func(t *testing.T) { |
|
|
|
ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ |
|
|
|
Keyword: "first", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}) |
|
|
|
assert.NoError(t, err) |
|
|
|
assert.EqualValues(t, []int64{1}, ids) |
|
|
|
}) |
|
|
|
t.Run("search issues with keyword", searchIssueWithKeyword) |
|
|
|
t.Run("search issues in repo", searchIssueInRepo) |
|
|
|
t.Run("search issues by ID", searchIssueByID) |
|
|
|
t.Run("search issues is pr", searchIssueIsPull) |
|
|
|
t.Run("search issues is closed", searchIssueIsClosed) |
|
|
|
t.Run("search issues by milestone", searchIssueByMilestoneID) |
|
|
|
t.Run("search issues by label", searchIssueByLabelID) |
|
|
|
t.Run("search issues by time", searchIssueByTime) |
|
|
|
t.Run("search issues with order", searchIssueWithOrder) |
|
|
|
t.Run("search issues in project", searchIssueInProject) |
|
|
|
t.Run("search issues with paginator", searchIssueWithPaginator) |
|
|
|
} |
|
|
|
|
|
|
|
t.Run("for", func(t *testing.T) { |
|
|
|
ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ |
|
|
|
Keyword: "for", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}) |
|
|
|
assert.NoError(t, err) |
|
|
|
assert.ElementsMatch(t, []int64{1, 2, 3, 5, 11}, ids) |
|
|
|
}) |
|
|
|
func searchIssueWithKeyword(t *testing.T) { |
|
|
|
tests := []struct { |
|
|
|
opts SearchOptions |
|
|
|
expectedIDs []int64 |
|
|
|
}{ |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
Keyword: "issue2", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}, |
|
|
|
[]int64{2}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
Keyword: "first", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}, |
|
|
|
[]int64{1}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
Keyword: "for", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}, |
|
|
|
[]int64{11, 5, 3, 2, 1}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
Keyword: "good", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}, |
|
|
|
[]int64{1}, |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
t.Run("good", func(t *testing.T) { |
|
|
|
ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ |
|
|
|
Keyword: "good", |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}) |
|
|
|
assert.NoError(t, err) |
|
|
|
assert.EqualValues(t, []int64{1}, ids) |
|
|
|
}) |
|
|
|
for _, test := range tests { |
|
|
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: add more tests |
|
|
|
func TestDBSearchIssueWithoutKeyword(t *testing.T) { |
|
|
|
assert.NoError(t, unittest.PrepareTestDatabase()) |
|
|
|
func searchIssueInRepo(t *testing.T) { |
|
|
|
tests := []struct { |
|
|
|
opts SearchOptions |
|
|
|
expectedIDs []int64 |
|
|
|
}{ |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
}, |
|
|
|
[]int64{11, 5, 3, 2, 1}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{2}, |
|
|
|
}, |
|
|
|
[]int64{7, 4}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{3}, |
|
|
|
}, |
|
|
|
[]int64{12, 6}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{4}, |
|
|
|
}, |
|
|
|
[]int64{}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{5}, |
|
|
|
}, |
|
|
|
[]int64{15}, |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
setting.Indexer.IssueType = "db" |
|
|
|
InitIssueIndexer(true) |
|
|
|
for _, test := range tests { |
|
|
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func searchIssueByID(t *testing.T) { |
|
|
|
int64Pointer := func(x int64) *int64 { |
|
|
|
return &x |
|
|
|
} |
|
|
|
for _, test := range []struct { |
|
|
|
tests := []struct { |
|
|
|
opts SearchOptions |
|
|
|
expectedIDs []int64 |
|
|
|
}{ |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
PosterID: int64Pointer(1), |
|
|
|
}, |
|
|
|
[]int64{11, 5, 3, 2, 1}, |
|
|
|
[]int64{11, 6, 3, 2, 1}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
AssigneeID: int64Pointer(1), |
|
|
|
}, |
|
|
|
[]int64{6, 1}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
MentionID: int64Pointer(4), |
|
|
|
}, |
|
|
|
[]int64{1}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
PosterID: int64Pointer(1), |
|
|
|
ReviewedID: int64Pointer(1), |
|
|
|
}, |
|
|
|
[]int64{}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
ReviewRequestedID: int64Pointer(1), |
|
|
|
}, |
|
|
|
[]int64{12}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
SubscriberID: int64Pointer(1), |
|
|
|
}, |
|
|
|
[]int64{11, 6, 5, 3, 2, 1}, |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
for _, test := range tests { |
|
|
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func searchIssueIsPull(t *testing.T) { |
|
|
|
tests := []struct { |
|
|
|
opts SearchOptions |
|
|
|
expectedIDs []int64 |
|
|
|
}{ |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
IsPull: util.OptionalBoolFalse, |
|
|
|
}, |
|
|
|
[]int64{17, 16, 15, 14, 13, 6, 5, 18, 10, 7, 4, 1}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
IsPull: util.OptionalBoolTrue, |
|
|
|
}, |
|
|
|
[]int64{11, 3, 2, 1}, |
|
|
|
[]int64{12, 11, 19, 9, 8, 3, 2}, |
|
|
|
}, |
|
|
|
} |
|
|
|
for _, test := range tests { |
|
|
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func searchIssueIsClosed(t *testing.T) { |
|
|
|
tests := []struct { |
|
|
|
opts SearchOptions |
|
|
|
expectedIDs []int64 |
|
|
|
}{ |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
IsClosed: util.OptionalBoolFalse, |
|
|
|
}, |
|
|
|
[]int64{11, 3, 2, 1}, |
|
|
|
[]int64{17, 16, 15, 14, 13, 12, 11, 6, 19, 18, 10, 7, 9, 8, 3, 2, 1}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
IsClosed: util.OptionalBoolTrue, |
|
|
|
}, |
|
|
|
[]int64{5}, |
|
|
|
[]int64{5, 4}, |
|
|
|
}, |
|
|
|
} |
|
|
|
for _, test := range tests { |
|
|
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func searchIssueByMilestoneID(t *testing.T) { |
|
|
|
tests := []struct { |
|
|
|
opts SearchOptions |
|
|
|
expectedIDs []int64 |
|
|
|
}{ |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
MilestoneIDs: []int64{1}, |
|
|
|
}, |
|
|
|
[]int64{2}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
MilestoneIDs: []int64{3}, |
|
|
|
}, |
|
|
|
[]int64{11, 5, 3, 2, 1}, |
|
|
|
[]int64{3}, |
|
|
|
}, |
|
|
|
} |
|
|
|
for _, test := range tests { |
|
|
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func searchIssueByLabelID(t *testing.T) { |
|
|
|
tests := []struct { |
|
|
|
opts SearchOptions |
|
|
|
expectedIDs []int64 |
|
|
|
}{ |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
IncludedLabelIDs: []int64{1}, |
|
|
|
}, |
|
|
|
[]int64{2, 1}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
AssigneeID: int64Pointer(1), |
|
|
|
IncludedLabelIDs: []int64{4}, |
|
|
|
}, |
|
|
|
[]int64{2}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
ExcludedLabelIDs: []int64{1}, |
|
|
|
}, |
|
|
|
[]int64{17, 16, 15, 14, 13, 12, 11, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3}, |
|
|
|
}, |
|
|
|
} |
|
|
|
for _, test := range tests { |
|
|
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func searchIssueByTime(t *testing.T) { |
|
|
|
int64Pointer := func(i int64) *int64 { |
|
|
|
return &i |
|
|
|
} |
|
|
|
tests := []struct { |
|
|
|
opts SearchOptions |
|
|
|
expectedIDs []int64 |
|
|
|
}{ |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
UpdatedAfterUnix: int64Pointer(0), |
|
|
|
}, |
|
|
|
[]int64{17, 16, 15, 14, 13, 12, 11, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1}, |
|
|
|
}, |
|
|
|
} |
|
|
|
for _, test := range tests { |
|
|
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func searchIssueWithOrder(t *testing.T) { |
|
|
|
tests := []struct { |
|
|
|
opts SearchOptions |
|
|
|
expectedIDs []int64 |
|
|
|
}{ |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
SortBy: internal.SortByCreatedAsc, |
|
|
|
}, |
|
|
|
[]int64{1, 2, 3, 8, 9, 4, 7, 10, 18, 19, 5, 6, 11, 12, 13, 14, 15, 16, 17}, |
|
|
|
}, |
|
|
|
} |
|
|
|
for _, test := range tests { |
|
|
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func searchIssueInProject(t *testing.T) { |
|
|
|
int64Pointer := func(i int64) *int64 { |
|
|
|
return &i |
|
|
|
} |
|
|
|
tests := []struct { |
|
|
|
opts SearchOptions |
|
|
|
expectedIDs []int64 |
|
|
|
}{ |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
ProjectID: int64Pointer(1), |
|
|
|
}, |
|
|
|
[]int64{5, 3, 2, 1}, |
|
|
|
}, |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
ProjectBoardID: int64Pointer(1), |
|
|
|
}, |
|
|
|
[]int64{1}, |
|
|
|
}, |
|
|
|
} |
|
|
|
for _, test := range tests { |
|
|
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func searchIssueWithPaginator(t *testing.T) { |
|
|
|
tests := []struct { |
|
|
|
opts SearchOptions |
|
|
|
expectedIDs []int64 |
|
|
|
expectedTotal int64 |
|
|
|
}{ |
|
|
|
{ |
|
|
|
SearchOptions{ |
|
|
|
RepoIDs: []int64{1}, |
|
|
|
PosterID: int64Pointer(1), |
|
|
|
Paginator: &db.ListOptions{ |
|
|
|
PageSize: 5, |
|
|
|
}, |
|
|
|
}, |
|
|
|
[]int64{11, 3, 2, 1}, |
|
|
|
[]int64{17, 16, 15, 14, 13}, |
|
|
|
19, |
|
|
|
}, |
|
|
|
} { |
|
|
|
t.Run(fmt.Sprintf("%#v", test.opts), func(t *testing.T) { |
|
|
|
issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
}) |
|
|
|
} |
|
|
|
for _, test := range tests { |
|
|
|
issueIDs, total, err := SearchIssues(context.TODO(), &test.opts) |
|
|
|
if !assert.NoError(t, err) { |
|
|
|
return |
|
|
|
} |
|
|
|
assert.Equal(t, test.expectedIDs, issueIDs) |
|
|
|
assert.Equal(t, test.expectedTotal, total) |
|
|
|
} |
|
|
|
} |