diff --git a/db_test.go b/db_test.go index 2063249..b38be93 100644 --- a/db_test.go +++ b/db_test.go @@ -28,13 +28,13 @@ func TestOpen_BadPath(t *testing.T) { // Ensure that a database can be opened without error. func TestOpen(t *testing.T) { - withTempPath(func(path string) { - db, err := Open(path, 0666, nil) - assert.NotNil(t, db) - assert.NoError(t, err) - assert.Equal(t, db.Path(), path) - assert.NoError(t, db.Close()) - }) + path := tempfile() + defer os.Remove(path) + db, err := Open(path, 0666, nil) + assert.NotNil(t, db) + assert.NoError(t, err) + assert.Equal(t, db.Path(), path) + assert.NoError(t, db.Close()) } // Ensure that opening an already open database file will timeout. @@ -42,21 +42,23 @@ func TestOpen_Timeout(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("timeout not supported on windows") } - withTempPath(func(path string) { - // Open a data file. - db0, err := Open(path, 0666, nil) - assert.NotNil(t, db0) - assert.NoError(t, err) - // Attempt to open the database again. - start := time.Now() - db1, err := Open(path, 0666, &Options{Timeout: 100 * time.Millisecond}) - assert.Nil(t, db1) - assert.Equal(t, ErrTimeout, err) - assert.True(t, time.Since(start) > 100*time.Millisecond) + path := tempfile() + defer os.Remove(path) - db0.Close() - }) + // Open a data file. + db0, err := Open(path, 0666, nil) + assert.NotNil(t, db0) + assert.NoError(t, err) + + // Attempt to open the database again. + start := time.Now() + db1, err := Open(path, 0666, &Options{Timeout: 100 * time.Millisecond}) + assert.Nil(t, db1) + assert.Equal(t, ErrTimeout, err) + assert.True(t, time.Since(start) > 100*time.Millisecond) + + db0.Close() } // Ensure that opening an already open database file will wait until its closed. @@ -64,48 +66,52 @@ func TestOpen_Wait(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("timeout not supported on windows") } - withTempPath(func(path string) { - // Open a data file. - db0, err := Open(path, 0666, nil) - assert.NotNil(t, db0) - assert.NoError(t, err) - // Close it in just a bit. - time.AfterFunc(100*time.Millisecond, func() { db0.Close() }) + path := tempfile() + defer os.Remove(path) - // Attempt to open the database again. - start := time.Now() - db1, err := Open(path, 0666, &Options{Timeout: 200 * time.Millisecond}) - assert.NotNil(t, db1) - assert.NoError(t, err) - assert.True(t, time.Since(start) > 100*time.Millisecond) - }) + // Open a data file. + db0, err := Open(path, 0666, nil) + assert.NotNil(t, db0) + assert.NoError(t, err) + + // Close it in just a bit. + time.AfterFunc(100*time.Millisecond, func() { db0.Close() }) + + // Attempt to open the database again. + start := time.Now() + db1, err := Open(path, 0666, &Options{Timeout: 200 * time.Millisecond}) + assert.NotNil(t, db1) + assert.NoError(t, err) + assert.True(t, time.Since(start) > 100*time.Millisecond) } // Ensure that a re-opened database is consistent. func TestOpen_Check(t *testing.T) { - withTempPath(func(path string) { - db, err := Open(path, 0666, nil) - assert.NoError(t, err) - assert.NoError(t, db.View(func(tx *Tx) error { return <-tx.Check() })) - db.Close() + path := tempfile() + defer os.Remove(path) - db, err = Open(path, 0666, nil) - assert.NoError(t, err) - assert.NoError(t, db.View(func(tx *Tx) error { return <-tx.Check() })) - db.Close() - }) + db, err := Open(path, 0666, nil) + assert.NoError(t, err) + assert.NoError(t, db.View(func(tx *Tx) error { return <-tx.Check() })) + db.Close() + + db, err = Open(path, 0666, nil) + assert.NoError(t, err) + assert.NoError(t, db.View(func(tx *Tx) error { return <-tx.Check() })) + db.Close() } // Ensure that the database returns an error if the file handle cannot be open. func TestDB_Open_FileError(t *testing.T) { - withTempPath(func(path string) { - _, err := Open(path+"/youre-not-my-real-parent", 0666, nil) - if err, _ := err.(*os.PathError); assert.Error(t, err) { - assert.Equal(t, path+"/youre-not-my-real-parent", err.Path) - assert.Equal(t, "open", err.Op) - } - }) + path := tempfile() + defer os.Remove(path) + + _, err := Open(path+"/youre-not-my-real-parent", 0666, nil) + if err, _ := err.(*os.PathError); assert.Error(t, err) { + assert.Equal(t, path+"/youre-not-my-real-parent", err.Path) + assert.Equal(t, "open", err.Op) + } } // Ensure that write errors to the meta file handler during initialization are returned. @@ -115,75 +121,78 @@ func TestDB_Open_MetaInitWriteError(t *testing.T) { // Ensure that a database that is too small returns an error. func TestDB_Open_FileTooSmall(t *testing.T) { - withTempPath(func(path string) { - db, err := Open(path, 0666, nil) - assert.NoError(t, err) - db.Close() + path := tempfile() + defer os.Remove(path) - // corrupt the database - assert.NoError(t, os.Truncate(path, int64(os.Getpagesize()))) + db, err := Open(path, 0666, nil) + assert.NoError(t, err) + db.Close() - db, err = Open(path, 0666, nil) - assert.Equal(t, errors.New("file size too small"), err) - }) + // corrupt the database + assert.NoError(t, os.Truncate(path, int64(os.Getpagesize()))) + + db, err = Open(path, 0666, nil) + assert.Equal(t, errors.New("file size too small"), err) } // Ensure that corrupt meta0 page errors get returned. func TestDB_Open_CorruptMeta0(t *testing.T) { - withTempPath(func(path string) { - var m meta - m.magic = magic - m.version = version - m.pageSize = 0x8000 + var m meta + m.magic = magic + m.version = version + m.pageSize = 0x8000 - // Create a file with bad magic. - b := make([]byte, 0x10000) - p0, p1 := (*page)(unsafe.Pointer(&b[0x0000])), (*page)(unsafe.Pointer(&b[0x8000])) - p0.meta().magic = 0 - p0.meta().version = version - p1.meta().magic = magic - p1.meta().version = version - err := ioutil.WriteFile(path, b, 0666) - assert.NoError(t, err) + path := tempfile() + defer os.Remove(path) - // Open the database. - _, err = Open(path, 0666, nil) - assert.Equal(t, err, errors.New("meta0 error: invalid database")) - }) + // Create a file with bad magic. + b := make([]byte, 0x10000) + p0, p1 := (*page)(unsafe.Pointer(&b[0x0000])), (*page)(unsafe.Pointer(&b[0x8000])) + p0.meta().magic = 0 + p0.meta().version = version + p1.meta().magic = magic + p1.meta().version = version + err := ioutil.WriteFile(path, b, 0666) + assert.NoError(t, err) + + // Open the database. + _, err = Open(path, 0666, nil) + assert.Equal(t, err, errors.New("meta0 error: invalid database")) } // Ensure that a corrupt meta page checksum causes the open to fail. func TestDB_Open_MetaChecksumError(t *testing.T) { for i := 0; i < 2; i++ { - withTempPath(func(path string) { - db, err := Open(path, 0600, nil) - pageSize := db.pageSize - db.Update(func(tx *Tx) error { - _, err := tx.CreateBucket([]byte("widgets")) - return err - }) - db.Update(func(tx *Tx) error { - _, err := tx.CreateBucket([]byte("woojits")) - return err - }) - db.Close() + path := tempfile() + defer os.Remove(path) - // Change a single byte in the meta page. - f, _ := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600) - f.WriteAt([]byte{1}, int64((i*pageSize)+(pageHeaderSize+12))) - f.Sync() - f.Close() - - // Reopen the database. - _, err = Open(path, 0600, nil) - if assert.Error(t, err) { - if i == 0 { - assert.Equal(t, "meta0 error: checksum error", err.Error()) - } else { - assert.Equal(t, "meta1 error: checksum error", err.Error()) - } - } + db, err := Open(path, 0600, nil) + pageSize := db.pageSize + db.Update(func(tx *Tx) error { + _, err := tx.CreateBucket([]byte("widgets")) + return err }) + db.Update(func(tx *Tx) error { + _, err := tx.CreateBucket([]byte("woojits")) + return err + }) + db.Close() + + // Change a single byte in the meta page. + f, _ := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600) + f.WriteAt([]byte{1}, int64((i*pageSize)+(pageHeaderSize+12))) + f.Sync() + f.Close() + + // Reopen the database. + _, err = Open(path, 0600, nil) + if assert.Error(t, err) { + if i == 0 { + assert.Equal(t, "meta0 error: checksum error", err.Error()) + } else { + assert.Equal(t, "meta1 error: checksum error", err.Error()) + } + } } } @@ -579,31 +588,25 @@ func tempfile() string { return f.Name() } -// withTempPath executes a function with a database reference. -func withTempPath(fn func(string)) { - path := tempfile() - defer os.RemoveAll(path) - fn(path) -} - // withOpenDB executes a function with an already opened database. func withOpenDB(fn func(*DB, string)) { - withTempPath(func(path string) { - db, err := Open(path, 0666, nil) - if err != nil { - panic("cannot open db: " + err.Error()) - } - defer db.Close() - fn(db, path) + path := tempfile() + defer os.Remove(path) - // Log statistics. - if *statsFlag { - logStats(db) - } + db, err := Open(path, 0666, nil) + if err != nil { + panic("cannot open db: " + err.Error()) + } + defer db.Close() + fn(db, path) - // Check database consistency after every test. - mustCheck(db) - }) + // Log statistics. + if *statsFlag { + logStats(db) + } + + // Check database consistency after every test. + mustCheck(db) } // mustCheck runs a consistency check on the database and panics if any errors are found.