Skip to content
This repository has been archived by the owner on Dec 17, 2024. It is now read-only.

Commit

Permalink
Merge pull request #433 from vania-pooh/master
Browse files Browse the repository at this point in the history
Added ability to override session timeout (fixes #262)
  • Loading branch information
aandryashin authored May 12, 2018
2 parents 9d08692 + f599b18 commit 366fb7e
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 6 deletions.
2 changes: 2 additions & 0 deletions docs/cli-flags.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ The following flags are supported by `selenoid` command:
Network address to accept connections (default ":4444")
-log-conf string
Container logging configuration file (default "config/container-logs.json")
-max-timeout duration
Maximum valid session idle timeout in time.Duration format (default 1h0m0s)
-mem value
Containers memory limit e.g. 128m or 1g
-retry-count int
Expand Down
11 changes: 11 additions & 0 deletions docs/special-capabilities.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ name: "myCoolTestName"

The main application of this capability - is debugging tests in the UI which is showing specified name for every running session.

=== Custom Session Timeout: sessionTimeout

Sometimes you may want to change idle timeout for selected browser session. To achieve this - pass the following capability:

.Type: int
----
sessionTimeout: 30
----

Timeout is always specified in seconds, should be positive and can be no more than the value set by `-max-timeout` flag.

=== Per-session Time Zone: timeZone

Some tests require particular time zone to be set in operating system.
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ var (
enableFileUpload bool
listen string
timeout time.Duration
maxTimeout time.Duration
newSessionAttemptTimeout time.Duration
sessionDeleteTimeout time.Duration
serviceStartupTimeout time.Duration
Expand Down Expand Up @@ -104,6 +105,7 @@ func init() {
flag.IntVar(&limit, "limit", 5, "Simultaneous container runs")
flag.IntVar(&retryCount, "retry-count", 1, "New session attempts retry count")
flag.DurationVar(&timeout, "timeout", 60*time.Second, "Session idle timeout in time.Duration format")
flag.DurationVar(&maxTimeout, "max-timeout", 1*time.Hour, "Maximum valid session idle timeout in time.Duration format")
flag.DurationVar(&newSessionAttemptTimeout, "session-attempt-timeout", 30*time.Second, "New session attempt timeout in time.Duration format")
flag.DurationVar(&sessionDeleteTimeout, "session-delete-timeout", 30*time.Second, "Session delete timeout in time.Duration format")
flag.DurationVar(&serviceStartupTimeout, "service-startup-timeout", 30*time.Second, "Service startup timeout in time.Duration format")
Expand Down
28 changes: 24 additions & 4 deletions selenoid.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ func create(w http.ResponseWriter, r *http.Request) {
browser.Caps = browser.W3CCaps.Caps
}
browser.Caps.ProcessExtensionCapabilities()
sessionTimeout, err := getSessionTimeout(browser.Caps.SessionTimeout, maxTimeout, timeout)
if err != nil {
log.Printf("[%d] [BAD_SESSION_TIMEOUT] [%ds]", requestId, browser.Caps.SessionTimeout)
util.JsonError(w, err.Error(), http.StatusBadRequest)
queue.Drop()
return
}
resolution, err := getScreenResolution(browser.Caps.ScreenResolution)
if err != nil {
log.Printf("[%d] [BAD_SCREEN_RESOLUTION] [%s]", requestId, browser.Caps.ScreenResolution)
Expand Down Expand Up @@ -273,7 +280,8 @@ func create(w http.ResponseWriter, r *http.Request) {
Fileserver: startedService.FileserverHostPort,
VNC: startedService.VNCHostPort,
Cancel: cancelAndRenameVideo,
Timeout: onTimeout(timeout, func() {
Timeout: sessionTimeout,
TimeoutCh: onTimeout(sessionTimeout, func() {
request{r}.session(s.ID).Delete(requestId)
})})
queue.Create()
Expand Down Expand Up @@ -320,6 +328,18 @@ func getVideoScreenSize(videoScreenSize string, screenResolution string) (string
return shortenScreenResolution(screenResolution), nil
}

func getSessionTimeout(sessionTimeout uint32, maxTimeout time.Duration, defaultTimeout time.Duration) (time.Duration, error) {
if sessionTimeout > 0 {
std := time.Duration(sessionTimeout) * time.Second
if std <= maxTimeout {
return std, nil
} else {
return 0, fmt.Errorf("Invalid sessionTimeout capability: should be <= %s", maxTimeout)
}
}
return defaultTimeout, nil
}

func getVideoFileName(videoOutputDir string) string {
filename := ""
for {
Expand Down Expand Up @@ -355,9 +375,9 @@ func proxy(w http.ResponseWriter, r *http.Request) {
sess.Lock.Lock()
defer sess.Lock.Unlock()
select {
case <-sess.Timeout:
case <-sess.TimeoutCh:
default:
close(sess.Timeout)
close(sess.TimeoutCh)
}
if r.Method == http.MethodDelete && len(fragments) == 3 {
if enableFileUpload {
Expand All @@ -368,7 +388,7 @@ func proxy(w http.ResponseWriter, r *http.Request) {
queue.Release()
log.Printf("[%d] [SESSION_DELETED] [%s]", requestId, id)
} else {
sess.Timeout = onTimeout(timeout, func() {
sess.TimeoutCh = onTimeout(sess.Timeout, func() {
request{r}.session(id).Delete(requestId)
})
if len(fragments) == 4 && fragments[len(fragments)-1] == "file" && enableFileUpload {
Expand Down
21 changes: 20 additions & 1 deletion selenoid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,24 @@ func TestGetShortScreenResolution(t *testing.T) {
AssertThat(t, res, EqualTo{"1024x768x24"})
}

func TestInvalidSessionTimeoutCapability(t *testing.T) {
testBadSessionTimeoutCapability(t, 3601)
}

func TestNegativeSessionTimeoutCapability(t *testing.T) {
testBadSessionTimeoutCapability(t, -1)
}

func testBadSessionTimeoutCapability(t *testing.T, timeoutValue int) {
manager = &BrowserNotFound{}

rsp, err := http.Post(With(srv.URL).Path("/wd/hub/session"), "", bytes.NewReader([]byte(fmt.Sprintf(`{"desiredCapabilities":{"sessionTimeout":%d}}`, timeoutValue))))
AssertThat(t, err, Is{nil})
AssertThat(t, rsp, Code{http.StatusBadRequest})

AssertThat(t, queue.Used(), EqualTo{0})
}

func TestMalformedScreenResolutionCapability(t *testing.T) {
manager = &BrowserNotFound{}

Expand Down Expand Up @@ -174,8 +192,9 @@ func TestNewSessionBadHostResponse(t *testing.T) {

func TestSessionCreated(t *testing.T) {
manager = &HTTPTest{Handler: Selenium()}
timeout = 5 * time.Second

resp, err := http.Post(With(srv.URL).Path("/wd/hub/session"), "", bytes.NewReader([]byte(`{"desiredCapabilities": {"enableVideo": true, "enableVNC": true}}`)))
resp, err := http.Post(With(srv.URL).Path("/wd/hub/session"), "", bytes.NewReader([]byte(`{"desiredCapabilities": {"enableVideo": true, "enableVNC": true, "sessionTimeout": 3}}`)))
AssertThat(t, err, Is{nil})
var sess map[string]string
AssertThat(t, resp, AllOf{Code{http.StatusOK}, IsJson{&sess}})
Expand Down
5 changes: 4 additions & 1 deletion session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"net/url"
"reflect"
"sync"
"time"
)

// Caps - user capabilities
Expand All @@ -24,6 +25,7 @@ type Caps struct {
ApplicationContainers []string `json:"applicationContainers"`
HostsEntries []string `json:"hostsEntries"`
Labels map[string]string `json:"labels"`
SessionTimeout uint32 `json:"sessionTimeout"`
ExtensionCapabilities map[string]interface{} `json:"selenoid:options"`
}

Expand Down Expand Up @@ -70,7 +72,8 @@ type Session struct {
Fileserver string
VNC string
Cancel func()
Timeout chan struct{}
Timeout time.Duration
TimeoutCh chan struct{}
Lock sync.Mutex
}

Expand Down

0 comments on commit 366fb7e

Please sign in to comment.