tests: Add BenchmarkLoadFile
This commit is contained in:
parent
f142b1c22f
commit
77ebb95d3d
6 changed files with 202 additions and 124 deletions
59
src/restic/backend/test/benchmarks.go
Normal file
59
src/restic/backend/test/benchmarks.go
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"restic"
|
||||||
|
"restic/test"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BackendBenchmarkLoad benchmarks the backend's Load function.
|
||||||
|
func BackendBenchmarkLoadFile(t *testing.B, s *Suite) {
|
||||||
|
be := s.open(t)
|
||||||
|
defer s.close(t, be)
|
||||||
|
|
||||||
|
length := 1<<24 + 2123
|
||||||
|
data := test.Random(23, length)
|
||||||
|
id := restic.Hash(data)
|
||||||
|
handle := restic.Handle{Type: restic.DataFile, Name: id.String()}
|
||||||
|
if err := be.Save(handle, bytes.NewReader(data)); err != nil {
|
||||||
|
t.Fatalf("Save() error: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := be.Remove(handle); err != nil {
|
||||||
|
t.Fatalf("Remove() returned error: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
buf := make([]byte, length)
|
||||||
|
|
||||||
|
t.SetBytes(int64(length))
|
||||||
|
t.ResetTimer()
|
||||||
|
|
||||||
|
for i := 0; i < t.N; i++ {
|
||||||
|
rd, err := be.Load(handle, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := io.ReadFull(rd, buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = rd.Close(); err != nil {
|
||||||
|
t.Fatalf("Close() returned error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n != length {
|
||||||
|
t.Fatalf("wrong number of bytes read: want %v, got %v", length, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(data, buf) {
|
||||||
|
t.Fatalf("wrong bytes returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ import (
|
||||||
|
|
||||||
var testFunctions = []struct {
|
var testFunctions = []struct {
|
||||||
Name string
|
Name string
|
||||||
Fn func(t testing.TB, suite *Suite)
|
Fn func(testing.TB, *Suite)
|
||||||
}{
|
}{
|
||||||
{"CreateWithConfig", BackendTestCreateWithConfig},
|
{"CreateWithConfig", BackendTestCreateWithConfig},
|
||||||
{"Location", BackendTestLocation},
|
{"Location", BackendTestLocation},
|
||||||
|
@ -22,5 +22,7 @@ var testFunctions = []struct {
|
||||||
|
|
||||||
var benchmarkFunctions = []struct {
|
var benchmarkFunctions = []struct {
|
||||||
Name string
|
Name string
|
||||||
Fn func(t testing.TB, suite *Suite)
|
Fn func(*testing.B, *Suite)
|
||||||
}{}
|
}{
|
||||||
|
{"LoadFile", BackendBenchmarkLoadFile},
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
@ -35,7 +36,7 @@ import (
|
||||||
|
|
||||||
var testFunctions = []struct {
|
var testFunctions = []struct {
|
||||||
Name string
|
Name string
|
||||||
Fn func(t testing.TB, suite *Suite)
|
Fn func(testing.TB, *Suite)
|
||||||
}{
|
}{
|
||||||
{{ range $f := .TestFuncs -}}
|
{{ range $f := .TestFuncs -}}
|
||||||
{"{{ $f }}", BackendTest{{ $f }},},
|
{"{{ $f }}", BackendTest{{ $f }},},
|
||||||
|
@ -44,7 +45,7 @@ var testFunctions = []struct {
|
||||||
|
|
||||||
var benchmarkFunctions = []struct {
|
var benchmarkFunctions = []struct {
|
||||||
Name string
|
Name string
|
||||||
Fn func(t testing.TB, suite *Suite)
|
Fn func(*testing.B, *Suite)
|
||||||
}{
|
}{
|
||||||
{{ range $f := .BenchmarkFuncs -}}
|
{{ range $f := .BenchmarkFuncs -}}
|
||||||
{"{{ $f }}", BackendBenchmark{{ $f }},},
|
{"{{ $f }}", BackendBenchmark{{ $f }},},
|
||||||
|
@ -52,7 +53,7 @@ var benchmarkFunctions = []struct {
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
var testFile = flag.String("testfile", "tests.go", "file to search test functions in")
|
var testFiles = flag.String("testfiles", "tests.go,benchmarks.go", "files to search test functions in (comma separated)")
|
||||||
var outputFile = flag.String("output", "funcs.go", "output file to write generated code to")
|
var outputFile = flag.String("output", "funcs.go", "output file to write generated code to")
|
||||||
var packageName = flag.String("package", "", "the package name to use")
|
var packageName = flag.String("package", "", "the package name to use")
|
||||||
var prefix = flag.String("prefix", "", "test function prefix")
|
var prefix = flag.String("prefix", "", "test function prefix")
|
||||||
|
@ -71,27 +72,30 @@ var testFuncRegex = regexp.MustCompile(`^func\s+BackendTest(.+)\s*\(`)
|
||||||
var benchmarkFuncRegex = regexp.MustCompile(`^func\s+BackendBenchmark(.+)\s*\(`)
|
var benchmarkFuncRegex = regexp.MustCompile(`^func\s+BackendBenchmark(.+)\s*\(`)
|
||||||
|
|
||||||
func findFunctions() (testFuncs, benchmarkFuncs []string) {
|
func findFunctions() (testFuncs, benchmarkFuncs []string) {
|
||||||
f, err := os.Open(*testFile)
|
for _, filename := range strings.Split(*testFiles, ",") {
|
||||||
errx(err)
|
f, err := os.Open(filename)
|
||||||
|
errx(err)
|
||||||
|
|
||||||
sc := bufio.NewScanner(f)
|
sc := bufio.NewScanner(f)
|
||||||
for sc.Scan() {
|
for sc.Scan() {
|
||||||
match := testFuncRegex.FindStringSubmatch(sc.Text())
|
match := testFuncRegex.FindStringSubmatch(sc.Text())
|
||||||
if len(match) > 0 {
|
if len(match) > 0 {
|
||||||
testFuncs = append(testFuncs, match[1])
|
testFuncs = append(testFuncs, match[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
match = benchmarkFuncRegex.FindStringSubmatch(sc.Text())
|
||||||
|
if len(match) > 0 {
|
||||||
|
benchmarkFuncs = append(benchmarkFuncs, match[1])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match = benchmarkFuncRegex.FindStringSubmatch(sc.Text())
|
if err := sc.Err(); err != nil {
|
||||||
if len(match) > 0 {
|
log.Fatalf("Error scanning file: %v", err)
|
||||||
benchmarkFuncs = append(benchmarkFuncs, match[1])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errx(f.Close())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sc.Err(); err != nil {
|
|
||||||
log.Fatalf("Error scanning file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
errx(f.Close())
|
|
||||||
return testFuncs, benchmarkFuncs
|
return testFuncs, benchmarkFuncs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
106
src/restic/backend/test/suite.go
Normal file
106
src/restic/backend/test/suite.go
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"restic"
|
||||||
|
"restic/test"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Suite implements a test suite for restic backends.
|
||||||
|
type Suite struct {
|
||||||
|
Config interface{}
|
||||||
|
|
||||||
|
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||||
|
NewConfig func() (interface{}, error)
|
||||||
|
|
||||||
|
// CreateFn is a function that creates a temporary repository for the tests.
|
||||||
|
Create func(cfg interface{}) (restic.Backend, error)
|
||||||
|
|
||||||
|
// OpenFn is a function that opens a previously created temporary repository.
|
||||||
|
Open func(cfg interface{}) (restic.Backend, error)
|
||||||
|
|
||||||
|
// CleanupFn removes data created during the tests.
|
||||||
|
Cleanup func(cfg interface{}) error
|
||||||
|
|
||||||
|
// MinimalData instructs the tests to not use excessive data.
|
||||||
|
MinimalData bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunTests executes all defined tests as subtests of t.
|
||||||
|
func (s *Suite) RunTests(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
s.Config, err = s.NewConfig()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test create/open functions first
|
||||||
|
be := s.create(t)
|
||||||
|
s.close(t, be)
|
||||||
|
|
||||||
|
for _, test := range testFunctions {
|
||||||
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
|
test.Fn(t, s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if !test.TestCleanupTempDirs {
|
||||||
|
t.Logf("not cleaning up backend")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = s.Cleanup(s.Config); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunBenchmarks executes all defined benchmarks as subtests of b.
|
||||||
|
func (s *Suite) RunBenchmarks(b *testing.B) {
|
||||||
|
var err error
|
||||||
|
s.Config, err = s.NewConfig()
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test create/open functions first
|
||||||
|
be := s.create(b)
|
||||||
|
s.close(b, be)
|
||||||
|
|
||||||
|
for _, test := range benchmarkFunctions {
|
||||||
|
b.Run(test.Name, func(b *testing.B) {
|
||||||
|
test.Fn(b, s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if !test.TestCleanupTempDirs {
|
||||||
|
b.Logf("not cleaning up backend")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = s.Cleanup(s.Config); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Suite) create(t testing.TB) restic.Backend {
|
||||||
|
be, err := s.Create(s.Config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return be
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Suite) open(t testing.TB) restic.Backend {
|
||||||
|
be, err := s.Open(s.Config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
return be
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Suite) close(t testing.TB, be restic.Backend) {
|
||||||
|
err := be.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,105 +20,6 @@ import (
|
||||||
"restic/backend"
|
"restic/backend"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Suite implements a test suite for restic backends.
|
|
||||||
type Suite struct {
|
|
||||||
Config interface{}
|
|
||||||
|
|
||||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
|
||||||
NewConfig func() (interface{}, error)
|
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
|
||||||
Create func(cfg interface{}) (restic.Backend, error)
|
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open func(cfg interface{}) (restic.Backend, error)
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup func(cfg interface{}) error
|
|
||||||
|
|
||||||
// MinimalData instructs the tests to not use excessive data.
|
|
||||||
MinimalData bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunTests executes all defined tests as subtests of t.
|
|
||||||
func (s *Suite) RunTests(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
s.Config, err = s.NewConfig()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// test create/open functions first
|
|
||||||
be := s.create(t)
|
|
||||||
s.close(t, be)
|
|
||||||
|
|
||||||
for _, test := range testFunctions {
|
|
||||||
t.Run(test.Name, func(t *testing.T) {
|
|
||||||
test.Fn(t, s)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if !test.TestCleanupTempDirs {
|
|
||||||
t.Logf("not cleaning up backend")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = s.Cleanup(s.Config); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunBenchmarks executes all defined benchmarks as subtests of b.
|
|
||||||
func (s *Suite) RunBenchmarks(b *testing.B) {
|
|
||||||
var err error
|
|
||||||
s.Config, err = s.NewConfig()
|
|
||||||
if err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// test create/open functions first
|
|
||||||
be := s.create(b)
|
|
||||||
s.close(b, be)
|
|
||||||
|
|
||||||
for _, test := range benchmarkFunctions {
|
|
||||||
b.Run(test.Name, func(b *testing.B) {
|
|
||||||
test.Fn(b, s)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if !test.TestCleanupTempDirs {
|
|
||||||
b.Logf("not cleaning up backend")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = s.Cleanup(s.Config); err != nil {
|
|
||||||
b.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Suite) create(t testing.TB) restic.Backend {
|
|
||||||
be, err := s.Create(s.Config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
return be
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Suite) open(t testing.TB) restic.Backend {
|
|
||||||
be, err := s.Open(s.Config)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
return be
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Suite) close(t testing.TB, be restic.Backend) {
|
|
||||||
err := be.Close()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BackendTestCreateWithConfig tests that creating a backend in a location which already
|
// BackendTestCreateWithConfig tests that creating a backend in a location which already
|
||||||
// has a config file fails.
|
// has a config file fails.
|
||||||
func BackendTestCreateWithConfig(t testing.TB, s *Suite) {
|
func BackendTestCreateWithConfig(t testing.TB, s *Suite) {
|
||||||
|
|
|
@ -15,8 +15,8 @@ type memConfig struct {
|
||||||
be restic.Backend
|
be restic.Backend
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSuiteBackendMem(t *testing.T) {
|
func newTestSuite(t testing.TB) *test.Suite {
|
||||||
suite := test.Suite{
|
return &test.Suite{
|
||||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||||
NewConfig: func() (interface{}, error) {
|
NewConfig: func() (interface{}, error) {
|
||||||
return &memConfig{}, nil
|
return &memConfig{}, nil
|
||||||
|
@ -55,6 +55,12 @@ func TestSuiteBackendMem(t *testing.T) {
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
}
|
||||||
suite.RunTests(t)
|
|
||||||
|
func TestSuiteBackendMem(t *testing.T) {
|
||||||
|
newTestSuite(t).RunTests(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSuiteBackendMem(b *testing.B) {
|
||||||
|
newTestSuite(b).RunBenchmarks(b)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue