diff --git a/common/browser_options.go b/common/browser_options.go index e86e0d0fe..c6121cfa2 100644 --- a/common/browser_options.go +++ b/common/browser_options.go @@ -5,7 +5,6 @@ import ( "time" "github.com/dop251/goja" - "golang.org/x/exp/slices" "github.com/grafana/xk6-browser/k6ext" "github.com/grafana/xk6-browser/log" @@ -118,5 +117,5 @@ func (l *LaunchOptions) shouldIgnoreOnCloud(opt string) bool { if !l.onCloud { return false } - return slices.Contains([]string{"devtools", "executablePath", "headless"}, opt) + return opt == "devtools" || opt == "executablePath" || opt == "headless" } diff --git a/common/remote_object.go b/common/remote_object.go index 37e661bdb..c93ad689d 100644 --- a/common/remote_object.go +++ b/common/remote_object.go @@ -13,7 +13,6 @@ import ( cdpruntime "github.com/chromedp/cdproto/runtime" "github.com/dop251/goja" - "github.com/hashicorp/go-multierror" "github.com/sirupsen/logrus" ) @@ -40,17 +39,62 @@ func (pe *objectPropertyParseError) Unwrap() error { return pe.error } +type multiError struct { + Errors []error +} + +func (me *multiError) append(err error) { + me.Errors = append(me.Errors, err) +} + +func (me multiError) Error() string { + if len(me.Errors) == 0 { + return "" + } + if len(me.Errors) == 1 { + return me.Errors[0].Error() + } + + var buf strings.Builder + fmt.Fprintf(&buf, "%d errors occurred:\n", len(me.Errors)) + for _, e := range me.Errors { + fmt.Fprintf(&buf, "\t* %s\n", e) + } + + return buf.String() +} + +func multierror(err error, errs ...error) error { + me := &multiError{} + // We can't use errors.As(), as we want to know if err is of type + // multiError, not any error in the chain. If err contains a wrapped + // multierror, start a new multiError that will contain err. + e, ok := err.(*multiError) //nolint:errorlint + + if ok { + me = e + } else if err != nil { + me.append(err) + } + + for _, e := range errs { + me.append(e) + } + + return me +} + func parseRemoteObjectPreview(op *cdpruntime.ObjectPreview) (map[string]any, error) { obj := make(map[string]any) var result error if op.Overflow { - result = multierror.Append(result, &objectOverflowError{}) + result = multierror(result, &objectOverflowError{}) } for _, p := range op.Properties { val, err := parseRemoteObjectValue(p.Type, p.Value, p.ValuePreview) if err != nil { - result = multierror.Append(result, &objectPropertyParseError{err, p.Name}) + result = multierror(result, &objectPropertyParseError{err, p.Name}) continue } obj[p.Name] = val @@ -145,8 +189,8 @@ func handleParseRemoteObjectErr(ctx context.Context, err error, logger *logrus.E ooe *objectOverflowError ope *objectPropertyParseError ) - merr, ok := err.(*multierror.Error) - if !ok { + var merr *multiError + if !errors.As(err, &merr) { // If this panics it's a bug :) k6ext.Panic(ctx, "parsing remote object value: %w", err) } diff --git a/common/remote_object_test.go b/common/remote_object_test.go index 88fcdd176..0519b76c1 100644 --- a/common/remote_object_test.go +++ b/common/remote_object_test.go @@ -2,6 +2,8 @@ package common import ( "encoding/json" + "errors" + "fmt" "math" "testing" @@ -234,3 +236,74 @@ func TestParseRemoteObject(t *testing.T) { }) } } + +func TestMultierror(t *testing.T) { + t.Parallel() + + var ( + mockErr1 = errors.New("mockErr1") + mockErr2 = errors.New("mockErr2") + mockErr3 = errors.New("mockErr3") + + mockMultiErr = &multiError{ + Errors: []error{mockErr1}, + } + mockWrappedMultiErr = fmt.Errorf("%w", mockMultiErr) + ) + + tests := []struct { + name string + initial error + errs []error + exp []error + expStr string + }{ + { + name: "initial error is nil", + initial: nil, + errs: []error{mockErr1}, + exp: []error{mockErr1}, + expStr: mockErr1.Error(), + }, + { + name: "initial error is std error", + initial: mockErr1, + errs: []error{mockErr2, mockErr3}, + exp: []error{mockErr1, mockErr2, mockErr3}, + expStr: fmt.Sprintf( + "3 errors occurred:\n\t* %s\n\t* %s\n\t* %s\n", + mockErr1, mockErr2, mockErr3), + }, + { + name: "initial error is multiError", + initial: mockMultiErr, + errs: []error{mockErr3}, + exp: []error{mockErr1, mockErr3}, + expStr: fmt.Sprintf( + "2 errors occurred:\n\t* %s\n\t* %s\n", + mockErr1, mockErr3), + }, + { + name: "initial error is wrapped multiError", + initial: mockWrappedMultiErr, + errs: []error{mockErr3, mockErr2}, + exp: []error{mockWrappedMultiErr, mockErr3, mockErr2}, + expStr: fmt.Sprintf( + "3 errors occurred:\n\t* %s\n\t* %s\n\t* %s\n", + mockWrappedMultiErr, mockErr3, mockErr2), + }, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + + err := multierror(tc.initial, tc.errs...) + var me *multiError + assert.True(t, errors.As(err, &me)) + assert.Equal(t, tc.exp, me.Errors) + assert.Equal(t, tc.expStr, me.Error()) + }) + } +} diff --git a/go.mod b/go.mod index 05bf2bff3..a36152bf3 100644 --- a/go.mod +++ b/go.mod @@ -5,19 +5,16 @@ go 1.19 require ( github.com/chromedp/cdproto v0.0.0-20221023212508-67ada9507fb2 github.com/dop251/goja v0.0.0-20221229151140-b95230a9dbad - github.com/fatih/color v1.13.0 github.com/gorilla/websocket v1.5.0 - github.com/hashicorp/go-multierror v1.1.1 github.com/mailru/easyjson v0.7.7 github.com/mccutchen/go-httpbin v1.1.2-0.20190116014521-c5cb2f4802fa github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.0 go.k6.io/k6 v0.42.1-0.20230109152238-8418147fa630 - golang.org/x/exp v0.0.0-20221106115401-f9659909a136 golang.org/x/net v0.1.0 golang.org/x/sync v0.1.0 - gopkg.in/guregu/null.v3 v3.5.0 + gopkg.in/guregu/null.v3 v3.3.0 ) require ( @@ -29,9 +26,10 @@ require ( github.com/chromedp/sysutil v1.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect + github.com/fatih/color v1.13.0 // indirect github.com/go-sourcemap/sourcemap v2.1.4-0.20211119122758-180fcef48034+incompatible // indirect github.com/golang/protobuf v1.5.2 // indirect - github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/google/go-cmp v0.5.8 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/compress v1.15.11 // indirect github.com/mattn/go-colorable v0.1.13 // indirect diff --git a/go.sum b/go.sum index d3ac07247..2fb1ec832 100644 --- a/go.sum +++ b/go.sum @@ -140,6 +140,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -162,11 +163,6 @@ github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8 github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= -github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -283,8 +279,6 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20221106115401-f9659909a136 h1:Fq7F/w7MAa1KJ5bt2aJ62ihqp9HDcRuyILskkpIAurw= -golang.org/x/exp v0.0.0-20221106115401-f9659909a136/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -593,8 +587,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/guregu/null.v3 v3.5.0 h1:xTcasT8ETfMcUHn0zTvIYtQud/9Mx5dJqD554SZct0o= -gopkg.in/guregu/null.v3 v3.5.0/go.mod h1:E4tX2Qe3h7QdL+uZ3a0vqvYwKQsRSQKM5V4YltdgH9Y= +gopkg.in/guregu/null.v3 v3.3.0 h1:8j3ggqq+NgKt/O7mbFVUFKUMWN+l1AmT5jQmJ6nPh2c= +gopkg.in/guregu/null.v3 v3.3.0/go.mod h1:E4tX2Qe3h7QdL+uZ3a0vqvYwKQsRSQKM5V4YltdgH9Y= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/log/logger.go b/log/logger.go index 0c651934c..722aae963 100644 --- a/log/logger.go +++ b/log/logger.go @@ -11,7 +11,6 @@ import ( "sync" "time" - "github.com/fatih/color" "github.com/sirupsen/logrus" ) @@ -33,10 +32,20 @@ func NewNullLogger() *Logger { // New creates a new logger. func New(logger *logrus.Logger, iterID string) *Logger { - return &Logger{ + var defLogger bool + if logger == nil { + defLogger = true + logger = logrus.New() + } + l := &Logger{ Logger: logger, iterID: iterID, } + if defLogger { + l.Warnf("Logger", "no logger supplied, using default") + } + + return l } // Tracef logs a trace message. @@ -88,11 +97,6 @@ func (l *Logger) Logf(level logrus.Level, category string, msg string, args ...a if l.categoryFilter != nil && !l.categoryFilter.MatchString(category) { return } - if l.Logger == nil { - magenta := color.New(color.FgMagenta).SprintFunc() - fmt.Printf("%s [%d]: %s - %s ms\n", magenta(category), goRoutineID(), string(msg), magenta(elapsed)) - return - } fields := logrus.Fields{ "category": category, "elapsed": fmt.Sprintf("%d ms", elapsed),