From f49b98aed6d6da29d7e09ee6cc261b8c4034db93 Mon Sep 17 00:00:00 2001 From: ankur22 Date: Mon, 18 Dec 2023 11:28:40 +0000 Subject: [PATCH] Update to browser v1.2.2 --- go.mod | 2 +- go.sum | 4 +- .../xk6-browser/common/frame_session.go | 11 +- .../grafana/xk6-browser/common/page.go | 29 +--- .../xk6-browser/common/remote_object.go | 160 +++++++++++++++--- .../grafana/xk6-browser/log/logger.go | 14 +- vendor/modules.txt | 2 +- 7 files changed, 151 insertions(+), 71 deletions(-) diff --git a/go.mod b/go.mod index 043a80c3829..e45ad7eb28d 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/go-sourcemap/sourcemap v2.1.4-0.20211119122758-180fcef48034+incompatible github.com/golang/protobuf v1.5.3 github.com/gorilla/websocket v1.5.1 - github.com/grafana/xk6-browser v1.2.1 + github.com/grafana/xk6-browser v1.2.2 github.com/grafana/xk6-output-prometheus-remote v0.3.1 github.com/grafana/xk6-redis v0.2.0 github.com/grafana/xk6-timers v0.2.2 diff --git a/go.sum b/go.sum index a32e6bcab17..aaf1b2692c5 100644 --- a/go.sum +++ b/go.sum @@ -93,8 +93,8 @@ github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/grafana/xk6-browser v1.2.1 h1:O2fuHHvmmhXvWTPXzD+jsnt1XkVgVjx0+Lj1hsGIWMM= -github.com/grafana/xk6-browser v1.2.1/go.mod h1:D3k9/MQHnNKfyzU3fh32pHlrh3GY2LAlkY4wYt/Vn4Y= +github.com/grafana/xk6-browser v1.2.2 h1:0SCVYzJ4j417ivN4mbY8/SjY55a6+O694NiYvR4WFGw= +github.com/grafana/xk6-browser v1.2.2/go.mod h1:D3k9/MQHnNKfyzU3fh32pHlrh3GY2LAlkY4wYt/Vn4Y= github.com/grafana/xk6-output-prometheus-remote v0.3.1 h1:X23rQzlJD8dXWB31DkxR4uPnuRFo8L0Y0H22fSG9xl0= github.com/grafana/xk6-output-prometheus-remote v0.3.1/go.mod h1:0JLAm4ONsNUlNoxJXAwOCfA6GtDwTPs557OplAvE+3o= github.com/grafana/xk6-redis v0.2.0 h1:iXmAKVlAxafZ/h8ptuXTFhGu63IFsyDI8QjUgWm66BU= diff --git a/vendor/github.com/grafana/xk6-browser/common/frame_session.go b/vendor/github.com/grafana/xk6-browser/common/frame_session.go index fffacb72ffd..101c5159557 100644 --- a/vendor/github.com/grafana/xk6-browser/common/frame_session.go +++ b/vendor/github.com/grafana/xk6-browser/common/frame_session.go @@ -596,16 +596,13 @@ func (fs *FrameSession) onConsoleAPICalled(event *cdpruntime.EventConsoleAPICall } */ - parsedObjects := make([]any, 0, len(event.Args)) + parsedObjects := make([]string, 0, len(event.Args)) for _, robj := range event.Args { - i, err := parseRemoteObject(robj) - if err != nil { - handleParseRemoteObjectErr(fs.ctx, err, l) - } - parsedObjects = append(parsedObjects, i) + s := parseConsoleRemoteObject(fs.logger, robj) + parsedObjects = append(parsedObjects, s) } - l = l.WithField("objects", parsedObjects) + l = l.WithField("stringObjects", parsedObjects) switch event.Type { case "log", "info": diff --git a/vendor/github.com/grafana/xk6-browser/common/page.go b/vendor/github.com/grafana/xk6-browser/common/page.go index 7fccbb109eb..66e5a90ee24 100644 --- a/vendor/github.com/grafana/xk6-browser/common/page.go +++ b/vendor/github.com/grafana/xk6-browser/common/page.go @@ -1344,21 +1344,14 @@ func (p *Page) consoleMsgFromConsoleEvent(e *cdpruntime.EventConsoleAPICalled) ( } var ( - l = p.logger.WithTime(e.Timestamp.Time()). - WithField("source", "browser"). - WithField("browser_source", "console-api") - - objects = make([]any, 0, len(e.Args)) + objects = make([]string, 0, len(e.Args)) objectHandles = make([]JSHandleAPI, 0, len(e.Args)) ) for _, robj := range e.Args { - i, err := parseRemoteObject(robj) - if err != nil { - handleParseRemoteObjectErr(p.ctx, err, l) - } + s := parseConsoleRemoteObject(p.logger, robj) - objects = append(objects, i) + objects = append(objects, s) objectHandles = append(objectHandles, NewJSHandle( p.ctx, p.session, execCtx, execCtx.Frame(), robj, p.logger, )) @@ -1399,7 +1392,7 @@ func (p *Page) sessionID() (sid target.SessionID) { // textForConsoleEvent generates the text representation for a consoleAPICalled event // mimicking Playwright's behavior. -func textForConsoleEvent(e *cdpruntime.EventConsoleAPICalled, args []any) string { +func textForConsoleEvent(e *cdpruntime.EventConsoleAPICalled, args []string) string { if e.Type.String() == "dir" || e.Type.String() == "dirxml" || e.Type.String() == "table" { if len(e.Args) > 0 { @@ -1409,17 +1402,5 @@ func textForConsoleEvent(e *cdpruntime.EventConsoleAPICalled, args []any) string return "" } - // args is a mix of string and non strings, so using fmt.Sprint(args...) - // might not add spaces between all elements, therefore use a strings.Builder - // and handle format and concatenation - var b strings.Builder - for i, a := range args { - format := " %v" - if i == 0 { - format = "%v" - } - b.WriteString(fmt.Sprintf(format, a)) - } - - return b.String() + return strings.Join(args, " ") } diff --git a/vendor/github.com/grafana/xk6-browser/common/remote_object.go b/vendor/github.com/grafana/xk6-browser/common/remote_object.go index b51da38a81c..4e35bf9e4fd 100644 --- a/vendor/github.com/grafana/xk6-browser/common/remote_object.go +++ b/vendor/github.com/grafana/xk6-browser/common/remote_object.go @@ -3,19 +3,21 @@ package common import ( "context" "encoding/json" - "errors" "fmt" "math" + "regexp" "strconv" "strings" "github.com/grafana/xk6-browser/k6ext" + "github.com/grafana/xk6-browser/log" cdpruntime "github.com/chromedp/cdproto/runtime" "github.com/dop251/goja" - "github.com/sirupsen/logrus" ) +var bigIntRegex = regexp.MustCompile("^[0-9]*n$") + type objectOverflowError struct{} // Error returns the description of the overflow error. @@ -84,6 +86,24 @@ func multierror(err error, errs ...error) error { return me } +type remoteObjectParseError struct { + error + typ string + subType string + val string +} + +// Error returns a string representation of the error. +func (e *remoteObjectParseError) Error() string { + return fmt.Sprintf("parsing remote object with type: %s subtype: %s val: %s err: %s", + e.typ, e.subType, e.val, e.error.Error()) +} + +// Unwrap returns the wrapped parsing error. +func (e *remoteObjectParseError) Unwrap() error { + return e.error +} + func parseRemoteObjectPreview(op *cdpruntime.ObjectPreview) (map[string]any, error) { obj := make(map[string]any) var result error @@ -140,7 +160,12 @@ func parseRemoteObjectValue( var v any if err := json.Unmarshal([]byte(val), &v); err != nil { - return nil, err + return nil, &remoteObjectParseError{ + error: err, + typ: string(t), + subType: string(st), + val: val, + } } return v, nil @@ -162,12 +187,24 @@ func parseExceptionDetails(exc *cdpruntime.ExceptionDetails) string { return errMsg } +// parseRemoteObject is to be used by callers that require the string value +// to be parsed to a Go type. func parseRemoteObject(obj *cdpruntime.RemoteObject) (any, error) { - if obj.UnserializableValue == "" { + uv := obj.UnserializableValue + + if uv == "" { return parseRemoteObjectValue(obj.Type, obj.Subtype, string(obj.Value), obj.Preview) } - switch obj.UnserializableValue.String() { + if bigIntRegex.Match([]byte(uv)) { + n, err := strconv.ParseInt(strings.ReplaceAll(uv.String(), "n", ""), 10, 64) + if err != nil { + return nil, BigIntParseError{err} + } + return n, nil + } + + switch uv.String() { case "-0": // To handle +0 divided by negative number return math.Float64frombits(0 | (1 << 63)), nil case "NaN": @@ -178,7 +215,10 @@ func parseRemoteObject(obj *cdpruntime.RemoteObject) (any, error) { return math.Inf(-1), nil } - return nil, UnserializableValueError{obj.UnserializableValue} + // We should never get here, as previous switch statement should + // be exhaustive and contain all possible unserializable values. + // See: https://chromedevtools.github.io/devtools-protocol/tot/Runtime/#type-UnserializableValue + return nil, UnserializableValueError{uv} } func valueFromRemoteObject(ctx context.Context, robj *cdpruntime.RemoteObject) (goja.Value, error) { @@ -189,25 +229,95 @@ func valueFromRemoteObject(ctx context.Context, robj *cdpruntime.RemoteObject) ( return k6ext.Runtime(ctx).ToValue(val), err } -func handleParseRemoteObjectErr(ctx context.Context, err error, logger *logrus.Entry) { - var ( - ooe *objectOverflowError - ope *objectPropertyParseError - ) - var merr *multiError - if !errors.As(err, &merr) { - // If this panics it's a bug :) - k6ext.Panic(ctx, "parsing remote object value: %w", err) - } - for _, e := range merr.Errors { - switch { - case errors.As(e, &ooe): - logger.Warn(ooe) - case errors.As(e, &ope): - logger.WithError(ope).Error() - default: - // If this panics it's a bug :) - k6ext.Panic(ctx, "parsing remote object value: %w", e) +func parseConsoleRemoteObjectPreview(logger *log.Logger, op *cdpruntime.ObjectPreview) string { + obj := make(map[string]string) + if op.Overflow { + logger.Infof("parseConsoleRemoteObjectPreview", "object is too large and will be parsed partially") + } + + for _, p := range op.Properties { + val := parseConsoleRemoteObjectValue(logger, p.Type, p.Subtype, p.Value, p.ValuePreview) + obj[p.Name] = val + } + + bb, err := json.Marshal(obj) + if err != nil { + logger.Errorf("parseConsoleRemoteObjectPreview", "failed to marshal object to string: %v", err) + } + + return string(bb) +} + +func parseConsoleRemoteArrayPreview(logger *log.Logger, op *cdpruntime.ObjectPreview) string { + arr := make([]any, 0, len(op.Properties)) + if op.Overflow { + logger.Warnf("parseConsoleRemoteArrayPreview", "array is too large and will be parsed partially") + } + + for _, p := range op.Properties { + val := parseConsoleRemoteObjectValue(logger, p.Type, p.Subtype, p.Value, p.ValuePreview) + arr = append(arr, val) + } + + bb, err := json.Marshal(arr) + if err != nil { + logger.Errorf("parseConsoleRemoteArrayPreview", "failed to marshal array to string: %v", err) + } + + return string(bb) +} + +//nolint:cyclop +func parseConsoleRemoteObjectValue( + logger *log.Logger, + t cdpruntime.Type, + st cdpruntime.Subtype, + val string, + op *cdpruntime.ObjectPreview, +) string { + switch t { + case cdpruntime.TypeAccessor: + return "accessor" + case cdpruntime.TypeFunction: + return "function()" + case cdpruntime.TypeString: + if strings.HasPrefix(val, `"`) { + val = strings.TrimPrefix(val, `"`) + val = strings.TrimSuffix(val, `"`) } + case cdpruntime.TypeObject: + if op != nil { + if st == "array" { + return parseConsoleRemoteArrayPreview(logger, op) + } + return parseConsoleRemoteObjectPreview(logger, op) + } + if val == "Object" { + return val + } + if st == "null" { + return "null" + } + case cdpruntime.TypeUndefined: + return "undefined" + // The following cases are here to clarify that all cases have been + // considered, but that the result will return val without processing it. + case cdpruntime.TypeNumber: + case cdpruntime.TypeBoolean: + case cdpruntime.TypeSymbol: + case cdpruntime.TypeBigint: } + + return val +} + +// parseConsoleRemoteObject is to be used by callers that are working with +// console messages that are written to Chrome's console by the website under +// test. +func parseConsoleRemoteObject(logger *log.Logger, obj *cdpruntime.RemoteObject) string { + if obj.UnserializableValue != "" { + return obj.UnserializableValue.String() + } + + return parseConsoleRemoteObjectValue(logger, obj.Type, obj.Subtype, string(obj.Value), obj.Preview) } diff --git a/vendor/github.com/grafana/xk6-browser/log/logger.go b/vendor/github.com/grafana/xk6-browser/log/logger.go index 3b1fb4bf922..666659565aa 100644 --- a/vendor/github.com/grafana/xk6-browser/log/logger.go +++ b/vendor/github.com/grafana/xk6-browser/log/logger.go @@ -1,7 +1,6 @@ package log import ( - "encoding/json" "fmt" "io" "regexp" @@ -183,16 +182,9 @@ type consoleLogFormatter struct { // Format assembles a message from marshalling elements in the "objects" field // to JSON separated by space, and deletes the field when done. func (f *consoleLogFormatter) Format(entry *logrus.Entry) ([]byte, error) { - if objects, ok := entry.Data["objects"].([]any); ok { - var msg []string - for _, obj := range objects { - // TODO: Log error? - if o, err := json.Marshal(obj); err == nil { - msg = append(msg, string(o)) - } - } - entry.Message = strings.Join(msg, " ") - delete(entry.Data, "objects") + if stringObjects, ok := entry.Data["stringObjects"].([]string); ok { + entry.Message = strings.Join(stringObjects, " ") + delete(entry.Data, "stringObjects") } return f.Formatter.Format(entry) } diff --git a/vendor/modules.txt b/vendor/modules.txt index 317e27d0fa7..19135ed79e0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -149,7 +149,7 @@ github.com/google/uuid # github.com/gorilla/websocket v1.5.1 ## explicit; go 1.20 github.com/gorilla/websocket -# github.com/grafana/xk6-browser v1.2.1 +# github.com/grafana/xk6-browser v1.2.2 ## explicit; go 1.19 github.com/grafana/xk6-browser/browser github.com/grafana/xk6-browser/chromium