[catapult] Convert HistogramSet whitespace to '_'

Change-Id: I951d1031d150e43f242828eedaaa65fd3d990d52
diff --git a/catapult/histogram.go b/catapult/histogram.go
index 56da838..b9582c8 100644
--- a/catapult/histogram.go
+++ b/catapult/histogram.go
@@ -8,6 +8,7 @@
 	"errors"
 	"log"
 	"math"
+	"strings"
 
 	schema "fuchsia.googlesource.com/infra/infra/perf/schema/v1"
 	uuid "github.com/satori/go.uuid"
@@ -123,6 +124,13 @@
 // The histogram's statistics are computed from the given slice of values, which
 // are assumed to be nanosecond measurements.
 //
+// This also performs the following normalizations on the input:
+//
+// * Converts values to milliseconds: Catapult doesn't support nanoseconds.
+// * Converts label whitespace to underscores: Catpapult forms a unique key
+//   for fetching graph data using the Histogram name. Whitespace breaks this
+//   key and causes Catapult to incorrectly process the data.
+//
 // Returns an error if values is empty.
 func createHistogram(name string, values []float64) (Histogram, error) {
 	var sampleValues []float64
@@ -131,12 +139,16 @@
 		return Histogram{}, errors.New("at least one sample value required")
 	}
 
+	// Fuchsia benchmarks use nanoseconds. Catapult doesn't support this,
+	// so convert to milliseconds instead.
 	for _, value := range values {
-		// Fuchsia benchmarks use nanoseconds. Catapult doesn't support this,
-		// so convert to milliseconds instead.
 		sampleValues = append(sampleValues, value/1e6)
 	}
 
+	// Catapult does not support whitespace in the Histogram name. Replace with
+	// underscores.  -1 specifies no limit on the number of replacements.
+	name = strings.Replace(name, " ", "_", -1)
+
 	return Histogram{
 		Name:    name,
 		Unit:    "ms_smallerIsBetter",
diff --git a/catapult/histogram_test.go b/catapult/histogram_test.go
index 6b4ce92..8282178 100644
--- a/catapult/histogram_test.go
+++ b/catapult/histogram_test.go
@@ -241,6 +241,40 @@
 			},
 		})
 	})
+
+	t.Run("when labels contain whitespace", func(t *testing.T) {
+		histograms, err := ConvertBenchmarkDataToHistograms(schema.BenchmarkData{
+			Label: "benchmark data label",
+			Unit:  "ns",
+			Samples: []schema.Sample{{
+				Label:  "sample label a",
+				Values: []float64{0},
+			}, {
+				Label:  "sample label b",
+				Values: []float64{0},
+			}},
+		})
+
+		if err != nil {
+			t.Fatal("failed to create histogram", err)
+		}
+
+		if len(histograms) != 2 {
+			t.Fatalf("should have created two histograms, instead got %v", histograms)
+		}
+
+		expectedName := "benchmark_data_label_sample_label_a"
+		if histograms[0].Name != expectedName {
+			t.Errorf("expect histogram to be named %s. Got %s",
+				expectedName, histograms[0].Name)
+		}
+
+		expectedName = "benchmark_data_label_sample_label_b"
+		if histograms[1].Name != expectedName {
+			t.Errorf("expect histogram to be named %s. Got %s",
+				expectedName, histograms[1].Name)
+		}
+	})
 }
 
 func TestHistogram_AddDiagnostic(t *testing.T) {