[Registry Parser] Added New Report Type to Registry Parser

Added UNIQUE_DEVICE_STRING_COUNTS report type to registry parser.
Bug: 91035

Change-Id: I93db4c54d45b184b99c737ac52eaf413e451babd
Reviewed-on: https://fuchsia-review.googlesource.com/c/cobalt/+/638061
Reviewed-by: Cameron Dale <camrdale@google.com>
Reviewed-by: Laura Peskin <pesk@google.com>
Commit-Queue: Andrew Hwang <anhwang@google.com>
diff --git a/src/bin/config_parser/src/config_parser/cobalt11_types.go b/src/bin/config_parser/src/config_parser/cobalt11_types.go
index 58aa499..78d9e50 100644
--- a/src/bin/config_parser/src/config_parser/cobalt11_types.go
+++ b/src/bin/config_parser/src/config_parser/cobalt11_types.go
@@ -27,4 +27,5 @@
 	config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS: true,
 	config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS:  true,
 	config.ReportDefinition_STRING_COUNTS:               true,
+	config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS: true,
 }
diff --git a/src/bin/config_parser/src/config_validator/report_definitions.go b/src/bin/config_parser/src/config_validator/report_definitions.go
index 5529e26..1d3f3a8 100644
--- a/src/bin/config_parser/src/config_validator/report_definitions.go
+++ b/src/bin/config_parser/src/config_validator/report_definitions.go
@@ -65,7 +65,8 @@
 		config.ReportDefinition_FLEETWIDE_HISTOGRAMS: true,
 	},
 	config.MetricDefinition_STRING: map[config.ReportDefinition_ReportType]bool{
-		config.ReportDefinition_STRING_COUNTS: true,
+		config.ReportDefinition_STRING_COUNTS:               true,
+		config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS: true,
 	},
 	config.MetricDefinition_CUSTOM: map[config.ReportDefinition_ReportType]bool{
 		config.ReportDefinition_CUSTOM_RAW_DUMP: true,
@@ -224,6 +225,10 @@
 		if err := validateStringCountsReportDef(r); err != nil {
 			reportErrors.addError("other", err)
 		}
+	case config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS:
+		if err := validateUniqueDeviceStringCountsReportDef(r); err != nil {
+			reportErrors.addError("other", err)
+		}
 	}
 
 	return reportErrors.err()
@@ -268,7 +273,8 @@
 	switch r.ReportType {
 	case config.ReportDefinition_UNIQUE_DEVICE_COUNTS,
 		config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS,
-		config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS:
+		config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS,
+		config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS:
 		if r.LocalAggregationPeriod == config.WindowSize_UNSET {
 			return fmt.Errorf("day based metrics must specify a local_aggregation_period")
 		}
@@ -344,6 +350,7 @@
 		default:
 			return fmt.Errorf("reports of type UNIQUE_DEVICE_COUNTS with expedited_sending enabled must specify a local_aggregation_procedure in the list (AT_LEAST_ONCE, SELECT_FIRST)")
 		}
+	case config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS:
 	default:
 		return fmt.Errorf("reports of type %v do not support expedited_sending", r.ReportType)
 	}
@@ -412,6 +419,14 @@
 	return nil
 }
 
+func validateUniqueDeviceStringCountsReportDef(r config.ReportDefinition) error {
+	if r.IntBuckets != nil {
+		return fmt.Errorf("int_buckets can not be specified for report of type %s.", r.ReportType)
+	}
+
+	return nil
+}
+
 /////////////////////////////////////////////////////////////////
 // Validation for specific fields of report definitions
 //
@@ -488,7 +503,8 @@
 			config.ReportDefinition_FLEETWIDE_HISTOGRAMS,
 			config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS,
 			config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS,
-			config.ReportDefinition_STRING_COUNTS:
+			config.ReportDefinition_STRING_COUNTS,
+			config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS:
 			if r.MinValue != 0 || r.MaxValue != 0 {
 				return fmt.Errorf("min_value and max_value should not be set for reports of type %s", r.ReportType)
 			}
@@ -527,7 +543,8 @@
 			config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS,
 			config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS,
 			config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS,
-			config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS:
+			config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS,
+			config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS:
 			if r.MaxCount != 0 {
 				return fmt.Errorf("max_count should not be set for reports of type %s", r.ReportType)
 			}
