Skip to content

feat(cli): apply the server SDK config override - #301

Open
kamal-kaur04 wants to merge 8 commits into
mainfrom
SDK-7954-server-config-override
Open

kamal-kaur04 wants to merge 8 commits into
mainfrom
SDK-7954-server-config-override

Conversation

@kamal-kaur04

@kamal-kaur04 kamal-kaur04 commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

What is this about?

In a binary-flow (central-auth) build, the SDK Config Server's sdk_config becomes the effective config for any key; parallelsPerPlatform is the primary one. The binary merges it and forwards two keys in the Start/ConnectBinSession config:

  • serverSdkConfig: the normalised server config;
  • serverSdkConfigKeys: the keys the server actually overrode.

This PR makes the service apply exactly those keys and map ppp onto WebdriverIO's concurrency.

Isolation: the new code runs only when the binary sends an object serverSdkConfig and an array serverSdkConfigKeys. With no override, on the fallback path, or with an older binary, behaviour is identical to main.

What it does:

  • Options merge (src/cli/index.ts applyServerConfig, called right after setConfig in loadModules, in the launcher and in every worker):
    • Only the listed keys are deep-merged into the service options: objects recursive, arrays element-wise, null replaces.
    • The renames getBinConfig makes are mapped back: browserStackLocalOptions → opts, and testContextOptions → setSessionName/setSessionStatus/sessionName*.
    • Merge logic: CLIUtils.applyServerSdkConfig.
  • Runner concurrency (src/launcher.ts _applyServerConfigToRunner, right after the binary starts in onPrepare, CLI flow only):
    • A listed parallelsPerPlatform sets each capability's wdio:maxInstances and raises config.maxInstances to at least capabilities × ppp. The runner builds its schedule after onPrepare, so this takes effect.
    • A server platforms[i] is layered onto capability i, with flattened keys put back under bstack:options.
    • A listed accessibility re-derives the launcher's accessibility flag.
  • Precedence: server > CLI > env > wdio.conf. A server ppp beats a user-written maxInstances.

Testing

  • Unit: 1456 passed vs 1438 on main. Lint and build/tsc pass.

  • E2E: this service × binary https://github.com/browserstack/browserstack-binary/pull/1967 (WDIO guard removal), mock config server, wdio 9.32 mocha, 12 specs × Win11 chrome + edge:

    Row Specs Peak concurrent Applied keys
    ppp-up (local 1 → server 3) 24/24 6 (runner maxInstances 6, per-capability [3,3]) parallelsPerPlatform
    ppp-down (local 3 → server 1) 24/24 2 (per-capability [1,1]) parallelsPerPlatform
    no override, head vs main build 24/24 each 4 / 4 none; config sent and capabilities after onPrepare identical
    fetch-fail (HTTP 500) 24/24 4 none
    echo-only 24/24 4 none
    multi-key (ppp 3 + skipSessionName + platforms[0] latest-1) 24/24 6 parallelsPerPlatform, platforms, testContextOptions (chrome ran latest-1, 0 sessions named)

Fixes after review / key matrix

  • applyServerPlatform: a server platforms[i] key that the capability holds both at the top level and in bstack:options is now written to bstack:options (getBinConfig flattens that copy last, so it is the one sent).
  • sessionNameFormat: a server value (always a string) is no longer mapped onto the option, which the automate module calls as a function. Previously every session failed naming/marking.

Key matrix (one combined override build + early-keys build + no-override control; mock config server, v9 service × binary #1967)

Key (local → server) Verdict Notes
parallelsPerPlatform ✅ runner maxInstances/per-capability set from the server value; peak follows it
browserstackLocal (both directions) + opts (localIdentifier, forceLocal) ✅ local:true with the server id, tunnel started --force-local, none left afterwards
accessibility false → true ✅ chrome sessions scanned (edge is not A11y-supported)
testObservability (both directions) ✅ O11y build with all tests / no O11y build
testContextOptions skipSessionName / skipSessionStatus (both directions) ✅
buildIdentifier ✅
networkLogs, consoleLogs, seleniumVersion, platforms browserVersion / os / osVersion ✅ reach the hub caps
userName / accessKey / hubUrl ✅ ignored binary-internal keys, never merged
buildName / projectName ⚠️ reach Automate; O11y/A11y builds keep the local identity (created at build start, before the merge)
accessibilityOptions.wcagVersion ⚠️ caps carry the server value; the A11y build keeps the local one (created at build start)
debug ⚠️ a per-capability value the user set beats the server's top-level value; target platforms[i] for those
logLevel ⚠️ changes the binary's log only; the service logger level is fixed at construction
buildTag (top level) ⚠️ merged, but nothing after the merge consumes it
accessibility true → false ⚠️ no scans, but caps keep accessibility:true; the no-override decline control shows the same (pre-existing)
testObservabilityOptions.buildTag ➖ WDIO-only keys inside it are dropped by the binary's yml-style validation
testOrchestrationOptions, testManagementOptions, framework ➖ consumed before the merge (build start / before bootstrap)
appended platform ➖ inert: no worker for an entry beyond the wdio.conf capabilities
null on a top-level key ➖ not listed, nothing changes
turboScale 💥 treated like any key: session naming/status move to the TurboScale API, so sessions aren't named/marked. Don't override it from the server
null on a capability key 💥 null replaces, and the hub rejects that platform's sessions. Rails must not send null for capability keys
percy, app / skipAppOverride not run Percy needs a project/token; App Automate needs an Appium sample. Both are decided at build start

Pre-existing (reproduce without an override, not changed here): stopBuild returns 401 when O11y and A11y are both off; a local sessionNameFormat function never reaches the CLI-flow module.

Limitations (documented)

  • Server platforms entries beyond the wdio.conf capabilities are inert.
  • Some flags never take the server value:
    • flags the worker service captures in its constructor (observability, accessibility, turboScale);
    • options read before the binary starts (e.g. the test-orchestration spec expansion and credentials).
  • Jasmine and multiremote don't use the CLI flow, so they get no override.
  • testContextOptions is listed as overridden on every override build (the server echo differs from the synthesised local value); applying it is a no-op.
  • v8 port: feat(cli): apply the server SDK config override (v8) #302

Sibling PRs (SDK-7954)

Related Jira task/s

Release (mandatory for every PR — required for the ready-for-review label)

Version bump: (required — tick exactly one)

  • minor (backwards-compatible feature)
  • patch (bug fix or other small change)

Release notes type: (optional)

  • New Feature
  • Bug Fix
  • Other Improvement

Release notes (customer-facing): (optional but encouraged)

  • Server-side configuration overrides from BrowserStack now take effect for WebdriverIO builds, for example parallelsPerPlatform (parallel sessions per capability). Your wdio.conf remains the fallback.

Release notes (internal): (required — engineer-facing; what actually changed / why)

  • BrowserstackCLI.applyServerConfig applies exactly the binary-listed overridden keys (serverSdkConfigKeys) of serverSdkConfig to the service options after setConfig, in the launcher and workers. The binary's renamed keys are mapped back to the service spellings.
  • The launcher maps a listed parallelsPerPlatform onto each capability's wdio:maxInstances and raises config.maxInstances, and layers server platforms[i] onto capability i.
  • Runs only when the binary sends an override; otherwise behaviour is identical to main.

Checklist

  • Ready to review
  • Has it been tested locally?

PR Validations

Run Tests: Comment RUN_TESTS to trigger sanity tests.

🤖 Generated with Claude Code

On the CLI flow the binary forwards the server's sdk_config as serverSdkConfig
with the list of overridden keys. The service deep-merges exactly those keys
into its options in the main process and every worker, mapping the keys
getBinConfig renames back to their option names. In onPrepare a server
parallelsPerPlatform becomes each capability's wdio:maxInstances, with
maxInstances raised to fit, and server platforms layer onto the capability at
the same index. Without the key list nothing changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Central YAML (base), Organization UI (inherited), Workspace UI (inherited); Enforced overrides: Organization
  • Review profile: ASSERTIVE
  • Plan: Enterprise
  • Run ID: 9acdaaeb-8cf6-4922-92a2-49631b234ebc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@kamal-kaur04

kamal-kaur04 commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator Author

✅ Good to go

File Status
cli/test/modules/testhub/index.test.js ✅ All Clear
cli/test/modules/testhub/lib/server-config.test.js ✅ All Clear
packages/@browserstack/testhub/lib/server-config.js ✅ All Clear
wdio-browserstack-service/.changeset/pr-301.md ✅ All Clear
wdio-browserstack-service/packages/browserstack-service/src/cli/cliUtils.ts ✅ All Clear
wdio-browserstack-service/packages/browserstack-service/src/cli/index.ts ✅ All Clear
wdio-browserstack-service/packages/browserstack-service/src/constants.ts ✅ All Clear
wdio-browserstack-service/packages/browserstack-service/src/launcher.ts ✅ All Clear
wdio-browserstack-service/packages/browserstack-service/src/util.ts ✅ All Clear
wdio-browserstack-service/packages/browserstack-service/tests/cli/cliUtils.test.ts ✅ All Clear
wdio-browserstack-service/packages/browserstack-service/tests/cli/index.test.ts ✅ All Clear
wdio-browserstack-service/packages/browserstack-service/tests/launcher.test.ts ✅ All Clear

Change map (generated deterministically from the diff)

graph LR
  subgraph nbinary["binary"]
    ncli_test_modules_testhub_lib_server_config_test_js["server-config.test.js<br/>~43 lines"]
    npackages__browserstack_testhub_lib_server_config_js["server-config.js<br/>~43 lines"]
    ncli_test_modules_testhub_index_test_js["index.test.js<br/>~26 lines"]
  end
  subgraph nwdio_service["wdio-service"]
    nwdio_browserstack_service_packages_browserstack_service_src_cli_cliUtils_ts["⚠ cliUtils.ts<br/>~129 lines"]
    nwdio_browserstack_service_packages_browserstack_service_tests_cli_cliUtils_test_ts["⚠ cliUtils.test.ts<br/>~129 lines"]
    nwdio_browserstack_service_packages_browserstack_service_src_cli_index_ts["index.ts<br/>~56 lines"]
    nwdio_browserstack_service_packages_browserstack_service_tests_cli_index_test_ts["index.test.ts<br/>~56 lines"]
    nwdio_browserstack_service_packages_browserstack_service_src_launcher_ts["⚠ launcher.ts<br/>~55 lines"]
    nwdio_browserstack_service_packages_browserstack_service_tests_launcher_test_ts["⚠ launcher.test.ts<br/>~55 lines"]
    nwdio_browserstack_service__changeset_pr_301_md["pr-301.md<br/>~5 lines"]
    nwdio_browserstack_service_packages_browserstack_service_src_constants_ts["constants.ts<br/>~2 lines"]
    nwdio_browserstack_service_packages_browserstack_service_src_util_ts["util.ts<br/>~2 lines"]
  end
  nsvc_Observability_TRA(["Observability/TRA"])
  nsvc_collector_observability_browserstack_com(["collector-observability.browserstack.com"])
  ncli_test_modules_testhub_lib_server_config_test_js --> nsvc_Observability_TRA
  ncli_test_modules_testhub_lib_server_config_test_js --> nsvc_collector_observability_browserstack_com
  npackages__browserstack_testhub_lib_server_config_js --> nsvc_Observability_TRA
  npackages__browserstack_testhub_lib_server_config_js --> nsvc_collector_observability_browserstack_com
Loading

↻ This verdict comment is the review anchor — it's updated in place on each run (the gate posts its status separately).

— SDK PR Review Agent

kamal-kaur04 and others added 2 commits October 22, 2026 18:47
…bility holds it at both levels

getBinConfig flattens bstack:options last, so a key written only to the
capability top level left the stale bstack:options copy in effect.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The option is a function; a server value can only be a string, which the
automate module then called, so no session was named or marked.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Comment thread packages/browserstack-service/src/cli/cliUtils.ts Fixed
Comment thread packages/browserstack-service/src/cli/cliUtils.ts Fixed
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@kamal-kaur04
kamal-kaur04 marked this pull request as ready for review October 22, 2026 15:29
@kamal-kaur04
kamal-kaur04 requested a review from a team as a code owner October 22, 2026 15:29
@github-actions

Copy link
Copy Markdown
Contributor

🟢 SDK PR Review gate is green — the SDK PR Review Agent has run on the current head commit (verdict: success).

This gate confirms a review ran on the latest commit. The verdict itself is advisory — read the findings and use your judgement; it does not block merge. A native GitHub reviewer approval is still separately required by branch protection before this PR can merge.

@kamal-kaur04

Copy link
Copy Markdown
Collaborator Author

RUN_TESTS

@github-actions

Copy link
Copy Markdown
Contributor

🟢 SDK PR Review gate is green — the SDK PR Review Agent has run on the current head commit (verdict: success).

This gate confirms a review ran on the latest commit. The verdict itself is advisory — read the findings and use your judgement; it does not block merge. A native GitHub reviewer approval is still separately required by branch protection before this PR can merge.

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

🟢 SDK PR Review gate is green — the SDK PR Review Agent has run on the current head commit (verdict: success).

This gate confirms a review ran on the latest commit. The verdict itself is advisory — read the findings and use your judgement; it does not block merge. A native GitHub reviewer approval is still separately required by branch protection before this PR can merge.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🔴 SDK PR Review gate is red. Pending:

  • The SDK PR Review Agent has not been run on the current head commit yet — run the SDK PR Review Agent (its verdict is advisory; this gate only requires that it ran on the latest commit).

It turns green once the SDK PR Review Agent has run on the current head commit (any verdict — the gate only requires that the review ran). A native reviewer approval is separately required by branch protection before merge.

@minionhelperappqa

Copy link
Copy Markdown

[SDK Wdio Test] TRA build state: passed | Stability 100% — verdict: success. Passed: 53, Failed: 0, Aggregate: 53. TRA: https://observability.browserstack.com/builds/zgxnpxplunaodsmhbh3iwuk2nswolwlyl6bn7oxz

@kamal-kaur04

Copy link
Copy Markdown
Collaborator Author

RUN_TESTS

@github-actions

Copy link
Copy Markdown
Contributor

🟢 SDK PR Review gate is green — the SDK PR Review Agent has run on the current head commit (verdict: failure).

This gate confirms a review ran on the latest commit. The verdict itself is advisory — read the findings and use your judgement; it does not block merge. A native GitHub reviewer approval is still separately required by branch protection before this PR can merge.

…per key

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@kamal-kaur04

Copy link
Copy Markdown
Collaborator Author

On the review-gate findings at a32f94e:

  • applyServerPlatform aliasing / bstack:options capture: fixed in 869e19e. The server platform entry is now cloned first (JSON round trip, as applyServerSdkConfig already does), and capability['bstack:options'] is re-read for every key, so a key that follows a merged bstack:options key is no longer written to a discarded object. Two tests cover this ("keeps routing into bstack:options after the entry merges a bstack:options key", "does not share objects with the server platform entry"). Suite 1462/0.
  • A key present at both levels goes only to bstack:options: intended.
    • getBinConfig flattens each capability with bstack:options last, so for the binary that copy is the effective one.
    • The binary builds the hub caps from that flattened, merged platforms[i], not from the runner capability.
    • E2E, combined override build: capability 0 held browserVersion at both levels and the server sent platforms[0].browserVersion: latest-1. The hub received latest-1. Writing the server value to the top level instead was the earlier critical finding.

@minionhelperappqa

Copy link
Copy Markdown

[SDK Wdio Test] TRA build state: passed | Stability 100% — verdict: success. Passed: 53, Failed: 0, Aggregate: 53. TRA: https://observability.browserstack.com/builds/ib9twvzhilh4axu6ycioevx8vsfba1cvrondjvwg

@github-actions

Copy link
Copy Markdown
Contributor

🟢 SDK PR Review gate is green — the SDK PR Review Agent has run on the current head commit (verdict: failure).

This gate confirms a review ran on the latest commit. The verdict itself is advisory — read the findings and use your judgement; it does not block merge. A native GitHub reviewer approval is still separately required by branch protection before this PR can merge.

…to it

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@kamal-kaur04

Copy link
Copy Markdown
Collaborator Author

On the review-gate findings at 869e19e:

  • In-place write into a shared bstack:options: fixed in 96a31e2. applyServerPlatform now writes a copy of bstack:options, so capabilities that share one object no longer leak overrides. There is a new test for the shared-object case, and the looped launcher test now resets serverConfigKeys per iteration. Suite 1463/0. The same change is on feat(cli): apply the server SDK config override (v8) #302 (4d19751).
  • Binary applies WDIO overrides even for older deployed services: known and decided, no change.
    • With an older or released service, only the binary-side merge applies (caps, session naming, Local, accessibility; the binary builds those from its merged config). Service-side keys keep the local value until the service is upgraded.
    • This is the same documented behaviour as the other SDKs (the older-SDK limitation on #1948).
    • The service code is gated on the binary sending serverSdkConfig + serverSdkConfigKeys, so an older binary leaves it inert.
  • A server accessibility override only updates the launcher flag, not the capability flags: works end to end, no change.
    • In the CLI flow the binary builds each driver's caps from its merged config, so the constructor-written capability flags aren't what the hub receives.
    • E2E: in the combined override build, accessibility false → true produced A11y scans on all chrome sessions (55 issues). Edge isn't A11y-supported.

@github-actions

Copy link
Copy Markdown
Contributor

🟢 SDK PR Review gate is green — the SDK PR Review Agent has run on the current head commit (verdict: success).

This gate confirms a review ran on the latest commit. The verdict itself is advisory — read the findings and use your judgement; it does not block merge. A native GitHub reviewer approval is still separately required by branch protection before this PR can merge.

@kamal-kaur04

Copy link
Copy Markdown
Collaborator Author

RUN_TESTS

@github-actions

Copy link
Copy Markdown
Contributor

🟢 SDK PR Review gate is green — the SDK PR Review Agent has run on the current head commit (verdict: success).

This gate confirms a review ran on the latest commit. The verdict itself is advisory — read the findings and use your judgement; it does not block merge. A native GitHub reviewer approval is still separately required by branch protection before this PR can merge.

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

🟢 SDK PR Review gate is green — the SDK PR Review Agent has run on the current head commit (verdict: success).

This gate confirms a review ran on the latest commit. The verdict itself is advisory — read the findings and use your judgement; it does not block merge. A native GitHub reviewer approval is still separately required by branch protection before this PR can merge.

@minionhelperappqa

Copy link
Copy Markdown

[SDK Wdio Test] TRA build state: passed | Stability 100% — verdict: success. Passed: 53, Failed: 0, Aggregate: 53. TRA: https://observability.browserstack.com/builds/r6lr0qhuifyuunevykpgobgdmxxt5cmorhe4rpc9

@07souravkunda 07souravkunda left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants