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  }