Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of sessionBrowserName and a fix for maxSessions (#2709 and #3061 #3062

Merged
merged 13 commits into from
May 25, 2022
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ To learn more about our roadmap, we recommend reading [this document](ROADMAP.md

### Improvements

- **Selenium Grid Scaler:** Edge active sessions not being properly counted ([#2709](https://github.com/kedacore/keda/issues/2709))
- **Selenium Grid Scaler:** Max Sessions implementation issue ([#3061](https://github.com/kedacore/keda/issues/3061))
- TODO ([#XXX](https://github.com/kedacore/keda/issue/XXX))

### Deprecations
Expand Down
33 changes: 21 additions & 12 deletions pkg/scalers/selenium_grid_scaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ type seleniumGridScaler struct {
}

type seleniumGridScalerMetadata struct {
url string
browserName string
targetValue int64
browserVersion string
unsafeSsl bool
scalerIndex int
url string
browserName string
sessionBrowserName string
targetValue int64
browserVersion string
unsafeSsl bool
scalerIndex int
}

type seleniumResponse struct {
Expand All @@ -47,6 +48,7 @@ type data struct {

type grid struct {
MaxSession int `json:"maxSession"`
NodeCount int `json:"nodeCount"`
}

type sessionsInfo struct {
Expand Down Expand Up @@ -109,6 +111,12 @@ func parseSeleniumGridScalerMetadata(config *ScalerConfig) (*seleniumGridScalerM
return nil, fmt.Errorf("no browser name given in metadata")
}

if val, ok := config.TriggerMetadata["sessionBrowserName"]; ok {
meta.sessionBrowserName = val
} else {
meta.sessionBrowserName = meta.browserName
}

if val, ok := config.TriggerMetadata["browserVersion"]; ok && val != "" {
meta.browserVersion = val
} else {
Expand Down Expand Up @@ -172,7 +180,7 @@ func (s *seleniumGridScaler) IsActive(ctx context.Context) (bool, error) {

func (s *seleniumGridScaler) getSessionsCount(ctx context.Context) (int64, error) {
body, err := json.Marshal(map[string]string{
"query": "{ grid { maxSession }, sessionsInfo { sessionQueueRequests, sessions { id, capabilities, nodeId } } }",
"query": "{ grid { maxSession, nodeCount }, sessionsInfo { sessionQueueRequests, sessions { id, capabilities, nodeId } } }",
})

if err != nil {
Expand All @@ -199,14 +207,14 @@ func (s *seleniumGridScaler) getSessionsCount(ctx context.Context) (int64, error
if err != nil {
return -1, err
}
v, err := getCountFromSeleniumResponse(b, s.metadata.browserName, s.metadata.browserVersion)
v, err := getCountFromSeleniumResponse(b, s.metadata.browserName, s.metadata.browserVersion, s.metadata.sessionBrowserName)
if err != nil {
return -1, err
}
return v, nil
}

func getCountFromSeleniumResponse(b []byte, browserName string, browserVersion string) (int64, error) {
func getCountFromSeleniumResponse(b []byte, browserName string, browserVersion string, sessionBrowserName string) (int64, error) {
var count int64
var seleniumResponse = seleniumResponse{}

Expand Down Expand Up @@ -234,7 +242,7 @@ func getCountFromSeleniumResponse(b []byte, browserName string, browserVersion s
for _, session := range sessions {
var capability = capability{}
if err := json.Unmarshal([]byte(session.Capabilities), &capability); err == nil {
if capability.BrowserName == browserName {
if capability.BrowserName == sessionBrowserName {
if strings.HasPrefix(capability.BrowserVersion, browserVersion) {
count++
} else if browserVersion == DefaultBrowserVersion {
Expand All @@ -247,9 +255,10 @@ func getCountFromSeleniumResponse(b []byte, browserName string, browserVersion s
}

var gridMaxSession = int64(seleniumResponse.Data.Grid.MaxSession)
var gridNodeCount = int64(seleniumResponse.Data.Grid.NodeCount)

if gridMaxSession > 0 {
count = (count + gridMaxSession - 1) / gridMaxSession
if gridMaxSession > 0 && gridNodeCount > 0 {
count /= (gridMaxSession / gridNodeCount)
}

return count, nil
Expand Down
91 changes: 71 additions & 20 deletions pkg/scalers/selenium_grid_scaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (

func Test_getCountFromSeleniumResponse(t *testing.T) {
type args struct {
b []byte
browserName string
browserVersion string
b []byte
browserName string
sessionBrowserName string
browserVersion string
}
tests := []struct {
name string
Expand All @@ -18,7 +19,7 @@ func Test_getCountFromSeleniumResponse(t *testing.T) {
wantErr bool
}{
{
name: "nil response body should through error",
name: "nil response body should throw error",
args: args{
b: []byte(nil),
browserName: "",
Expand All @@ -27,7 +28,7 @@ func Test_getCountFromSeleniumResponse(t *testing.T) {
wantErr: true,
},
{
name: "empty response body should through error",
name: "empty response body should throw error",
args: args{
b: []byte(""),
browserName: "",
Expand All @@ -41,7 +42,8 @@ func Test_getCountFromSeleniumResponse(t *testing.T) {
b: []byte(`{
"data": {
"grid":{
"maxSession": 1
"maxSession": 0,
"nodeCount": 0
},
"sessionsInfo": {
"sessionQueueRequests": [],
Expand All @@ -60,7 +62,8 @@ func Test_getCountFromSeleniumResponse(t *testing.T) {
b: []byte(`{
"data": {
"grid":{
"maxSession": 1
"maxSession": 1,
"nodeCount": 1
},
"sessionsInfo": {
"sessionQueueRequests": ["{\n \"browserName\": \"chrome\"\n}","{\n \"browserName\": \"chrome\"\n}"],
Expand All @@ -86,7 +89,8 @@ func Test_getCountFromSeleniumResponse(t *testing.T) {
b: []byte(`{
"data": {
"grid":{
"maxSession": 1
"maxSession": 1,
"nodeCount": 1
},
"sessionsInfo": {
"sessionQueueRequests": ["{\n \"browserName\": \"chrome\"\n}","{\n \"browserName\": \"chrome\"\n}"],
Expand All @@ -101,40 +105,58 @@ func Test_getCountFromSeleniumResponse(t *testing.T) {
wantErr: false,
},
{
name: "active sessions with matching browsername and maxSession=2 should return count as 1",
name: "2 active sessions with matching browsername on 2 nodes and maxSession=4 should return count as 3",
args: args{
b: []byte(`{
"data": {
"grid":{
"maxSession": 2
"maxSession": 4,
"nodeCount": 2
},
"sessionsInfo": {
"sessionQueueRequests": ["{\n \"browserName\": \"chrome\",\n \"browserVersion\": \"91.0\"\n}","{\n \"browserName\": \"chrome\"\n}"],
"sessions": []
"sessionQueueRequests": ["{\n \"browserName\": \"chrome\",\n \"browserVersion\": \"91.0\"\n}","{\n \"browserName\": \"chrome\"\n}","{\n \"browserName\": \"chrome\"\n}"],
"sessions": [
{
"id": "0f9c5a941aa4d755a54b84be1f6535b1",
"capabilities": "{\n \"acceptInsecureCerts\": false,\n \"browserName\": \"chrome\",\n \"browserVersion\": \"91.0.4472.114\",\n \"chrome\": {\n \"chromedriverVersion\": \"91.0.4472.101 (af52a90bf87030dd1523486a1cd3ae25c5d76c9b-refs\\u002fbranch-heads\\u002f4472@{#1462})\",\n \"userDataDir\": \"\\u002ftmp\\u002f.com.google.Chrome.DMqx9m\"\n },\n \"goog:chromeOptions\": {\n \"debuggerAddress\": \"localhost:35839\"\n },\n \"networkConnectionEnabled\": false,\n \"pageLoadStrategy\": \"normal\",\n \"platformName\": \"linux\",\n \"proxy\": {\n },\n \"se:cdp\": \"http:\\u002f\\u002flocalhost:35839\",\n \"se:cdpVersion\": \"91.0.4472.114\",\n \"se:vncEnabled\": true,\n \"se:vncLocalAddress\": \"ws:\\u002f\\u002flocalhost:7900\\u002fwebsockify\",\n \"setWindowRect\": true,\n \"strictFileInteractability\": false,\n \"timeouts\": {\n \"implicit\": 0,\n \"pageLoad\": 300000,\n \"script\": 30000\n },\n \"unhandledPromptBehavior\": \"dismiss and notify\",\n \"webauthn:extension:largeBlob\": true,\n \"webauthn:virtualAuthenticators\": true\n}",
"nodeId": "d44dcbc5-0b2c-4d5e-abf4-6f6aa5e0983c"
},
{
"id": "0f9c5a941aa4d755a54b84be1f6535b2",
"capabilities": "{\n \"acceptInsecureCerts\": false,\n \"browserName\": \"chrome\",\n \"browserVersion\": \"91.0.4472.114\",\n \"chrome\": {\n \"chromedriverVersion\": \"91.0.4472.101 (af52a90bf87030dd1523486a1cd3ae25c5d76c9b-refs\\u002fbranch-heads\\u002f4472@{#1462})\",\n \"userDataDir\": \"\\u002ftmp\\u002f.com.google.Chrome.DMqx9m\"\n },\n \"goog:chromeOptions\": {\n \"debuggerAddress\": \"localhost:35839\"\n },\n \"networkConnectionEnabled\": false,\n \"pageLoadStrategy\": \"normal\",\n \"platformName\": \"linux\",\n \"proxy\": {\n },\n \"se:cdp\": \"http:\\u002f\\u002flocalhost:35839\",\n \"se:cdpVersion\": \"91.0.4472.114\",\n \"se:vncEnabled\": true,\n \"se:vncLocalAddress\": \"ws:\\u002f\\u002flocalhost:7900\\u002fwebsockify\",\n \"setWindowRect\": true,\n \"strictFileInteractability\": false,\n \"timeouts\": {\n \"implicit\": 0,\n \"pageLoad\": 300000,\n \"script\": 30000\n },\n \"unhandledPromptBehavior\": \"dismiss and notify\",\n \"webauthn:extension:largeBlob\": true,\n \"webauthn:virtualAuthenticators\": true\n}",
"nodeId": "d44dcbc5-0b2c-4d5e-abf4-6f6aa5e0983c"
}
]
}
}
}`),
browserName: "chrome",
browserVersion: "latest",
},
want: 1,
want: 3,
wantErr: false,
},
{
name: "active sessions with matching browsername should return count as 3",
name: "2 active sessions with matching browsername on 2 nodes should return count as 5",
args: args{
b: []byte(`{
"data": {
"sessionsInfo": {
"grid":{
"maxSession": 1
"maxSession": 2,
"nodeCount": 2
},
"sessionQueueRequests": ["{\n \"browserName\": \"chrome\"\n}","{\n \"browserName\": \"chrome\"\n}"],
"sessionQueueRequests": ["{\n \"browserName\": \"chrome\"\n}","{\n \"browserName\": \"chrome\"\n}","{\n \"browserName\": \"chrome\"\n}"],
"sessions": [
{
"id": "0f9c5a941aa4d755a54b84be1f6535b1",
"capabilities": "{\n \"acceptInsecureCerts\": false,\n \"browserName\": \"chrome\",\n \"browserVersion\": \"91.0.4472.114\",\n \"chrome\": {\n \"chromedriverVersion\": \"91.0.4472.101 (af52a90bf87030dd1523486a1cd3ae25c5d76c9b-refs\\u002fbranch-heads\\u002f4472@{#1462})\",\n \"userDataDir\": \"\\u002ftmp\\u002f.com.google.Chrome.DMqx9m\"\n },\n \"goog:chromeOptions\": {\n \"debuggerAddress\": \"localhost:35839\"\n },\n \"networkConnectionEnabled\": false,\n \"pageLoadStrategy\": \"normal\",\n \"platformName\": \"linux\",\n \"proxy\": {\n },\n \"se:cdp\": \"http:\\u002f\\u002flocalhost:35839\",\n \"se:cdpVersion\": \"91.0.4472.114\",\n \"se:vncEnabled\": true,\n \"se:vncLocalAddress\": \"ws:\\u002f\\u002flocalhost:7900\\u002fwebsockify\",\n \"setWindowRect\": true,\n \"strictFileInteractability\": false,\n \"timeouts\": {\n \"implicit\": 0,\n \"pageLoad\": 300000,\n \"script\": 30000\n },\n \"unhandledPromptBehavior\": \"dismiss and notify\",\n \"webauthn:extension:largeBlob\": true,\n \"webauthn:virtualAuthenticators\": true\n}",
"nodeId": "d44dcbc5-0b2c-4d5e-abf4-6f6aa5e0983c"
},
{
"id": "0f9c5a941aa4d755a54b84be1f6535b2",
"capabilities": "{\n \"acceptInsecureCerts\": false,\n \"browserName\": \"chrome\",\n \"browserVersion\": \"91.0.4472.114\",\n \"chrome\": {\n \"chromedriverVersion\": \"91.0.4472.101 (af52a90bf87030dd1523486a1cd3ae25c5d76c9b-refs\\u002fbranch-heads\\u002f4472@{#1462})\",\n \"userDataDir\": \"\\u002ftmp\\u002f.com.google.Chrome.DMqx9m\"\n },\n \"goog:chromeOptions\": {\n \"debuggerAddress\": \"localhost:35839\"\n },\n \"networkConnectionEnabled\": false,\n \"pageLoadStrategy\": \"normal\",\n \"platformName\": \"linux\",\n \"proxy\": {\n },\n \"se:cdp\": \"http:\\u002f\\u002flocalhost:35839\",\n \"se:cdpVersion\": \"91.0.4472.114\",\n \"se:vncEnabled\": true,\n \"se:vncLocalAddress\": \"ws:\\u002f\\u002flocalhost:7900\\u002fwebsockify\",\n \"setWindowRect\": true,\n \"strictFileInteractability\": false,\n \"timeouts\": {\n \"implicit\": 0,\n \"pageLoad\": 300000,\n \"script\": 30000\n },\n \"unhandledPromptBehavior\": \"dismiss and notify\",\n \"webauthn:extension:largeBlob\": true,\n \"webauthn:virtualAuthenticators\": true\n}",
"nodeId": "d44dcbc5-0b2c-4d5e-abf4-6f6aa5e0983c"
}
]
}
Expand All @@ -143,16 +165,17 @@ func Test_getCountFromSeleniumResponse(t *testing.T) {
browserName: "chrome",
browserVersion: "latest",
},
want: 3,
want: 5,
wantErr: false,
},
{
name: "active sessions with matching browsername and version should return count as 2",
name: "1 active session with matching browsername and version should return count as 2",
args: args{
b: []byte(`{
"data": {
"grid":{
"maxSession": 1
"maxSession": 1,
"nodeCount": 1
},
"sessionsInfo": {
"sessionQueueRequests": ["{\n \"browserName\": \"chrome\",\n \"browserVersion\": \"91.0\"\n}","{\n \"browserName\": \"chrome\"\n}"],
Expand All @@ -172,10 +195,38 @@ func Test_getCountFromSeleniumResponse(t *testing.T) {
want: 2,
wantErr: false,
},
{
name: "1 active msedge session with matching browsername/sessionBroswerName should return count as 3",
args: args{
b: []byte(`{
"data": {
"grid":{
"maxSession": 1,
"nodeCount": 1
},
"sessionsInfo": {
"sessionQueueRequests": ["{\n \"browserName\": \"MicrosoftEdge\"\n}","{\n \"browserName\": \"MicrosoftEdge\"\n}"],
"sessions": [
{
"id": "0f9c5a941aa4d755a54b84be1f6535b1",
"capabilities": "{\n \"acceptInsecureCerts\": false,\n \"browserName\": \"msedge\",\n \"browserVersion\": \"91.0.4472.114\",\n \"msedge\": {\n \"msedgedriverVersion\": \"91.0.4472.101 (af52a90bf87030dd1523486a1cd3ae25c5d76c9b-refs\\u002fbranch-heads\\u002f4472@{#1462})\",\n \"userDataDir\": \"\\u002ftmp\\u002f.com.google.Chrome.DMqx9m\"\n },\n \"ms:edgeOptions\": {\n \"debuggerAddress\": \"localhost:35839\"\n },\n \"networkConnectionEnabled\": false,\n \"pageLoadStrategy\": \"normal\",\n \"platformName\": \"linux\",\n \"proxy\": {\n },\n \"se:cdp\": \"http:\\u002f\\u002flocalhost:35839\",\n \"se:cdpVersion\": \"91.0.4472.114\",\n \"se:vncEnabled\": true,\n \"se:vncLocalAddress\": \"ws:\\u002f\\u002flocalhost:7900\\u002fwebsockify\",\n \"setWindowRect\": true,\n \"strictFileInteractability\": false,\n \"timeouts\": {\n \"implicit\": 0,\n \"pageLoad\": 300000,\n \"script\": 30000\n },\n \"unhandledPromptBehavior\": \"dismiss and notify\",\n \"webauthn:extension:largeBlob\": true,\n \"webauthn:virtualAuthenticators\": true\n}",
"nodeId": "d44dcbc5-0b2c-4d5e-abf4-6f6aa5e0983c"
}
]
}
}
}`),
browserName: "MicrosoftEdge",
sessionBrowserName: "msedge",
browserVersion: "latest",
},
want: 3,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := getCountFromSeleniumResponse(tt.args.b, tt.args.browserName, tt.args.browserVersion)
got, err := getCountFromSeleniumResponse(tt.args.b, tt.args.browserName, tt.args.browserVersion, tt.args.sessionBrowserName)
if (err != nil) != tt.wantErr {
t.Errorf("getCountFromSeleniumResponse() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down