godev/cmd/worker: refactor partition & unit test

1. switch partition from function to method.
2. remove un-used xs in unit test args{}.
3. add two more missing unit test cases.

Change-Id: I2de9a72b59d0df5dcf16c508654942041d31f845
Reviewed-on: https://go-review.googlesource.com/c/telemetry/+/597695
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/godev/cmd/worker/main.go b/godev/cmd/worker/main.go
index 372976f..5b45d74 100644
--- a/godev/cmd/worker/main.go
+++ b/godev/cmd/worker/main.go
@@ -273,16 +273,16 @@
 		result.Programs = append(result.Programs, prog)
 		var charts []*chart
 		if !telemetry.IsToolchainProgram(p.Name) {
-			charts = append(charts, partition(d, p.Name, "Version", p.Versions))
+			charts = append(charts, d.partition(p.Name, "Version", p.Versions))
 		}
 		charts = append(charts,
-			partition(d, p.Name, "GOOS", cfg.GOOS),
-			partition(d, p.Name, "GOARCH", cfg.GOARCH),
-			partition(d, p.Name, "GoVersion", cfg.GoVersion))
+			d.partition(p.Name, "GOOS", cfg.GOOS),
+			d.partition(p.Name, "GOARCH", cfg.GOARCH),
+			d.partition(p.Name, "GoVersion", cfg.GoVersion))
 		for _, c := range p.Counters {
 			// TODO: add support for histogram counters by getting the counter type
 			// from the chart config.
-			charts = append(charts, partition(d, p.Name, c.Name, tconfig.Expand(c.Name)))
+			charts = append(charts, d.partition(p.Name, c.Name, tconfig.Expand(c.Name)))
 		}
 		for _, p := range charts {
 			if p != nil {
@@ -335,7 +335,7 @@
 
 // partition builds a chart for the program and the counter. It can return nil
 // if there is no data for the counter in dat.
-func partition(dat data, program, counterPrefix string, counters []string) *chart {
+func (d data) partition(program, counterPrefix string, counters []string) *chart {
 	count := &chart{
 		ID:   "charts:" + program + ":" + counterPrefix,
 		Name: counterPrefix,
@@ -344,10 +344,10 @@
 	pk := programKey{program}
 	prefix, _ := splitCounterName(counterPrefix)
 	gk := graphKey{prefix}
-	for wk := range dat {
+	for wk := range d {
 		// TODO: when should this be number of reports?
 		// total := len(xs)
-		total := len(dat[wk][pk][gk][counterKey{gk.prefix}])
+		total := len(d[wk][pk][gk][counterKey{gk.prefix}])
 		if total == 0 {
 			return nil
 		}
@@ -363,7 +363,7 @@
 			seen[counter] = true
 			ck := counterKey{counter}
 			// number of reports where count prefix:bucket > 0
-			n := len(dat[wk][pk][gk][ck])
+			n := len(d[wk][pk][gk][ck])
 			_, bucket := splitCounterName(counter)
 			d := &datum{
 				Week:  wk.date,
@@ -427,7 +427,7 @@
 }
 
 // readCount reads the count value based on the input keys.
-// Return nil if any key does not exist.
+// Return error if any key does not exist.
 func (d data) readCount(week, program, prefix, counter string, x float64) (int64, error) {
 	wk := weekKey{week}
 	if _, ok := d[wk]; !ok {
diff --git a/godev/cmd/worker/main_test.go b/godev/cmd/worker/main_test.go
index 824a97c..fff40b2 100644
--- a/godev/cmd/worker/main_test.go
+++ b/godev/cmd/worker/main_test.go
@@ -295,7 +295,6 @@
 		program string
 		name    string
 		buckets []string
-		xs      []float64
 	}
 	tests := []struct {
 		name string
@@ -303,14 +302,13 @@
 		want *chart
 	}{
 		{
-			"versions counter",
-			args{
-				"example.com/mod/pkg",
-				"Version",
-				[]string{"v1.2.3", "v2.3.4"},
-				[]float64{0.123456789, 0.987654321},
+			name: "major.minor.patch version counter",
+			args: args{
+				program: "example.com/mod/pkg",
+				name:    "Version",
+				buckets: []string{"v1.2.3", "v2.3.4"},
 			},
-			&chart{
+			want: &chart{
 				ID:   "charts:example.com/mod/pkg:Version",
 				Name: "Version",
 				Type: "partition",
@@ -329,14 +327,63 @@
 			},
 		},
 		{
-			"goos counter",
-			args{
-				"example.com/mod/pkg",
-				"GOOS",
-				[]string{"darwin", "linux"},
-				[]float64{0.123456789, 0.987654321},
+			name: "major.minor version counter should have same result as major.minor.patch",
+			args: args{
+				program: "example.com/mod/pkg",
+				name:    "Version",
+				buckets: []string{"v1.2", "v2.3"},
 			},
-			&chart{
+			want: &chart{
+				ID:   "charts:example.com/mod/pkg:Version",
+				Name: "Version",
+				Type: "partition",
+				Data: []*datum{
+					{
+						Week:  "2999-01-01",
+						Key:   "v1.2",
+						Value: 1,
+					},
+					{
+						Week:  "2999-01-01",
+						Key:   "v2.3",
+						Value: 0.5,
+					},
+				},
+			},
+		},
+		{
+			name: "duplicated counter should be ignored",
+			args: args{
+				program: "example.com/mod/pkg",
+				name:    "Version",
+				buckets: []string{"v1.2.3", "v2.3.4", "v1.2.3"},
+			},
+			want: &chart{
+				ID:   "charts:example.com/mod/pkg:Version",
+				Name: "Version",
+				Type: "partition",
+				Data: []*datum{
+					{
+						Week:  "2999-01-01",
+						Key:   "v1.2",
+						Value: 1,
+					},
+					{
+						Week:  "2999-01-01",
+						Key:   "v2.3",
+						Value: 0.5,
+					},
+				},
+			},
+		},
+		{
+			name: "goos counter",
+			args: args{
+				program: "example.com/mod/pkg",
+				name:    "GOOS",
+				buckets: []string{"darwin", "linux"},
+			},
+			want: &chart{
 				ID:   "charts:example.com/mod/pkg:GOOS",
 				Name: "GOOS",
 				Type: "partition",
@@ -357,8 +404,8 @@
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			if got := partition(dat, tt.args.program, tt.args.name, tt.args.buckets); !reflect.DeepEqual(got, tt.want) {
-				t.Errorf("histogram() = %v, want %v", got, tt.want)
+			if got := dat.partition(tt.args.program, tt.args.name, tt.args.buckets); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("partition() = %v, want %v", got, tt.want)
 			}
 		})
 	}