Ban the use of id zero for encodings, metrics and report configs.

We want to reserve the zero for future use.

Change-Id: I6514f9f97dcae9047ad4a47b021df7912fedc4e3
diff --git a/config/config_parser/CMakeLists.txt b/config/config_parser/CMakeLists.txt
index bcf1465..413a72c 100644
--- a/config/config_parser/CMakeLists.txt
+++ b/config/config_parser/CMakeLists.txt
@@ -36,6 +36,7 @@
 
 set(CONFIG_VALIDATOR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/config_validator/validator.go
                          ${CMAKE_CURRENT_SOURCE_DIR}/src/config_validator/system_profile_field.go
+                         ${CMAKE_CURRENT_SOURCE_DIR}/src/config_validator/encodings.go
                          ${CMAKE_CURRENT_SOURCE_DIR}/src/config_validator/metrics.go
                          ${CMAKE_CURRENT_SOURCE_DIR}/src/config_validator/common_validator.go
                          ${CMAKE_CURRENT_SOURCE_DIR}/src/config_validator/reports.go)
@@ -70,6 +71,7 @@
 
 set(CONFIG_VALIDATOR_TEST_BIN ${GO_TESTS}/config_validator_tests)
 set(CONFIG_VALIDATOR_TEST_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/config_validator/system_profile_field_test.go
+                              ${CMAKE_CURRENT_SOURCE_DIR}/src/config_validator/encodings_test.go
                               ${CMAKE_CURRENT_SOURCE_DIR}/src/config_validator/reports_test.go
                               ${CMAKE_CURRENT_SOURCE_DIR}/src/config_validator/metrics_test.go
                               ${CMAKE_CURRENT_SOURCE_DIR}/src/config_validator/common_validator_test.go
diff --git a/config/config_parser/src/config_validator/encodings.go b/config/config_parser/src/config_validator/encodings.go
new file mode 100644
index 0000000..28d1552
--- /dev/null
+++ b/config/config_parser/src/config_validator/encodings.go
@@ -0,0 +1,29 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package config_validator
+
+import (
+	"config"
+	"fmt"
+)
+
+func validateConfiguredEncodings(config *config.CobaltConfig) (err error) {
+	// Set of encoding ids. Used detect duplicates.
+	encodingIds := map[string]bool{}
+
+	for i, encoding := range config.EncodingConfigs {
+		if encoding.Id == 0 {
+			return fmt.Errorf("Encoding id '0' is invalid.")
+		}
+
+		encodingKey := formatId(encoding.CustomerId, encoding.ProjectId, encoding.Id)
+		if encodingIds[encodingKey] {
+			return fmt.Errorf("Encoding id %s is repeated in encoding config entry number %v. Encoding ids must be unique.", encodingKey, i+1)
+		}
+		encodingIds[encodingKey] = true
+	}
+
+	return nil
+}
diff --git a/config/config_parser/src/config_validator/encodings_test.go b/config/config_parser/src/config_validator/encodings_test.go
new file mode 100644
index 0000000..d09e622
--- /dev/null
+++ b/config/config_parser/src/config_validator/encodings_test.go
@@ -0,0 +1,48 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package config_validator
+
+import (
+	"config"
+	"testing"
+)
+
+// Tests that we catch encodings with id = 0.
+func TestValidateNoZeroEncodingIds(t *testing.T) {
+	config := &config.CobaltConfig{
+		EncodingConfigs: []*config.EncodingConfig{
+			&config.EncodingConfig{
+				CustomerId: 1,
+				ProjectId:  1,
+				Id:         0,
+			},
+		},
+	}
+
+	if err := validateConfiguredEncodings(config); err == nil {
+		t.Error("Accepted encoding config with id of 0.")
+	}
+}
+
+// Tests that we catch non-unique encoding ids.
+func TestValidateUniqueEncodingIds(t *testing.T) {
+	config := &config.CobaltConfig{
+		EncodingConfigs: []*config.EncodingConfig{
+			&config.EncodingConfig{
+				CustomerId: 1,
+				ProjectId:  1,
+				Id:         1,
+			},
+			&config.EncodingConfig{
+				CustomerId: 1,
+				ProjectId:  1,
+				Id:         1,
+			},
+		},
+	}
+	if err := validateConfiguredEncodings(config); err == nil {
+		t.Error("Accepted non-unique encoding id.")
+	}
+}
diff --git a/config/config_parser/src/config_validator/metrics.go b/config/config_parser/src/config_validator/metrics.go
index fe0f36b..afa4398 100644
--- a/config/config_parser/src/config_validator/metrics.go
+++ b/config/config_parser/src/config_validator/metrics.go
@@ -37,6 +37,10 @@
 }
 
 func validateMetric(m *config.Metric) (err error) {
+	if m.Id == 0 {
+		return fmt.Errorf("Metric id '0' is invalid.")
+	}
+
 	for name, v := range m.Parts {
 		if v == nil {
 			return fmt.Errorf("Metric part '%v' is null. This is not allowed.", name)
diff --git a/config/config_parser/src/config_validator/metrics_test.go b/config/config_parser/src/config_validator/metrics_test.go
index f3cc060..0abf9ae 100644
--- a/config/config_parser/src/config_validator/metrics_test.go
+++ b/config/config_parser/src/config_validator/metrics_test.go
@@ -38,6 +38,19 @@
 	}
 }
 
+// Tests that we catch encodings with id = 0.
+func TestValidateNoZeroMetricIds(t *testing.T) {
+	config := &config.CobaltConfig{
+		MetricConfigs: []*config.Metric{
+			makeMetric(0, nil),
+		},
+	}
+
+	if err := validateConfiguredMetrics(config); err == nil {
+		t.Error("Accepted metric config with id of 0.")
+	}
+}
+
 // Tests that we catch non-unique metric ids.
 func TestValidateUniqueMetricIds(t *testing.T) {
 	config := &config.CobaltConfig{
diff --git a/config/config_parser/src/config_validator/reports.go b/config/config_parser/src/config_validator/reports.go
index d9afb23..7a2597e 100644
--- a/config/config_parser/src/config_validator/reports.go
+++ b/config/config_parser/src/config_validator/reports.go
@@ -22,6 +22,10 @@
 	}
 
 	for i, report := range config.ReportConfigs {
+		if report.Id == 0 {
+			return fmt.Errorf("Error validating report %v: Report id '0' is invalid.", report.Name)
+		}
+
 		reportKey := formatId(report.CustomerId, report.ProjectId, report.Id)
 		if reportIds[reportKey] {
 			return fmt.Errorf("Report id %s is repeated in report config entry number %v. Report ids must be unique.", reportKey, i+1)
diff --git a/config/config_parser/src/config_validator/reports_test.go b/config/config_parser/src/config_validator/reports_test.go
index 56f60d2..8f77d02 100644
--- a/config/config_parser/src/config_validator/reports_test.go
+++ b/config/config_parser/src/config_validator/reports_test.go
@@ -37,6 +37,7 @@
 		},
 		ReportConfigs: []*config.ReportConfig{
 			&config.ReportConfig{
+				Id: 1,
 				Variable: []*config.ReportVariable{
 					&config.ReportVariable{
 						MetricPart: "int_part",
@@ -135,6 +136,19 @@
 	}
 }
 
+// Tests that we catch reports with id = 0.
+func TestValidateNoZeroReportIds(t *testing.T) {
+	config := &config.CobaltConfig{
+		ReportConfigs: []*config.ReportConfig{
+			makeReport(0, 1, nil),
+		},
+	}
+
+	if err := validateConfiguredReports(config); err == nil {
+		t.Error("Accepted report config with id of 0.")
+	}
+}
+
 // Tests that we catch non-unique report ids.
 func TestValidateUniqueReportIds(t *testing.T) {
 	config := &config.CobaltConfig{
diff --git a/config/config_parser/src/config_validator/validator.go b/config/config_parser/src/config_validator/validator.go
index 82de583..2c043a7 100644
--- a/config/config_parser/src/config_validator/validator.go
+++ b/config/config_parser/src/config_validator/validator.go
@@ -14,6 +14,10 @@
 }
 
 func ValidateConfig(config *config.CobaltConfig) (err error) {
+	if err = validateConfiguredEncodings(config); err != nil {
+		return
+	}
+
 	if err = validateConfiguredMetrics(config); err != nil {
 		return
 	}