Skip to content

Commit ae38fa3

Browse files
authored
Speed up integration tests (kopia#653)
* testing: don't use expensive scrypt-65536-8-1 in integration tests * testing: use platform-specific encryption and hashing for arm and arm64 to speed up tests * testing: manually manage log directory to be able to analyze integration test failures * testing: snapshot_gc_test was too quick * Makefile: renamed target building integration test binary
1 parent 044b170 commit ae38fa3

File tree

7 files changed

+125
-36
lines changed

7 files changed

+125
-36
lines changed

Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,15 @@ test: $(gotestsum)
193193
vtest: $(gotestsum)
194194
$(GO_TEST) -count=1 -short -v -timeout $(UNIT_TESTS_TIMEOUT) ./...
195195

196-
dist-binary:
196+
build-integration-test-binary:
197197
go build -o $(KOPIA_INTEGRATION_EXE) -tags testing github.com/kopia/kopia
198198

199199
integration-tests: export KOPIA_EXE ?= $(KOPIA_INTEGRATION_EXE)
200-
integration-tests: dist-binary $(gotestsum)
200+
integration-tests: build-integration-test-binary $(gotestsum)
201201
$(GO_TEST) $(TEST_FLAGS) -count=1 -parallel $(PARALLEL) -timeout 3600s github.com/kopia/kopia/tests/end_to_end_test
202202

203203
endurance-tests: export KOPIA_EXE ?= $(KOPIA_INTEGRATION_EXE)
204-
endurance-tests: dist-binary $(gotestsum)
204+
endurance-tests: build-integration-test-binary $(gotestsum)
205205
$(GO_TEST) $(TEST_FLAGS) -count=1 -parallel $(PARALLEL) -timeout 3600s github.com/kopia/kopia/tests/endurance_test
206206

207207
robustness-tool-tests: $(gotestsum)
@@ -279,7 +279,7 @@ endif
279279

280280
ifneq ($(TRAVIS_TAG),)
281281

282-
travis-create-long-term-repository: dist-binary travis-install-cloud-sdk
282+
travis-create-long-term-repository: build-integration-test-binary travis-install-cloud-sdk
283283
echo Creating long-term repository $(TRAVIS_TAG)...
284284
KOPIA_EXE=$(KOPIA_INTEGRATION_EXE) ./tests/compat_test/gen-compat-repo.sh
285285

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// +build !testing
2+
3+
package repo
4+
5+
import (
6+
"github.com/pkg/errors"
7+
"golang.org/x/crypto/scrypt"
8+
)
9+
10+
// defaultKeyDerivationAlgorithm is the key derivation algorithm for new configurations.
11+
const defaultKeyDerivationAlgorithm = "scrypt-65536-8-1"
12+
13+
func (f *formatBlob) deriveMasterKeyFromPassword(password string) ([]byte, error) {
14+
const masterKeySize = 32
15+
16+
switch f.KeyDerivationAlgorithm {
17+
case "scrypt-65536-8-1":
18+
return scrypt.Key([]byte(password), f.UniqueID, 65536, 8, 1, masterKeySize)
19+
20+
default:
21+
return nil, errors.Errorf("unsupported key algorithm: %v", f.KeyDerivationAlgorithm)
22+
}
23+
}

repo/crypto_key_derivation.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,9 @@ import (
44
"crypto/sha256"
55
"io"
66

7-
"github.com/pkg/errors"
87
"golang.org/x/crypto/hkdf"
9-
"golang.org/x/crypto/scrypt"
108
)
119

12-
// defaultKeyDerivationAlgorithm is the key derivation algorithm for new configurations.
13-
const defaultKeyDerivationAlgorithm = "scrypt-65536-8-1"
14-
15-
func (f *formatBlob) deriveMasterKeyFromPassword(password string) ([]byte, error) {
16-
const masterKeySize = 32
17-
18-
switch f.KeyDerivationAlgorithm {
19-
case "scrypt-65536-8-1":
20-
return scrypt.Key([]byte(password), f.UniqueID, 65536, 8, 1, masterKeySize)
21-
22-
default:
23-
return nil, errors.Errorf("unsupported key algorithm: %v", f.KeyDerivationAlgorithm)
24-
}
25-
}
26-
2710
// deriveKeyFromMasterKey computes a key for a specific purpose and length using HKDF based on the master key.
2811
func deriveKeyFromMasterKey(masterKey, uniqueID, purpose []byte, length int) []byte {
2912
key := make([]byte, length)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// +build testing
2+
3+
package repo
4+
5+
import (
6+
"crypto/sha256"
7+
8+
"github.com/pkg/errors"
9+
)
10+
11+
// defaultKeyDerivationAlgorithm is the key derivation algorithm for new configurations.
12+
const defaultKeyDerivationAlgorithm = "testing-only-insecure"
13+
14+
func (f *formatBlob) deriveMasterKeyFromPassword(password string) ([]byte, error) {
15+
const masterKeySize = 32
16+
17+
switch f.KeyDerivationAlgorithm {
18+
case defaultKeyDerivationAlgorithm:
19+
h := sha256.New()
20+
if _, err := h.Write([]byte(password)); err != nil {
21+
return nil, err
22+
}
23+
24+
return h.Sum(nil), nil
25+
26+
default:
27+
return nil, errors.Errorf("unsupported key algorithm: %v", f.KeyDerivationAlgorithm)
28+
}
29+
}

tests/end_to_end_test/all_formats_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ import (
99
)
1010

1111
func TestAllFormatsSmokeTest(t *testing.T) {
12+
srcDir := t.TempDir()
13+
14+
// 3-level directory with <=10 files and <=10 subdirectories at each level
15+
testenv.CreateDirectoryTree(srcDir, testenv.DirectoryTreeOptions{
16+
Depth: 2,
17+
MaxSubdirsPerDirectory: 5,
18+
MaxFilesPerDirectory: 5,
19+
MaxFileSize: 100,
20+
}, nil)
21+
1222
for _, encryptionAlgo := range encryption.SupportedAlgorithms(false) {
1323
encryptionAlgo := encryptionAlgo
1424

@@ -22,8 +32,10 @@ func TestAllFormatsSmokeTest(t *testing.T) {
2232
e := testenv.NewCLITest(t)
2333
defer e.RunAndExpectSuccess(t, "repo", "disconnect")
2434

35+
e.DefaultRepositoryCreateFlags = nil
36+
2537
e.RunAndExpectSuccess(t, "repo", "create", "filesystem", "--path", e.RepoDir, "--block-hash", hashAlgo, "--encryption", encryptionAlgo)
26-
e.RunAndExpectSuccess(t, "snap", "create", sharedTestDataDir1)
38+
e.RunAndExpectSuccess(t, "snap", "create", srcDir)
2739

2840
sources := e.ListSnapshotsAndExpectSuccess(t)
2941
if got, want := len(sources), 1; got != want {

tests/end_to_end_test/snapshot_gc_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"path/filepath"
77
"strings"
88
"testing"
9+
"time"
910

1011
"github.com/kopia/kopia/tests/testenv"
1112
)
@@ -61,6 +62,9 @@ how are you
6162
// data block + directory block + manifest block + manifest block from manifest deletion
6263
e.RunAndVerifyOutputLineCount(t, expectedContentCount, "content", "list")
6364

65+
// make sure we are not too quick
66+
time.Sleep(2 * time.Second)
67+
6468
// garbage-collect for real, this time without age limit
6569
e.RunAndExpectSuccess(t, "snapshot", "gc", "--delete", "--min-age", "0s")
6670

tests/testenv/cli_test_env.go

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ type CLITest struct {
4141
fixedArgs []string
4242
Environment []string
4343

44+
DefaultRepositoryCreateFlags []string
45+
4446
PassthroughStderr bool
4547

4648
LogsDir string
@@ -70,7 +72,22 @@ func NewCLITest(t *testing.T) *CLITest {
7072
}
7173

7274
configDir := t.TempDir()
73-
logsDir := t.TempDir()
75+
76+
cleanName := strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(
77+
t.Name(),
78+
"/", "_"), "\\", "_"), ":", "_")
79+
80+
logsDir := filepath.Join(os.TempDir(), "kopia-logs", cleanName+"."+clock.Now().Local().Format("20060102150405"))
81+
82+
t.Cleanup(func() {
83+
if t.Failed() {
84+
t.Logf("logs are available in %v", logsDir)
85+
return
86+
}
87+
88+
os.RemoveAll(logsDir)
89+
})
90+
7491
fixedArgs := []string{
7592
// use per-test config file, to avoid clobbering current user's setup.
7693
"--config-file", filepath.Join(configDir, ".kopia.config"),
@@ -87,13 +104,24 @@ func NewCLITest(t *testing.T) *CLITest {
87104
fixedArgs = append(fixedArgs, "--no-use-keyring")
88105
}
89106

107+
var formatFlags []string
108+
109+
switch runtime.GOARCH {
110+
case "arm64", "arm":
111+
formatFlags = []string{
112+
"--encryption", "CHACHA20-POLY1305-HMAC-SHA256",
113+
"--block-hash", "BLAKE2S-256",
114+
}
115+
}
116+
90117
return &CLITest{
91-
startTime: clock.Now(),
92-
RepoDir: t.TempDir(),
93-
ConfigDir: configDir,
94-
Exe: filepath.FromSlash(exe),
95-
fixedArgs: fixedArgs,
96-
LogsDir: logsDir,
118+
startTime: clock.Now(),
119+
RepoDir: t.TempDir(),
120+
ConfigDir: configDir,
121+
Exe: filepath.FromSlash(exe),
122+
fixedArgs: fixedArgs,
123+
DefaultRepositoryCreateFlags: formatFlags,
124+
LogsDir: logsDir,
97125
Environment: []string{
98126
"KOPIA_PASSWORD=" + TestRepoPassword,
99127
"KOPIA_ADVANCED_COMMANDS=enabled",
@@ -117,11 +145,9 @@ func (e *CLITest) RunAndExpectSuccess(t *testing.T, args ...string) []string {
117145
func (e *CLITest) RunAndProcessStderr(t *testing.T, callback func(line string) bool, args ...string) *exec.Cmd {
118146
t.Helper()
119147

120-
t.Logf("running 'kopia %v'", strings.Join(args, " "))
121-
cmdArgs := append(append([]string(nil), e.fixedArgs...), args...)
122-
123-
c := exec.Command(e.Exe, cmdArgs...)
148+
c := exec.Command(e.Exe, e.cmdArgs(args)...)
124149
c.Env = append(os.Environ(), e.Environment...)
150+
t.Logf("running '%v %v'", c.Path, c.Args)
125151

126152
stderrPipe, err := c.StderrPipe()
127153
if err != nil {
@@ -184,15 +210,27 @@ func (e *CLITest) RunAndVerifyOutputLineCount(t *testing.T, wantLines int, args
184210
return lines
185211
}
186212

213+
func (e *CLITest) cmdArgs(args []string) []string {
214+
var suffix []string
215+
216+
// detect repository creation and override DefaultRepositoryCreateFlags for best
217+
// performance on the current platform.
218+
if len(args) >= 2 && (args[0] == "repo" && args[1] == "create") {
219+
suffix = e.DefaultRepositoryCreateFlags
220+
}
221+
222+
return append(append(append([]string(nil), e.fixedArgs...), args...), suffix...)
223+
}
224+
187225
// Run executes kopia with given arguments and returns the output lines.
188226
func (e *CLITest) Run(t *testing.T, expectedError bool, args ...string) (stdout, stderr []string, err error) {
189227
t.Helper()
190-
t.Logf("running '%v %v'", e.Exe, strings.Join(args, " "))
191-
cmdArgs := append(append([]string(nil), e.fixedArgs...), args...)
192228

193-
c := exec.Command(e.Exe, cmdArgs...)
229+
c := exec.Command(e.Exe, e.cmdArgs(args)...)
194230
c.Env = append(os.Environ(), e.Environment...)
195231

232+
t.Logf("running '%v %v'", c.Path, c.Args)
233+
196234
errOut := &bytes.Buffer{}
197235
c.Stderr = errOut
198236

0 commit comments

Comments
 (0)