blob: c6230d60f8aae824cc28e5509a313ef9bd14308c [file] [log] [blame] [edit]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package repoimport
import (
"context"
"strconv"
"testing"
"time"
"go.chromium.org/luci/appengine/gaetesting"
"go.chromium.org/luci/common/clock"
"go.chromium.org/luci/common/clock/testclock"
"go.chromium.org/luci/common/proto/git"
gitilesProto "go.chromium.org/luci/common/proto/gitiles"
"go.chromium.org/luci/common/testing/ftt"
"go.chromium.org/luci/common/testing/truth/assert"
"go.chromium.org/luci/common/testing/truth/should"
"go.chromium.org/luci/gae/service/datastore"
"go.chromium.org/infra/appengine/cr-rev/backend/gitiles"
"go.chromium.org/infra/appengine/cr-rev/common"
"go.chromium.org/infra/appengine/cr-rev/models"
)
func TestGitilesImporter(t *testing.T) {
repo := common.GitRepository{
Host: "foo",
Name: "bar",
}
doc := &models.Repository{
ID: models.RepoID{
Host: "foo",
Repository: "bar",
},
}
prepareEnvironment := func() (context.Context, *gitilesProto.Fake, Importer) {
ctx := gaetesting.TestingContext()
ds := datastore.GetTestable(ctx)
ds.Consistent(true)
ds.AutoIndex(true)
testclock := testclock.New(time.Now())
ctx = clock.Set(ctx, testclock)
client := &gitilesProto.Fake{}
ctx = gitiles.SetClient(ctx, client)
imp := NewGitilesImporter(ctx, repo)
return ctx, client, imp
}
assertCommitDocuments := func(ctx context.Context, expected int) []*models.Commit {
dsCommits := []*models.Commit{}
q := datastore.NewQuery("Commit")
datastore.GetAll(ctx, q, &dsCommits)
assert.Loosely(t, len(dsCommits), should.Equal(expected))
return dsCommits
}
ftt.Run("non existing repository", t, func(t *ftt.Test) {
ctx, _, importer := prepareEnvironment()
err := importer.Run(ctx)
assert.Loosely(t, err, should.ErrLike("Repository not found"))
assert.Loosely(t, err.Error(), should.Equal("Repository not found"))
// Datastore should not have lock anymore, and should unset last run
datastore.Get(ctx, doc)
assert.Loosely(t, doc.FullScanLeaseStartTime, should.Match(time.Time{}))
assert.Loosely(t, doc.FullScanLastRun, should.Match(time.Time{}))
})
ftt.Run("existing repository", t, func(t *ftt.Test) {
t.Run("empty repository", func(t *ftt.Test) {
ctx, client, importer := prepareEnvironment()
client.SetRepository("bar", map[string]string{}, []*git.Commit{})
err := importer.Run(ctx)
assert.NoErr(t, err)
// Datastore should not have lock anymore, and last run should be set
datastore.Get(ctx, doc)
assert.Loosely(t, doc.FullScanLeaseStartTime, should.Match(time.Time{}))
assert.Loosely(t, doc.FullScanLastRun, should.Match(clock.Get(ctx).Now().UTC().Round(time.Millisecond)))
})
t.Run("empty default branch", func(t *ftt.Test) {
ctx, client, importer := prepareEnvironment()
refs := map[string]string{
"main": "",
}
commits := []*git.Commit{}
client.SetRepository("bar", refs, commits)
err := importer.Run(ctx)
assert.NoErr(t, err)
// Datastore should not have lock anymore, and last run should be set
datastore.Get(ctx, doc)
assert.Loosely(t, doc.FullScanLeaseStartTime, should.Match(time.Time{}))
assert.Loosely(t, doc.FullScanLastRun, should.Match(clock.Get(ctx).Now().UTC().Round(time.Millisecond)))
assertCommitDocuments(ctx, 0)
})
t.Run("one commit, two branches", func(t *ftt.Test) {
ctx, client, importer := prepareEnvironment()
refs := map[string]string{
"refs/heads/main": "0000000000000000000000000000000000000000",
"refs/heads/release": "0000000000000000000000000000000000000000",
}
commits := []*git.Commit{
{
Id: "0000000000000000000000000000000000000000",
Message: `Commit message
Bug: 123
Change-Id: Ifoo
Cr-Commit-Position: refs/heads/main@{#1}`,
},
}
client.SetRepository("bar", refs, commits)
err := importer.Run(ctx)
assert.NoErr(t, err)
datastore.Get(ctx, doc)
assert.Loosely(t, doc.FullScanLeaseStartTime, should.Match(time.Time{}))
assert.Loosely(t, doc.FullScanLastRun, should.Match(clock.Get(ctx).Now().UTC().Round(time.Millisecond)))
docs := assertCommitDocuments(ctx, 1)
assert.Loosely(t, docs[0].PositionRef, should.Equal("refs/heads/main"))
assert.Loosely(t, docs[0].PositionNumber, should.Equal(1))
})
t.Run("not indexed branch", func(t *ftt.Test) {
ctx, client, importer := prepareEnvironment()
refs := map[string]string{
"refs/for/refs/heads/main": "5",
"refs/heads/main": "2",
}
commits := make([]*git.Commit, 5)
for i := range 5 {
commits[i] = &git.Commit{
Id: strconv.Itoa(i + 1),
}
if i > 0 {
commits[i].Parents = []string{commits[i-1].GetId()}
}
}
client.SetRepository("bar", refs, commits)
err := importer.Run(ctx)
assert.NoErr(t, err)
datastore.Get(ctx, doc)
assert.Loosely(t, doc.FullScanLeaseStartTime, should.Match(time.Time{}))
assert.Loosely(t, doc.FullScanLastRun, should.Match(clock.Get(ctx).Now().UTC().Round(time.Millisecond)))
assertCommitDocuments(ctx, 2)
})
t.Run("diverged branches", func(t *ftt.Test) {
ctx, client, importer := prepareEnvironment()
refs := map[string]string{
"refs/heads/main": "5",
"refs/heads/release": "2",
}
commits := make([]*git.Commit, 5)
for i := range 5 {
commits[i] = &git.Commit{
Id: strconv.Itoa(i + 1),
}
if i > 0 {
commits[i].Parents = []string{commits[i-1].GetId()}
}
}
client.SetRepository("bar", refs, commits)
err := importer.Run(ctx)
assert.NoErr(t, err)
datastore.Get(ctx, doc)
assert.Loosely(t, doc.FullScanLeaseStartTime, should.Match(time.Time{}))
assert.Loosely(t, doc.FullScanLastRun, should.Match(clock.Get(ctx).Now().UTC().Round(time.Millisecond)))
assertCommitDocuments(ctx, 5)
})
t.Run("Log commit caching", func(t *ftt.Test) {
ctx, client, importer := prepareEnvironment()
// Require two Log pages for each branch
refs := map[string]string{
"refs/heads/main": strconv.Itoa(gitilesLogPageSize + 2),
"refs/heads/release": strconv.Itoa(gitilesLogPageSize + 1),
}
commits := make([]*git.Commit, gitilesLogPageSize+2)
for i := range gitilesLogPageSize + 2 {
commits[i] = &git.Commit{
Id: strconv.Itoa(i + 1),
}
if i > 0 {
commits[i].Parents = []string{commits[i-1].GetId()}
}
}
client.SetRepository("bar", refs, commits)
err := importer.Run(ctx)
assert.NoErr(t, err)
datastore.Get(ctx, doc)
assert.Loosely(t, doc.FullScanLeaseStartTime, should.Match(time.Time{}))
assert.Loosely(t, doc.FullScanLastRun, should.Match(clock.Get(ctx).Now().UTC().Round(time.Millisecond)))
assertCommitDocuments(ctx, gitilesLogPageSize+2)
// We expect 4 calls.
// One is for listing all refs and their revisions.
// Very first indexed branch should make two calls to
// Gitiles, and the last should make only one.
assert.Loosely(t, len(client.GetCallLogs()), should.Equal(4))
})
})
}