mirror of https://github.com/etcd-io/bbolt.git
Remove withTempPath() helper.
parent
d021755f07
commit
06222e06de
255
db_test.go
255
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.
|
||||
|
|
Loading…
Reference in New Issue