diff --git a/src/bin/config_parser/src/config_validator/report_definitions_test.go b/src/bin/config_parser/src/config_validator/report_definitions_test.go
index cf4c4cf..ea67912 100644
--- a/src/bin/config_parser/src/config_validator/report_definitions_test.go
+++ b/src/bin/config_parser/src/config_validator/report_definitions_test.go
@@ -152,6 +152,7 @@
 		config.ReportDefinition_FLEETWIDE_HISTOGRAMS,
 		config.ReportDefinition_FLEETWIDE_MEANS,
 		config.ReportDefinition_STRING_COUNTS,
+		config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS,
 	}
 	type args struct {
 		minValue int64
@@ -200,6 +201,7 @@
 		config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS,
 		config.ReportDefinition_FLEETWIDE_HISTOGRAMS,
 		config.ReportDefinition_STRING_COUNTS,
+		config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS,
 	}
 	type args struct {
 		reportTypes []config.ReportDefinition_ReportType
@@ -253,6 +255,7 @@
 		config.ReportDefinition_FLEETWIDE_HISTOGRAMS,
 		config.ReportDefinition_FLEETWIDE_MEANS,
 		config.ReportDefinition_STRING_COUNTS,
+		config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS,
 	}
 	var tests = []struct {
 		maxCount uint64
@@ -294,6 +297,7 @@
 		config.ReportDefinition_HOURLY_VALUE_NUMERIC_STATS,
 		config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS,
 		config.ReportDefinition_HOURLY_VALUE_HISTOGRAMS,
+		config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS,
 	}
 	type args struct {
 		reportTypes []config.ReportDefinition_ReportType
@@ -448,6 +452,24 @@
 	}
 }
 
+// Test that int_buckets is not set if the report type is UNIQUE_DEVICE_STRING_COUNTS.
+func TestValidateReportDefitionForUniqueDeviceStringCounts(t *testing.T) {
+	m := makeValidMetric(config.MetricDefinition_EVENT_COUNT)
+	r := makeValidReport()
+	r.ReportType = config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS
+	r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY
+	r.LocalAggregationPeriod = config.WindowSize_WINDOW_1_DAY
+
+	if err := validateReportDefinition(m, r); err != nil {
+		t.Errorf("Failed validation for valid report of type UNIQUE_DEVICE_STRING_COUNTS: %v", err)
+	}
+
+	r.IntBuckets = &config.IntegerBuckets{}
+	if err := validateReportDefinition(m, r); err == nil {
+		t.Errorf("Accepted report definition of type UNIQUE_DEVICE_STRING_COUNTS with int_buckets specified.")
+	}
+}
+
 // Test that Histogram report types get properly validated for int_buckets in main validation functions.
 func TestHistogramReportsHaveIntBuckets(t *testing.T) {
 	// ================================================================================
@@ -788,6 +810,7 @@
 		config.ReportDefinition_UNIQUE_DEVICE_COUNTS,
 		config.ReportDefinition_UNIQUE_DEVICE_HISTOGRAMS,
 		config.ReportDefinition_UNIQUE_DEVICE_NUMERIC_STATS,
+		config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS,
 	}
 	hourlyReportTypes := []config.ReportDefinition_ReportType{
 		config.ReportDefinition_FLEETWIDE_OCCURRENCE_COUNTS,
@@ -930,6 +953,15 @@
 	if err := validateExpeditedSending(m, r); err != nil {
 		t.Errorf("Rejected report with expedited_sending unset: %v", err)
 	}
+
+	m = makeValidMetric(config.MetricDefinition_STRING)
+	r = makeValidReportWithType(config.ReportDefinition_UNIQUE_DEVICE_STRING_COUNTS)
+	r.ExpeditedSending = true
+	r.LocalAggregationProcedure = config.ReportDefinition_LOCAL_AGGREGATION_PROCEDURE_UNSET
+	r.PrivacyLevel = config.ReportDefinition_NO_ADDED_PRIVACY
+	if err := validateExpeditedSending(m, r); err != nil {
+		t.Errorf("Rejected report with expedited_sending and valid report type: %v", err)
+	}
 }
 
 func TestValidateReportAll(t *testing.T) {