Ensure that bundle download failures are reported to the server, define error codes
diff --git a/api.go b/api.go
index ae92a0d..00dc633 100644
--- a/api.go
+++ b/api.go
@@ -13,12 +13,23 @@
 	"time"
 )
 
+// todo: the full set of states should probably be RECEIVED, READY, FAIL, SUCCESS
 const (
 	RESPONSE_STATUS_SUCCESS = "SUCCESS"
 	RESPONSE_STATUS_FAIL    = "FAIL"
+)
 
-	// todo: add error codes where this is used
-	ERROR_CODE_TODO = 0
+const (
+	TRACKER_ERR_BUNDLE_TIMEOUT = iota
+	TRACKER_ERR_PARSE_FAILED
+	TRACKER_ERR_INVALID_CHECKSUM
+)
+
+const (
+	API_ERR_BAD_BLOCK = iota
+	API_ERR_BAD_JSON
+	API_ERR_INVALID_CONTENT
+	API_ERR_INTERNAL
 )
 
 var (
@@ -81,7 +92,7 @@
 }
 
 func writeDatabaseError(w http.ResponseWriter) {
-	writeError(w, http.StatusInternalServerError, ERROR_CODE_TODO, "database error")
+	writeError(w, http.StatusInternalServerError, API_ERR_INTERNAL, "database error")
 }
 
 func distributeEvents() {
@@ -143,7 +154,7 @@
 		var err error
 		timeout, err = strconv.Atoi(b)
 		if err != nil {
-			writeError(w, http.StatusBadRequest, ERROR_CODE_TODO, "bad block value, must be number of seconds")
+			writeError(w, http.StatusBadRequest, API_ERR_BAD_BLOCK, "bad block value, must be number of seconds")
 			return
 		}
 	}
@@ -235,7 +246,7 @@
 	err := json.Unmarshal(buf, &results)
 	if err != nil {
 		log.Errorf("Resp Handler Json Unmarshal err: ", err)
-		writeError(w, http.StatusBadRequest, ERROR_CODE_TODO, "Malformed JSON")
+		writeError(w, http.StatusBadRequest, API_ERR_BAD_JSON, "Malformed JSON")
 		return
 	}
 
@@ -269,12 +280,11 @@
 	}
 
 	if errs.Len() > 0 {
-		writeError(w, http.StatusBadRequest, ERROR_CODE_TODO, errs.String())
+		writeError(w, http.StatusBadRequest, API_ERR_INVALID_CONTENT, errs.String())
 		return
 	}
 
 	if len(validResults) > 0 {
-		go transmitDeploymentResultsToServer(validResults)
 		setDeploymentResults(validResults)
 	}
 
diff --git a/bundle.go b/bundle.go
index 1105606..e877ad2 100644
--- a/bundle.go
+++ b/bundle.go
@@ -47,7 +47,7 @@
 			{
 				ID:        dep.ID,
 				Status:    RESPONSE_STATUS_FAIL,
-				ErrorCode: ERROR_CODE_TODO,
+				ErrorCode: TRACKER_ERR_INVALID_CHECKSUM,
 				Message:   msg,
 			},
 		})
@@ -132,7 +132,7 @@
 				{
 					ID:        r.dep.ID,
 					Status:    RESPONSE_STATUS_FAIL,
-					ErrorCode: ERROR_CODE_TODO,
+					ErrorCode: TRACKER_ERR_BUNDLE_TIMEOUT,
 					Message:   "bundle download failed",
 				},
 			})
diff --git a/bundle_test.go b/bundle_test.go
index 84989ea..15fd8e3 100644
--- a/bundle_test.go
+++ b/bundle_test.go
@@ -8,6 +8,8 @@
 	"net/http"
 	"net/http/httptest"
 
+	"io/ioutil"
+
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
 )
@@ -134,6 +136,31 @@
 			err = tx.Commit()
 			Expect(err).ShouldNot(HaveOccurred())
 
