Merge "Use nanoseconds instead of seconds as unique db ID."
diff --git a/cherry/rpc.go b/cherry/rpc.go
index 579b8b8..5c42682 100644
--- a/cherry/rpc.go
+++ b/cherry/rpc.go
@@ -108,8 +108,7 @@
 
 	// Generate time-based id for batch result.
 	startTime := time.Now()
-	batchResultId	:= startTime.Format(time.RFC3339)
-	batchResultName	:= startTime.Format(defaultHumanReadableTimeFormat)
+	batchResultName := startTime.Format(defaultHumanReadableTimeFormat)
 
 	// Execute tests in background.
 	execParams := BatchExecParams {
@@ -127,7 +126,8 @@
 		// tests
 		TestNameFilters:		strings.Split(args.TestNameFilters, ";"),
 	}
-	handler.testRunner.ExecuteTestBatch(batchResultId, batchResultName, execParams, startTime)
+	batchResultId, err := handler.testRunner.ExecuteTestBatch(batchResultName, execParams, startTime)
+	if err != nil { return "", err }
 
 	return batchResultId, nil
 }
@@ -153,12 +153,12 @@
 
 	// Generate time-based id for batch result.
 	startTime := time.Now()
-	batchResultId	:= startTime.Format(time.RFC3339)
-	batchResultName	:= startTime.Format(defaultHumanReadableTimeFormat)
+	batchResultName := startTime.Format(defaultHumanReadableTimeFormat)
 
 	testCasePaths := filterTestCaseNames(originalCaseList.Paths, strings.Split(args.TestNameFilters, ";"))
 
-	handler.testRunner.ExecuteTestBatchWithCaseList(batchResultId, batchResultName, original.ExecParams, startTime, testCasePaths)
+	batchResultId, err := handler.testRunner.ExecuteTestBatchWithCaseList(batchResultName, original.ExecParams, startTime, testCasePaths)
+	if err != nil { return "", err }
 
 	return batchResultId, nil
 }
diff --git a/cherry/testrunner.go b/cherry/testrunner.go
index d9ddc47..668afc7 100644
--- a/cherry/testrunner.go
+++ b/cherry/testrunner.go
@@ -655,18 +655,19 @@
 }
 
 // Create a new batch and start executing asynchronously.
-func (runner *TestRunner) ExecuteTestBatch (batchResultId string, batchName string, batchParams BatchExecParams, timestamp time.Time) error {
+func (runner *TestRunner) ExecuteTestBatch (batchName string, batchParams BatchExecParams, timestamp time.Time) (string, error) {
 	// Resolve test case list to execute.
 	// \todo [petri] fetch testCaseList dynamically from target?
 	log.Printf("[runner] test name filters: %q\n", batchParams.TestNameFilters)
 	testCasePaths := filterTestCaseNames(runner.fullTestCaseList, batchParams.TestNameFilters)
 	log.Printf("[runner] filtered from %d cases to %d\n", len(runner.fullTestCaseList), len(testCasePaths))
 
-	return runner.ExecuteTestBatchWithCaseList(batchResultId, batchName, batchParams, timestamp, testCasePaths)
+	return runner.ExecuteTestBatchWithCaseList(batchName, batchParams, timestamp, testCasePaths)
 }
 
 // Create a new batch, with a specific case list and no regard to batchParams.TestNameFilters, and start executing asynchronously.
-func (runner *TestRunner) ExecuteTestBatchWithCaseList (batchResultId string, batchName string, batchParams BatchExecParams, timestamp time.Time, testCasePaths []string) error {
+func (runner *TestRunner) ExecuteTestBatchWithCaseList (batchName string, batchParams BatchExecParams, timestamp time.Time, testCasePaths []string) (string, error) {
+	batchResultId := runner.rtdbServer.MakeUniqueID()
 	opSet := rtdb.NewOpSet()
 
 	// Empty batch result.
@@ -704,7 +705,7 @@
 		}
 	}()
 
-	return nil
+	return batchResultId, nil
 }
 
 // Send a stop request to the given batch execution or import.
@@ -781,7 +782,9 @@
 	return <-executionLogChan, nil
 }
 
-func (runner *TestRunner) ImportBatch (batchResultId string, batchResultDefaultName string, qpaReader *multipart.Part, totalContentLength int64) error {
+func (runner *TestRunner) ImportBatch (batchResultDefaultName string, qpaReader *multipart.Part, totalContentLength int64) error {
+	batchResultId := runner.rtdbServer.MakeUniqueID()
+
 	var stopRequest <-chan struct{}
 	{
 		stopRequestBidir := make(chan struct{})
diff --git a/rtdb/rtdb.go b/rtdb/rtdb.go
index 2ef7e75..e25a512 100644
--- a/rtdb/rtdb.go
+++ b/rtdb/rtdb.go
@@ -22,6 +22,8 @@
 	"fmt"
 	"log"
 	"reflect"
+	"time"
+	"strconv"
 )
 
 type Object struct {
@@ -507,3 +509,12 @@
 	}
 	return <- ret
 }
+
+func (server *Server) MakeUniqueID () string {
+	ret := make(chan string)
+	server.requestQueue <- func() {
+		// requestQueue serializes accesses -> time will be unique
+		ret <- strconv.FormatInt(time.Now().UnixNano(), 10)
+	}
+	return <- ret
+}
diff --git a/server.go b/server.go
index f1df121..e7a40a5 100644
--- a/server.go
+++ b/server.go
@@ -268,9 +268,8 @@
 		}
 
 		startTime := time.Now()
-		batchResultId			:= startTime.Format(time.RFC3339)
-		batchResultDefaultName	:= startTime.Format("2006-Jan-02 15:04:05")
-		err = testRunner.ImportBatch(batchResultId, batchResultDefaultName, file, request.ContentLength)
+		batchResultDefaultName := "Import-" + startTime.Format("2006-Jan-02 15:04:05")
+		err = testRunner.ImportBatch(batchResultDefaultName, file, request.ContentLength)
 		if err != nil {
 			log.Printf("[import] Import failed with error %v\n", err)
 			anyImportFailed = true