test(general): fix TestSnapshotNoLeftoverCheckpoints slowness (#4611)

Avoid allocating 1GB of RAM to write a test file.
Exclude test from race detector.

- Fixes: #4610
- Ref: #4439

nits:
- use `require.Greater`.
- add types to constants to used them with `require.*`.
- factor out function to write file with random data.
This commit is contained in:
Julio Lopez
2025-05-28 19:01:01 -07:00
committed by GitHub
parent 11049fd3ae
commit eadcdc753d
2 changed files with 73 additions and 60 deletions

View File

@@ -0,0 +1,73 @@
//go:build !race
// +build !race
package endtoend_test
import (
"io"
"math/rand"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"github.com/kopia/kopia/internal/clock"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/tests/clitestutil"
"github.com/kopia/kopia/tests/testenv"
)
// Exclude tests below from the -race detection test, because they are resource
// intensive and way too slow.
func TestSnapshotNoLeftoverCheckpoints(t *testing.T) {
// 1 GiB of data seems to be enough for the snapshot time to exceed one second.
const (
fileSize = int64(1) << 30
checkpointInterval = "1s"
checkpointIntervalSeconds = float64(1)
)
t.Parallel()
runner := testenv.NewInProcRunner(t)
e := testenv.NewCLITest(t, testenv.RepoFormatNotImportant, runner)
defer e.RunAndExpectSuccess(t, "repo", "disconnect")
e.RunAndExpectSuccess(t, "repo", "create", "filesystem", "--path", e.RepoDir)
baseDir := testutil.TempDirectory(t)
writeRandomFile(t, filepath.Join(baseDir, "foo"), fileSize)
startTime := clock.Now()
e.RunAndExpectSuccess(t, "snapshot", "create", baseDir, "--checkpoint-interval", checkpointInterval)
require.Greater(t, clock.Now().Sub(startTime).Seconds(), checkpointIntervalSeconds)
// This exploits the implementation detail of `ListSnapshotsAndExpectSuccess`, that it does
// not sanitize `targets` to exclude flags.
si := clitestutil.ListSnapshotsAndExpectSuccess(t, e, "--incomplete", baseDir)
require.Len(t, si, 1)
require.Len(t, si[0].Snapshots, 1)
require.False(t, si[0].Snapshots[0].Incomplete)
}
func writeRandomFile(t *testing.T, name string, fileSize int64) {
t.Helper()
f, err := os.Create(name)
require.NoError(t, err)
require.NotNil(t, f)
defer func() {
require.NoError(t, f.Close())
}()
n, err := io.CopyN(f, rand.New(rand.NewSource(0)), fileSize)
require.NoError(t, err)
require.Equal(t, fileSize, n)
}

View File

@@ -1,7 +1,6 @@
package endtoend_test
import (
"math/rand"
"os"
"path"
"path/filepath"
@@ -18,7 +17,6 @@
"github.com/kopia/kopia/cli"
"github.com/kopia/kopia/internal/cachedir"
"github.com/kopia/kopia/internal/clock"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/snapshot"
"github.com/kopia/kopia/snapshot/policy"
@@ -801,61 +799,3 @@ func TestSnapshotCreateWithAllAndPath(t *testing.T) {
e.RunAndExpectSuccess(t, "snapshot", "create", sharedTestDataDir2)
e.RunAndExpectFailure(t, "snapshot", "create", sharedTestDataDir1, "--all")
}
func TestSnapshotNoLeftoverCheckpoints(t *testing.T) {
// 1 GiB of data seems to be enough for the snapshot time to exceed one second.
const (
fileSize = 1 << 30
checkpointInterval = "1s"
checkpointIntervalSeconds = 1
)
t.Parallel()
runner := testenv.NewInProcRunner(t)
e := testenv.NewCLITest(t, testenv.RepoFormatNotImportant, runner)
defer e.RunAndExpectSuccess(t, "repo", "disconnect")
e.RunAndExpectSuccess(t, "repo", "create", "filesystem", "--path", e.RepoDir)
baseDir := testutil.TempDirectory(t)
files := []testFileEntry{
{
Name: "/foo",
Content: []string{
generateRandomLetters(fileSize),
},
},
}
require.NoError(t, createFileStructure(baseDir, files))
startTime := clock.Now()
e.RunAndExpectSuccess(t, "snapshot", "create", baseDir, "--checkpoint-interval", checkpointInterval)
endTime := clock.Now()
snapshotTimeSurpassedCheckpointInterval := endTime.Sub(startTime).Seconds() > checkpointIntervalSeconds
require.True(t, snapshotTimeSurpassedCheckpointInterval)
// This exploits the implementation detail of `ListSnapshotsAndExpectSuccess`, that it does
// not sanitize `targets` to exclude flags.
si := clitestutil.ListSnapshotsAndExpectSuccess(t, e, "--incomplete", baseDir)
require.Len(t, si, 1)
require.Len(t, si[0].Snapshots, 1)
require.False(t, si[0].Snapshots[0].Incomplete)
}
// https://stackoverflow.com/a/31832326
func generateRandomLetters(n int) string {
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Int63()%int64(len(letterBytes))]
}
return string(b)
}