From e83211501aef854bf0168389539dec1034f47a95 Mon Sep 17 00:00:00 2001 From: Cristina Leon Date: Thu, 10 Oct 2024 15:49:18 +0000 Subject: [PATCH] Convert max_elapsed_time to microseconds --- handler/ndt7.go | 59 ++++++++++++++++++++---------- handler/ndt7_test.go | 76 +++++++++++++++++++++++++++++++++++++++ pkg/ndt7/sender/sender.go | 8 ++--- 3 files changed, 120 insertions(+), 23 deletions(-) diff --git a/handler/ndt7.go b/handler/ndt7.go index 53c8785..51b478f 100644 --- a/handler/ndt7.go +++ b/handler/ndt7.go @@ -42,7 +42,12 @@ func (c *Client) NDT7Download(rw http.ResponseWriter, req *http.Request) { } // Get client parameters. - params, err := getParams(req.URL.Query()) + params, err := GetParams(req.URL.Query()) + if err != nil { + log.Errorf("Invalid parameters: %v", req.URL.Query()) + rw.WriteHeader(http.StatusBadRequest) + return + } // Get data. data, err := getData(conn) @@ -75,40 +80,56 @@ func (c *Client) NDT7Download(rw http.ResponseWriter, req *http.Request) { } } -func getData(conn *websocket.Conn) (*model.ArchivalData, error) { - ci := netx.ToConnInfo(conn.UnderlyingConn()) - uuid, err := ci.GetUUID() - if err != nil { - return nil, err - } - data := &model.ArchivalData{ - UUID: uuid, - } - return data, nil -} - -func getParams(urlValues url.Values) (*sender.Params, error) { +// GetParams interprets and returns the client parameters. +func GetParams(urlValues url.Values) (*sender.Params, error) { params := &sender.Params{} + for name, values := range urlValues { value := values[0] name = strings.TrimPrefix(name, "client_") + switch name { case static.EarlyExitParameterName: - bytes, _ := strconv.ParseInt(value, 10, 64) + bytes, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return nil, err + } params.MaxBytes = bytes * 1000000 // Convert MB to bytes. case static.MaxCwndGainParameterName: - cwnd, _ := strconv.ParseUint(value, 10, 32) + cwnd, err := strconv.ParseUint(value, 10, 32) + if err != nil { + return nil, err + } params.MaxCwndGain = uint32(cwnd) case static.MaxElapsedTimeParameterName: - time, _ := strconv.ParseInt(value, 10, 64) - params.MaxElapsedTime = time + time, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return nil, err + } + params.MaxElapsedTime = time * 1e6 // Convert seconds to microseconds. case static.ImmediateExitParameterName: - params.ImmediateExit, _ = strconv.ParseBool(value) + immExit, err := strconv.ParseBool(value) + if err != nil { + return nil, err + } + params.ImmediateExit = immExit } } return params, nil } +func getData(conn *websocket.Conn) (*model.ArchivalData, error) { + ci := netx.ToConnInfo(conn.UnderlyingConn()) + uuid, err := ci.GetUUID() + if err != nil { + return nil, err + } + data := &model.ArchivalData{ + UUID: uuid, + } + return data, nil +} + // setupResult creates an NDT7Result from the given conn. func setupResult(conn *websocket.Conn) *data.NDT7Result { // NOTE: unless we plan to run the NDT server over different protocols than TCP, diff --git a/handler/ndt7_test.go b/handler/ndt7_test.go index f560a9b..929df7d 100644 --- a/handler/ndt7_test.go +++ b/handler/ndt7_test.go @@ -5,12 +5,15 @@ import ( "net/http" "net/url" "os" + "reflect" "testing" "time" "github.com/gorilla/websocket" "github.com/m-lab/go/testingx" "github.com/m-lab/ndt-server/ndt7/spec" + "github.com/m-lab/packet-test/handler" + "github.com/m-lab/packet-test/pkg/ndt7/sender" "github.com/m-lab/packet-test/static" "github.com/m-lab/packet-test/testdata" ) @@ -50,3 +53,76 @@ func simpleDownload(ctx context.Context, t *testing.T, conn *websocket.Conn) err // We only read one message, so this is an early close. return conn.Close() } + +func Test_getParams(t *testing.T) { + type args struct { + urlValues url.Values + } + tests := []struct { + name string + vals url.Values + want *sender.Params + wantErr bool + }{ + { + name: static.EarlyExitParameterName, + vals: url.Values{ + static.EarlyExitParameterName: []string{"10"}, // 10 MB. + }, + want: &sender.Params{ + MaxBytes: 10000000, // 10000000 Bytes. + }, + wantErr: false, + }, + { + name: static.MaxCwndGainParameterName, + vals: url.Values{ + static.MaxCwndGainParameterName: []string{"512"}, + }, + want: &sender.Params{ + MaxCwndGain: 512, + }, + wantErr: false, + }, + { + name: static.MaxElapsedTimeParameterName, + vals: url.Values{ + static.MaxElapsedTimeParameterName: []string{"5"}, // 5 seconds. + }, + want: &sender.Params{ + MaxElapsedTime: 5000000, // 5000000 microseconds. + }, + wantErr: false, + }, + { + name: static.ImmediateExitParameterName, + vals: url.Values{ + static.ImmediateExitParameterName: []string{"true"}, + }, + want: &sender.Params{ + ImmediateExit: true, + }, + wantErr: false, + }, + { + name: "error", + vals: url.Values{ + static.EarlyExitParameterName: []string{"foo"}, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := handler.GetParams(tt.vals) + if (err != nil) != tt.wantErr { + t.Errorf("handler.GetParams() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("handler.GetParams() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/ndt7/sender/sender.go b/pkg/ndt7/sender/sender.go index ae7fb22..2824e97 100644 --- a/pkg/ndt7/sender/sender.go +++ b/pkg/ndt7/sender/sender.go @@ -16,8 +16,8 @@ import ( // Params defines the parameters for the sender to end the test early. type Params struct { - MaxBytes int64 // TCPInfo.BytesAcked is of type int64. - MaxElapsedTime int64 // TCPInfo.ElapsedTime is of type int64. + MaxBytes int64 // TCPInfo.BytesAcked is of type int64 (bytes). + MaxElapsedTime int64 // TCPInfo.ElapsedTime is of type int64 (microseconds). MaxCwndGain uint32 // BBRInfo.CwndGain is of type uint32. ImmediateExit bool } @@ -175,7 +175,7 @@ func terminateTest(p *Params, m model.Measurement) bool { switch { case p.isMaxCwndGainLimit() && p.isMaxElapsedTimeLimit(): if p.isMaxCwndGainDone(m) && p.isMaxElapsedTimeDone(m) { - log.Infof("sender: terminating test after %d CwndGain and %d ElapsedTime (s)", m.BBRInfo.CwndGain, m.TCPInfo.ElapsedTime) + log.Infof("sender: terminating test after %d CwndGain and %d ElapsedTime (µs)", m.BBRInfo.CwndGain, m.TCPInfo.ElapsedTime) return true } case p.isMaxCwndGainLimit() && p.isEarlyExitLimit(): @@ -190,7 +190,7 @@ func terminateTest(p *Params, m model.Measurement) bool { log.Infof("sender: terminating test after %d BytesAcked", m.TCPInfo.BytesAcked) return true case p.isMaxElapsedTimeLimit() && p.isMaxElapsedTimeDone(m): - log.Infof("sender: terminating test after %d ElapsedTime (s)", m.TCPInfo.ElapsedTime) + log.Infof("sender: terminating test after %d ElapsedTime (µs)", m.TCPInfo.ElapsedTime) return true }