Skip to content

Fix cross-personality node misrouting; add Slot Matching RFC support

Choose a tag to compare

@sbabcoc sbabcoc released this 29 Jul 00:05
· 22 commits to main since this release

Fixes a real-world node misrouting bug in FoundationSlotMatcher — both the Selenium 4 SlotMatcher and Selenium 3 CapabilityMatcher implementations — where automation requests could intermittently match the wrong node on a grid running more than one Appium personality.

Fixed

  • Cross-personality node misrouting (S4 and S3). On a grid whose stereotypes share a platform family — a Windows-automation node and an Edge browser node both reporting platformName: Windows; an HtmlUnit node and a Mac2 node both reporting platform: MAC; an Espresso node and a UiAutomator2 node both reporting platformName: Android — requests could land on the wrong node. Neither matcher previously checked appium:automationName at all. It's now checked explicitly and bidirectionally in both variants: a request specifying an automationName the target stereotype doesn't declare, or declares differently, is correctly rejected instead of silently passing.

Changed

  • browserVersion matching is now semver-aware (S4 and S3). A request for browserVersion: "131" now matches a stereotype reporting "131.0.6778.85", instead of requiring an exact string match. Segments are compared left-to-right; a mismatch in any shared segment (e.g. "131.0.6778.95" vs. "131.0.6778.85") still fails the match.
  • Extension-capability categorization (S4) now follows the Selenium 4 Grid Slot Matching RFC. A capability is excluded from identity matching if it has the se: prefix, or ends in options, Options, loggingPrefs, or debuggerAddress — regardless of vendor. This deliberately does not reproduce upstream DefaultSlotMatcher's hardcoded vendor-prefix exclusion list (goog:/moz:/ms:/safari:), which treats identical capability shapes differently depending on which vendor owns the prefix.

⚠️ Breaking: capability shape for Appium personalities

Non-identity, per-session Appium capabilities — app, bundleId, deviceName, noReset, forceEspressoRebuild, showGradleLog, and similar — must now be nested inside the vendor's options object (e.g. appium:options) rather than sent as bare appium:-namespaced keys. A bare appium:-namespaced capability outside options is treated as an identity value and matched against the node stereotype; since stereotypes don't declare per-session values like these, a bare appium:app or appium:bundleId will now cause the request to be rejected by every node.

Before:

{"platformName":"Android","appium:automationName":"UiAutomator2","appium:app":"https://.../app.apk"}

After:

{"platformName":"Android","appium:automationName":"UiAutomator2","appium:options":{"app":"https://.../app.apk"}}

platformName and appium:automationName stay outside options — those are the identity capabilities that differentiate node types and need to be matched.

Compatibility

  • S4 (FoundationSlotMatcher implements SlotMatcher) and S3 (FoundationSlotMatcher implements CapabilityMatcher) both received equivalent fixes for the misrouting and browserVersion issues.
  • S3's implementation remains Java 8-compatible — no external version-parsing libraries were introduced for the semver comparison.
  • Extension-capability categorization (the RFC piece) applies to S4 only. Selenium 3's capability model predates the extension-capability concept entirely, so there's no S3 equivalent to change.