github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/error_test.go (about) 1 // Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package pebble 6 7 import ( 8 "fmt" 9 "io" 10 "os" 11 "sync/atomic" 12 "testing" 13 14 "github.com/petermattis/pebble/vfs" 15 ) 16 17 type panicLogger struct{} 18 19 func (l panicLogger) Infof(format string, args ...interface{}) { 20 } 21 22 func (l panicLogger) Fatalf(format string, args ...interface{}) { 23 panic(fmt.Errorf("fatal: "+format, args...)) 24 } 25 26 type errorFS struct { 27 fs vfs.FS 28 index int32 29 } 30 31 func newErrorFS(index int32) *errorFS { 32 return &errorFS{ 33 fs: vfs.NewMem(), 34 index: index, 35 } 36 } 37 38 func (fs *errorFS) maybeError() error { 39 if atomic.AddInt32(&fs.index, -1) == -1 { 40 return fmt.Errorf("injected error") 41 } 42 return nil 43 } 44 45 func (fs *errorFS) Create(name string) (vfs.File, error) { 46 if err := fs.maybeError(); err != nil { 47 return nil, err 48 } 49 f, err := fs.fs.Create(name) 50 if err != nil { 51 return nil, err 52 } 53 return errorFile{f, fs}, nil 54 } 55 56 func (fs *errorFS) Link(oldname, newname string) error { 57 if err := fs.maybeError(); err != nil { 58 return err 59 } 60 return fs.fs.Link(oldname, newname) 61 } 62 63 func (fs *errorFS) Open(name string, opts ...vfs.OpenOption) (vfs.File, error) { 64 if err := fs.maybeError(); err != nil { 65 return nil, err 66 } 67 f, err := fs.fs.Open(name) 68 if err != nil { 69 return nil, err 70 } 71 ef := errorFile{f, fs} 72 for _, opt := range opts { 73 opt.Apply(ef) 74 } 75 return ef, nil 76 } 77 78 func (fs *errorFS) OpenDir(name string) (vfs.File, error) { 79 if err := fs.maybeError(); err != nil { 80 return nil, err 81 } 82 f, err := fs.fs.OpenDir(name) 83 if err != nil { 84 return nil, err 85 } 86 return errorFile{f, fs}, nil 87 } 88 89 func (fs *errorFS) Remove(name string) error { 90 if _, err := fs.fs.Stat(name); os.IsNotExist(err) { 91 return nil 92 } 93 94 if err := fs.maybeError(); err != nil { 95 return err 96 } 97 return fs.fs.Remove(name) 98 } 99 100 func (fs *errorFS) Rename(oldname, newname string) error { 101 if err := fs.maybeError(); err != nil { 102 return err 103 } 104 return fs.fs.Rename(oldname, newname) 105 } 106 107 func (fs *errorFS) MkdirAll(dir string, perm os.FileMode) error { 108 if err := fs.maybeError(); err != nil { 109 return err 110 } 111 return fs.fs.MkdirAll(dir, perm) 112 } 113 114 func (fs *errorFS) Lock(name string) (io.Closer, error) { 115 if err := fs.maybeError(); err != nil { 116 return nil, err 117 } 118 return fs.fs.Lock(name) 119 } 120 121 func (fs *errorFS) List(dir string) ([]string, error) { 122 if err := fs.maybeError(); err != nil { 123 return nil, err 124 } 125 return fs.fs.List(dir) 126 } 127 128 func (fs *errorFS) Stat(name string) (os.FileInfo, error) { 129 if err := fs.maybeError(); err != nil { 130 return nil, err 131 } 132 return fs.fs.Stat(name) 133 } 134 135 type errorFile struct { 136 file vfs.File 137 fs *errorFS 138 } 139 140 func (f errorFile) Close() error { 141 // We don't inject errors during close as those calls should never fail in 142 // practice. 143 return f.file.Close() 144 } 145 146 func (f errorFile) Read(p []byte) (int, error) { 147 if err := f.fs.maybeError(); err != nil { 148 return 0, err 149 } 150 return f.file.Read(p) 151 } 152 153 func (f errorFile) ReadAt(p []byte, off int64) (int, error) { 154 if err := f.fs.maybeError(); err != nil { 155 return 0, err 156 } 157 return f.file.ReadAt(p, off) 158 } 159 160 func (f errorFile) Write(p []byte) (int, error) { 161 if err := f.fs.maybeError(); err != nil { 162 return 0, err 163 } 164 return f.file.Write(p) 165 } 166 167 func (f errorFile) Stat() (os.FileInfo, error) { 168 if err := f.fs.maybeError(); err != nil { 169 return nil, err 170 } 171 return f.file.Stat() 172 } 173 174 func (f errorFile) Sync() error { 175 if err := f.fs.maybeError(); err != nil { 176 return err 177 } 178 return f.file.Sync() 179 } 180 181 // TestErrors repeatedly runs a short sequence of operations, injecting FS 182 // errors at different points, until success is achieved. 183 func TestErrors(t *testing.T) { 184 run := func(fs *errorFS) (err error) { 185 defer func() { 186 if r := recover(); r != nil { 187 if e, ok := r.(error); ok { 188 err = e 189 } else { 190 err = fmt.Errorf("%v", r) 191 } 192 } 193 }() 194 195 d, err := Open("", &Options{ 196 FS: fs, 197 Logger: panicLogger{}, 198 }) 199 if err != nil { 200 return err 201 } 202 203 key := []byte("a") 204 value := []byte("b") 205 if err := d.Set(key, value, nil); err != nil { 206 return err 207 } 208 if err := d.Flush(); err != nil { 209 return err 210 } 211 if err := d.Compact(nil, nil); err != nil { 212 return err 213 } 214 215 iter := d.NewIter(nil) 216 for valid := iter.First(); valid; valid = iter.Next() { 217 } 218 if err := iter.Close(); err != nil { 219 return err 220 } 221 return d.Close() 222 } 223 224 errorCounts := make(map[string]int) 225 for i := int32(0); ; i++ { 226 fs := newErrorFS(i) 227 err := run(fs) 228 if err == nil { 229 t.Logf("success %d\n", i) 230 break 231 } 232 errorCounts[err.Error()]++ 233 } 234 235 expectedErrors := []string{ 236 "fatal: MANIFEST flush failed: injected error", 237 "fatal: MANIFEST sync failed: injected error", 238 "fatal: MANIFEST set current failed: injected error", 239 "fatal: MANIFEST dirsync failed: injected error", 240 } 241 for _, expected := range expectedErrors { 242 if errorCounts[expected] == 0 { 243 t.Errorf("expected error %q did not occur", expected) 244 } 245 } 246 }