Skip to content

Commit

Permalink
Merge pull request #342 from vmi/refine-parallel-execution
Browse files Browse the repository at this point in the history
refine parallel execution.
  • Loading branch information
vmi authored Mar 22, 2023
2 parents 5b21451 + fe3ec24 commit b05c4be
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 26 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ https://github.com/vmi/selenese-runner-java/releases
Release Note
------------

### 4.2.0
### 4.3.0

* Catch up Selenium 4.4.0 and update dependency versions.
* Catch up Selenium 4.8.1 and update dependency versions.
* Fix several problems associated with the update.
* Remove dependency on `xalan` for security reason. (#337)
* Run multiple test files in parallel. (PR #340)
* Add new option `--parallel` to parallel execution.

Please check [RELEASENOTE.md](RELEASENOTE.md).

Expand Down Expand Up @@ -50,6 +53,7 @@ Usage
--config (-c) <file> : load option information from file.
--driver (-d) <driver> : firefox (default) | chrome | ie | edge | safari | htmlunit | remote | appium | FQCN-of-WebDriverFactory
--headless : use headless mode if driver is supported (currently, Chrome and Firefox)
--parallel <threads> : run multiple test files in parallel (if set <threads> to "max", all files are executed in parallel at once)
--profile (-p) <name> : profile name (Firefox only *1)
--profile-dir (-P) <dir> : profile directory (Firefox only *1)
--chrome-experimental-options <file> : path to json file specify experimental options for chrome (Chrome only *1)
Expand Down
2 changes: 2 additions & 0 deletions RELEASENOTE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Selenese Runner Java Relase Note
* Catch up Selenium 4.8.1 and update dependency versions.
* Fix several problems associated with the update.
* Remove dependency on `xalan` for security reason. (#337)
* Run multiple test files in parallel. (PR #340)
* Add new option `--parallel` to parallel execution.

### 4.2.0

Expand Down
4 changes: 4 additions & 0 deletions src/generator/config.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ headless {
driverOption = true
}

parallel {
metaVar = "<threads>"
usage = "run multiple test files in parallel (if set <threads> to \"max\", all files are executed in parallel at once)"
}

profile {
aliases = "-p"
Expand Down
62 changes: 38 additions & 24 deletions src/main/java/jp/vmi/selenium/selenese/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand All @@ -22,7 +21,6 @@
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;

import jp.vmi.html.result.HtmlResult;
import jp.vmi.selenium.runner.converter.Converter;
import jp.vmi.selenium.selenese.command.ICommandFactory;
import jp.vmi.selenium.selenese.config.DefaultConfig;
Expand All @@ -38,9 +36,9 @@
import jp.vmi.selenium.webdriver.DriverOptions;
import jp.vmi.selenium.webdriver.DriverOptions.DriverOption;
import jp.vmi.selenium.webdriver.WebDriverManager;
import static jp.vmi.selenium.selenese.result.Unexecuted.*;

import static jp.vmi.selenium.selenese.config.DefaultConfig.*;
import static jp.vmi.selenium.selenese.result.Unexecuted.*;

/**
* Provide command line interface.
Expand Down Expand Up @@ -90,18 +88,22 @@ private void help(String... msgs) {
/**
* New object to hold result and selenese
*/
private class ResultObject{
private class ResultObject {
Result result;
Selenese selenese;

public Result getResult() {
return result;
}

public void setResult(Result result) {
this.result = result;
}

public Selenese getSelenese() {
return selenese;
}

public void setSelenese(Selenese selenese) {
this.selenese = selenese;
}
Expand All @@ -120,12 +122,28 @@ public void run(String[] args) {
if (filenames.length == 0)
help();
log.info("Start: " + PROG_TITLE + " {}", getVersion());
Result totalResult = UNEXECUTED;
ExecutorService executor = Executors.newFixedThreadPool(filenames.length);
CompletionService<ResultObject> completionService = new ExecutorCompletionService<ResultObject>(executor);
for (String fileName : filenames) {
completionService.submit(new Callable<ResultObject>() {
public ResultObject call() {
Result totalResult;
String parallel = config.getParallel();
if (parallel == null) {
Runner runner = new Runner();
runner.setCommandLineArgs(args);
setupRunner(runner, config, filenames);
totalResult = runner.run(filenames);
runner.finish();
} else {
int threads;
if ("max".equalsIgnoreCase(parallel)) {
threads = filenames.length;
} else {
threads = NumberUtils.toInt(parallel);
if (threads == 0)
help("Error: Illegal argument of --parallel: " + parallel);
}
totalResult = UNEXECUTED;
ExecutorService executor = Executors.newFixedThreadPool(threads);
CompletionService<ResultObject> completionService = new ExecutorCompletionService<ResultObject>(executor);
for (String fileName : filenames) {
completionService.submit(() -> {
Runner runner = new Runner();
Selenese selenese = Parser.parse(fileName, runner.getCommandFactory());
runner.setCommandLineArgs(args);
Expand All @@ -136,20 +154,16 @@ public ResultObject call() {
resultObject.setResult(result);
resultObject.setSelenese(selenese);
return resultObject;
});
}
for (int received = 0; received < filenames.length; received++) {
try {
Future<ResultObject> resultFuture = completionService.take(); // blocks if none available
ResultObject resultObject = resultFuture.get();
totalResult = totalResult.updateWithChildResult(resultObject.getSelenese(), resultObject.getResult());
} catch (InterruptedException | ExecutionException e) {
log.error("During parallel execution", e);
}
});
}
int received = 0;
boolean errors = false;

while (received < filenames.length && !errors) {
Future<ResultObject> resultFuture = completionService.take(); //blocks if none available
try {
ResultObject resultObject = resultFuture.get();
received++;
totalResult = totalResult.updateWithChildResult(resultObject.getSelenese(), resultObject.getResult());
} catch (Exception e) {
e.printStackTrace();
}
}
exitLevel = totalResult.getLevel();
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/jp/vmi/selenium/selenese/config/DefaultConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ private static String statusListItem(Level level) {
@Option(name = "--" + HEADLESS, usage = "use headless mode if driver is supported (currently, Chrome and Firefox)")
private Boolean headless;

@Option(name = "--" + PARALLEL, metaVar = "<threads>", usage = "run multiple test files in parallel (if set <threads> to \"max\", all files are executed in parallel at once)")
private String parallel;

@Option(name = "--" + PROFILE, aliases = "-p", metaVar = "<name>", usage = "profile name (Firefox only *1)")
private String profile;

Expand Down Expand Up @@ -282,6 +285,15 @@ public void setHeadless(boolean headless) {
this.headless = headless;
}

@Override
public String getParallel() {
return parallel != null ? parallel : (parentOptions != null ? parentOptions.getParallel() : null);
}

public void setParallel(String parallel) {
this.parallel = parallel;
}

@Override
public String getProfile() {
return profile != null ? profile : (parentOptions != null ? parentOptions.getProfile() : null);
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/jp/vmi/selenium/selenese/config/IConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public interface IConfig {

public static final String DRIVER = "driver";
public static final String HEADLESS = "headless";
public static final String PARALLEL = "parallel";
public static final String PROFILE = "profile";
public static final String PROFILE_DIR = "profile-dir";
public static final String CHROME_EXPERIMENTAL_OPTIONS = "chrome-experimental-options";
Expand Down Expand Up @@ -110,6 +111,8 @@ public interface IConfig {

boolean isHeadless();

String getParallel();

String getProfile();

String getProfileDir();
Expand Down
1 change: 1 addition & 0 deletions tools/update-readme-cmd-opts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ while (<>) {
}
while (<>) {
s/\s+\z//s;
s/;(selenese-runner\.jar)/:\1/;
last if (/\[INFO\]\s+Exit\s+code:/);
print " $_\n";
}
Expand Down

0 comments on commit b05c4be

Please sign in to comment.