diff --git a/pkg/client/error.go b/pkg/client/error.go index ba7cbd5c..8d8153db 100644 --- a/pkg/client/error.go +++ b/pkg/client/error.go @@ -7,10 +7,12 @@ import ( const ( ErrGRPCDialCode = "1000" ErrInvalidEndpointCode = "1001" + ErrResponseNilCode = "1002" ) var ( ErrInvalidEndpoint = errors.NewDefault(ErrInvalidEndpointCode, "Endpoint not reachable") + ErrResponseNil = errors.NewDefault(ErrResponseNilCode, "Response is nil from the generator") ) func ErrGRPCDial(err error) error { diff --git a/pkg/client/nighthawk.go b/pkg/client/nighthawk.go index a5d0e0a0..2899f1cb 100644 --- a/pkg/client/nighthawk.go +++ b/pkg/client/nighthawk.go @@ -23,7 +23,6 @@ type Client struct { // New creates a new instance of the nighthawk client connection func New(opts Options) (*Client, error) { - if !utils.TcpCheck(&utils.HostPort{ Address: opts.ServerHost, Port: opts.ServerPort, @@ -31,10 +30,10 @@ func New(opts Options) (*Client, error) { return nil, ErrInvalidEndpoint } - var dial_options []grpc.DialOption - dial_options = append(dial_options, grpc.WithInsecure()) + var dialOptions []grpc.DialOption + dialOptions = append(dialOptions, grpc.WithInsecure()) - conn, err := grpc.Dial(fmt.Sprintf("%s:%d", opts.ServerHost, opts.ServerPort), dial_options...) + conn, err := grpc.Dial(fmt.Sprintf("%s:%d", opts.ServerHost, opts.ServerPort), dialOptions...) if err != nil { return nil, ErrGRPCDial(err) } diff --git a/pkg/client/nighthawk_test.go b/pkg/client/nighthawk_test.go index c65b3520..7a4e2ce4 100644 --- a/pkg/client/nighthawk_test.go +++ b/pkg/client/nighthawk_test.go @@ -29,6 +29,7 @@ func TestNew(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { got, err := New(tt.args.opts) if (err != nil) != tt.wantErr { diff --git a/pkg/client/transform.go b/pkg/client/transform.go index c6d15b76..76e77f03 100644 --- a/pkg/client/transform.go +++ b/pkg/client/transform.go @@ -121,64 +121,9 @@ type TransformResult struct { } func Transform(res *nighthawk_client.ExecutionResponse, typ string) ([]byte, error) { - - //dur, err := time.ParseDuration(fmt.Sprintf("%ds%dµs", res.Output.Timestamp.Seconds, res.Output.Timestamp.Nanos)) - //if err != nil { - // return nil, err - //} - - results := make([]Result, 0) - - for _, r := range res.Output.Results { - statistics := make([]Statistic, 0) - counters := make([]Counter, 0) - for _, c := range r.Counters { - counters = append(counters, Counter{ - Name: c.Name, - Value: strconv.Itoa(int(c.Value)), - }) - } - - for _, s := range r.Statistics { - percentiles := make([]Percentile, 0) - for _, p := range s.Percentiles { - percentiles = append(percentiles, Percentile{ - Percentile: int(p.Percentile), - Count: strconv.Itoa(int(p.Count)), - Duration: formatToNs(p.GetDuration()), - }) - } - - sts := Statistic{ - Count: strconv.Itoa(int(s.Count)), - ID: s.Id, - Percentiles: percentiles, - Mean: formatToNs(s.GetMean()), - Pstdev: formatToNs(s.GetPstdev()), - Min: formatToNs(s.GetMin()), - Max: formatToNs(s.GetMax()), - } - if sts.Mean == "" { - sts.RawMean = int(s.GetRawMean()) - } - if sts.Pstdev == "" { - sts.RawPstdev = int(s.GetRawPstdev()) - } - if sts.Min == "" { - sts.RawMin = strconv.Itoa(int(s.GetRawMin())) - } - if sts.Max == "" { - sts.RawMax = strconv.Itoa(int(s.GetRawMax())) - } - statistics = append(statistics, sts) - } - results = append(results, Result{ - Name: r.Name, - ExecutionStart: r.ExecutionStart.AsTime(), - ExecutionDuration: formatToNs(r.ExecutionDuration), - Statistics: statistics, - Counters: counters, - }) + results, err := constructResults(res) + if err != nil { + return nil, err } expStrategy := res.Output.Options.ExperimentalH1ConnectionReuseStrategy.String() @@ -241,20 +186,118 @@ func Transform(res *nighthawk_client.ExecutionResponse, typ string) ([]byte, err if err != nil { return nil, err } - fmt.Println("input: ", input) - command := "/private/var/tmp/_bazel_abishekk/eaf1167d72f4772496616c435b301da8/execroot/nighthawk/bazel-out/darwin-opt/bin/nighthawk_output_transform" + command := "./nighthawk_output_transform" cmd := exec.Command(command, "--output-format", "fortio") cmd.Stdin = strings.NewReader(input) out, err := cmd.Output() if err != nil { return nil, err } - fmt.Println("output: ", string(out)) // Hack due to bug in nighthawk + outputFinal, err := hackFormat(out) + if err != nil { + return nil, err + } + + return outputFinal, nil +} + +func constructResults(res *nighthawk_client.ExecutionResponse) ([]Result, error) { + results := make([]Result, 0) + if res == nil { + return nil, ErrResponseNil + } + + for _, r := range res.Output.Results { + statistics := make([]Statistic, 0) + counters := make([]Counter, 0) + for _, c := range r.Counters { + counters = append(counters, Counter{ + Name: c.Name, + Value: strconv.Itoa(int(c.Value)), + }) + } + + for _, s := range r.Statistics { + percentiles := make([]Percentile, 0) + for _, p := range s.Percentiles { + percentiles = append(percentiles, Percentile{ + Percentile: int(p.Percentile), + Count: strconv.Itoa(int(p.Count)), + Duration: formatToNs(p.GetDuration()), + }) + } + + sts := Statistic{ + Count: strconv.Itoa(int(s.Count)), + ID: s.Id, + Percentiles: percentiles, + Mean: formatToNs(s.GetMean()), + Pstdev: formatToNs(s.GetPstdev()), + Min: formatToNs(s.GetMin()), + Max: formatToNs(s.GetMax()), + } + if sts.Mean == "" { + sts.RawMean = int(s.GetRawMean()) + } + if sts.Pstdev == "" { + sts.RawPstdev = int(s.GetRawPstdev()) + } + if sts.Min == "" { + sts.RawMin = strconv.Itoa(int(s.GetRawMin())) + } + if sts.Max == "" { + sts.RawMax = strconv.Itoa(int(s.GetRawMax())) + } + statistics = append(statistics, sts) + } + results = append(results, Result{ + Name: r.Name, + ExecutionStart: r.ExecutionStart.AsTime(), + ExecutionDuration: formatToNs(r.ExecutionDuration), + Statistics: statistics, + Counters: counters, + }) + } + return results, nil +} + +func formatToNs(s *duration.Duration) string { + ss := s.AsDuration().String() + if strings.Contains(ss, "ms") { + sep := strings.Split(ss, "m") + f, _ := strconv.ParseFloat(sep[0], 64) + f /= 1000 + st := fmt.Sprintf("%f", f) + sep[0] = st + ss = strings.Join(sep, "") + } else if strings.Contains(ss, "µs") { + sep := strings.Split(ss, "µ") + f, _ := strconv.ParseFloat(sep[0], 64) + f /= 1000000 + st := fmt.Sprintf("%f", f) + sep[0] = st + ss = strings.Join(sep, "") + } else if strings.Contains(ss, "ns") { + sep := strings.Split(ss, "n") + f, _ := strconv.ParseFloat(sep[0], 64) + f /= 10000000 + st := fmt.Sprintf("%f", f) + sep[0] = st + ss = strings.Join(sep, "") + } + return ss +} + +func hackFormat(out []byte) ([]byte, error) { m := map[string]interface{}{} - err = json.Unmarshal(out, &m) + err := json.Unmarshal(out, &m) + if err != nil { + return nil, err + } + m["RequestedQPS"] = fmt.Sprint(m["RequestedQPS"].(float64)) if m["DurationHistogram"] != nil { @@ -298,35 +341,5 @@ func Transform(res *nighthawk_client.ExecutionResponse, typ string) ([]byte, err } m["Sizes"].(map[string]interface{})["Count"] = h } - - outTemp, _ := json.Marshal(m) - - return outTemp, nil -} - -func formatToNs(s *duration.Duration) string { - ss := s.AsDuration().String() - if strings.Contains(ss, "ms") { - sep := strings.Split(ss, "m") - f, _ := strconv.ParseFloat(sep[0], 64) - f = f / 1000 - st := fmt.Sprintf("%f", f) - sep[0] = st - ss = strings.Join(sep, "") - } else if strings.Contains(ss, "µs") { - sep := strings.Split(ss, "µ") - f, _ := strconv.ParseFloat(sep[0], 64) - f = f / 1000000 - st := fmt.Sprintf("%f", f) - sep[0] = st - ss = strings.Join(sep, "") - } else if strings.Contains(ss, "ns") { - sep := strings.Split(ss, "n") - f, _ := strconv.ParseFloat(sep[0], 64) - f = f / 10000000 - st := fmt.Sprintf("%f", f) - sep[0] = st - ss = strings.Join(sep, "") - } - return ss + return json.Marshal(m) }