unit-test return the right errors for locked DBs
This commit is contained in:
parent
77a48ca9cb
commit
bd5b8ee815
@ -6,6 +6,7 @@ package database
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"gomark/logging"
|
"gomark/logging"
|
||||||
"gomark/tree"
|
"gomark/tree"
|
||||||
@ -78,16 +79,24 @@ type DsnOptions map[string]string
|
|||||||
|
|
||||||
type DBError struct {
|
type DBError struct {
|
||||||
// Database object where error occured
|
// Database object where error occured
|
||||||
D *DB
|
DBName string
|
||||||
|
|
||||||
// Error that occured
|
// Error that occured
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e DBError) Error() string {
|
func DBErr(dbName string, err error) DBError {
|
||||||
return fmt.Sprintf("<%s>: %s", e.D.Name, e.Err)
|
return DBError{Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e DBError) Error() string {
|
||||||
|
return fmt.Sprintf("<%s>: %s", e.DBName, e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrVfsLocked = errors.New("vfs locked")
|
||||||
|
)
|
||||||
|
|
||||||
type Opener interface {
|
type Opener interface {
|
||||||
Open(driver string, dsn string) error
|
Open(driver string, dsn string) error
|
||||||
}
|
}
|
||||||
@ -208,6 +217,7 @@ func New(name string, dbPath string, dbFormat string, opts ...DsnOptions) *DB {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: try unlock at the browser level !
|
||||||
func (db *DB) tryUnlock() error {
|
func (db *DB) tryUnlock() error {
|
||||||
log.Debug("Unlocking ...")
|
log.Debug("Unlocking ...")
|
||||||
|
|
||||||
@ -239,12 +249,11 @@ func (db *DB) Init() (*DB, error) {
|
|||||||
locked, err := db.Locked()
|
locked, err := db.Locked()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, DBError{D: db, Err: err}
|
return nil, DBError{DBName: db.Name, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if locked {
|
if locked {
|
||||||
log.Warningf("<%s> is locked !", db.Path)
|
return nil, DBErr(db.Name, ErrVfsLocked)
|
||||||
db.tryUnlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -256,13 +265,13 @@ func (db *DB) Init() (*DB, error) {
|
|||||||
|
|
||||||
// Secondary lock check provided by sqlx Ping() method
|
// Secondary lock check provided by sqlx Ping() method
|
||||||
if err != nil && sqlErr.Code == sqlite3.ErrBusy {
|
if err != nil && sqlErr.Code == sqlite3.ErrBusy {
|
||||||
return nil, DBError{D: db, Err: err}
|
return nil, DBError{DBName: db.Name, Err: err}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return all other errors
|
// Return all other errors
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, DBError{D: db, Err: err}
|
return nil, DBError{DBName: db.Name, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
return db, nil
|
return db, nil
|
||||||
@ -273,20 +282,20 @@ func (db *DB) InitSchema() error {
|
|||||||
// Populate db schema
|
// Populate db schema
|
||||||
tx, err := db.Handle.Begin()
|
tx, err := db.Handle.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DBError{D: db, Err: err}
|
return DBError{DBName: db.Name, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt, err := tx.Prepare(QCreateGomarkDBSchema)
|
stmt, err := tx.Prepare(QCreateGomarkDBSchema)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DBError{D: db, Err: err}
|
return DBError{DBName: db.Name, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = stmt.Exec(); err != nil {
|
if _, err = stmt.Exec(); err != nil {
|
||||||
return DBError{D: db, Err: err}
|
return DBError{DBName: db.Name, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = tx.Commit(); err != nil {
|
if err = tx.Commit(); err != nil {
|
||||||
return DBError{D: db, Err: err}
|
return DBError{DBName: db.Name, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("<%s> initialized", db.Name)
|
log.Debugf("<%s> initialized", db.Name)
|
||||||
|
@ -72,11 +72,11 @@ func TestNew(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AlwaysLockedChecker struct {
|
type AlwaysLockedChecker struct {
|
||||||
err error
|
locked bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *AlwaysLockedChecker) Locked() (bool, error) {
|
func (f *AlwaysLockedChecker) Locked() (bool, error) {
|
||||||
return true, nil
|
return f.locked, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type LockedSQLXOpener struct {
|
type LockedSQLXOpener struct {
|
||||||
@ -99,42 +99,57 @@ func TestInitLocked(t *testing.T) {
|
|||||||
err: sqlite3.Error{Code: sqlite3.ErrBusy},
|
err: sqlite3.Error{Code: sqlite3.ErrBusy},
|
||||||
}
|
}
|
||||||
|
|
||||||
lockChecker := &AlwaysLockedChecker{}
|
lockCheckerTrue := &AlwaysLockedChecker{locked: true}
|
||||||
|
lockCheckerFalse := &AlwaysLockedChecker{locked: false}
|
||||||
|
|
||||||
|
t.Run("VFSLockChecker", func(t *testing.T) {
|
||||||
|
|
||||||
testDB := &DB{
|
testDB := &DB{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Path: "file:test",
|
Path: "file:test",
|
||||||
EngineMode: DriverDefault,
|
EngineMode: DriverDefault,
|
||||||
|
LockChecker: lockCheckerTrue,
|
||||||
SQLXOpener: lockedOpener,
|
SQLXOpener: lockedOpener,
|
||||||
Type: DBTypeRegularFile,
|
Type: DBTypeRegularFile,
|
||||||
LockChecker: lockChecker,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := testDB.Init()
|
_, err := testDB.Init()
|
||||||
|
|
||||||
if err != nil {
|
if err == nil {
|
||||||
t.Log(err)
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
t.Run("VFSLockChecker", func(t *testing.T) {
|
if err != DBErr(testDB.Name, ErrVfsLocked) {
|
||||||
|
t.Fail()
|
||||||
t.Error("TODO")
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("SQLXLockChecker", func(t *testing.T) {
|
t.Run("SQLXLockChecker", func(t *testing.T) {
|
||||||
|
|
||||||
e, _ := err.(DBError).Err.(sqlite3.Error)
|
testDB := &DB{
|
||||||
|
Name: "test",
|
||||||
|
Path: "file:test",
|
||||||
|
EngineMode: DriverDefault,
|
||||||
|
LockChecker: lockCheckerFalse,
|
||||||
|
SQLXOpener: lockedOpener,
|
||||||
|
Type: DBTypeRegularFile,
|
||||||
|
}
|
||||||
|
|
||||||
if e.Code == sqlite3.ErrBusy {
|
_, err := testDB.Init()
|
||||||
t.Error("should handle locked database")
|
|
||||||
} else {
|
if err == nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
e, _ := err.(DBError).Err.(sqlite3.Error)
|
||||||
|
|
||||||
|
if e.Code != sqlite3.ErrBusy {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
t.Error("TODO")
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGomarkDBCeate(t *testing.T) {
|
func TestGomarkDBCeate(t *testing.T) {
|
||||||
|
@ -140,6 +140,8 @@ func NewFFBrowser() IBrowser {
|
|||||||
bookmarkPath,
|
bookmarkPath,
|
||||||
database.DBTypeFileDSN, opts).Init()
|
database.DBTypeFileDSN, opts).Init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
|
//Check Lock Error
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user