Skip to content

Commit

Permalink
dcrsqlite: create DB-file parent directory when necessary (decred#516)
Browse files Browse the repository at this point in the history
* dcrsqlite: add test to reproduce the issue decred#515

decred#515

* dcrsqlite: create DB-file parent directory when necessary

Fixes decred#515

* dcrsqlite: move test helpers to a testutil package

* testutil functions take *testing.T (#1)
  • Loading branch information
JFixby authored and chappjc committed Jun 30, 2018
1 parent 5e31c50 commit 75f18a3
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,4 @@ ffldb_stake*/
*.pprof
testnet/
.DS_Store
testdata/
1 change: 1 addition & 0 deletions db/dcrsqlite/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test.data
25 changes: 25 additions & 0 deletions db/dcrsqlite/dcrsqlite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package dcrsqlite

import (
"testing"

"github.com/decred/dcrdata/testutil"
)

// TestMissingParentFolder ensures InitDB() is able to create a new DB-file parent directory if necessary
// See https://github.com/decred/dcrdata/issues/515
func TestMissingParentFolder(t *testing.T) {
// Specify DB file in non-existent path
testutil.ResetTempFolder(t)
targetDBFile := testutil.FilePathInsideTempDir(t, "x/y/z/"+testutil.DefaultDBFileName)

dbInfo := &DBInfo{FileName: targetDBFile}
db, err := InitDB(dbInfo)
if err != nil {
t.Fatalf("InitDB() failed: %v", err)
}

if db == nil {
t.Fatalf("InitDB() failed")
}
}
19 changes: 16 additions & 3 deletions db/dcrsqlite/sqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ package dcrsqlite
import (
"database/sql"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"sync"

"github.com/decred/slog"

"github.com/decred/dcrd/wire"
apitypes "github.com/decred/dcrdata/api/types"
"github.com/decred/dcrdata/blockdata"
"github.com/decred/slog"
_ "github.com/mattn/go-sqlite3" // register sqlite driver with database/sql
)

Expand Down Expand Up @@ -146,7 +147,19 @@ func NewDB(db *sql.DB) (*DB, error) {
// InitDB creates a new DB instance from a DBInfo containing the name of the
// file used to back the underlying sql database.
func InitDB(dbInfo *DBInfo) (*DB, error) {
db, err := sql.Open("sqlite3", dbInfo.FileName)
dbPath, err := filepath.Abs(dbInfo.FileName)
if err != nil {
return nil, err
}

// Ensures target DB-file has a parent folder
parent := filepath.Dir(dbPath)
err = os.MkdirAll(parent, 0755)
if err != nil {
return nil, err
}

db, err := sql.Open("sqlite3", dbPath)
if err != nil || db == nil {
return nil, err
}
Expand Down
1 change: 0 additions & 1 deletion stakedb/stakedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,6 @@ func (db *StakeDatabase) ConnectBlock(block *dcrutil.Block) error {

func (db *StakeDatabase) connectBlock(block *dcrutil.Block, spent []chainhash.Hash,
revoked []chainhash.Hash, maturing []chainhash.Hash) error {

hB, err := block.BlockHeaderBytes()
if err != nil {
return fmt.Errorf("unable to serialize block header: %v", err)
Expand Down
45 changes: 45 additions & 0 deletions testutil/tempfiles.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// package testutil provides some helper functions to be used in unit tests.
package testutil

import (
"os"
"path/filepath"
"testing"
)

const (
DefaultDataDirname = "test.data"
DefaultDBFileName = "test.dcrdata.sqlt.db"
)

// TempFolderPath returns path of a temporary directory used by these tests to
// store data.
func TempFolderPath(t *testing.T) string {
testDir, err := filepath.Abs(DefaultDataDirname)
if err != nil {
t.Fatalf("Failed to produce DB-test folder path")
}
return testDir
}

// Ensures we run our test in a clean room. Removes all files created by any of
// these tests in the temp directory.
func ResetTempFolder(t *testing.T) {
testFolderPath := TempFolderPath(t)
err := os.RemoveAll(testFolderPath)
// Failed to clear test-files
if err != nil {
t.Fatalf("Failed to clear temp folder")
}
}

// FilePathInsideTempDir creates a path to a file inside the temp directory.
func FilePathInsideTempDir(t *testing.T, pathInsideTempFolder string) string {
tempDir := TempFolderPath(t)
targetPath := filepath.Join(tempDir, pathInsideTempFolder)
targetPath, err := filepath.Abs(targetPath)
if err != nil {
t.Fatalf("Failed to build a path: " + pathInsideTempFolder)
}
return targetPath
}

0 comments on commit 75f18a3

Please sign in to comment.