Fix cross-personality node misrouting; add Slot Matching RFC support
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 reportingplatform: MAC; an Espresso node and a UiAutomator2 node both reportingplatformName: Android— requests could land on the wrong node. Neither matcher previously checkedappium:automationNameat all. It's now checked explicitly and bidirectionally in both variants: a request specifying anautomationNamethe target stereotype doesn't declare, or declares differently, is correctly rejected instead of silently passing.
Changed
browserVersionmatching is now semver-aware (S4 and S3). A request forbrowserVersion: "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 inoptions,Options,loggingPrefs, ordebuggerAddress— regardless of vendor. This deliberately does not reproduce upstreamDefaultSlotMatcher'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 andbrowserVersionissues. - 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.