-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Core] Race condition in Timeout #1241
Comments
@AndyLPK247 I see you're using v1.2.5; have you tried v2.0.x yet? |
I updated my Maven dependencies:
And I still get the same error:
|
Please note that these are not identical: Before(new String[]{"@web"}, 1000, 1, (Scenario scenario) -> {
driver = new ChromeDriver();
});
@Before(value = "@web", order = 1)
public void initWebDriver() throws Throwable {
driver = new ChromeDriver();
} The lambda step definition includes a timeout while the annotation step definition does not. So as a work around I would suggest not using the timeout by setting it to 0. I also can not reproduce your problem consistently from the provided sample. These two in combination with the stack trace provide a hint towards the underlying issue. The stack trace suggests that while shutting down the web driver the currently executing thread was either interrupted or already in an interrupted state. The Java8HookDefinition uses Timeout to wrap the lambda invocation in a timeout. And suppose that starting up chrome took about 1000ms - not unreasonable on a regular machine - then it would be reasonable to conclude that there is a race condition in Timeout. And looking at the code I am quite certain there is. final Thread executionThread = Thread.currentThread();
final AtomicBoolean done = new AtomicBoolean();
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> timer = executorService.schedule(new Runnable() {
@Override
public void run() {
if (!done.get()) {
executionThread.interrupt();
}
}
}, timeoutMillis, TimeUnit.MILLISECONDS);
try {
return callback.call();
} catch (InterruptedException timeout) {
throw new TimeoutException("Timed out after " + timeoutMillis + "ms.");
} finally {
done.set(true);
timer.cancel(true);
executorService.shutdownNow();
}
} While |
Changing the timeout to 0 resolved the issue. Thanks! |
We need to ensure a happens before relation exists between these events; a. the timer setting the interrupt flag on the execution thread. b. terminating and cleaning up the timer To do this we synchronize on monitor. The atomic boolean is merely a convenient container. Additionally Timeout did not throw any exceptions when the callback was busy waiting but did set the interrupted flag. To resolve this we check and throw after the completion of the callback. This fixes #1241
We need to ensure a happens before relation exists between these events; a. the timer setting the interrupt flag on the execution thread. b. terminating and cleaning up the timer To do this we synchronize on monitor. The atomic boolean is merely a convenient container. Additionally Timeout did not throw any exceptions when the callback was busy waiting but did set the interrupted flag. To resolve this we check and throw after the completion of the callback. This fixes #1241
We need to ensure a happens before relation exists between these events; a. the timer setting the interrupt flag on the execution thread. b. terminating and cleaning up the timer To do this we synchronize on monitor. The atomic boolean is merely a convenient container. Additionally Timeout did not throw any exceptions when the callback was busy waiting but did set the interrupted flag. To resolve this we check and throw after the completion of the callback. This fixes #1241
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Summary
I recently created an example test automation project for Cucumber-JVM using Java 8. It contains a basic Google searching test that uses Selenium WebDriver. The step definitions are written using the new Java 8 lambda style, rather than the traditional method annotation style. The Before and After hooks, also written using the lambda style, respectively initialize and quit a ChromeDriver instance. However, while the init is successful and steps can run, the quit consistently fails with an exception:
Source Code Projects
The example project with the failure is located at:
https://github.com/AndyLPK247/cucumber-jvm-java8-example
I also wrote a nearly-identical project that uses the method annotations for step defs:
https://github.com/AndyLPK247/cucumber-jvm-java-example
The project with method annotations for step defs works flawlessly.
Feature File Example
Step Definition Snippet
Expected Behavior
The expected behavior is that the web driver should work fine. It should be instantiated in the Before, used in the steps, and quit in the After. This works perfectly when the step definitions are written using method annotations.
Current Behavior
When the step definitions are written using lambda expressions, the web driver instance exhibits failing behavior. The exception indicates that the web driver is no longer available when it hits the After hook.
The Maven test output is:
Possible Solution
I don't know what is causing this problem. However, a workaround is to specify the web driver instantiation in a traditional method annotation style Before hook.
Steps to Reproduce (for bugs)
Context & Motivation
It makes no sense why Selenium web driver would work with the old style of step defs but not the new style of step defs.
Your Environment
I tested this on macOS Sierra using ChromeDriver. I also tested with FirefoxDriver and got similar errors.
The text was updated successfully, but these errors were encountered: