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.
|
// Ensure that a database can be opened without error.
|
||||||
func TestOpen(t *testing.T) {
|
func TestOpen(t *testing.T) {
|
||||||
withTempPath(func(path string) {
|
path := tempfile()
|
||||||
db, err := Open(path, 0666, nil)
|
defer os.Remove(path)
|
||||||
assert.NotNil(t, db)
|
db, err := Open(path, 0666, nil)
|
||||||
assert.NoError(t, err)
|
assert.NotNil(t, db)
|
||||||
assert.Equal(t, db.Path(), path)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, db.Close())
|
assert.Equal(t, db.Path(), path)
|
||||||
})
|
assert.NoError(t, db.Close())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that opening an already open database file will timeout.
|
// Ensure that opening an already open database file will timeout.
|
||||||
|
@ -42,21 +42,23 @@ func TestOpen_Timeout(t *testing.T) {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
t.Skip("timeout not supported on 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.
|
path := tempfile()
|
||||||
start := time.Now()
|
defer os.Remove(path)
|
||||||
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()
|
// 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.
|
// 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" {
|
if runtime.GOOS == "windows" {
|
||||||
t.Skip("timeout not supported on 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.
|
path := tempfile()
|
||||||
time.AfterFunc(100*time.Millisecond, func() { db0.Close() })
|
defer os.Remove(path)
|
||||||
|
|
||||||
// Attempt to open the database again.
|
// Open a data file.
|
||||||
start := time.Now()
|
db0, err := Open(path, 0666, nil)
|
||||||
db1, err := Open(path, 0666, &Options{Timeout: 200 * time.Millisecond})
|
assert.NotNil(t, db0)
|
||||||
assert.NotNil(t, db1)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.True(t, time.Since(start) > 100*time.Millisecond)
|
// 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.
|
// Ensure that a re-opened database is consistent.
|
||||||
func TestOpen_Check(t *testing.T) {
|
func TestOpen_Check(t *testing.T) {
|
||||||
withTempPath(func(path string) {
|
path := tempfile()
|
||||||
db, err := Open(path, 0666, nil)
|
defer os.Remove(path)
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NoError(t, db.View(func(tx *Tx) error { return <-tx.Check() }))
|
|
||||||
db.Close()
|
|
||||||
|
|
||||||
db, err = Open(path, 0666, nil)
|
db, err := Open(path, 0666, nil)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, db.View(func(tx *Tx) error { return <-tx.Check() }))
|
assert.NoError(t, db.View(func(tx *Tx) error { return <-tx.Check() }))
|
||||||
db.Close()
|
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.
|
// Ensure that the database returns an error if the file handle cannot be open.
|
||||||
func TestDB_Open_FileError(t *testing.T) {
|
func TestDB_Open_FileError(t *testing.T) {
|
||||||
withTempPath(func(path string) {
|
path := tempfile()
|
||||||
_, err := Open(path+"/youre-not-my-real-parent", 0666, nil)
|
defer os.Remove(path)
|
||||||
if err, _ := err.(*os.PathError); assert.Error(t, err) {
|
|
||||||
assert.Equal(t, path+"/youre-not-my-real-parent", err.Path)
|
_, err := Open(path+"/youre-not-my-real-parent", 0666, nil)
|
||||||
assert.Equal(t, "open", err.Op)
|
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.
|
// 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.
|
// Ensure that a database that is too small returns an error.
|
||||||
func TestDB_Open_FileTooSmall(t *testing.T) {
|
func TestDB_Open_FileTooSmall(t *testing.T) {
|
||||||
withTempPath(func(path string) {
|
path := tempfile()
|
||||||
db, err := Open(path, 0666, nil)
|
defer os.Remove(path)
|
||||||
assert.NoError(t, err)
|
|
||||||
db.Close()
|
|
||||||
|
|
||||||
// corrupt the database
|
db, err := Open(path, 0666, nil)
|
||||||
assert.NoError(t, os.Truncate(path, int64(os.Getpagesize())))
|
assert.NoError(t, err)
|
||||||
|
db.Close()
|
||||||
|
|
||||||
db, err = Open(path, 0666, nil)
|
// corrupt the database
|
||||||
assert.Equal(t, errors.New("file size too small"), err)
|
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.
|
// Ensure that corrupt meta0 page errors get returned.
|
||||||
func TestDB_Open_CorruptMeta0(t *testing.T) {
|
func TestDB_Open_CorruptMeta0(t *testing.T) {
|
||||||
withTempPath(func(path string) {
|
var m meta
|
||||||
var m meta
|
m.magic = magic
|
||||||
m.magic = magic
|
m.version = version
|
||||||
m.version = version
|
m.pageSize = 0x8000
|
||||||
m.pageSize = 0x8000
|
|
||||||
|
|
||||||
// Create a file with bad magic.
|
path := tempfile()
|
||||||
b := make([]byte, 0x10000)
|
defer os.Remove(path)
|
||||||
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.
|
// Create a file with bad magic.
|
||||||
_, err = Open(path, 0666, nil)
|
b := make([]byte, 0x10000)
|
||||||
assert.Equal(t, err, errors.New("meta0 error: invalid database"))
|
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.
|
// Ensure that a corrupt meta page checksum causes the open to fail.
|
||||||
func TestDB_Open_MetaChecksumError(t *testing.T) {
|
func TestDB_Open_MetaChecksumError(t *testing.T) {
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
withTempPath(func(path string) {
|
path := tempfile()
|
||||||
db, err := Open(path, 0600, nil)
|
defer os.Remove(path)
|
||||||
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.
|
db, err := Open(path, 0600, nil)
|
||||||
f, _ := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
|
pageSize := db.pageSize
|
||||||
f.WriteAt([]byte{1}, int64((i*pageSize)+(pageHeaderSize+12)))
|
db.Update(func(tx *Tx) error {
|
||||||
f.Sync()
|
_, err := tx.CreateBucket([]byte("widgets"))
|
||||||
f.Close()
|
return err
|
||||||
|
|
||||||
// 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.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()
|
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.
|
// withOpenDB executes a function with an already opened database.
|
||||||
func withOpenDB(fn func(*DB, string)) {
|
func withOpenDB(fn func(*DB, string)) {
|
||||||
withTempPath(func(path string) {
|
path := tempfile()
|
||||||
db, err := Open(path, 0666, nil)
|
defer os.Remove(path)
|
||||||
if err != nil {
|
|
||||||
panic("cannot open db: " + err.Error())
|
|
||||||
}
|
|
||||||
defer db.Close()
|
|
||||||
fn(db, path)
|
|
||||||
|
|
||||||
// Log statistics.
|
db, err := Open(path, 0666, nil)
|
||||||
if *statsFlag {
|
if err != nil {
|
||||||
logStats(db)
|
panic("cannot open db: " + err.Error())
|
||||||
}
|
}
|
||||||
|
defer db.Close()
|
||||||
|
fn(db, path)
|
||||||
|
|
||||||
// Check database consistency after every test.
|
// Log statistics.
|
||||||
mustCheck(db)
|
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.
|
// mustCheck runs a consistency check on the database and panics if any errors are found.
|
||||||
|
|
Loading…
Reference in New Issue