Let users customize the path to the scouting database
I want to write a script that runs the scouting webserver. For that to
work elegantly, I need to be able to customize the database path.
Otherwise it gets created in the runfiles tree.
Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
Change-Id: I6f06f9b82ca2d3476c76d795ad57b06f7b360ba8
diff --git a/scouting/db/db.go b/scouting/db/db.go
index 86d332e..1d0081b 100644
--- a/scouting/db/db.go
+++ b/scouting/db/db.go
@@ -26,9 +26,11 @@
climbing int
}
-func NewDatabase() (*Database, error) {
+// Opens a database at the specified path. If the path refers to a non-existent
+// file, the database will be created and initialized with empty tables.
+func NewDatabase(path string) (*Database, error) {
database := new(Database)
- database.DB, _ = sql.Open("sqlite3", "./scouting.db")
+ database.DB, _ = sql.Open("sqlite3", path)
statement, error_ := database.Prepare("CREATE TABLE IF NOT EXISTS matches " +
"(id INTEGER PRIMARY KEY, matchNumber INTEGER, round INTEGER, compLevel INTEGER, r1 INTEGER, r2 INTEGER, r3 INTEGER, b1 INTEGER, b2 INTEGER, b3 INTEGER, r1ID INTEGER, r2ID INTEGER, r3ID INTEGER, b1ID INTEGER, b2ID INTEGER, b3ID INTEGER)")
defer statement.Close()
diff --git a/scouting/db/db_test.go b/scouting/db/db_test.go
index 3c6d9c5..39f12e3 100644
--- a/scouting/db/db_test.go
+++ b/scouting/db/db_test.go
@@ -1,16 +1,28 @@
package db
import (
- "fmt"
+ "os"
+ "path/filepath"
"reflect"
"testing"
)
-func TestAddToMatchDB(t *testing.T) {
- db, error_ := NewDatabase()
- if error_ != nil {
- t.Fatalf(error_.Error())
+// Creates a database in TEST_TMPDIR so that we don't accidentally write it
+// into the runfiles directory.
+func createDatabase(t *testing.T) *Database {
+ // Get the path to our temporary writable directory.
+ testTmpdir := os.Getenv("TEST_TMPDIR")
+ db, err := NewDatabase(filepath.Join(testTmpdir, "scouting.db"))
+ if err != nil {
+ t.Fatal("Failed to create a new database: ", err)
}
+ return db
+}
+
+func TestAddToMatchDB(t *testing.T) {
+ db := createDatabase(t)
+ defer db.Delete()
+
correct := []Match{Match{matchNumber: 7, round: 1, compLevel: "quals", r1: 9999, r2: 1000, r3: 777, b1: 0000, b2: 4321, b3: 1234, r1ID: 1, r2ID: 2, r3ID: 3, b1ID: 4, b2ID: 5, b3ID: 6}}
db.AddToMatch(correct[0])
got, error_ := db.ReturnMatches()
@@ -20,14 +32,12 @@
if !reflect.DeepEqual(correct, got) {
t.Fatalf("Got %#v,\nbut expected %#v.", got, correct)
}
- db.Delete()
}
func TestAddToStatsDB(t *testing.T) {
- db, error_ := NewDatabase()
- if error_ != nil {
- t.Fatalf(error_.Error())
- }
+ db := createDatabase(t)
+ defer db.Delete()
+
correct := []Stats{
Stats{teamNumber: 1236, matchNumber: 7, shotsMissed: 9, upperGoalShots: 5, lowerGoalShots: 4, shotsMissedAuto: 3, upperGoalAuto: 2, lowerGoalAuto: 1, playedDefense: 2, climbing: 3},
Stats{teamNumber: 1001, matchNumber: 7, shotsMissed: 6, upperGoalShots: 9, lowerGoalShots: 9, shotsMissedAuto: 0, upperGoalAuto: 0, lowerGoalAuto: 0, playedDefense: 0, climbing: 0},
@@ -47,15 +57,11 @@
if !reflect.DeepEqual(correct, got) {
t.Errorf("Got %#v,\nbut expected %#v.", got, correct)
}
- db.Delete()
}
func TestQueryMatchDB(t *testing.T) {
- db, error_ := NewDatabase()
- if error_ != nil {
- t.Fatalf(error_.Error())
- fmt.Println("Error creating new database")
- }
+ db := createDatabase(t)
+ defer db.Delete()
testDatabase := []Match{
Match{matchNumber: 2, round: 1, compLevel: "quals", r1: 251, r2: 169, r3: 286, b1: 253, b2: 538, b3: 149},
@@ -74,17 +80,18 @@
}
got, error_ := db.QueryMatches(538)
+ if error_ != nil {
+ t.Fatal("Failed to query matches for 538: ", error_)
+ }
if !reflect.DeepEqual(correct, got) {
t.Fatalf("Got %#v,\nbut expected %#v.", got, correct)
}
- db.Delete()
}
func TestQueryStatsDB(t *testing.T) {
- db, error_ := NewDatabase()
- if error_ != nil {
- t.Fatalf(error_.Error())
- }
+ db := createDatabase(t)
+ defer db.Delete()
+
testDatabase := []Stats{
Stats{teamNumber: 1235, matchNumber: 94, shotsMissed: 2, upperGoalShots: 2, lowerGoalShots: 2, shotsMissedAuto: 2, upperGoalAuto: 2, lowerGoalAuto: 2, playedDefense: 2, climbing: 2},
Stats{teamNumber: 1234, matchNumber: 94, shotsMissed: 4, upperGoalShots: 4, lowerGoalShots: 4, shotsMissedAuto: 4, upperGoalAuto: 4, lowerGoalAuto: 4, playedDefense: 7, climbing: 2},
@@ -107,14 +114,12 @@
if !reflect.DeepEqual(correct, got) {
t.Errorf("Got %#v,\nbut expected %#v.", got, correct)
}
- db.Delete()
}
func TestReturnMatchDB(t *testing.T) {
- db, error_ := NewDatabase()
- if error_ != nil {
- t.Fatalf(error_.Error())
- }
+ db := createDatabase(t)
+ defer db.Delete()
+
correct := []Match{
Match{matchNumber: 2, round: 1, compLevel: "quals", r1: 251, r2: 169, r3: 286, b1: 253, b2: 538, b3: 149, r1ID: 1, r2ID: 2, r3ID: 3, b1ID: 4, b2ID: 5, b3ID: 6},
Match{matchNumber: 3, round: 1, compLevel: "quals", r1: 147, r2: 421, r3: 538, b1: 126, b2: 448, b3: 262, r1ID: 7, r2ID: 8, r3ID: 9, b1ID: 10, b2ID: 11, b3ID: 12},
@@ -132,14 +137,12 @@
if !reflect.DeepEqual(correct, got) {
t.Errorf("Got %#v,\nbut expected %#v.", got, correct)
}
- db.Delete()
}
func TestReturnStatsDB(t *testing.T) {
- db, error_ := NewDatabase()
- if error_ != nil {
- t.Fatalf(error_.Error())
- }
+ db := createDatabase(t)
+ defer db.Delete()
+
correct := []Stats{
Stats{teamNumber: 1235, matchNumber: 94, shotsMissed: 2, upperGoalShots: 2, lowerGoalShots: 2, shotsMissedAuto: 2, upperGoalAuto: 2, lowerGoalAuto: 2, playedDefense: 2, climbing: 2},
Stats{teamNumber: 1236, matchNumber: 94, shotsMissed: 4, upperGoalShots: 4, lowerGoalShots: 4, shotsMissedAuto: 4, upperGoalAuto: 4, lowerGoalAuto: 4, playedDefense: 7, climbing: 2},
@@ -159,5 +162,4 @@
if !reflect.DeepEqual(correct, got) {
t.Errorf("Got %#v,\nbut expected %#v.", got, correct)
}
- db.Delete()
}
diff --git a/scouting/webserver/main.go b/scouting/webserver/main.go
index 668104b..3c699fd 100644
--- a/scouting/webserver/main.go
+++ b/scouting/webserver/main.go
@@ -3,9 +3,11 @@
import (
"flag"
"fmt"
+ "io/ioutil"
"log"
"os"
"os/signal"
+ "path/filepath"
"syscall"
"github.com/frc971/971-Robot-Code/scouting/db"
@@ -14,12 +16,33 @@
"github.com/frc971/971-Robot-Code/scouting/webserver/static"
)
+func getDefaultDatabasePath() string {
+ // If using `bazel run`, let's create the database in the root of the
+ // workspace.
+ workspaceDir := os.Getenv("BUILD_WORKSPACE_DIRECTORY")
+ if workspaceDir != "" {
+ return filepath.Join(workspaceDir, "scouting.db")
+ }
+ // If we're inside a `bazel test`, then we will create the database in
+ // a temporary directory.
+ testTempDir := os.Getenv("TEST_TMPDIR")
+ if testTempDir != "" {
+ tempDir, err := ioutil.TempDir(testTempDir, "db")
+ if err != nil {
+ log.Fatal("Failed to create temporary directory in TEST_TMPDIR: ", err)
+ }
+ return filepath.Join(tempDir, "scouting.db")
+ }
+ return filepath.Join(".", "scouting.db")
+}
+
func main() {
portPtr := flag.Int("port", 8080, "The port number to bind to.")
dirPtr := flag.String("directory", ".", "The directory to serve at /.")
+ dbPathPtr := flag.String("database", getDefaultDatabasePath(), "The path to the database.")
flag.Parse()
- database, err := db.NewDatabase()
+ database, err := db.NewDatabase(*dbPathPtr)
if err != nil {
log.Fatal("Failed to connect to database: ", err)
}
diff --git a/scouting/webserver/requests/debug/cli/cli_test.py b/scouting/webserver/requests/debug/cli/cli_test.py
index 925cb99..682e179 100644
--- a/scouting/webserver/requests/debug/cli/cli_test.py
+++ b/scouting/webserver/requests/debug/cli/cli_test.py
@@ -31,12 +31,7 @@
class TestDebugCli(unittest.TestCase):
def setUp(self):
- # Since the webserver creates a database in the current directory,
- # let's run the test in TEST_TMPDIR where we can do whatever we want.
- self.webserver_working_dir = Path(os.environ["TEST_TMPDIR"]) / "webserver"
- os.mkdir(self.webserver_working_dir)
- webserver_path = os.path.abspath("scouting/webserver/webserver_/webserver")
- self.webserver = subprocess.Popen([webserver_path], cwd=self.webserver_working_dir)
+ self.webserver = subprocess.Popen(["scouting/webserver/webserver_/webserver"])
# Wait for the server to respond to requests.
while True:
@@ -52,7 +47,6 @@
def tearDown(self):
self.webserver.terminate()
self.webserver.wait()
- shutil.rmtree(self.webserver_working_dir)
def test_submit_data_scouting(self):
json_path = write_json({