Merge pull request #19 from 30x/XAPID-821

Xapid 821
diff --git a/api_test.go b/api_test.go
index e793251..665074e 100644
--- a/api_test.go
+++ b/api_test.go
@@ -374,7 +374,7 @@
 	bundle := bundleConfigJson{
 		Name:         uri.Path,
 		URI:          bundleUri,
-		ChecksumType: "crc-32",
+		ChecksumType: "crc32",
 	}
 	bundle.Checksum = testGetChecksum(bundle.ChecksumType, bundleUri)
 	bundleJson, err := json.Marshal(bundle)
diff --git a/apidGatewayDeploy_suite_test.go b/apidGatewayDeploy_suite_test.go
index 227276d..23981e8 100644
--- a/apidGatewayDeploy_suite_test.go
+++ b/apidGatewayDeploy_suite_test.go
@@ -71,7 +71,7 @@
 	router.HandleFunc("/bundles/{id}", func(w http.ResponseWriter, req *http.Request) {
 		count++
 		vars := apid.API().Vars(req)
-		if count%2 == 0 {
+		if count%2 == 0 && vars["id"] != "checksum" {
 			w.WriteHeader(500)
 			return
 		}
diff --git a/bundle.go b/bundle.go
index 8d03074..740947d 100644
--- a/bundle.go
+++ b/bundle.go
@@ -2,6 +2,8 @@
 
 import (
 	"crypto/md5"
+	"crypto/sha256"
+	"crypto/sha512"
 	"encoding/base64"
 	"encoding/hex"
 	"errors"
@@ -14,6 +16,7 @@
 	"net/url"
 	"os"
 	"path"
+	"strings"
 	"time"
 )
 
@@ -201,7 +204,7 @@
 
 	// todo: add authentication - TBD?
 
-	// assume it's a file if no scheme
+	// assume it's a file if no scheme - todo: remove file support?
 	if uri.Scheme == "" || uri.Scheme == "file" {
 		f, err := os.Open(uri.Path)
 		if err != nil {
@@ -228,15 +231,20 @@
 
 	var hashWriter hash.Hash
 
-	switch hashType {
+	switch strings.ToLower(hashType) {
+	case "":
+		hashWriter = fakeHash{md5.New()}
 	case "md5":
 		hashWriter = md5.New()
-	case "crc-32":
+	case "crc32":
 		hashWriter = crc32.NewIEEE()
+	case "sha256":
+		hashWriter = sha256.New()
+	case "sha512":
+		hashWriter = sha512.New()
 	default:
-		// todo: temporary - this disables checksums until server implements (XAPID-544)
-		hashWriter = fakeHash{md5.New()}
-		//return nil, errors.New("checksumType must be md5 or crc-32")
+		return nil, errors.New(
+			fmt.Sprintf("invalid checksumType: %s. valid types: md5, crc32, sha256, sha512", hashType))
 	}
 
 	return hashWriter, nil
diff --git a/bundle_test.go b/bundle_test.go
index fd2be63..46e7a74 100644
--- a/bundle_test.go
+++ b/bundle_test.go
@@ -30,7 +30,6 @@
 					time.Sleep(1 * time.Second)
 					w.WriteHeader(500)
 				} else {
-					//proceed <- true
 					w.Write([]byte("/bundles/longfail"))
 				}
 			}))
@@ -48,8 +47,8 @@
 				ID:                 deploymentID,
 				DataScopeID:        deploymentID,
 				BundleURI:          uri.String(),
-				BundleChecksum:     testGetChecksum("crc-32", uri.String()),
-				BundleChecksumType: "crc-32",
+				BundleChecksum:     testGetChecksum("crc32", uri.String()),
+				BundleChecksumType: "crc32",
 			}
 
 			err = InsertDeployment(tx, dep)
@@ -97,7 +96,7 @@
 			bundle := bundleConfigJson{
 				Name:         uri.Path,
 				URI:          bundleUri,
-				ChecksumType: "crc-32",
+				ChecksumType: "crc32",
 			}
 			bundle.Checksum = testGetChecksum(bundle.ChecksumType, bundleUri)
 			bundleJson, err := json.Marshal(bundle)
@@ -208,7 +207,7 @@
 			bundle := bundleConfigJson{
 				Name:         uri.Path,
 				URI:          bundleUri,
-				ChecksumType: "crc-32",
+				ChecksumType: "crc32",
 			}
 			bundle.Checksum = testGetChecksum(bundle.ChecksumType, bundleUri)
 			bundleJson, err := json.Marshal(bundle)
@@ -262,69 +261,78 @@
 			// No way to test this programmatically currently
 			// search logs for "never mind, deployment bundle_download_deployment_deleted was deleted"
 		})
+	})
 
-		// todo: temporary - this tests that checksum is disabled until server implements (XAPID-544)
-		It("should TEMPORARILY download even if empty Checksum and ChecksumType", func() {
+	Context("checksums", func() {
 
-			deploymentID := "bundle_download_temporary"
+		It("should download with empty checksumType", func() {
+			checksumDownloadValid("")
+		})
 
-			uri, err := url.Parse(testServer.URL)
-			Expect(err).ShouldNot(HaveOccurred())
+		It("should fail download with bad empty checksumType", func() {
+			checksumDownloadInvalid("")
+		})
 
-			uri.Path = "/bundles/1"
-			bundleUri := uri.String()
-			bundle := bundleConfigJson{
-				Name:         uri.Path,
-				URI:          bundleUri,
-				ChecksumType: "",
-				Checksum:     "",
-			}
-			bundleJson, err := json.Marshal(bundle)
-			Expect(err).ShouldNot(HaveOccurred())
+		It("should fail download with bad md5", func() {
+			checksumDownloadInvalid("md5")
+		})
 
-			tx, err := getDB().Begin()
-			Expect(err).ShouldNot(HaveOccurred())
+		It("should download with good md5", func() {
+			checksumDownloadValid("md5")
+		})
 
-			dep := DataDeployment{
-				ID:                 deploymentID,
-				BundleConfigID:     deploymentID,
-				ApidClusterID:      deploymentID,
-				DataScopeID:        deploymentID,
-				BundleConfigJSON:   string(bundleJson),
-				ConfigJSON:         string(bundleJson),
-				Created:            "",
-				CreatedBy:          "",
-				Updated:            "",
-				UpdatedBy:          "",
-				BundleName:         deploymentID,
-				BundleURI:          bundle.URI,
-				BundleChecksum:     bundle.Checksum,
-				BundleChecksumType: bundle.ChecksumType,
-				LocalBundleURI:     "",
-				DeployStatus:       "",
-				DeployErrorCode:    0,
-				DeployErrorMessage: "",
-			}
+		It("should fail download with bad md5", func() {
+			checksumDownloadInvalid("md5")
+		})
 
-			err = InsertDeployment(tx, dep)
-			Expect(err).ShouldNot(HaveOccurred())
+		It("should download with good crc32", func() {
+			checksumDownloadValid("crc32")
+		})
 
-			err = tx.Commit()
-			Expect(err).ShouldNot(HaveOccurred())
+		It("should fail download with bad crc32", func() {
+			checksumDownloadInvalid("crc32")
+		})
 
-			queueDownloadRequest(dep)
+		It("should download with good sha256", func() {
+			checksumDownloadValid("sha256")
+		})
 
-			// give download time to finish
-			time.Sleep(markDeploymentFailedAfter + (100 * time.Millisecond))
+		It("should fail download with bad sha256", func() {
+			checksumDownloadInvalid("sha256")
+		})
 
-			deployments, err := getReadyDeployments()
-			Expect(err).ShouldNot(HaveOccurred())
+		It("should download correctly with sha512", func() {
+			checksumDownloadValid("sha512")
+		})
 
-			Expect(len(deployments)).To(Equal(1))
-			d := deployments[0]
-
-			Expect(d.ID).To(Equal(deploymentID))
-			Expect(d.LocalBundleURI).To(BeAnExistingFile())
+		It("should fail download with bad sha512", func() {
+			checksumDownloadInvalid("sha512")
 		})
 	})
 })
+
+func checksumDownloadValid(checksumType string) {
+	defer GinkgoRecover()
+
+	uri, err := url.Parse(testServer.URL)
+	Expect(err).ShouldNot(HaveOccurred())
+	uri.Path = "/bundles/checksum"
+	checksum := testGetChecksum(checksumType, uri.String())
+	hash, err := getHashWriter(checksumType)
+	Expect(err).NotTo(HaveOccurred())
+	_, err = downloadFromURI(uri.String(), hash, checksum)
+	Expect(err).NotTo(HaveOccurred())
+}
+
+func checksumDownloadInvalid(checksumType string) {
+	defer GinkgoRecover()
+
+	uri, err := url.Parse(testServer.URL)
+	Expect(err).ShouldNot(HaveOccurred())
+	uri.Path = "/bundles/checksum"
+	checksum := "invalidchecksum"
+	hash, err := getHashWriter(checksumType)
+	Expect(err).NotTo(HaveOccurred())
+	_, err = downloadFromURI(uri.String(), hash, checksum)
+	Expect(err).To(HaveOccurred())
+}
diff --git a/listener_test.go b/listener_test.go
index 33ebd41..0c79f3f 100644
--- a/listener_test.go
+++ b/listener_test.go
@@ -30,7 +30,7 @@
 			bundle1 := bundleConfigJson{
 				Name:         uri.Path,
 				URI:          bundleUri,
-				ChecksumType: "crc-32",
+				ChecksumType: "crc32",
 			}
 			bundle1.Checksum = testGetChecksum(bundle1.ChecksumType, bundleUri)
 			bundle1Json, err := json.Marshal(bundle1)
@@ -92,7 +92,7 @@
 			bundle := bundleConfigJson{
 				Name:         uri.Path,
 				URI:          bundleUri,
-				ChecksumType: "crc-32",
+				ChecksumType: "crc32",
 			}
 			bundle.Checksum = testGetChecksum(bundle.ChecksumType, bundleUri)
 
@@ -243,7 +243,7 @@
 			bundle := bundleConfigJson{
 				Name:         uri.Path,
 				URI:          bundleUri,
-				ChecksumType: "crc-32",
+				ChecksumType: "crc32",
 			}
 			bundle.Checksum = testGetChecksum(bundle.ChecksumType, bundleUri)
 			bundle1Json, err := json.Marshal(bundle)