github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/db/db_test.go (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package db 5 6 import ( 7 "fmt" 8 "math/rand" 9 "os" 10 "reflect" 11 "testing" 12 13 "github.com/google/syzkaller/pkg/osutil" 14 "github.com/stretchr/testify/assert" 15 ) 16 17 func TestBasic(t *testing.T) { 18 fn := tempFile(t) 19 defer os.Remove(fn) 20 db, err := Open(fn, false) 21 if err != nil { 22 t.Fatalf("failed to open db: %v", err) 23 } 24 if len(db.Records) != 0 { 25 t.Fatalf("empty db contains records") 26 } 27 db.Save("", nil, 0) 28 db.Save("1", []byte("ab"), 1) 29 db.Save("23", []byte("abcd"), 2) 30 31 want := map[string]Record{ 32 "": {Val: nil, Seq: 0}, 33 "1": {Val: []byte("ab"), Seq: 1}, 34 "23": {Val: []byte("abcd"), Seq: 2}, 35 } 36 if !reflect.DeepEqual(db.Records, want) { 37 t.Fatalf("bad db after save: %v, want: %v", db.Records, want) 38 } 39 if err := db.Flush(); err != nil { 40 t.Fatalf("failed to flush db: %v", err) 41 } 42 if !reflect.DeepEqual(db.Records, want) { 43 t.Fatalf("bad db after flush: %v, want: %v", db.Records, want) 44 } 45 db, err = Open(fn, false) 46 if err != nil { 47 t.Fatalf("failed to open db: %v", err) 48 } 49 if !reflect.DeepEqual(db.Records, want) { 50 t.Fatalf("bad db after reopen: %v, want: %v", db.Records, want) 51 } 52 } 53 54 func TestModify(t *testing.T) { 55 fn := tempFile(t) 56 defer os.Remove(fn) 57 db, err := Open(fn, false) 58 if err != nil { 59 t.Fatalf("failed to open db: %v", err) 60 } 61 db.Save("1", []byte("ab"), 0) 62 db.Save("23", nil, 1) 63 db.Save("456", []byte("abcd"), 1) 64 db.Save("7890", []byte("a"), 0) 65 db.Delete("23") 66 db.Save("1", nil, 5) 67 db.Save("456", []byte("ef"), 6) 68 db.Delete("7890") 69 db.Save("456", []byte("efg"), 0) 70 db.Save("7890", []byte("bc"), 0) 71 72 want := map[string]Record{ 73 "1": {Val: nil, Seq: 5}, 74 "456": {Val: []byte("efg"), Seq: 0}, 75 "7890": {Val: []byte("bc"), Seq: 0}, 76 } 77 if !reflect.DeepEqual(db.Records, want) { 78 t.Fatalf("bad db after modification: %v, want: %v", db.Records, want) 79 } 80 if err := db.Flush(); err != nil { 81 t.Fatalf("failed to flush db: %v", err) 82 } 83 if !reflect.DeepEqual(db.Records, want) { 84 t.Fatalf("bad db after flush: %v, want: %v", db.Records, want) 85 } 86 db, err = Open(fn, false) 87 if err != nil { 88 t.Fatalf("failed to open db: %v", err) 89 } 90 if !reflect.DeepEqual(db.Records, want) { 91 t.Fatalf("bad db after reopen: %v, want: %v", db.Records, want) 92 } 93 } 94 95 func TestLarge(t *testing.T) { 96 fn := tempFile(t) 97 defer os.Remove(fn) 98 db, err := Open(fn, false) 99 if err != nil { 100 t.Fatalf("failed to open db: %v", err) 101 } 102 const nrec = 1000 103 val := make([]byte, 1000) 104 for i := range val { 105 val[i] = byte(rand.Intn(256)) 106 } 107 for i := 0; i < nrec; i++ { 108 db.Save(fmt.Sprintf("%v", i), val, 0) 109 } 110 if err := db.Flush(); err != nil { 111 t.Fatalf("failed to flush db: %v", err) 112 } 113 db, err = Open(fn, false) 114 if err != nil { 115 t.Fatalf("failed to open db: %v", err) 116 } 117 if len(db.Records) != nrec { 118 t.Fatalf("wrong record count: %v, want %v", len(db.Records), nrec) 119 } 120 } 121 122 func TestDiscardData(t *testing.T) { 123 fn := tempFile(t) 124 defer os.Remove(fn) 125 db, err := Open(fn, false) 126 if err != nil { 127 t.Fatalf("failed to open db: %v", err) 128 } 129 db.DiscardData() 130 131 db.Save("1", []byte("11"), 1) 132 db.Save("2", []byte("22"), 2) 133 db.Save("3", []byte("33"), 3) 134 db.Delete("2") 135 if err := db.Flush(); err != nil { 136 t.Fatalf("failed to flush db: %v", err) 137 } 138 assert.Nil(t, db.Records["1"].Val) 139 assert.Nil(t, db.Records["2"].Val) 140 assert.Nil(t, db.Records["3"].Val) 141 142 db, err = Open(fn, false) 143 if err != nil { 144 t.Fatalf("failed to open db: %v", err) 145 } 146 want := map[string]Record{ 147 "1": {Val: []byte("11"), Seq: 1}, 148 "3": {Val: []byte("33"), Seq: 3}, 149 } 150 if !reflect.DeepEqual(db.Records, want) { 151 t.Fatalf("bad db after save: %v, want: %v", db.Records, want) 152 } 153 db.Save("3", []byte("333"), 33) 154 db.Save("4", []byte("44"), 4) 155 db.Delete("1") 156 db.DiscardData() 157 assert.Nil(t, db.Records["3"].Val) 158 assert.Nil(t, db.Records["4"].Val) 159 // Force compaction. 160 for i := 0; i < 200; i++ { 161 db.Save("5", []byte("55"), 5) 162 } 163 if err := db.Flush(); err != nil { 164 t.Fatalf("failed to flush db: %v", err) 165 } 166 db, err = Open(fn, false) 167 if err != nil { 168 t.Fatalf("failed to open db: %v", err) 169 } 170 want = map[string]Record{ 171 "3": {Val: []byte("333"), Seq: 33}, 172 "4": {Val: []byte("44"), Seq: 4}, 173 "5": {Val: []byte("55"), Seq: 5}, 174 } 175 if !reflect.DeepEqual(db.Records, want) { 176 t.Fatalf("bad db after save: %v, want: %v", db.Records, want) 177 } 178 } 179 180 func TestOpenInvalid(t *testing.T) { 181 f, err := os.CreateTemp("", "syz-db-test") 182 if err != nil { 183 t.Error(err) 184 } 185 186 defer f.Close() 187 defer os.Remove(f.Name()) 188 if _, err := f.Write([]byte(`some invalid data`)); err != nil { 189 t.Error(err) 190 } 191 if db, err := Open(f.Name(), true); err == nil { 192 t.Fatal("opened invalid db") 193 } else if db == nil { 194 t.Fatal("db is nil") 195 } 196 } 197 198 func TestOpenInaccessible(t *testing.T) { 199 if os.Getuid() == 0 { 200 t.Skip("opening inaccessible file won't fail under root") 201 } 202 f, err := os.CreateTemp("", "syz-db-test") 203 if err != nil { 204 t.Error(err) 205 } 206 f.Close() 207 os.Chmod(f.Name(), 0) 208 defer os.Chmod(f.Name(), 0777) 209 defer os.Remove(f.Name()) 210 if db, err := Open(f.Name(), false); err == nil { 211 t.Fatal("opened inaccessible db") 212 } else if db != nil { 213 t.Fatal("db is not nil") 214 } 215 } 216 217 func TestOpenCorrupted(t *testing.T) { 218 fn := tempFile(t) 219 defer os.Remove(fn) 220 db, err := Open(fn, false) 221 if err != nil { 222 t.Fatalf("failed to open db: %v", err) 223 } 224 // Write 1000 records, then wipe half of the file and test that we 225 // (1) get an error, (2) still get 450-550 records. 226 for i := 0; i < 1000; i++ { 227 db.Save(fmt.Sprintf("%v", i), []byte{byte(i)}, 0) 228 } 229 if err := db.Flush(); err != nil { 230 t.Fatalf("failed to flush db: %v", err) 231 } 232 data, err := os.ReadFile(fn) 233 if err != nil { 234 t.Fatalf("failed to read db: %v", err) 235 } 236 for i := len(data) / 2; i < len(data); i++ { 237 data[i] = 0 238 } 239 if err := osutil.WriteFile(fn, data); err != nil { 240 t.Fatalf("failed to write db: %v", err) 241 } 242 db, err = Open(fn, true) 243 if err == nil { 244 t.Fatalf("no error for corrutped db") 245 } 246 t.Logf("records %v, error: %v", len(db.Records), err) 247 if len(db.Records) < 450 || len(db.Records) > 550 { 248 t.Fatalf("wrong record count: %v", len(db.Records)) 249 } 250 } 251 252 func tempFile(t *testing.T) string { 253 fn, err := osutil.TempFile("syzkaller.test.db") 254 if err != nil { 255 t.Fatal(err) 256 } 257 return fn 258 }