diff --git a/src/go/mongolib/stats/stats_test.go b/src/go/mongolib/stats/stats_test.go index 68f01c7f..6207bb04 100644 --- a/src/go/mongolib/stats/stats_test.go +++ b/src/go/mongolib/stats/stats_test.go @@ -1,13 +1,17 @@ package stats import ( + "bytes" + "fmt" + "io/ioutil" "log" "os" "reflect" + "sort" + "strings" "testing" + "text/template" "time" - "io/ioutil" - "fmt" "github.com/golang/mock/gomock" "github.com/percona/percona-toolkit/src/go/lib/tutil" @@ -232,16 +236,16 @@ func TestStatsAll(t *testing.T) { s := New(fp) for _, file := range files { - doc := proto.SystemProfile{} - err = tutil.LoadBson(dir+file.Name(), &doc) - if err != nil { - t.Fatalf("cannot load sample %s: %s", dir+file.Name(), err) - } + doc := proto.SystemProfile{} + err = tutil.LoadBson(dir+file.Name(), &doc) + if err != nil { + t.Fatalf("cannot load sample %s: %s", dir+file.Name(), err) + } - err = s.Add(doc) - if err != nil { - t.Errorf("Error processing doc: %s\n", err.Error()) - } + err = s.Add(doc) + if err != nil { + t.Errorf("Error processing doc: %s\n", err.Error()) + } } got := s.Queries() @@ -261,3 +265,197 @@ func TestStatsAll(t *testing.T) { } } +func TestAvailableMetrics(t *testing.T) { + t.Parallel() + + var err error + dirExpect := vars.RootPath + samples + "/expect/available_metrics/" + dir := vars.RootPath + samples + "/doc/out/" + + versions := []string{ + "2.6.12", + "3.0.15", + "3.2.16", + "3.4.7", + "3.5.11", + } + + samples := []string{ + "aggregate", + "count", + "count_with_query", + "delete", + "delete_all", + "distinct", + "find", + "find_andrii", + "find_empty", + "findandmodify", + "geonear", + "group", + "insert", + "mapreduce", + "update", + "explain", + "eval", + } + + type sp struct { + DocsExamined *int `bson:"docsExamined" json:",omitempty"` + NscannedObjects *int `bson:"nscannedObjects" json:",omitempty"` + Millis *int `bson:"millis" json:",omitempty"` + Nreturned *int `bson:"nreturned" json:",omitempty"` + ResponseLength *int `bson:"responseLength" json:",omitempty"` + } + + data := map[string]map[string]sp{} + + for _, sample := range samples { + for _, v := range versions { + f := sample + "_" + v + s := sp{} + err = tutil.LoadBson(dir+f, &s) + if err != nil { + t.Fatalf("cannot load sample %s: %s", dir+f, err) + } + + if data[sample] == nil { + data[sample] = map[string]sp{} + } + data[sample][v] = s + } + } + + t.Run("available_metrics", func(t *testing.T) { + got := data + fExpect := dirExpect + "available_metrics" + if tutil.ShouldUpdateSamples() { + err := tutil.WriteJson(fExpect, got) + if err != nil { + fmt.Printf("cannot update samples: %s", err.Error()) + } + } + + expect := map[string]map[string]sp{} + err = tutil.LoadJson(fExpect, &expect) + if err != nil { + t.Fatalf("cannot load expected data %s: %s", fExpect, err) + } + + if !reflect.DeepEqual(got, expect) { + t.Errorf("s.Queries() = %s, want %s", got, expect) + } + + }) + + t.Run("cmd_metric", func(t *testing.T) { + got := map[string]map[string][]string{} + for s := range data { + for v := range data[s] { + if got[s] == nil { + got[s] = map[string][]string{} + } + if data[s][v].Millis != nil { + got[s]["Query Time"] = append(got[s]["Query Time"], v) + } + if data[s][v].DocsExamined != nil || data[s][v].NscannedObjects != nil { + got[s]["Docs Scanned"] = append(got[s]["Docs Scanned"], v) + } + if data[s][v].Nreturned != nil { + got[s]["Docs Returned"] = append(got[s]["Docs Returned"], v) + } + if data[s][v].ResponseLength != nil { + got[s]["Bytes Sent"] = append(got[s]["Bytes Sent"], v) + } + } + } + + metrics := []string{ + "Query Time", + "Docs Scanned", + "Docs Returned", + "Bytes Sent", + } + for cmd := range got { + for metric := range got[cmd] { + if len(got[cmd][metric]) == len(versions) { + got[cmd][metric] = []string{"yes"} + } else { + sort.Strings(got[cmd][metric]) + } + } + + for _, metric := range metrics { + if len(got[cmd][metric]) == 0 { + got[cmd][metric] = []string{"no"} + } + } + } + + fExpect := dirExpect + "cmd_metric" + if tutil.ShouldUpdateSamples() { + err := tutil.WriteJson(fExpect, got) + if err != nil { + fmt.Printf("cannot update samples: %s", err.Error()) + } + } + + expect := map[string]map[string][]string{} + err = tutil.LoadJson(fExpect, &expect) + if err != nil { + t.Fatalf("cannot load expected data %s: %s", fExpect, err) + } + + if !reflect.DeepEqual(got, expect) { + t.Errorf("s.Queries() = %s, want %s", got, expect) + } + + data := got + t.Run("md", func(t *testing.T) { + type result struct { + Metrics []string + Samples []string + Data map[string]map[string][]string + } + r := result{ + Metrics: metrics, + Samples: samples, + Data: data, + } + sort.Strings(r.Metrics) + sort.Strings(r.Samples) + + tmpl := template.New("") + tmpl = tmpl.Funcs(template.FuncMap{"join": strings.Join}) + tmpl, err := tmpl.Parse(`| | {{range .Metrics}}{{.}} | {{end}} +| - | {{range .Metrics}}- | {{end}}{{range $s := .Samples}} +| {{$s}} | {{range $m := $.Metrics}}{{join (index $.Data $s $m) ", "}} | {{end}}{{end}}`) + if err != nil { + panic(err) + } + var got bytes.Buffer + err = tmpl.Execute(&got, r) + if err != nil { + panic(err) + } + + fExpect := dirExpect + "cmd_metric.md" + if tutil.ShouldUpdateSamples() { + err = ioutil.WriteFile(fExpect, got.Bytes(), 0777) + if err != nil { + fmt.Printf("cannot update samples: %s", err.Error()) + } + } + + buf, err := ioutil.ReadFile(fExpect) + if err != nil { + t.Fatalf("cannot load expected data %s: %s", fExpect, err) + } + expect := string(buf) + + if !reflect.DeepEqual(got, expect) { + t.Errorf("s.Queries() = %s, want %s", got, expect) + } + }) + }) +} diff --git a/src/go/tests/expect/available_metrics/available_metrics b/src/go/tests/expect/available_metrics/available_metrics new file mode 100755 index 00000000..c512073d --- /dev/null +++ b/src/go/tests/expect/available_metrics/available_metrics @@ -0,0 +1,421 @@ +{ + "aggregate": { + "2.6.12": { + "Millis": 0, + "ResponseLength": 385 + }, + "3.0.15": { + "Millis": 2, + "ResponseLength": 385 + }, + "3.2.16": { + "Millis": 2, + "ResponseLength": 388 + }, + "3.4.7": { + "DocsExamined": 8, + "Millis": 0, + "Nreturned": 8, + "ResponseLength": 370 + }, + "3.5.11": { + "DocsExamined": 8, + "Millis": 2, + "Nreturned": 8, + "ResponseLength": 370 + } + }, + "count": { + "2.6.12": { + "Millis": 0, + "ResponseLength": 48 + }, + "3.0.15": { + "Millis": 0, + "ResponseLength": 44 + }, + "3.2.16": { + "Millis": 0, + "ResponseLength": 47 + }, + "3.4.7": { + "DocsExamined": 0, + "Millis": 0, + "ResponseLength": 29 + }, + "3.5.11": { + "DocsExamined": 0, + "Millis": 0, + "ResponseLength": 29 + } + }, + "count_with_query": { + "2.6.12": { + "Millis": 0, + "ResponseLength": 48 + }, + "3.0.15": { + "Millis": 0, + "ResponseLength": 44 + }, + "3.2.16": { + "Millis": 0, + "ResponseLength": 47 + }, + "3.4.7": { + "DocsExamined": 0, + "Millis": 0, + "ResponseLength": 29 + }, + "3.5.11": { + "DocsExamined": 0, + "Millis": 0, + "ResponseLength": 29 + } + }, + "delete": { + "2.6.12": { + "Millis": 0 + }, + "3.0.15": { + "Millis": 0 + }, + "3.2.16": { + "Millis": 1 + }, + "3.4.7": { + "DocsExamined": 4, + "Millis": 0 + }, + "3.5.11": { + "DocsExamined": 4, + "Millis": 0 + } + }, + "delete_all": { + "2.6.12": { + "Millis": 0 + }, + "3.0.15": { + "Millis": 1 + }, + "3.2.16": { + "Millis": 0 + }, + "3.4.7": { + "DocsExamined": 39, + "Millis": 0 + }, + "3.5.11": { + "DocsExamined": 39, + "Millis": 0 + } + }, + "distinct": { + "2.6.12": { + "Millis": 0, + "ResponseLength": 254 + }, + "3.0.15": { + "Millis": 0, + "ResponseLength": 261 + }, + "3.2.16": { + "Millis": 0, + "ResponseLength": 264 + }, + "3.4.7": { + "DocsExamined": 10, + "Millis": 0, + "ResponseLength": 145 + }, + "3.5.11": { + "DocsExamined": 10, + "Millis": 0, + "ResponseLength": 145 + } + }, + "eval": { + "2.6.12": { + "Millis": 65, + "ResponseLength": 108 + }, + "3.0.15": { + "Millis": 35, + "ResponseLength": 108 + }, + "3.2.16": { + "Millis": 88, + "ResponseLength": 93 + }, + "3.4.7": { + "Millis": 91, + "ResponseLength": 93 + }, + "3.5.11": { + "Millis": 47, + "ResponseLength": 93 + } + }, + "explain": { + "2.6.12": { + "NscannedObjects": 44, + "Millis": 0, + "Nreturned": 1, + "ResponseLength": 583 + }, + "3.0.15": { + "Millis": 0, + "ResponseLength": 379 + }, + "3.2.16": { + "Millis": 0, + "ResponseLength": 364 + }, + "3.4.7": { + "Millis": 0, + "ResponseLength": 328 + }, + "3.5.11": { + "Millis": 0, + "ResponseLength": 329 + } + }, + "find": { + "2.6.12": { + "NscannedObjects": 6, + "Millis": 0, + "Nreturned": 6, + "ResponseLength": 251 + }, + "3.0.15": { + "NscannedObjects": 6, + "Millis": 0, + "Nreturned": 6, + "ResponseLength": 251 + }, + "3.2.16": { + "DocsExamined": 6, + "Millis": 0, + "Nreturned": 6, + "ResponseLength": 349 + }, + "3.4.7": { + "DocsExamined": 6, + "Millis": 0, + "Nreturned": 6, + "ResponseLength": 331 + }, + "3.5.11": { + "DocsExamined": 6, + "Millis": 1, + "Nreturned": 6, + "ResponseLength": 331 + } + }, + "find_andrii": { + "2.6.12": { + "NscannedObjects": 98, + "Millis": 0, + "Nreturned": 0, + "ResponseLength": 20 + }, + "3.0.15": { + "NscannedObjects": 98, + "Millis": 0, + "Nreturned": 0, + "ResponseLength": 20 + }, + "3.2.16": { + "DocsExamined": 49, + "Millis": 0, + "Nreturned": 0, + "ResponseLength": 100 + }, + "3.4.7": { + "DocsExamined": 49, + "Millis": 0, + "Nreturned": 0, + "ResponseLength": 82 + }, + "3.5.11": { + "DocsExamined": 49, + "Millis": 0, + "Nreturned": 0, + "ResponseLength": 82 + } + }, + "find_empty": { + "2.6.12": { + "NscannedObjects": 49, + "Millis": 0, + "Nreturned": 49, + "ResponseLength": 1846 + }, + "3.0.15": { + "NscannedObjects": 49, + "Millis": 0, + "Nreturned": 49, + "ResponseLength": 1846 + }, + "3.2.16": { + "DocsExamined": 49, + "Millis": 0, + "Nreturned": 49, + "ResponseLength": 2112 + }, + "3.4.7": { + "DocsExamined": 49, + "Millis": 0, + "Nreturned": 49, + "ResponseLength": 2094 + }, + "3.5.11": { + "DocsExamined": 49, + "Millis": 0, + "Nreturned": 49, + "ResponseLength": 2094 + } + }, + "findandmodify": { + "2.6.12": { + "NscannedObjects": 1, + "Millis": 0, + "ResponseLength": 131 + }, + "3.0.15": { + "NscannedObjects": 1, + "Millis": 0, + "ResponseLength": 131 + }, + "3.2.16": { + "DocsExamined": 3, + "Millis": 0, + "ResponseLength": 116 + }, + "3.4.7": { + "DocsExamined": 3, + "Millis": 0, + "ResponseLength": 116 + }, + "3.5.11": { + "DocsExamined": 3, + "Millis": 0, + "ResponseLength": 116 + } + }, + "geonear": { + "2.6.12": { + "Millis": 1, + "ResponseLength": 1406 + }, + "3.0.15": { + "Millis": 3, + "ResponseLength": 1398 + }, + "3.2.16": { + "Millis": 8, + "ResponseLength": 1401 + }, + "3.4.7": { + "DocsExamined": 10, + "Millis": 11, + "ResponseLength": 1383 + }, + "3.5.11": { + "DocsExamined": 10, + "Millis": 7, + "ResponseLength": 1383 + } + }, + "group": { + "2.6.12": { + "Millis": 77, + "ResponseLength": 135 + }, + "3.0.15": { + "Millis": 54, + "ResponseLength": 139 + }, + "3.2.16": { + "Millis": 74, + "ResponseLength": 142 + }, + "3.4.7": { + "DocsExamined": 2, + "Millis": 77, + "ResponseLength": 124 + }, + "3.5.11": { + "DocsExamined": 2, + "Millis": 68, + "ResponseLength": 124 + } + }, + "insert": { + "2.6.12": { + "Millis": 0 + }, + "3.0.15": { + "Millis": 0 + }, + "3.2.16": { + "Millis": 0, + "ResponseLength": 25 + }, + "3.4.7": { + "Millis": 0, + "ResponseLength": 29 + }, + "3.5.11": { + "Millis": 0, + "ResponseLength": 29 + } + }, + "mapreduce": { + "2.6.12": { + "Millis": 33, + "ResponseLength": 233 + }, + "3.0.15": { + "Millis": 26, + "ResponseLength": 233 + }, + "3.2.16": { + "Millis": 31, + "ResponseLength": 218 + }, + "3.4.7": { + "DocsExamined": 3, + "Millis": 43, + "ResponseLength": 218 + }, + "3.5.11": { + "DocsExamined": 3, + "Millis": 35, + "ResponseLength": 218 + } + }, + "update": { + "2.6.12": { + "NscannedObjects": 1, + "Millis": 0 + }, + "3.0.15": { + "NscannedObjects": 1, + "Millis": 0 + }, + "3.2.16": { + "DocsExamined": 1, + "Millis": 0 + }, + "3.4.7": { + "DocsExamined": 1, + "Millis": 0 + }, + "3.5.11": { + "DocsExamined": 1, + "Millis": 0 + } + } +} \ No newline at end of file diff --git a/src/go/tests/expect/available_metrics/cmd_metric b/src/go/tests/expect/available_metrics/cmd_metric new file mode 100755 index 00000000..31ee3e8a --- /dev/null +++ b/src/go/tests/expect/available_metrics/cmd_metric @@ -0,0 +1,252 @@ +{ + "aggregate": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "3.4.7", + "3.5.11" + ], + "Docs Scanned": [ + "3.4.7", + "3.5.11" + ], + "Query Time": [ + "yes" + ] + }, + "count": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "3.4.7", + "3.5.11" + ], + "Query Time": [ + "yes" + ] + }, + "count_with_query": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "3.4.7", + "3.5.11" + ], + "Query Time": [ + "yes" + ] + }, + "delete": { + "Bytes Sent": [ + "no" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "3.4.7", + "3.5.11" + ], + "Query Time": [ + "yes" + ] + }, + "delete_all": { + "Bytes Sent": [ + "no" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "3.4.7", + "3.5.11" + ], + "Query Time": [ + "yes" + ] + }, + "distinct": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "3.4.7", + "3.5.11" + ], + "Query Time": [ + "yes" + ] + }, + "eval": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "no" + ], + "Query Time": [ + "yes" + ] + }, + "explain": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "2.6.12" + ], + "Docs Scanned": [ + "2.6.12" + ], + "Query Time": [ + "yes" + ] + }, + "find": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "yes" + ], + "Docs Scanned": [ + "yes" + ], + "Query Time": [ + "yes" + ] + }, + "find_andrii": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "yes" + ], + "Docs Scanned": [ + "yes" + ], + "Query Time": [ + "yes" + ] + }, + "find_empty": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "yes" + ], + "Docs Scanned": [ + "yes" + ], + "Query Time": [ + "yes" + ] + }, + "findandmodify": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "yes" + ], + "Query Time": [ + "yes" + ] + }, + "geonear": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "3.4.7", + "3.5.11" + ], + "Query Time": [ + "yes" + ] + }, + "group": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "3.4.7", + "3.5.11" + ], + "Query Time": [ + "yes" + ] + }, + "insert": { + "Bytes Sent": [ + "3.2.16", + "3.4.7", + "3.5.11" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "no" + ], + "Query Time": [ + "yes" + ] + }, + "mapreduce": { + "Bytes Sent": [ + "yes" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "3.4.7", + "3.5.11" + ], + "Query Time": [ + "yes" + ] + }, + "update": { + "Bytes Sent": [ + "no" + ], + "Docs Returned": [ + "no" + ], + "Docs Scanned": [ + "yes" + ], + "Query Time": [ + "yes" + ] + } +} \ No newline at end of file diff --git a/src/go/tests/expect/available_metrics/cmd_metric.md b/src/go/tests/expect/available_metrics/cmd_metric.md new file mode 100755 index 00000000..034dc818 --- /dev/null +++ b/src/go/tests/expect/available_metrics/cmd_metric.md @@ -0,0 +1,19 @@ +| | Bytes Sent | Docs Returned | Docs Scanned | Query Time | +| - | - | - | - | - | +| aggregate | yes | >=3.4 | >=3.4 | yes | +| count | yes | no | >=3.4 | yes | +| count_with_query | yes | no | >=3.4 | yes | +| delete | no | no | >=3.4 | yes | +| delete_all | no | no | >=3.4 | yes | +| distinct | yes | no | >=3.4 | yes | +| eval | yes | no | no | yes | +| explain | yes | no | no | yes | +| find | yes | yes | yes | yes | +| find_andrii | yes | yes | yes | yes | +| find_empty | yes | yes | yes | yes | +| findandmodify | yes | no | yes | yes | +| geonear | yes | no | >=3.4 | yes | +| group | yes | no | >=3.4 | yes | +| insert | >=3.2 | no | no | yes | +| mapreduce | yes | no | >=3.4 | yes | +| update | no | no | yes | yes | \ No newline at end of file