java - 以编程方式将第二个 Selenium Grid 节点作为 Grid 进程中的另一个进程生成时出现 ParameterException

标签 java multithreading selenium selenium-grid java-threads

我正在设置 Selenium Grid,它可以从 Grid Servlet 端点上的 HTTP 请求生成新的节点实例:SpawnNodeServlet。 GET 请求上的 Servlet 正在创建新的 Selenium Grid 节点,并配置将其注册到集线器。通过这种方式,我可以在需要时通过在 http://localhost:4444/grid/admin/SpawnNodeServlet 下发送 GET 请求来添加节点。一切正常,直到我想生成第二个或下一个节点。只有第一个正常工作,之后我得到了 ParameterException(下面的所有代码)。由于第一个节点正确注册,参数应该没问题。任何想法可能是错的?我认为,问题可能出在流程创建实现中。

我尝试从 Runtime exec 作为普通命令执行 jars,但这也没有正常工作。

final Runtime runtime = Runtime.getRuntime();
final Process command = runtime.exec(executionArgs.toArray(new String[0]));

下面是 InstanceExecutor 的主要代码,它允许创建新的 Node 实例:

public class InstanceExecutor {

    private final Logger logger = Logger.getLogger(getClass().getName());

    private BufferedReader errorBufferedReader;
    private BufferedReader outputBufferedReader;
    private int exitValue;

    public void execute(List<String> args) throws InstanceExecutorException {

        final List<String> executionArgs = new ArrayList<String>();
        executionArgs.add(0, "java");
        executionArgs.addAll(args);

        try {
            final ProcessBuilder processBuilder = new ProcessBuilder(executionArgs.toArray(new String[0]));
            Process process = processBuilder.start();

            logger.info("processBuilder.start()");

            this.errorBufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            this.outputBufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

            logger.info("BufferedReader's");

            process.waitFor();
            this.exitValue = process.exitValue();

            if (this.exitValue != 0) {
                throw new IOException("Failed to execute jar, " + this.getExecutionLog());
            }
        } catch (final IOException | InterruptedException e) {
            throw new InstanceExecutorException(e);
        }
    }

    public String getExecutionLog() {
        StringBuilder error = new StringBuilder();
        String line;

        try {
            while((line = this.errorBufferedReader.readLine()) != null) {
                error
                    .append("\n")
                    .append(line);
            }
        } catch (final IOException ignored) { }

        StringBuilder output = new StringBuilder();

        try {
            while((line = this.outputBufferedReader.readLine()) != null) {
                output
                    .append("\n")
                    .append(line);
            }
        } catch (final IOException ignored) { }

        try {
            this.errorBufferedReader.close();
            this.outputBufferedReader.close();
        } catch (final IOException ignored) { }

        return "exitValue: " + this.exitValue + ", error: " + error + ", output: " + output;
    }
}

InstanceExecutor类在SpawnNodeServletdoGet中使用:

public class SpawnNodeServlet extends RegistryBasedServlet {

    public SpawnNodeServlet() {
        this(null);
    }

    public SpawnNodeServlet(GridRegistry registry) {
        super(registry);
    }

    private final Logger logger = Logger.getLogger(getClass().getName());

    private InstanceExecutor instanceExecutor = new InstanceExecutor();

    private final List<String> nodeArgs = new ArrayList<String>();

    private void sendResponse(HttpServletResponse response) throws IOException {
        PrintWriter out = response.getWriter();
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        response.setStatus(200);
        out.flush();
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        logger.info("Spawning additional node");

        nodeArgs.add("-Dwebdriver.chrome.driver=\"libs//chromedriver\"");
        nodeArgs.add("-cp");
        nodeArgs.add("hub/target/hub-1.0.0-jar-with-dependencies.jar:node/target/node-1.0.0-jar-with-dependencies.jar");
        nodeArgs.add("org.openqa.grid.selenium.GridLauncherV3");
        nodeArgs.add("-role");
        nodeArgs.add("node");
        nodeArgs.add("-nodeConfig");
        nodeArgs.add("node/config.json");

        try {
            instanceExecutor.execute(nodeArgs);
        } catch (InstanceExecutorException e) {
            throw new IOException(e);
        }

        sendResponse(response);
    }
}

这是我在 http://localhost:4444/grid/admin/SpawnNodeServlet 上执行 GET 请求两次后的控制台日志:

