github.com/mckael/restic@v0.8.3/internal/backend/test/suite.go (about) 1 package test 2 3 import ( 4 "reflect" 5 "strings" 6 "testing" 7 "time" 8 9 "github.com/restic/restic/internal/restic" 10 "github.com/restic/restic/internal/test" 11 ) 12 13 // Suite implements a test suite for restic backends. 14 type Suite struct { 15 // Config should be used to configure the backend. 16 Config interface{} 17 18 // NewConfig returns a config for a new temporary backend that will be used in tests. 19 NewConfig func() (interface{}, error) 20 21 // CreateFn is a function that creates a temporary repository for the tests. 22 Create func(cfg interface{}) (restic.Backend, error) 23 24 // OpenFn is a function that opens a previously created temporary repository. 25 Open func(cfg interface{}) (restic.Backend, error) 26 27 // CleanupFn removes data created during the tests. 28 Cleanup func(cfg interface{}) error 29 30 // MinimalData instructs the tests to not use excessive data. 31 MinimalData bool 32 33 // WaitForDelayedRemoval is set to a non-zero value to instruct the test 34 // suite to wait for this amount of time until a file that was removed 35 // really disappeared. 36 WaitForDelayedRemoval time.Duration 37 38 // ErrorHandler allows ignoring certain errors. 39 ErrorHandler func(testing.TB, restic.Backend, error) error 40 } 41 42 // RunTests executes all defined tests as subtests of t. 43 func (s *Suite) RunTests(t *testing.T) { 44 var err error 45 s.Config, err = s.NewConfig() 46 if err != nil { 47 t.Fatal(err) 48 } 49 50 // test create/open functions first 51 be := s.create(t) 52 s.close(t, be) 53 54 for _, test := range s.testFuncs(t) { 55 t.Run(test.Name, test.Fn) 56 } 57 58 if !test.TestCleanupTempDirs { 59 t.Logf("not cleaning up backend") 60 return 61 } 62 63 if err = s.Cleanup(s.Config); err != nil { 64 t.Fatal(err) 65 } 66 } 67 68 type testFunction struct { 69 Name string 70 Fn func(*testing.T) 71 } 72 73 func (s *Suite) testFuncs(t testing.TB) (funcs []testFunction) { 74 tpe := reflect.TypeOf(s) 75 v := reflect.ValueOf(s) 76 77 for i := 0; i < tpe.NumMethod(); i++ { 78 methodType := tpe.Method(i) 79 name := methodType.Name 80 81 // discard functions which do not have the right name 82 if !strings.HasPrefix(name, "Test") { 83 continue 84 } 85 86 iface := v.Method(i).Interface() 87 f, ok := iface.(func(*testing.T)) 88 if !ok { 89 t.Logf("warning: function %v of *Suite has the wrong signature for a test function\nwant: func(*testing.T),\nhave: %T", 90 name, iface) 91 continue 92 } 93 94 funcs = append(funcs, testFunction{ 95 Name: name, 96 Fn: f, 97 }) 98 } 99 100 return funcs 101 } 102 103 type benchmarkFunction struct { 104 Name string 105 Fn func(*testing.B) 106 } 107 108 func (s *Suite) benchmarkFuncs(t testing.TB) (funcs []benchmarkFunction) { 109 tpe := reflect.TypeOf(s) 110 v := reflect.ValueOf(s) 111 112 for i := 0; i < tpe.NumMethod(); i++ { 113 methodType := tpe.Method(i) 114 name := methodType.Name 115 116 // discard functions which do not have the right name 117 if !strings.HasPrefix(name, "Benchmark") { 118 continue 119 } 120 121 iface := v.Method(i).Interface() 122 f, ok := iface.(func(*testing.B)) 123 if !ok { 124 t.Logf("warning: function %v of *Suite has the wrong signature for a test function\nwant: func(*testing.T),\nhave: %T", 125 name, iface) 126 continue 127 } 128 129 funcs = append(funcs, benchmarkFunction{ 130 Name: name, 131 Fn: f, 132 }) 133 } 134 135 return funcs 136 } 137 138 // RunBenchmarks executes all defined benchmarks as subtests of b. 139 func (s *Suite) RunBenchmarks(b *testing.B) { 140 var err error 141 s.Config, err = s.NewConfig() 142 if err != nil { 143 b.Fatal(err) 144 } 145 146 // test create/open functions first 147 be := s.create(b) 148 s.close(b, be) 149 150 for _, test := range s.benchmarkFuncs(b) { 151 b.Run(test.Name, test.Fn) 152 } 153 154 if !test.TestCleanupTempDirs { 155 b.Logf("not cleaning up backend") 156 return 157 } 158 159 if err = s.Cleanup(s.Config); err != nil { 160 b.Fatal(err) 161 } 162 } 163 164 func (s *Suite) create(t testing.TB) restic.Backend { 165 be, err := s.Create(s.Config) 166 if err != nil { 167 t.Fatal(err) 168 } 169 return be 170 } 171 172 func (s *Suite) open(t testing.TB) restic.Backend { 173 be, err := s.Open(s.Config) 174 if err != nil { 175 t.Fatal(err) 176 } 177 return be 178 } 179 180 func (s *Suite) close(t testing.TB, be restic.Backend) { 181 err := be.Close() 182 if err != nil { 183 t.Fatal(err) 184 } 185 }