blob: dc4adbb0048ae208a796060c44d9f915119313a5 [file] [log] [blame]
package syncer
import (
"context"
"errors"
"io/ioutil"
"strings"
"testing"
"github.com/stretchr/testify/require"
depot_tools_testutils "go.skia.org/infra/go/depot_tools/testutils"
"go.skia.org/infra/go/exec"
"go.skia.org/infra/go/git"
"go.skia.org/infra/go/git/repograph"
"go.skia.org/infra/go/testutils"
"go.skia.org/infra/go/testutils/unittest"
tcc_testutils "go.skia.org/infra/task_scheduler/go/task_cfg_cache/testutils"
"go.skia.org/infra/task_scheduler/go/types"
)
func TestTempGitRepoBadRev(t *testing.T) {
// TODO(borenet): Git wrapper automatically retries commands when it
// encounters "transient" errors. I'm not sure why it thinks "fatal:
// couldn't find remote ref" is transient, but these retries cause the
// test to time out.
unittest.ManualTest(t)
unittest.LargeTest(t)
_, gb, _, _ := tempGitRepoSetup(t)
defer gb.Cleanup()
cases := map[types.RepoState]error{
{
Repo: gb.RepoUrl(),
Revision: "bogusRev",
}: ERR_DONT_CARE,
}
tempGitRepoGclientTests(t, cases)
}
func TestTempGitRepoErr(t *testing.T) {
// TODO(borenet): Git wrapper automatically retries commands when it
// encounters "transient" errors. I'm not sure why it thinks this error
// is transient, but these retries cause the test to time out.
unittest.ManualTest(t)
unittest.LargeTest(t)
ctx, gb, c1, _ := tcc_testutils.SetupTestRepo(t)
defer gb.Cleanup()
tmp, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer testutils.RemoveAll(t, tmp)
repos, err := repograph.NewLocalMap(ctx, []string{gb.RepoUrl()}, tmp)
require.NoError(t, err)
s := New(ctx, repos, depot_tools_testutils.GetDepotTools(t, ctx), tmp, DEFAULT_NUM_WORKERS)
defer testutils.AssertCloses(t, s)
// gclient will fail to apply the issue if we don't fake it in Git.
rs := types.RepoState{
Patch: types.Patch{
Issue: "my-issue",
Patchset: "my-patchset",
Server: "my-server",
},
Repo: gb.RepoUrl(),
Revision: c1,
}
require.Error(t, s.TempGitRepo(ctx, rs, func(c *git.TempCheckout) error {
// This may fail with a nil pointer dereference due to a nil
// git.TempCheckout.
require.FailNow(t, "We should not have gotten here.")
return nil
}))
}
func TestLazyTempGitRepo(t *testing.T) {
unittest.LargeTest(t)
// TODO(borenet): This test only takes ~5 seconds locally, but for some
// reason it consistently times out after 4 minutes on the bots.
unittest.ManualTest(t)
ctx, gb, c1, _ := tcc_testutils.SetupTestRepo(t)
defer gb.Cleanup()
tmp, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer testutils.RemoveAll(t, tmp)
repos, err := repograph.NewLocalMap(ctx, []string{gb.RepoUrl()}, tmp)
require.NoError(t, err)
syncCount := 0
mockRun := exec.CommandCollector{}
mockRun.SetDelegateRun(func(ctx context.Context, cmd *exec.Command) error {
gclient := false
sync := false
for _, arg := range cmd.Args {
if strings.Contains(arg, "gclient") {
gclient = true
}
if strings.Contains(arg, "sync") {
sync = true
}
}
if gclient && sync {
syncCount++
}
return exec.DefaultRun(ctx, cmd)
})
ctx = exec.NewContext(context.Background(), mockRun.Run)
s := New(ctx, repos, depot_tools_testutils.GetDepotTools(t, ctx), tmp, DEFAULT_NUM_WORKERS)
defer testutils.AssertCloses(t, s)
rs1 := types.RepoState{
Repo: gb.RepoUrl(),
Revision: c1,
}
ltgr := s.LazyTempGitRepo(rs1)
// This isn't a great marker, but it indicates whether the goroutine
// with the TempGitRepo is running.
require.Nil(t, ltgr.queue)
ran := false
require.NoError(t, ltgr.Do(ctx, func(co *git.TempCheckout) error {
ran = true
return nil
}))
require.True(t, ran)
require.Equal(t, 1, syncCount)
// See above comment.
require.NotNil(t, ltgr.queue)
ran2 := false
require.NoError(t, ltgr.Do(ctx, func(co *git.TempCheckout) error {
ran2 = true
return nil
}))
require.True(t, ran2)
require.Equal(t, 1, syncCount)
// See above comment.
require.NotNil(t, ltgr.queue)
ltgr.Done()
// What happens if we hit a sync error?
rs2 := types.RepoState{
Repo: gb.RepoUrl(),
Revision: c1,
Patch: types.Patch{
Issue: "12345",
Patchset: "1",
Server: "fake.fake/fake",
},
}
ltgr = s.LazyTempGitRepo(rs2)
notSyncError := errors.New("not a sync error")
syncErr := ltgr.Do(ctx, func(co *git.TempCheckout) error {
return notSyncError
})
require.NotNil(t, syncErr)
require.NotEqual(t, syncErr, notSyncError)
require.Equal(t, 2, syncCount)
// Subsequent calls should receive the same sync error, without another
// "gclient sync" invocation.
err = ltgr.Do(ctx, func(co *git.TempCheckout) error {
return notSyncError
})
require.NotNil(t, err)
require.EqualError(t, syncErr, err.Error())
require.Equal(t, 2, syncCount)
ltgr.Done()
// Errors returned by passed-in funcs should be forwarded through to
// the caller.
ltgr = s.LazyTempGitRepo(rs1)
err = ltgr.Do(ctx, func(co *git.TempCheckout) error {
return notSyncError
})
require.EqualError(t, notSyncError, err.Error())
require.Equal(t, 3, syncCount)
// ... but we should still be able to run other funcs.
ran = false
require.NoError(t, ltgr.Do(ctx, func(co *git.TempCheckout) error {
ran = true
return nil
}))
require.True(t, ran)
ltgr.Done()
}