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.
|
// Initialize the database if it doesn't exist.
|
||||||
if info, err := db.file.Stat(); err != nil {
|
if info, err := db.file.Stat(); err != nil {
|
||||||
return nil, fmt.Errorf("stat error: %s", err)
|
return nil, err
|
||||||
} else if info.Size() == 0 {
|
} else if info.Size() == 0 {
|
||||||
// Initialize new files with meta pages.
|
// Initialize new files with meta pages.
|
||||||
if err := db.init(); err != nil {
|
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 {
|
if _, err := db.file.ReadAt(buf[:], 0); err == nil {
|
||||||
m := db.pageInBuffer(buf[:], 0).meta()
|
m := db.pageInBuffer(buf[:], 0).meta()
|
||||||
if err := m.validate(); err != nil {
|
if err := m.validate(); err != nil {
|
||||||
return nil, fmt.Errorf("meta0 error: %s", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
db.pageSize = int(m.pageSize)
|
db.pageSize = int(m.pageSize)
|
||||||
}
|
}
|
||||||
|
@ -253,10 +253,10 @@ func (db *DB) mmap(minsz int) error {
|
||||||
|
|
||||||
// Validate the meta pages.
|
// Validate the meta pages.
|
||||||
if err := db.meta0.validate(); err != nil {
|
if err := db.meta0.validate(); err != nil {
|
||||||
return fmt.Errorf("meta0 error: %s", err)
|
return err
|
||||||
}
|
}
|
||||||
if err := db.meta1.validate(); err != nil {
|
if err := db.meta1.validate(); err != nil {
|
||||||
return fmt.Errorf("meta1 error: %s", err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
118
db_test.go
118
db_test.go
|
@ -7,29 +7,48 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"github.com/boltdb/bolt"
|
"github.com/boltdb/bolt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var statsFlag = flag.Bool("stats", false, "show performance stats")
|
var statsFlag = flag.Bool("stats", false, "show performance stats")
|
||||||
|
|
||||||
// Ensure that opening a database with a bad path returns an error.
|
// version is the data file format version.
|
||||||
func TestOpen_BadPath(t *testing.T) {
|
const version = 2
|
||||||
db, err := bolt.Open("", 0666, nil)
|
|
||||||
assert(t, err != nil, "err: %s", err)
|
// magic is the marker value to indicate that a file is a Bolt DB.
|
||||||
assert(t, db == nil, "")
|
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.
|
// Ensure that a database can be opened without error.
|
||||||
func TestOpen(t *testing.T) {
|
func TestOpen(t *testing.T) {
|
||||||
path := tempfile()
|
path := tempfile()
|
||||||
defer os.Remove(path)
|
|
||||||
db, err := bolt.Open(path, 0666, nil)
|
db, err := bolt.Open(path, 0666, nil)
|
||||||
assert(t, db != nil, "")
|
assert(t, db != nil, "")
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
@ -37,6 +56,73 @@ func TestOpen(t *testing.T) {
|
||||||
ok(t, db.Close())
|
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.
|
// Ensure that opening an already open database file will timeout.
|
||||||
func TestOpen_Timeout(t *testing.T) {
|
func TestOpen_Timeout(t *testing.T) {
|
||||||
if runtime.GOOS == "solaris" {
|
if runtime.GOOS == "solaris" {
|
||||||
|
@ -44,7 +130,6 @@ func TestOpen_Timeout(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
path := tempfile()
|
path := tempfile()
|
||||||
defer os.Remove(path)
|
|
||||||
|
|
||||||
// Open a data file.
|
// Open a data file.
|
||||||
db0, err := bolt.Open(path, 0666, nil)
|
db0, err := bolt.Open(path, 0666, nil)
|
||||||
|
@ -68,7 +153,6 @@ func TestOpen_Wait(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
path := tempfile()
|
path := tempfile()
|
||||||
defer os.Remove(path)
|
|
||||||
|
|
||||||
// Open a data file.
|
// Open a data file.
|
||||||
db0, err := bolt.Open(path, 0666, nil)
|
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.
|
// Ensure that a re-opened database is consistent.
|
||||||
func TestOpen_Check(t *testing.T) {
|
func TestOpen_Check(t *testing.T) {
|
||||||
path := tempfile()
|
path := tempfile()
|
||||||
defer os.Remove(path)
|
|
||||||
|
|
||||||
db, err := bolt.Open(path, 0666, nil)
|
db, err := bolt.Open(path, 0666, nil)
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
@ -192,26 +275,14 @@ func TestOpen_Check(t *testing.T) {
|
||||||
db.Close()
|
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.
|
// 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")
|
t.Skip("pending")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that a database that is too small returns an error.
|
// 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()
|
path := tempfile()
|
||||||
defer os.Remove(path)
|
|
||||||
|
|
||||||
db, err := bolt.Open(path, 0666, nil)
|
db, err := bolt.Open(path, 0666, nil)
|
||||||
ok(t, err)
|
ok(t, err)
|
||||||
|
@ -235,7 +306,6 @@ func TestOpen_ReadOnly(t *testing.T) {
|
||||||
bucket, key, value := []byte(`bucket`), []byte(`key`), []byte(`value`)
|
bucket, key, value := []byte(`bucket`), []byte(`key`), []byte(`value`)
|
||||||
|
|
||||||
path := tempfile()
|
path := tempfile()
|
||||||
defer os.Remove(path)
|
|
||||||
|
|
||||||
// Open in read-write mode.
|
// Open in read-write mode.
|
||||||
db, err := bolt.Open(path, 0666, nil)
|
db, err := bolt.Open(path, 0666, nil)
|
||||||
|
|
Loading…
Reference in New Issue