3:27:46.126 INFO [SpawnNodeServlet.doGet] - Spawning additional node
23:27:46.141 INFO [InstanceExecutor.execute] - processBuilder.start()
23:27:46.142 INFO [InstanceExecutor.execute] - BufferedReader's
23:27:47.018 INFO [DefaultGridRegistry.add] - Registered a node http://169.254.168.67:8992
23:27:47.018 INFO [DefaultProxy.startPolling] - startPolling()
23:30:33.954 INFO [SpawnNodeServlet.doGet] - Spawning additional node
23:30:33.959 INFO [InstanceExecutor.execute] - processBuilder.start()
23:30:33.960 INFO [InstanceExecutor.execute] - BufferedReader's
2019-09-08 23:30:34.203:WARN:osjs.HttpChannel:qtp1128948651-14: /grid/admin/SpawnNodeServlet java.io.IOException: exception.InstanceExecutorException: java.io.IOException: Failed to execute jar, exitValue: 1, error:
Exception in thread "main" com.beust.jcommander.ParameterException: Was passed main parameter '-Dwebdriver.chrome.driver="libs//chromedriver"' but no main parameter was defined in your arg class
    at com.beust.jcommander.JCommander.initMainParameterValue(JCommander.java:936)
    at com.beust.jcommander.JCommander.parseValues(JCommander.java:752)
    at com.beust.jcommander.JCommander.parse(JCommander.java:340)
    at com.beust.jcommander.JCommander.parse(JCommander.java:319)
    at org.openqa.grid.selenium.GridLauncherV3.parse(GridLauncherV3.java:218)
    at org.openqa.grid.selenium.GridLauncherV3.lambda$buildLaunchers$7(GridLauncherV3.java:271)
    at org.openqa.grid.selenium.GridLauncherV3.lambda$launch$0(GridLauncherV3.java:86)
    at java.base/java.util.Optional.map(Optional.java:265)
    at org.openqa.grid.selenium.GridLauncherV3.launch(GridLauncherV3.java:86)
    at org.openqa.grid.selenium.GridLauncherV3.main(GridLauncherV3.java:70), output:

如您所见,第一次执行正确生成了 Node,但第二次执行时出现此错误。

应该如何更改此流程构建器逻辑以不等待流程结束(我尝试删除它并仅创建流程但它也没有工作)并且能够生成超过 1 个 Selenium 网格节点?

最佳答案

在 SpawnNodeServlet 中,您应该删除类字段 nodeArgs,并将 nodeArgs 定义为本地方法变量。

你有实例字段:

private final List<String> nodeArgs = new ArrayList<String>();

第一次服务调用列表包含:

    "-Dwebdriver.chrome.driver=\"libs//chromedriver\""
    "-cp"
    "hub/target/hub-1.0.0-jar-with-dependencies.jar:node/target/node-1.0.0-jar-with-dependencies.jar"
    "org.openqa.grid.selenium.GridLauncherV3"
    "-role"
    "node"
    "-nodeConfig"
    "node/config.json"

第二次调用后:

    "-Dwebdriver.chrome.driver=\"libs//chromedriver\""
    "-cp"
    "hub/target/hub-1.0.0-jar-with-dependencies.jar:node/target/node-1.0.0-jar-with-dependencies.jar"
    "org.openqa.grid.selenium.GridLauncherV3"
    "-role"
    "node"
    "-nodeConfig"
    "node/config.json"
    "-Dwebdriver.chrome.driver=\"libs//chromedriver\""
    "-cp"
    "hub/target/hub-1.0.0-jar-with-dependencies.jar:node/target/node-1.0.0-jar-with-dependencies.jar"
    "org.openqa.grid.selenium.GridLauncherV3"
    "-role"
    "node"
    "-nodeConfig"
    "node/config.json"

然后你将这个列表传递给执行者:

instanceExecutor.execute(nodeArgs);

这不是有效的 java 参数列表。

关于java - 以编程方式将第二个 Selenium Grid 节点作为 Grid 进程中的另一个进程生成时出现 ParameterException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57846285/

相关文章:

java - 如何打印出当前在特定非线程类上运行的线程名称?

实现简单内存池的 C 库

python - 如何获取href中的链接?

java - 两个 Joda DateTime 之间的差异(以月为单位)和剩余天数

ruby-on-rails - 如何使用线程池写入我的数据库?

java - 检查 Java 反射类型的类

java - 每小时自动运行一个jar文件

python - 使用 Selenium 和 Python 迭代 Accordion block 中的每个项目

java - 迭代查询

java - 如何使用 Java 发送 ISO8583 消息