Appearance
四、Grid
要在多台计算机上并行运行测试吗? 那么, Grid正是为你准备的.
通过将客户端命令发送到远程浏览器的实例, Selenium Grid 允许在远程计算机 (虚拟或真实) 上执行WebDriver脚本. 它旨在提供一种在多台计算机上并行运行测试的简便方法.
Selenium Grid允许我们在多台计算机上并行运行测试, 并集中管理不同的浏览器版本和浏览器配置 (而不是在每个独立的测试中).
Selenium Grid不是银弹. 它解决了一些常见的委派和分布式问题, 但是例如无法管理基础架构这样的问题, 可能不适合您的特定需求.
目的和主要功能
- 为所有的测试提供统一的入口
- 管理和控制运行着浏览器的节点/环境
- 扩展
- 并行测试
- 跨平台(操作系统)测试
- 负载测试
1、快速使用
Standalone 是所有组件的联合,在用户看来,它们是作为一个整体执行的。在独立模式下启动后,可以使用一个功能齐全的网格。
Standalone 也是启动 Selenium Grid 的最简单模式。默认情况下,服务器将监听http://localhost:4444
,这就是你应该指向你的 RemoteWebDriver
测试的 URL。服务器将检测它可以从系统中使用的可用驱动程序PATH
。
网格角色
几个组件组成了一个 Selenium Grid。根据您的需要,您可以单独启动它们中的每一个,或者使用 Grid 角色同时启动几个。
Standalone
Standalone 是所有组件的联合,在用户看来,它们是作为一个整体执行的。在独立模式下启动后,可以使用一个功能齐全的网格。
Standalone 也是启动 Selenium Grid 的最简单模式。默认情况下,服务器将监听http://localhost:4444
,这就是你应该指向你的 RemoteWebDriver
测试的 URL。服务器将检测它可以从系统中使用的可用驱动程序PATH
。
shell
java -jar selenium-server-<version>.jar standalone
集线器和节点
它启用了经典的集线器和节点设置。这些角色适用于中小型网格。
中心
集线器是以下组件的联合:
- 路由器
- 经销商
- 会话图
- 新会话队列
- 事件总线
shell
java -jar selenium-server-<version>.jar hub
默认情况下,服务器将监听http://localhost:4444
,这就是你应该指向你的RemoteWebDriver
测试的 URL。
节点
在此设置中可以启动一个或多个节点,服务器将检测可以从 System 使用的可用驱动程序PATH
。
shell
java -jar selenium-server-<version>.jar node
分散式
在分布式模式下,每个组件都需要自己启动。此设置更适合大型网格。
组件的启动顺序并不重要,但是,我们建议在启动分布式网格时遵循这些步骤。
事件总线:在后续步骤中用作与其他网格组件的通信路径。
shell
java -jar selenium-server-<version>.jar event-bus
会话映射:负责将会话 ID 映射到会话运行所在的节点。
shell
java -jar selenium-server-<version>.jar sessions
新会话队列:将新的会话请求添加到队列中,然后分发器对其进行处理。
shell
java -jar selenium-server-<version>.jar sessionqueue
分发者:节点注册到它,并为会话请求分配一个节点。
shell
java -jar selenium-server-<version>.jar distributor --sessions http://localhost:5556 --sessionqueue http://localhost:5559 --bind-bus false
路由器:Grid 入口点,负责将请求重定向到正确的组件。
shell
java -jar selenium-server-<version>.jar router --sessions http://localhost:5556 --distributor http://localhost:5553 --sessionqueue http://localhost:5559
节点
shell
java -jar selenium-server-<version>.jar node
查询 Selenium 网格
Grid 启动后,查询其状态的方式主要有两种,通过 Grid UI 或通过 API 调用。
可以通过打开首选浏览器并前往 http://localhost:4444来访问 Grid UI 。
API 调用可以通过http://localhost:4444/status 端点或使用 GraphQL 完成:
shell
curl -X POST -H "Content-Type: application/json" --data '{ "query": "{grid{uri}}" }' -s http://localhost:4444/graphql | jq .
为简单起见,本页中显示的所有命令示例都假定组件在本地运行。更详细的示例和用法可以在 配置组件部分找到。
警告
必须使用适当的防火墙权限保护 Selenium Grid 免受外部访问。
未能保护您的电网可能会导致以下一种或多种情况发生:
- 您提供对您的网格基础设施的开放访问
- 您允许第三方访问内部 Web 应用程序和文件
- 您允许第三方运行自定义二进制文件
请参阅Detectify上的这篇博客文章,它很好地概述了公开暴露的网格如何被滥用: 不要让你的网格大开
提醒
Selenium服务网格需要使用合适的防火墙许可来隔离外部访问。
如果不能有效的保护你的服务网格,可能会导致以下问题:
- 提供了一个开发的接口来访问服务网格的基础设施
- 你将会允许第三方来访问内部web服务和文件
- 你将会允许第三方来执行定制的二进制文件
2、什么时候应该使用Grid
Grid是适合您的工具吗?
通常来说,有2个原因你需要使用Grid。
- 在多种浏览器,多种版本的浏览器,不同操作系统里的浏览器里执行你的测试
- 缩短完成测试的时间
Grid通过使用多台终端机器来并行执行测试,以达到加速测试执行的目的。 比如的测试套件里包含100个测试,你的Grid支持4种不同的终端(虚拟机或者独立的物理设备) 来执行这些测试,相比你只有一台终端来执行,你的测试套件只需要4分之1的时间。 在一些大型测试套件,或者一些长时间执行的测试比如执行大量的数据校验,这样做会节约大量的时间。 一些测试会需要几个小时。另一个改善的动力来自缩短这种耗时的测试的是为了开发人员从提交代码到获得测试结果的期间。软件开发团队实践敏捷开发时期望尽可能早的得到测试反馈,而不是一晚一晚的等测试通过。
Grid也会被用来支持在不同的运行环境的测试,比如,在同一实践针对不同浏览器的测试。 比如,一个由虚拟机组成的Grid,每一个终端机可以支持一个不同的应用程序需要支持的浏览器。 比如终端1有IE8,终端2有IE9,终端3有最新的Chrmoe,终端4有最新的Firefox。当所有的测试套件都执行了, Selenium Grid会接受每个测试浏览器组合的要求,然后安排每个测试被执行在所要求的浏览器上。
另外,一个Grid可以包含同样的浏览器,类型,版本。比如,你可以有一个包含4台终端,没个终端包含3个 Firefox70的实例的网格,提供了一个服务器集群提供可用的Firefox实例。当测试套件被执行的时候,每个被提交进Grid的测试会被分发到可用的Firefox实例。在这个情况下,同一时间可以有12个测试被并行的执行, 显著的缩短的整个测试完成的时间。
Grid是弹性的。这2个例子可以被组合来创建多种实例的浏览器和版本。通过配置,可以提供并行执行以加速测试,或者支持多种浏览器版本的模拟2中能力。
3、组件
1、路由
路由负责将请求转发到正确的组件.
它是Grid的入口点, 所有外部请求都将由其接收. 路由的行为因请求而异. 当请求一个新的会话时, 路由将把它添加到新的会话队列中. 分发器定期检查是否有空闲槽. 若有, 则从新会话队列中删除第一个匹配请求. 如果请求属于存量会话, 这个路由将会话id发送到会话表, 会话表将返回正在运行会话的节点. 在此之后, 路由将 将请求转发到节点.
为了更好地发挥效力, 路由通过将请求发送到组件的方式, 来平衡Grid的负载, 从而使处理过程中不会有任何的过载组件.
2、分发器
分发器知道所有节点及其功能. 它的主要作用是接收新的会话请求 并找到可以在其中创建会话的适当节点. 创建会话后, 分发器在会话集合中存储会话ID与正在执行会话的节点之间的关系.
3、节点
一个节点可以在网格中出现多次. 每个节点负责管理其运行机器的可用浏览器的插槽.
节点通过事件总线将其自身注册到分发服务器, 并且将其配置作为注册消息的组成部分一起发送.
默认情况下, 节点自动注册其运行机器路径上的 所有可用浏览器驱动程序. 它还为基于Chromium的浏览器和Firefox的 每个可用CPU创建一个插槽. 对于Safari和Internet Explorer, 只创建一个插槽. 通过特定的配置, 它可以在Docker容器或中继命令中运行会话. 您可以在下一 章节 中看到更多配置详细信息.
节点仅执行接收到的命令, 它不进行评估、做出判断或控制任何事情. 运行节点的计算机不需要与其他组件具有相同的操作系统. 例如, Windows节点可以具有将Internet Explorer作为浏览器选项的功能, 而在Linux或Mac上则无法实现.
4、会话表
会话表是一种数据存储的方式, 用于保存会话id和会话运行的节点的信息. 它作为路由支持, 在向节点转发请求的过程中起作用. 路由将通过会话表获取与会话id关联的节点.
5、新会话队列
新会话队列以先进先出的顺序保存所有新会话请求. 其具有用于设置请求超时和请求重试间隔的可配置参数.
路由将新会话请求添加到新会话队列并等待响应. 新会话队列定期检查队列中的任何请求是否已超时, 若有,则请求将被拒绝并立即删除.
分发器定期检查是否有可用槽. 若有, 分发器将为第一个匹配的请求索取新会话队列. 然后分发器会尝试创建新的会话.
一旦请求的功能与任何空闲节点槽匹配, 分发器将尝试获取可用槽. 如果没有空闲槽, 分发器会要求队列将请求添加到队列前面. 如果请求在重试或添加到队列头时超时, 则该请求将被拒绝.
成功创建会话后, 分发器将会话信息发送到新会话队列. 新会话队列将响应发送回客户端.
6、事件总线
事件总线充当节点、分发服务器、新的会话队列器和会话表之间的通信路径. 网格通过消息进行大部分内部通信, 避免了昂贵的HTTP调用. 当以完全分布式模式启动网格时, 事件总线是应该启动的第一个组件.
4、配置
1、配置帮助
Help命令显示基于当前代码实现的信息. 因此, 如果文档没有更新, 它将提供准确的信息. 这是了解任何新版本Grid4配置的最便捷方法.
通过运行以下命令快速获取配置帮助:
sh
java -jar selenium-server-<version>.jar info config
1、信息命令
Info命令提供以下主题的详细文档:
- 配置Selenium
- 安全
- 会话表配置
- 追踪
2、安全
获取构建网格服务器的详细信息, 用于安全通信和节点注册.
sh
java -jar selenium-server-<version>.jar info security
3、会话表配置
默认情况下, 网格使用本地会话表来存储会话信息. 网格支持额外的存储选项, 比如Redis和JDBC-SQL支持的数据库. 要设置不同的会话存储, 请使用以下命令获取设置步骤:
sh
java -jar selenium-server-<version>.jar info sessionmap
4、基于OpenTelemetry和Jaeger的追踪配置
默认情况下, 追踪是启用的. 要通过Jaeger导出追踪并将其可视化, 请使用以下命令进行说明:
sh
java -jar selenium-server-<version>.jar info tracing
5、列出Selenium网格的命令
sh
java -jar selenium-server-<version>.jar --config-help
6、组件帮助命令
在Selenium后面键入–help的配置选项, 以获取特定组件的配置信息.
Standalone
sh
java -jar selenium-server-<version>.jar standalone --help
Hub
sh
java -jar selenium-server-<version>.jar hub --help
Sessions
sh
java -jar selenium-server-<version>.jar sessions --help
7、队列器
sh
java -jar selenium-server-<version>.jar sessionqueue --help
Distributor
sh
java -jar selenium-server-<version>.jar distributor --help
Router
sh
java -jar selenium-server-<version>.jar router --help
Node
sh
java -jar selenium-server-<version>.jar node --help
2、CLI配置选项
所有网格组件配置CLI选项的详细信息.
Standalone | Hub | Node | Distributor | Router | Sessions | SessionQueue | |
---|---|---|---|---|---|---|---|
Distributor | √ | √ | √ | √ | |||
Docker | √ | √ | |||||
Events | √ | √ | √ | √ | √ | ||
Logging | √ | √ | √ | √ | √ | √ | √ |
Network | √ | √ | √ | ||||
Node | √ | √ | |||||
Router | √ | √ | √ | ||||
Relay | √ | √ | |||||
Server | √ | √ | √ | √ | √ | √ | √ |
SessionQueue | √ | √ | √ | √ | √ | ||
Sessions | √ | √ | √ |
1、Distributor
选项 | 类型 | 价值/示例 | 描述 |
---|---|---|---|
--grid-model | string | org.openqa.selenium.grid.distributor.GridModel | 非默认网格模型的完整类名。这用于存储所有已注册节点的状态。 |
--healthcheck-interval | int | 120 | 对所有节点运行健康检查的频率(以秒为单位)。这确保服务器可以成功 ping 所有节点。 |
--distributor | uri | http://localhost:5553 | 分销商的网址。 |
--distributor-host | string | localhost | 分发服务器正在侦听的主机。 |
--distributor-implementation | string | org.openqa.selenium.grid.distributor.local.LocalDistributor | 非默认分发器实现的完整类名 |
--distributor-port | int | 5553 | 分发器正在侦听的端口。 |
--reject-unsupported-caps | boolean | false | 如果 Grid 不支持请求的功能,允许 Distributor 立即拒绝请求。立即拒绝请求适用于不按需启动节点的网格设置。 |
--slot-matcher | string | org.openqa.selenium.grid.data.DefaultSlotMatcher | 要使用的非默认槽匹配器的完整类名。这用于确定节点是否可以支持特定会话。 |
--slot-selector | string | org.openqa.selenium.grid.distributor.selector.DefaultSlotSelector | 非默认槽选择器的完整类名。这用于在节点匹配后选择节点中的插槽。 |
2、Docker
选项 | 类型 | 价值/示例 | 描述 |
---|---|---|---|
--docker-assets-path | string | /opt/selenium/assets | 将存储资产的绝对路径 |
--docker- | string[] | selenium/standalone-firefox:latest '{"browserName": "firefox"}' | 将图像名称映射到构造型功能的 Docker 配置(例如 `-D selenium/standalone-firefox:latest '{“browserName”: “firefox”}') |
--docker-host | string | localhost | 运行 Docker 守护程序的主机名 |
--docker-port | int | 2375 | 运行 Docker 守护程序的端口 |
--docker-url | string | http://localhost:2375 | 用于连接到 Docker 守护程序的 URL |
--docker-video-image | string | selenium/video:latest | 启用视频录制时要使用的 Docker 映像 |
3、Events
选项 | 类型 | 价值/示例 | 描述 |
---|---|---|---|
--bind-bus | boolean | false | 连接字符串是否应该绑定或连接。 当为 true 时,组件将绑定到事件总线(因为事件总线也将由组件启动,通常由分发器和集线器启动)。 当为 false 时,组件将连接到事件总线。 |
--events-implementation | string | org.openqa.selenium.events.zeromq.ZeroMqEventBus | 非默认事件总线实现的全类名 |
--publish-events | string | tcp://*:4442 | 用于将事件发布到事件总线的连接字符串 |
--subscribe-events | string | tcp://*:4443 | 用于从事件总线订阅事件的连接字符串 |
4、Logging
选项 | 类型 | 价值/示例 | 描述 |
---|---|---|---|
--http-logs | boolean | false | 启用 http 日志记录。应启用跟踪以记录 http 日志。 |
--log-encoding | string | UTF-8 | 日志编码 |
--log | string | Windows 路径示例: '\path\to\file\gridlog.log' 或 'C:\path\path\to\file\gridlog.log' Linux/Unix/MacOS 路径示例: '/path/to/file/gridlog.log' | 用于写出日志的文件。确保文件路径与操作系统的文件路径兼容。 |
--log-level | string | “INFO” | 日志级别。默认日志记录级别为 INFO。此处描述了日志级别https://docs.oracle.com/javase/7/docs/api/java/util/logging/Level.html |
--plain-logs | boolean | true | 使用普通的日志行 |
--structured-logs | boolean | false | 使用结构化日志 |
--tracing | boolean | true | 启用跟踪收集 |
--log-timestamp-format | string | HH:mm:ss.SSS | 允许配置日志时间戳格式 |
5、Network
选项 | 类型 | 价值/示例 | 描述 |
---|---|---|---|
--relax-checks | boolean | false | 放松对传入请求的原始标头和内容类型的检查,这违反了严格的 W3C 规范合规性。 |
6、Node
选项 | 类型 | 价值/示例 | 描述 | |
---|---|---|---|---|
--detect-drivers | boolean | true | 自动检测当前系统上可用的驱动程序,并将它们添加到节点。 | |
--driver-configuration | string[] | display-name="Firefox Nightly" max-sessions=2 webdriver-path="/usr/local/bin/geckodriver" stereotype='{"browserName": "firefox", "browserVersion": "86", "moz:firefoxOptions": {"binary":"/Applications/Firefox Nightly.app/Contents/MacOS/firefox-bin"}}' | 节点支持的已配置驱动程序列表。建议通过 toml 配置文件提供此类配置,以提高可读性 | |
--driver-factory | string[] | org.openqa.selenium.example.LynxDriverFactory '{"browserName": "lynx"}' | 将完全限定的类名映射到与之匹配的浏览器配置。 | |
--driver-implementation | string[] | "firefox" | 应该检查的驱动程序。如果指定,将跳过自动配置。 | |
--node-implementation | string | "org.openqa.selenium.grid.node.local.LocalNodeFactory" | 非默认节点实现的完整类名。这用于管理会话的生命周期。 | |
--grid-url | string | https://grid.example.com | 整个网格的公共 URL(通常是集线器或路由器的地址) | |
--heartbeat-period | int | 60 | 节点多久会以秒为单位向分配器发送心跳事件以通知它节点已启动。 | |
--max-sessions | int | 8 | 最大并发会话数。默认值是可用处理器的数量。 | |
--override-max-sessions | boolean | false | 可用处理器的数量是建议的最大会话值(每个处理器 1 个浏览器会话)。将此标志设置为 true 允许覆盖建议的最大值。由于主机可能耗尽资源,会话稳定性和可靠性可能会受到影响。 | |
--register-cycle | int | 10 | 节点第一次尝试将自己注册到分发服务器的频率(以秒为单位)。 | |
--register-period | int | 120 | 节点首次尝试注册到分发服务器的时间(以秒为单位)。这段时间结束后,节点将不再尝试注册。 | |
--session-timeout | int | 300 | 设 X 为会话超时(以秒为单位)。节点将自动终止在最后 X 秒内没有任何活动的会话。这将释放用于其他测试的插槽。 | |
--vnc-env-var | string | START_XVFB | 检查环境变量以确定 vnc 流是否可用。 | |
--no-vnc-port | int | 7900 | 如果VNC可用,设置可以获取本地noVNC流的端口 |
7、Router
选项 | 类型 | 价值/示例 | 描述 |
---|---|---|---|
--password | string | myStrongPassword | 客户端必须使用密码才能连接到服务器。这和用户名都需要设置才能使用。 |
--username | string | admin | 客户端必须使用用户名连接到服务器。这和密码都需要设置才能使用。 |
8、Relay
选项 | 类型 | 价值/示例 | 描述 |
---|---|---|---|
--service-url | string | http://localhost:4723 | 用于连接到支持 WebDriver 命令的服务的 URL,例如 Appium 服务器或云服务。 |
--service-host | string | localhost | 运行支持 WebDriver 命令的服务的主机名 |
--service-port | int | 4723 | 运行支持 WebDriver 命令的服务的端口 |
--service-status-endpoint | string | /status | 可选的,用于查询 WebDriver 服务状态的端点,应有 HTTP 200 响应 |
--service-configuration | string[] | max-sessions=2 stereotype='{"browserName": "safari", "platformName": "iOS", "appium:platformVersion": "14.5"}}' | 将呼叫中继到的服务的配置。建议通过 toml 配置文件提供此类配置以提高可读性。 |
9、Server
选项 | 类型 | 价值/示例 | 描述 |
---|---|---|---|
--allow-cors | boolean | true | Selenium 服务器是否应该允许来自任何主机的 Web 浏览器连接 |
--host | string | localhost | 服务器 IP 或主机名:通常自动确定。 |
--bind-host | boolean | true | 服务器是否应该绑定到主机地址/名称,或者仅使用它来报告其可访问的 url。在复杂的网络拓扑中很有帮助,因为服务器无法使用当前 IP/主机名报告自己,而是使用外部 IP 或主机名(例如内部一个 Docker 容器) |
--https-certificate | path | /path/to/cert.pem | https 的服务器证书。通过运行“java -jar selenium-server.jar info security”获取更多详细信息 |
--https-private-key | path | /path/to/key.pkcs8 | https 的私钥。通过运行“java -jar selenium-server.jar info security”获取更多详细信息 |
--max-threads | int | 24 | 最大侦听器线程数。默认值为:(可用处理器)* 3。 |
--port | int | 4444 | 要监听的端口。没有默认值,因为此参数由不同的组件使用,例如,Router/Hub/Standalone 将使用 4444,Node 将使用 5555。 |
10、SessionQueue
选项 | 类型 | 价值/示例 | 描述 |
---|---|---|---|
--sessionqueue | uri | http://localhost:1237 | 会话队列服务器的地址。 |
-sessionqueue-host | string | localhost | 会话队列服务器正在侦听的主机。 |
--sessionqueue-port | int | 1234 | 会话队列服务器正在侦听的端口。 |
--session-request-timeout | int | 300 | 以秒为单位的超时。新的传入会话请求被添加到队列中。排队等候时间超过配置时间的请求将超时。 |
--session-retry-interval | int | 5 | 重试间隔以秒为单位。如果所有槽都忙,新的会话请求将在给定的时间间隔后重试。 |
11、Sessions
选项 | 类型 | 价值/示例 | 描述 |
---|---|---|---|
--sessions | uti | http://localhost:1234 | 会话映射服务器的地址。 |
--sessions-host | string | localhost | 会话映射服务器正在侦听的主机。 |
--sessions-port | int | 1234 | 会话映射服务器正在侦听的端口。 |
12、配置示例
我们建议使用Toml 文件来配置 Grid。配置文件提高了可读性,您还可以在源代码管理中检查它们。
需要时,您可以将 Toml 文件配置与 CLI 参数结合使用。
命令行标志
要将配置选项作为命令行标志传递,请确定组件的有效选项并遵循以下模板。
sh
java -jar selenium-server-<version>.jar <component> --<option> value
独立,设置最大会话和主端口
sh
java -jar selenium-server-<version>.jar standalone --max-sessions 4 --port 4444
集线器,设置新会话请求超时、主端口和禁用跟踪
sh
java -jar selenium-server-<version>.jar hub --session-request-timeout 500 --port 3333 --tracing false
节点,最多 4 个会话,带有调试(精细)日志,7777 作为端口,并且仅适用于 Firefox 和 Edge
sh
java -jar selenium-server-<version>.jar node --max-sessions 4 --log-level "fine" --port 7777 --driver-implementation "firefox" --driver-implementation "edge"
Distributor,设置 Session Map server url,Session Queue server url,禁用总线
sh
java -jar selenium-server-<version>.jar distributor --sessions http://localhost:5556 --sessionqueue http://localhost:5559 --bind-bus false
设置自定义功能以匹配特定节点
**重要提示:**需要在所有节点的配置中设置自定义功能。它们还需要始终包含在每个会话请求中。
启动集线器
sh
java -jar selenium-server-<version>.jar hub
启动节点 A 并将自定义上限设置为true
sh
java -jar selenium-server-<version>.jar node --detect-drivers false --driver-configuration display-name="Chrome (custom capability true)" max-sessions=1 stereotype='{"browserName":"chrome","gsg:customcap":true}' --port 6161
启动节点 B 并将自定义上限设置为false
sh
java -jar selenium-server-<version>.jar node --detect-drivers false --driver-configuration display-name="Chrome (custom capability true)" max-sessions=1 stereotype='{"browserName":"chrome","gsg:customcap":false}' --port 6262
匹配节点 A
java
ChromeOptions options = new ChromeOptions();
options.setCapability("gsg:customcap", true);
WebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444"), options);
driver.get("https://selenium.dev");
driver.quit();
将自定义功能设置为false
以匹配节点 B。
3、Toml配置选项
CLI选项 中 显示的所有选项都可以通过 TOML 文件进行配置. 此页面显示不同Grid组件的配置示例.
Selenium Grid对配置文件使用 TOML 格式. 配置文件由多个部分组成, 每个部分都有选项及其各自的值.
有关详细的使用指南, 请参阅TOML文档 . 如果出现解析错误, 请使用 TOML linter 验证配置.
一般配置结构具有以下模式:
toml
[section1]
option1="value"
[section2]
option2=["value1","value2"]
option3=true
下面是一些使用Toml文件配置的 Grid组件示例, 该组件可以 从下面的方式开始:
sh
java -jar selenium-server-<version>.jar <component> --config /path/to/file/<file-name>.toml
1、单机模式
单机服务器, 在端口4449上运行, 新会话请求超时500秒.
toml
[server]
port = 4449
[sessionqueue]
session-request-timeout = 500
2、特定浏览器和最大会话数限制
默认情况下仅启用Firefox 和Chrome的单机服务器或节点.
toml
[node]
drivers = ["chrome", "firefox"]
max-sessions = 3
3、配置和定制驱动程序
具有定制驱动程序的单机或节点服务器, 允许使用Firefox试用或者每日构建的功能, 并且有不同的浏览器版本.
toml
[node]
detect-drivers = false
[[node.driver-configuration]]
max-sessions = 100
display-name = "Firefox Nightly"
stereotype = "{\"browserName\": \"firefox\", \"browserVersion\": \"93\", \"platformName\": \"MAC\", \"moz:firefoxOptions\": {\"binary\": \"/Applications/Firefox Nightly.app/Contents/MacOS/firefox-bin\"}}"
[[node.driver-configuration]]
display-name = "Chrome Beta"
stereotype = "{\"browserName\": \"chrome\", \"browserVersion\": \"94\", \"platformName\": \"MAC\", \"goog:chromeOptions\": {\"binary\": \"/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta\"}}"
[[node.driver-configuration]]
display-name = "Chrome Dev"
stereotype = "{\"browserName\": \"chrome\", \"browserVersion\": \"95\", \"platformName\": \"MAC\", \"goog:chromeOptions\": {\"binary\": \"/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev\"}}"
webdriver-executable = '/path/to/chromedriver/95/chromedriver'
4、带Docker的单机或节点
单机或节点服务器能够在Docker容器中运行每个新会话. 禁用驱动程序检测, 则最多有2个并发会话. 原型配置需要映射一个Docker映像, Docker的守护进程需要通过http/tcp公开.
toml
[node]
detect-drivers = false
max-sessions = 2
[docker]
configs = [
"selenium/standalone-chrome:93.0", "{\"browserName\": \"chrome\", \"browserVersion\": \"91\"}",
"selenium/standalone-firefox:92.0", "{\"browserName\": \"firefox\", \"browserVersion\": \"92\"}"
]
url = "http://localhost:2375"
video-image = "selenium/video:latest"
5、将命令中继到支持WebDriver的服务端点
连接到支持WebDriver外部服务 的Selenium Grid非常有用. 这种服务的一个例子可以是 云提供商或Appium服务器. 这样, Grid可以实现对本地不存在的平台和版本的更多覆盖.
下面是一个将Appium服务器连接到Grid的示例.
toml
[server]
port = 5555
[node]
detect-drivers = false
[relay]
# Default Appium server endpoint
url = "http://localhost:4723/wd/hub"
status-endpoint = "/status"
# Stereotypes supported by the service
configs = [
"1", "{\"browserName\": \"chrome\", \"platformName\": \"android\", \"appium:platformVersion\": \"11\"}"
]
6、启用基本身份验证
通过配置包含用户名和密码的 路由器/集线器/单机的方式, 可以使用这样的基本身份验证保护Grid. 加载Grid UI或者开始一个新的会话时 需要此用户/密码组合.
toml
[router]
username = "admin"
password = "myStrongPassword"
下面是一个Java示例, 演示如何使用配置的用户和密码启动会话.
java
URL gridUrl = new URL("http://admin:myStrongPassword@localhost:4444");
RemoteWebDriver webDriver = new RemoteWebDriver(gridUrl, new ChromeOptions());
7、设置自定义功能以匹配特定节点
**重要提示:**需要在所有节点的配置中设置自定义功能。它们还需要始终包含在每个会话请求中。
toml
[node]
detect-drivers = false
[[node.driver-configuration]]
display-name = "firefox"
stereotype = '{"browserName": "firefox", "platformName": "macOS", "browserVersion":"96", "networkname:applicationName":"node_1", "nodename:applicationName":"app_1" }'
max-sessions = 5
这是一个 Java 示例,展示了如何匹配该节点
java
FirefoxOptions options = new FirefoxOptions();
options.setCapability("networkname:applicationName", "node_2");
options.setCapability("nodename:applicationName", "app_2");
options.setBrowserVersion("96");
options.setPlatformName("macOS");
WebDriver driver = new RemoteWebDriver(new URL("http://localhost:4444"), options);
driver.get("https://selenium.dev");
driver.quit();
5、Grid架构
1、关键组件
事件总线
用于发送可能在其他组件之间异步接收的消息。
会话队列
维护尚未由分发服务器分配给节点的传入会话列表。
经销商
负责维护网格中可能运行会话的可用位置的模型(称为“槽”),并接受任何传入的新会话请求并将它们分配给槽。
节点
运行WebDriver 会话。每个会话都分配给一个槽,每个节点都有一个或多个槽。
会话图
维护会话 ID和运行会话的节点地址之间的映射。
路由器
充当网格的前端。这是网格中唯一_可能_暴露于更广泛的网络的部分(尽管我们强烈警告不要这样做)。这会将传入请求路由到新会话队列或正在运行会话的节点。
在讨论网格时,还有一些其他有用的概念需要牢记:
- 插槽是会话可以运行的地方。
- 每个插槽都有一个原型。这是新会话会话请求必须匹配的最小功能集,分发服务器将请求发送到拥有该插槽的节点。
- 网格模型是分发器跟踪网格状态的方式。顾名思义,这有时可能与现实不同步(可能是因为分发器才刚刚开始)。它优先用于查询每个节点,以便分发者可以快速为新会话请求分配一个槽。
2、同步和异步调用
网格中使用了两种主要的通信机制:
- 基于 HTTP 请求的同步“REST-ish”JSON。
- 发送到事件总线的异步事件。
我们如何选择使用哪种通信机制?毕竟,我们可以以基于事件的方式对整个 Grid 进行建模,并且效果很好。
答案是,如果正在执行的操作是同步的(例如,大多数 WebDriver 调用),或者如果缺少响应会出现问题,则 Grid 使用同步调用。相反,如果我们想向任何感兴趣的人广播信息,或者如果错过响应并不重要,那么我们更喜欢使用事件总线。
需要注意的一件有趣的事情是,与同步调用相比,异步调用与其侦听器更加分离。
3、启动顺序和组件之间的依赖关系
尽管 Grid 旨在允许组件以任何顺序启动,但从概念上讲,组件启动的顺序是:
- 事件总线和会话映射首先启动。它们没有其他依赖关系,甚至没有相互依赖关系,因此可以安全地并行启动。
- 会话队列接下来开始。
- 现在可以启动 Distributor。这将定期连接到会话队列并轮询作业,尽管此轮询可能由事件(新会话已添加到队列)或定期启动。
- 可以启动路由器。新的会话请求将被定向到会话队列,分发器将尝试找到一个插槽来运行会话。
- 我们现在可以启动一个节点。有关如何在 Grid 中注册节点的详细信息,请参见下文。注册完成后,网格就可以为流量提供服务了。
您可以通过这种方式描绘组件之间的依赖关系,其中“✅”表示组件之间存在同步依赖关系。
事件总线 | 经销商 | 节点 | 路由器 | 会话图 | 会话队列 | |
---|---|---|---|---|---|---|
事件总线 | X | |||||
经销商 | ✅ | X | ✅ | ✅ | ||
节点 | ✅ | X | ||||
路由器 | ✅ | X | ✅ | |||
会话图 | X | |||||
会话队列 | ✅ | X |
4、节点注册
将新节点注册到 Grid 的过程是轻量级的。
- 当节点启动时,它应该定期发出“心跳”事件。此心跳包含节点状态。
- Distributor 监听心跳事件。当它看到一个时,它会尝试到节点
GET
的/status
端点。正是根据这些信息建立了网格。
Distributor 将使用相同的/status
端点定期检查 Node,但 Node 应在启动后继续发送心跳事件,以便可以重新启动没有持久存储 Grid 状态的 Distributor 并将(最终)启动迄今为止并正确。
1、节点状态对象
节点状态是一个 JSON blob,包含以下字段:
Name | 类型 | 描述 |
---|---|---|
availability | string | 一个字符串,它是up 、draining 或之一down 。重要的是draining ,它表示不应向节点发送新会话,一旦其上的最后一个会话关闭,节点将退出或重新启动。 |
externalUrl | string | Grid 中的其他组件应连接到的 URI。 |
lastSessionCreated | int | 在此节点上创建最后一个会话时的纪元时间戳。如果所有其他条件都相同,分发者将尝试向空闲时间最长的节点发送新会话。 |
maxSessionCount | int | 尽管可以通过计算可用槽的数量来推断会话计数,但该整数值用于确定在节点被视为“满”之前应在节点上同时运行的最大会话数。 |
nodeId | string | 用于标识此节点实例的 UUID。 |
osInfo | object | 具有arch 、name 和version 字段的对象。这由 Grid UI 和 GraphQL 查询使用。 |
slots | array | 一组 Slot 对象(如下所述) |
version | string | 节点的版本(对于 Selenium,这将匹配 Selenium 版本号) |
建议在所有字段中输入值。
2、插槽对象
Slot 对象表示节点中的单个插槽。“槽”是可以运行单个会话的位置。一个节点的槽数可能比它可以同时运行的多。例如,一个节点可能能够运行 10 个会话,但它们可以是 Chrome、Edge 或 Firefox 的任意组合;在这种情况下,节点将指示“最大会话计数”为 10,然后还说它有 10 个用于 Chrome 的插槽,10 个用于 Edge,10 个用于 Firefox。
Name | 类型 | 描述 |
---|---|---|
ID | string | 用于引用插槽的 UUID |
lastStarted | string | 插槽上次启动会话的时间,采用 ISO-8601 格式 |
stereotype | object | 此插槽将匹配的最小功能集。一个最小的例子是{"browserName": "firefox"} |
session | object | Session 对象(见下文) |
3、会话对象
这表示插槽内正在运行的会话
Name | 类型 | 描述 |
---|---|---|
capabilities | object | 会话提供的实际功能。将匹配新会话命令的返回值 |
startTime | string | ISO-8601 格式的会话开始时间 |
stereotype | object | 此插槽将匹配的最小功能集。一个最小的例子是{"browserName": "firefox"} |
uri | string | 节点用于与会话通信的 URI |
6、高级功能
1、GraphQL查询支持
GraphQL 是一种用于API的查询语言, 也是用于使用现有数据完成这些查询的运行时. 其仅仅是使用户能够准确地获取所需.
1、枚举
枚举是表示字段的可能值的集合.
例如, Node
对象具有一个称为status
的字段. 状态是一个枚举 (特别是Status
类型) , 因为它可能是UP
, DRAINING
或 UNAVAILABLE
.
2、标量
标量是基本类型的值: Int
, Float
, String
, Boolean
, 或 ID
.
在调用GraphQL API时, 必须指定嵌套子字段, 直到只返回标量.
3、模式的结构
网格模式的结构如下:
shell
{
session(id: "<session-id>") : {
id,
capabilities,
startTime,
uri,
nodeId,
nodeUri,
sessionDurationMillis
slot : {
id,
stereotype,
lastStarted
}
}
grid: {
uri,
totalSlots,
nodeCount,
maxSession,
sessionCount,
version,
sessionQueueSize
}
sessionsInfo: {
sessionQueueRequests,
sessions: [
{
id,
capabilities,
startTime,
uri,
nodeId,
nodeUri,
sessionDurationMillis
slot : {
id,
stereotype,
lastStarted
}
}
]
}
nodesInfo: {
nodes : [
{
id,
uri,
status,
maxSession,
slotCount,
sessions: [
{
id,
capabilities,
startTime,
uri,
nodeId,
nodeUri,
sessionDurationMillis
slot : {
id,
stereotype,
lastStarted
}
}
],
sessionCount,
stereotypes,
version,
osInfo: {
arch,
name,
version
}
}
]
}
}
4、查询 GraphQL
查询GraphQL的最佳方法是使用curl
请求. GraphQL允许您仅获取所需的数据, 仅此而已.
下面给出了一些GraphQL查询的示例. 您可以根据需要构建自己的查询.
1、查询网格中 maxSession
和 sessionCount
的数量:
shell
curl -X POST -H "Content-Type: application/json" --data '{"query": "{ grid { maxSession, sessionCount } }"}' -s <LINK_TO_GRAPHQL_ENDPOINT>
通常在本地机器上 <LINK_TO_GRAPHQL_ENDPOINT>
会是 http://localhost:4444/graphql
2、查询全部会话、及节点以及网格的详情 :
shell
curl -X POST -H "Content-Type: application/json" --data '{"query":"{ grid { uri, maxSession, sessionCount }, nodesInfo { nodes { id, uri, status, sessions { id, capabilities, startTime, uri, nodeId, nodeUri, sessionDurationMillis, slot { id, stereotype, lastStarted } }, slotCount, sessionCount }} }"}' -s <LINK_TO_GRAPHQL_ENDPOINT>
3、查询以获取当前网格的会话总数 :
shell
curl -X POST -H "Content-Type: application/json" --data '{"query":"{ grid { sessionCount } }"}' -s <LINK_TO_GRAPHQL_ENDPOINT>
4、查询以获取网格中的最大会话数量 :
shell
curl -X POST -H "Content-Type: application/json" --data '{"query":"{ grid { maxSession } }"}' -s <LINK_TO_GRAPHQL_ENDPOINT>
5、查询以获取网格中所有节点的全部会话详情 :
shell
curl -X POST -H "Content-Type: application/json" --data '{"query":"{ sessionsInfo { sessions { id, capabilities, startTime, uri, nodeId, nodeId, sessionDurationMillis } } }"}' -s <LINK_TO_GRAPHQL_ENDPOINT>
6、查询以获取网格中每个节点中所有会话的插槽信息 :
shell
curl -X POST -H "Content-Type: application/json" --data '{"query":"{ sessionsInfo { sessions { id, slot { id, stereotype, lastStarted } } } }"}' -s <LINK_TO_GRAPHQL_ENDPOINT>
7、查询以获取给定会话的会话信息查询以获取给定会话的会话信息 :
shell
curl -X POST -H "Content-Type: application/json" --data '{"query":"{ session (id: \"<session-id>\") { id, capabilities, startTime, uri, nodeId, nodeUri, sessionDurationMillis, slot { id, stereotype, lastStarted } } } "}' -s <LINK_TO_GRAPHQL_ENDPOINT>
8、查询网格中每个节点的功能 :
shell
curl -X POST -H "Content-Type: application/json" --data '{"query": "{ nodesInfo { nodes { stereotypes } } }"}' -s <LINK_TO_GRAPHQL_ENDPOINT>
9、查询网格中每个节点的状态 :
shell
curl -X POST -H "Content-Type: application/json" --data '{"query": "{ nodesInfo { nodes { status } } }"}' -s <LINK_TO_GRAPHQL_ENDPOINT>
10、查询每个节点和网格的 URI :
shell
curl -X POST -H "Content-Type: application/json" --data '{"query": "{ nodesInfo { nodes { uri } } }"}' -s <LINK_TO_GRAPHQL_ENDPOINT>
11、Query for getting the current requests in the New Session Queue:
shell
curl -X POST -H "Content-Type: application/json" --data '{"query":"{ sessionsInfo { sessionQueueRequests } }"}' -s <LINK_TO_GRAPHQL_ENDPOINT>
12、Query for getting the New Session Queue size :
shell
curl -X POST -H "Content-Type: application/json" --data '{"query":"{ grid { sessionQueueSize } }"}' -s <LINK_TO_GRAPHQL_ENDPOINT>
2、Grid端点
1、Grid 状态
Grid状态提供Grid的当前状态. 它包含每个注册节点的详细信息. 对于每个节点, 状态包括有关节点可用性、会话和插槽的信息.
shell
cURL GET 'http://localhost:4444/status'
在独立模式下, Grid URL是独立服务器的地址.
在集线器节点模式下, Grid URL是集线器服务器的地址.
在完全分布式模式下, Grid URL是路由服务器的地址.
以上所有模式的默认URL皆为http://localhost:4444.
2、分发器
1、删除节点
要从Grid中删除节点, 请使用下面列出的cURL命令. 它不会停止在该节点上运行的任何持续中的会话. 除非显式终止, 否则节点将继续按原样运行. 分发器不再知晓该节点, 因此任何匹配的新会话请求 也不会转发到该节点.
在独立模式下, 分发器URL是独立服务器的地址.
在集线器节点模式下, 分发器URL是集线器服务器的地址.
shell
cURL --request DELETE 'http://localhost:4444/se/grid/distributor/node/<node-id>' --header 'X-REGISTRATION-SECRET: <secret> '
在完全分布式模式下, URL是分发器的地址.
shell
cURL --request DELETE 'http://localhost:5553/se/grid/distributor/node/<node-id>' --header 'X-REGISTRATION-SECRET: <secret>'
如果在设置Grid时未配置注册密码, 则使用
shell
cURL --request DELETE 'http://<Distributor-URL>/se/grid/distributor/node/<node-id>' --header 'X-REGISTRATION-SECRET;'
2、放空节点
节点放空命令用于优雅地关闭节点. 放空节点将在所有持续中的会话完成后停止节点. 但是, 它不接受任何新的会话请求.
在独立模式下, 分发器URL是独立服务器的地址.
在集线器节点模式下, 分发器URL是集线器服务器的地址.
shell
cURL --request POST 'http://localhost:4444/se/grid/distributor/node/<node-id>/drain' --header 'X-REGISTRATION-SECRET: <secret> '
在完全分布式模式下, URL是分发服务器的地址.
shell
cURL --request POST 'http://localhost:5553/se/grid/distributor/node/<node-id>/drain' --header 'X-REGISTRATION-SECRET: <secret>'
如果在设置Grid时未配置注册密码, 则使用
shell
cURL --request POST 'http://<Distributor-URL>/se/grid/distributor/node/<node-id>/drain' --header 'X-REGISTRATION-SECRET;'
3、节点
本节中的端点适用于 集线器节点模式和 节点独立运行的完全分布式网格模式. 在一个节点的情况下, 默认节点的URL为 http://localhost:5555 . 如果有多个节点, 请使用 Grid 状态 获取所有节点详细信息 以及定位地址.
1、状态
节点状态本质上是节点的运行状况检查. 分发器定期ping节点状态, 并相应地更新Grid模型. 状态包括相关的可用性, 会话和插槽的信息.
shell
cURL --request GET 'http://localhost:5555/status'
2、放空
分发器将 放空 命令传递给 由node-id标识的相应节点. 要直接放空节点, 请使用下面列出的cuRL命令. 两个端点都有效并产生相同的结果. 放空会等待持续中的会话完成后 才停止节点.
shell
cURL --request POST 'http://localhost:5555/se/grid/node/drain' --header 'X-REGISTRATION-SECRET: <secret>'
如果在设置Grid时未配置注册密码, 则使用
shell
cURL --request POST 'http://<node-URL>/se/grid/node/drain' --header 'X-REGISTRATION-SECRET;'
3、检查会话所有者
要检查会话是否属于某一节点, 请使用下面列出的cURL命令.
shell
cURL --request GET 'http://localhost:5555/se/grid/node/owner/<session-id>' --header 'X-REGISTRATION-SECRET: <secret>'
如果在设置Grid时未配置注册密码, 则使用
shell
cURL --request GET 'http://<node-URL>/se/grid/node/owner/<session-id>' --header 'X-REGISTRATION-SECRET;'
如果会话属于该节点, 则返回true, 否则返回false.
4、删除会话
删除会话将终止WebDriver会话, 退出驱动程序 并将其从活动会话集合中删除. 任何使用删除的会话id 或重用驱动程序实例的请求 都将抛出错误.
shell
cURL --request DELETE 'http://localhost:5555/se/grid/node/session/<session-id>' --header 'X-REGISTRATION-SECRET: <secret>'
如果在设置Grid时未配置注册密码, 则使用
shell
cURL --request DELETE 'http://<node-URL>/se/grid/node/session/<session-id>' --header 'X-REGISTRATION-SECRET;'
4、新会话队列
1、清除新会话队列
新会话请求队列保存新会话请求. 要清除队列, 请使用下面列出的cURL命令. 清除队列将拒绝队列中的所有请求. 对于每个这样的请求, 服务器都会向相应的客户端返回一个错误响应. 清除命令的返回结果是 已删除请求的总数.
在独立模式下, 队列URL是独立服务器的地址. 在集线器节点模式下, 队列URL是集线器服务器的地址.
shell
cURL --request DELETE 'http://localhost:4444/se/grid/newsessionqueue/queue' --header 'X-REGISTRATION-SECRET: <secret>'
在完全分布式模式下, 队列URL是新会话队列服务器的地址.
shell
cURL --request DELETE 'http://localhost:5559/se/grid/newsessionqueue/queue' --header 'X-REGISTRATION-SECRET: <secret>'
如果在设置Grid时未配置注册密码, 则使用
shell
cURL --request DELETE 'http://<URL>/se/grid/newsessionqueue/queue' --header 'X-REGISTRATION-SECRET;'
2、获取新会话队列请求
New Session Request Queue holds the new session requests. To get the current requests in the queue, use the cURL command enlisted below. The response returns the total number of requests in the queue and the request payloads. 新会话请求队列保存新会话请求. 要获取队列中的当前请求, 请使用下面列出的cURL命令. 响应会返回队列中的请求总数以及请求内容.
在独立模式下, 队列URL是独立服务器的地址. 在集线器节点模式下, 队列URL是集线器服务器的地址.
shell
cURL --request GET 'http://localhost:4444/se/grid/newsessionqueue/queue'
在完全分布式模式下, 队列URL是新会话队列服务器的地址.
shell
cURL --request GET 'http://localhost:5559/se/grid/newsessionqueue/queue'