mirror of https://github.com/hak5/bolt.git
Make bolt.Open return the documented errors
- ErrInvalid is returned when a data file is not a Bolt-formatted database. - ErrVersionMismatch is returned when the data file was created with a different version of Bolt. - ErrChecksum is returned when either meta page checksum does not match. Also: - Do not wrap errors from os.Stat, so that a caller could handle os.Stat errors just like it can handle errors from os.Open that bolt.Open might return. - Name tests consistently, following the pattern "TestOpen_*". - Remove deferred calls to `os.Remove(path)`. The calls are not only unnecessary, but also in all cases `os.Remove` returns an error that is ignored. All those calls are meant to remove a file that was already removed by `tmpfile()`. - Combine "bad path" tests and use filepath.Join to build the path.master
parent
b34b35ea8d
commit
058a7ab347
8
db.go
8
db.go
|
@ -177,7 +177,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
|
|||
|
||||
// Initialize the database if it doesn't exist.
|
||||
if info, err := db.file.Stat(); err != nil {
|
||||
return nil, fmt.Errorf("stat error: %s", err)
|
||||
return nil, err
|
||||
} else if info.Size() == 0 {
|
||||
// Initialize new files with meta pages.
|
||||
if err := db.init(); err != nil {
|
||||
|
@ -189,7 +189,7 @@ func Open(path string, mode os.FileMode, options *Options) (*DB, error) {
|
|||
if _, err := db.file.ReadAt(buf[:], 0); err == nil {
|
||||
m := db.pageInBuffer(buf[:], 0).meta()
|
||||
if err := m.validate(); err != nil {
|
||||
return nil, fmt.Errorf("meta0 error: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
db.pageSize = int(m.pageSize)
|
||||
}
|
||||
|
@ -253,10 +253,10 @@ func (db *DB) mmap(minsz int) error {
|
|||
|
||||
// Validate the meta pages.
|
||||
if err := db.meta0.validate(); err != nil {
|
||||
return fmt.Errorf("meta0 error: %s", err)
|
||||
return err
|
||||
}
|
||||
if err := db.meta1.validate(); err != nil {
|
||||
return fmt.Errorf("meta1 error: %s", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
118
db_test.go
118
db_test.go
|
@ -7,29 +7,48 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
var statsFlag = flag.Bool("stats", false, "show performance stats")
|
||||
|
||||
// Ensure that opening a database with a bad path returns an error.
|
||||
func TestOpen_BadPath(t *testing.T) {
|
||||
db, err := bolt.Open("", 0666, nil)
|
||||
assert(t, err != nil, "err: %s", err)
|
||||
assert(t, db == nil, "")
|
||||
// version is the data file format version.
|
||||
const version = 2
|
||||
|
||||
// magic is the marker value to indicate that a file is a Bolt DB.
|
||||
const magic uint32 = 0xED0CDAED
|
||||
|
||||
// pageSize is the size of one page in the data file.
|
||||
const pageSize = 4096
|
||||
|
||||
// pageHeaderSize is the size of a page header.
|
||||
const pageHeaderSize = 16
|
||||
|
||||
// meta represents a simplified version of a database meta page for testing.
|
||||
type meta struct {
|
||||
magic uint32
|
||||
version uint32
|
||||
_ uint32
|
||||
_ uint32
|
||||
_ [16]byte
|
||||
_ uint64
|
||||
_ uint64
|
||||
_ uint64
|
||||
checksum uint64
|
||||
}
|
||||
|
||||
// Ensure that a database can be opened without error.
|
||||
func TestOpen(t *testing.T) {
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
db, err := bolt.Open(path, 0666, nil)
|
||||
assert(t, db != nil, "")
|
||||
ok(t, err)
|
||||
|
@ -37,6 +56,73 @@ func TestOpen(t *testing.T) {
|
|||
ok(t, db.Close())
|
||||
}
|
||||
|
||||
// Ensure that opening a database with a bad path returns an error.
|
||||
func TestOpen_BadPath(t *testing.T) {
|
||||
for _, path := range []string{
|
||||
"",
|
||||
filepath.Join(tempfile(), "youre-not-my-real-parent"),
|
||||
} {
|
||||
t.Logf("path = %q", path)
|
||||
db, err := bolt.Open(path, 0666, nil)
|
||||
assert(t, err != nil, "err: %s", err)
|
||||
equals(t, path, err.(*os.PathError).Path)
|
||||
equals(t, "open", err.(*os.PathError).Op)
|
||||
equals(t, (*bolt.DB)(nil), db)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that opening a file with wrong checksum returns ErrChecksum.
|
||||
func TestOpen_ErrChecksum(t *testing.T) {
|
||||
buf := make([]byte, pageSize)
|
||||
meta := (*meta)(unsafe.Pointer(&buf[0]))
|
||||
meta.magic = magic
|
||||
meta.version = version
|
||||
meta.checksum = 123
|
||||
|
||||
path := tempfile()
|
||||
f, err := os.Create(path)
|
||||
equals(t, nil, err)
|
||||
f.WriteAt(buf, pageHeaderSize)
|
||||
f.Close()
|
||||
defer os.Remove(path)
|
||||
|
||||
_, err = bolt.Open(path, 0666, nil)
|
||||
equals(t, bolt.ErrChecksum, err)
|
||||
}
|
||||
|
||||
// Ensure that opening a file that is not a Bolt database returns ErrInvalid.
|
||||
func TestOpen_ErrInvalid(t *testing.T) {
|
||||
path := tempfile()
|
||||
|
||||
f, err := os.Create(path)
|
||||
equals(t, nil, err)
|
||||
fmt.Fprintln(f, "this is not a bolt database")
|
||||
f.Close()
|
||||
defer os.Remove(path)
|
||||
|
||||
_, err = bolt.Open(path, 0666, nil)
|
||||
equals(t, bolt.ErrInvalid, err)
|
||||
}
|
||||
|
||||
// Ensure that opening a file created with a different version of Bolt returns
|
||||
// ErrVersionMismatch.
|
||||
func TestOpen_ErrVersionMismatch(t *testing.T) {
|
||||
buf := make([]byte, pageSize)
|
||||
meta := (*meta)(unsafe.Pointer(&buf[0]))
|
||||
meta.magic = magic
|
||||
meta.version = version + 100
|
||||
|
||||
path := tempfile()
|
||||
f, err := os.Create(path)
|
||||
equals(t, nil, err)
|
||||
f.WriteAt(buf, pageHeaderSize)
|
||||
f.Close()
|
||||
defer os.Remove(path)
|
||||
|
||||
_, err = bolt.Open(path, 0666, nil)
|
||||
equals(t, bolt.ErrVersionMismatch, err)
|
||||
}
|
||||
|
||||
// Ensure that opening an already open database file will timeout.
|
||||
func TestOpen_Timeout(t *testing.T) {
|
||||
if runtime.GOOS == "solaris" {
|
||||
|
@ -44,7 +130,6 @@ func TestOpen_Timeout(t *testing.T) {
|
|||
}
|
||||
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
// Open a data file.
|
||||
db0, err := bolt.Open(path, 0666, nil)
|
||||
|
@ -68,7 +153,6 @@ func TestOpen_Wait(t *testing.T) {
|
|||
}
|
||||
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
// Open a data file.
|
||||
db0, err := bolt.Open(path, 0666, nil)
|
||||
|
@ -179,7 +263,6 @@ func TestOpen_Size_Large(t *testing.T) {
|
|||
// Ensure that a re-opened database is consistent.
|
||||
func TestOpen_Check(t *testing.T) {
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
db, err := bolt.Open(path, 0666, nil)
|
||||
ok(t, err)
|
||||
|
@ -192,26 +275,14 @@ func TestOpen_Check(t *testing.T) {
|
|||
db.Close()
|
||||
}
|
||||
|
||||
// Ensure that the database returns an error if the file handle cannot be open.
|
||||
func TestDB_Open_FileError(t *testing.T) {
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
_, err := bolt.Open(path+"/youre-not-my-real-parent", 0666, nil)
|
||||
assert(t, err.(*os.PathError) != nil, "")
|
||||
equals(t, path+"/youre-not-my-real-parent", err.(*os.PathError).Path)
|
||||
equals(t, "open", err.(*os.PathError).Op)
|
||||
}
|
||||
|
||||
// Ensure that write errors to the meta file handler during initialization are returned.
|
||||
func TestDB_Open_MetaInitWriteError(t *testing.T) {
|
||||
func TestOpen_MetaInitWriteError(t *testing.T) {
|
||||
t.Skip("pending")
|
||||
}
|
||||
|
||||
// Ensure that a database that is too small returns an error.
|
||||
func TestDB_Open_FileTooSmall(t *testing.T) {
|
||||
func TestOpen_FileTooSmall(t *testing.T) {
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
db, err := bolt.Open(path, 0666, nil)
|
||||
ok(t, err)
|
||||
|
@ -235,7 +306,6 @@ func TestOpen_ReadOnly(t *testing.T) {
|
|||
bucket, key, value := []byte(`bucket`), []byte(`key`), []byte(`value`)
|
||||
|
||||
path := tempfile()
|
||||
defer os.Remove(path)
|
||||
|
||||
// Open in read-write mode.
|
||||
db, err := bolt.Open(path, 0666, nil)
|
||||
|
|
Loading…
Reference in New Issue