github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/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 ) 15 16 func TestBasic(t *testing.T) { 17 fn := tempFile(t) 18 defer os.Remove(fn) 19 db, err := Open(fn, false) 20 if err != nil { 21 t.Fatalf("failed to open db: %v", err) 22 } 23 if len(db.Records) != 0 { 24 t.Fatalf("empty db contains records") 25 } 26 db.Save("", nil, 0) 27 db.Save("1", []byte("ab"), 1) 28 db.Save("23", []byte("abcd"), 2) 29 30 want := map[string]Record{ 31 "": {Val: nil, Seq: 0}, 32 "1": {Val: []byte("ab"), Seq: 1}, 33 "23": {Val: []byte("abcd"), Seq: 2}, 34 } 35 if !reflect.DeepEqual(db.Records, want) { 36 t.Fatalf("bad db after save: %v, want: %v", db.Records, want) 37 } 38 if err := db.Flush(); err != nil { 39 t.Fatalf("failed to flush db: %v", err) 40 } 41 if !reflect.DeepEqual(db.Records, want) { 42 t.Fatalf("bad db after flush: %v, want: %v", db.Records, want) 43 } 44 db, err = Open(fn, false) 45 if err != nil { 46 t.Fatalf("failed to open db: %v", err) 47 } 48 if !reflect.DeepEqual(db.Records, want) { 49 t.Fatalf("bad db after reopen: %v, want: %v", db.Records, want) 50 } 51 } 52 53 func TestModify(t *testing.T) { 54 fn := tempFile(t) 55 defer os.Remove(fn) 56 db, err := Open(fn, false) 57 if err != nil { 58 t.Fatalf("failed to open db: %v", err) 59 } 60 db.Save("1", []byte("ab"), 0) 61 db.Save("23", nil, 1) 62 db.Save("456", []byte("abcd"), 1) 63 db.Save("7890", []byte("a"), 0) 64 db.Delete("23") 65 db.Save("1", nil, 5) 66 db.Save("456", []byte("ef"), 6) 67 db.Delete("7890") 68 db.Save("456", []byte("efg"), 0) 69 db.Save("7890", []byte("bc"), 0) 70 71 want := map[string]Record{ 72 "1": {Val: nil, Seq: 5}, 73 "456": {Val: []byte("efg"), Seq: 0}, 74 "7890": {Val: []byte("bc"), Seq: 0}, 75 } 76 if !reflect.DeepEqual(db.Records, want) { 77 t.Fatalf("bad db after modification: %v, want: %v", db.Records, want) 78 } 79 if err := db.Flush(); err != nil { 80 t.Fatalf("failed to flush db: %v", err) 81 } 82 if !reflect.DeepEqual(db.Records, want) { 83 t.Fatalf("bad db after flush: %v, want: %v", db.Records, want) 84 } 85 db, err = Open(fn, false) 86 if err != nil { 87 t.Fatalf("failed to open db: %v", err) 88 } 89 if !reflect.DeepEqual(db.Records, want) { 90 t.Fatalf("bad db after reopen: %v, want: %v", db.Records, want) 91 } 92 } 93 94 func TestLarge(t *testing.T) { 95 fn := tempFile(t) 96 defer os.Remove(fn) 97 db, err := Open(fn, false) 98 if err != nil { 99 t.Fatalf("failed to open db: %v", err) 100 } 101 const nrec = 1000 102 val := make([]byte, 1000) 103 for i := range val { 104 val[i] = byte(rand.Intn(256)) 105 } 106 for i := 0; i < nrec; i++ { 107 db.Save(fmt.Sprintf("%v", i), val, 0) 108 } 109 if err := db.Flush(); err != nil { 110 t.Fatalf("failed to flush db: %v", err) 111 } 112 db, err = Open(fn, false) 113 if err != nil { 114 t.Fatalf("failed to open db: %v", err) 115 } 116 if len(db.Records) != nrec { 117 t.Fatalf("wrong record count: %v, want %v", len(db.Records), nrec) 118 } 119 } 120 121 func TestOpenInvalid(t *testing.T) { 122 f, err := os.CreateTemp("", "syz-db-test") 123 if err != nil { 124 t.Error(err) 125 } 126 127 defer f.Close() 128 defer os.Remove(f.Name()) 129 if _, err := f.Write([]byte(`some invalid data`)); err != nil { 130 t.Error(err) 131 } 132 if db, err := Open(f.Name(), true); err == nil { 133 t.Fatal("opened invalid db") 134 } else if db == nil { 135 t.Fatal("db is nil") 136 } 137 } 138 139 func TestOpenInaccessible(t *testing.T) { 140 if os.Getuid() == 0 { 141 t.Skip("opening inaccessible file won't fail under root") 142 } 143 f, err := os.CreateTemp("", "syz-db-test") 144 if err != nil { 145 t.Error(err) 146 } 147 f.Close() 148 os.Chmod(f.Name(), 0) 149 defer os.Chmod(f.Name(), 0777) 150 defer os.Remove(f.Name()) 151 if db, err := Open(f.Name(), false); err == nil { 152 t.Fatal("opened inaccessible db") 153 } else if db != nil { 154 t.Fatal("db is not nil") 155 } 156 } 157 158 func TestOpenCorrupted(t *testing.T) { 159 fn := tempFile(t) 160 defer os.Remove(fn) 161 db, err := Open(fn, false) 162 if err != nil { 163 t.Fatalf("failed to open db: %v", err) 164 } 165 // Write 1000 records, then wipe half of the file and test that we 166 // (1) get an error, (2) still get 450-550 records. 167 for i := 0; i < 1000; i++ { 168 db.Save(fmt.Sprintf("%v", i), []byte{byte(i)}, 0) 169 } 170 if err := db.Flush(); err != nil { 171 t.Fatalf("failed to flush db: %v", err) 172 } 173 data, err := os.ReadFile(fn) 174 if err != nil { 175 t.Fatalf("failed to read db: %v", err) 176 } 177 for i := len(data) / 2; i < len(data); i++ { 178 data[i] = 0 179 } 180 if err := osutil.WriteFile(fn, data); err != nil { 181 t.Fatalf("failed to write db: %v", err) 182 } 183 db, err = Open(fn, true) 184 if err == nil { 185 t.Fatalf("no error for corrutped db") 186 } 187 t.Logf("records %v, error: %v", len(db.Records), err) 188 if len(db.Records) < 450 || len(db.Records) > 550 { 189 t.Fatalf("wrong record count: %v", len(db.Records)) 190 } 191 } 192 193 func tempFile(t *testing.T) string { 194 fn, err := osutil.TempFile("syzkaller.test.db") 195 if err != nil { 196 t.Fatal(err) 197 } 198 return fn 199 }