+			trackerHit := false
+			tracker := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+				defer GinkgoRecover()
+
+				b, err := ioutil.ReadAll(r.Body)
+				Expect(err).ShouldNot(HaveOccurred())
+				var received apiDeploymentResults
+				json.Unmarshal(b, &received)
+
+				expected := apiDeploymentResults{
+					{
+						ID:        deploymentID,
+						Status:    RESPONSE_STATUS_FAIL,
+						ErrorCode: TRACKER_ERR_BUNDLE_TIMEOUT,
+						Message:   "bundle download failed",
+					},
+				}
+				Expect(received).To(Equal(expected))
+				trackerHit = true
+				w.Write([]byte("OK"))
+			}))
+			defer tracker.Close()
+			apiServerBaseURI, err = url.Parse(tracker.URL)
+			Expect(err).ShouldNot(HaveOccurred())
+
 			queueDownloadRequest(dep)
 
 			<-proceed
@@ -147,10 +174,12 @@
 
 			Expect(d.ID).To(Equal(deploymentID))
 			Expect(d.DeployStatus).To(Equal(RESPONSE_STATUS_FAIL))
-			Expect(d.DeployErrorCode).To(Equal(ERROR_CODE_TODO))
+			Expect(d.DeployErrorCode).To(Equal(TRACKER_ERR_BUNDLE_TIMEOUT))
 			Expect(d.DeployErrorMessage).ToNot(BeEmpty())
 			Expect(d.LocalBundleURI).To(BeEmpty())
 
+			Expect(trackerHit).To(BeTrue())
+
 			var listener = make(chan string)
 			addSubscriber <- listener
 			<-listener
@@ -165,7 +194,7 @@
 
 			Expect(d.ID).To(Equal(deploymentID))
 			Expect(d.DeployStatus).To(Equal(RESPONSE_STATUS_FAIL))
-			Expect(d.DeployErrorCode).To(Equal(ERROR_CODE_TODO))
+			Expect(d.DeployErrorCode).To(Equal(TRACKER_ERR_BUNDLE_TIMEOUT))
 			Expect(d.DeployErrorMessage).ToNot(BeEmpty())
 			Expect(d.LocalBundleURI).To(BeAnExistingFile())
 		})
diff --git a/data.go b/data.go
index d36e745..ad67728 100644
--- a/data.go
+++ b/data.go
@@ -155,7 +155,7 @@
 
 // getUnreadyDeployments() returns array of deployments that are not yet ready to deploy
 func getUnreadyDeployments() (deployments []DataDeployment, err error) {
-	return getDeployments("WHERE local_bundle_uri = $1 and deploy_status = $2", "", "")
+	return getDeployments("WHERE local_bundle_uri = $1", "")
 }
 
 // getDeployments() accepts a "WHERE ..." clause and optional parameters and returns the list of deployments
@@ -207,6 +207,9 @@
 
 func setDeploymentResults(results apiDeploymentResults) error {
 
+	// also send results to server
+	go transmitDeploymentResultsToServer(results)
+
 	log.Debugf("setDeploymentResults: %v", results)
 
 	tx, err := getDB().Begin()
@@ -265,12 +268,3 @@
 
 	return nil
 }
-
-func getLocalBundleURI(depID string) (localBundleUri string, err error) {
-
-	err = getDB().QueryRow("SELECT local_bundle_uri FROM deployments WHERE id=$1;", depID).Scan(&localBundleUri)
-	if err == sql.ErrNoRows {
-		err = nil
-	}
-	return
-}
diff --git a/listener.go b/listener.go
index e4290d5..339213a 100644
--- a/listener.go
+++ b/listener.go
@@ -72,7 +72,7 @@
 					result := apiDeploymentResult{
 						ID:        dep.ID,
 						Status:    RESPONSE_STATUS_FAIL,
-						ErrorCode: ERROR_CODE_TODO,
+						ErrorCode: TRACKER_ERR_PARSE_FAILED,
 						Message:   fmt.Sprintf("unable to parse deployment: %v", err),
 					}
 					errResults = append(errResults, result)
@@ -174,7 +174,7 @@
 					result := apiDeploymentResult{
 						ID:        dep.ID,
 						Status:    RESPONSE_STATUS_FAIL,
-						ErrorCode: ERROR_CODE_TODO,
+						ErrorCode: TRACKER_ERR_PARSE_FAILED,
 						Message:   fmt.Sprintf("unable to parse deployment: %v", err),
 					}
 					errResults = append(errResults, result)