From 2df743a97042c7cc66836b518c9656b41942b463 Mon Sep 17 00:00:00 2001 From: Roberto Mier Escandon Date: Wed, 3 May 2023 20:10:46 +0200 Subject: [PATCH] feat: return error when session could not be created. Add session request timeout --- remote.go | 23 ++++++++++++++++++++--- service.go | 14 +++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/remote.go b/remote.go index 5818bc0..5284059 100644 --- a/remote.go +++ b/remote.go @@ -93,6 +93,17 @@ type serverReply struct { Error } +type StackItem struct { + FileName string `json:"fileName"` + ModuleVersion *string `json:"moduleVersion"` + ModuleName *string `json:"moduleName"` + NativeMethod bool `json:"nativeMethod"` + MethodName string `json:"methodName"` + ClassName string `json:"className"` + LineNumber int `json:"lineNumber"` + ClassLoaderName *string `json:"classLoaderName"` +} + // Error contains information about a failure of a command. See the table of // these strings at https://www.w3.org/TR/webdriver/#handling-errors . // @@ -104,7 +115,7 @@ type Error struct { // Message is a detailed, human-readable message specific to the failure. Message string `json:"message"` // Stacktrace may contain the server-side stacktrace where the error occurred. - Stacktrace string `json:"stacktrace"` + Stacktrace []StackItem `json:"stacktrace"` // HTTPCode is the HTTP status code returned by the server. HTTPCode int // LegacyCode is the "Response Status Code" defined in the legacy Selenium @@ -460,9 +471,11 @@ func (wd *remoteWD) NewSession() (string, error) { } return "", err } + if reply.Status != 0 && i < len(attempts) { continue } + if reply.SessionID != nil { wd.id = *reply.SessionID } @@ -495,10 +508,14 @@ func (wd *remoteWD) NewSession() (string, error) { // Legacy implementations returned most data directly in the "values" // key. returnedCapabilities - }{} + Error + }{} if err := json.Unmarshal(reply.Value, &value); err != nil { - return "", fmt.Errorf("error unmarshalling value: %v", err) + return "", fmt.Errorf("error unmarshalling value: %s", err) + } + if len(value.Err) > 0 { + return "", errors.New(value.Message) } if value.SessionID != "" && wd.id == "" { wd.id = value.SessionID diff --git a/service.go b/service.go index bd4a075..a971346 100644 --- a/service.go +++ b/service.go @@ -139,6 +139,14 @@ func V4() ServiceOption { } } +// SessionRequestTimeout specifies the timeout it takes to discard a session request +func SessionRequestTimeout(seconds int) ServiceOption { + return func(s *Service) error { + s.sessionRequestTimeout = seconds + return nil + } +} + // HTMLUnit specifies the path to the JAR for the HTMLUnit driver (compiled // with its dependencies). // @@ -166,7 +174,8 @@ type Service struct { output io.Writer - v4 bool + v4 bool + sessionRequestTimeout int } // FrameBuffer returns the FrameBuffer if one was started by the service and nil otherwise. @@ -201,6 +210,9 @@ func NewSeleniumService(jarPath string, port int, opts ...ServiceOption) (*Servi s.cmd.Args = append(s.cmd.Args, "--ext", strings.Join(classpath, ":")) } s.cmd.Args = append(s.cmd.Args, "standalone", "--port", strconv.Itoa(port)) + if s.sessionRequestTimeout > 0 { + s.cmd.Args = append(s.cmd.Args, "--session-request-timeout", strconv.Itoa(s.sessionRequestTimeout)) + } } else { if s.geckoDriverPath != "" { s.cmd.Args = append([]string{"java", "-Dwebdriver.gecko.driver=" + s.geckoDriverPath}, s.cmd.Args[1:]...)