Skip to content

Commit 08a90a0

Browse files
committed
Revert "Fix FluentWait so it completes in more cases."
This reverts commit 51de536. We decided to revert back to legacy (blocking) implementation because the new one causes issues with clients' code that uses ThreadLocal variables in conditions.
1 parent 5e8cb3a commit 08a90a0

File tree

2 files changed

+32
-79
lines changed

2 files changed

+32
-79
lines changed

java/client/src/org/openqa/selenium/support/ui/FluentWait.java

+32-60
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,10 @@
2727
import java.time.Clock;
2828
import java.time.Duration;
2929
import java.time.Instant;
30+
import java.time.temporal.ChronoUnit;
3031
import java.util.ArrayList;
3132
import java.util.Collection;
3233
import java.util.List;
33-
import java.util.concurrent.CompletableFuture;
34-
import java.util.concurrent.ExecutionException;
3534
import java.util.concurrent.TimeUnit;
3635
import java.util.function.Function;
3736
import java.util.function.Supplier;
@@ -203,71 +202,44 @@ public FluentWait<T> ignoring(Class<? extends Throwable> firstType,
203202
*/
204203
@Override
205204
public <V> V until(Function<? super T, V> isTrue) {
206-
try {
207-
return CompletableFuture.supplyAsync(checkConditionInLoop(isTrue))
208-
.get(deriveSafeTimeout(), TimeUnit.MILLISECONDS);
209-
} catch (ExecutionException cause) {
210-
if (cause.getCause() instanceof RuntimeException) {
211-
throw (RuntimeException) cause.getCause().fillInStackTrace();
212-
} else if (cause.getCause() instanceof Error) {
213-
throw (Error) cause.getCause();
214-
}
215-
216-
throw new RuntimeException(cause);
217-
} catch (InterruptedException cause) {
218-
Thread.currentThread().interrupt();
219-
throw new RuntimeException(cause);
220-
} catch (java.util.concurrent.TimeoutException cause) {
221-
throw new TimeoutException("Supplied function might have stalled", cause);
222-
}
223-
}
224-
225-
private <V> Supplier<V> checkConditionInLoop(Function<? super T, V> isTrue) {
226-
return () -> {
227-
Instant end = clock.instant().plus(timeout);
228-
229-
Throwable lastException;
230-
while (true) {
231-
//noinspection ProhibitedExceptionCaught
232-
try {
233-
V value = isTrue.apply(input);
234-
if (value != null && (Boolean.class != value.getClass() || Boolean.TRUE.equals(value))) {
235-
return value;
236-
}
205+
Instant end = clock.instant().plus(timeout);
237206

238-
// Clear the last exception; if another retry or timeout exception would
239-
// be caused by a false or null value, the last exception is not the
240-
// cause of the timeout.
241-
lastException = null;
242-
} catch (Throwable e) {
243-
lastException = propagateIfNotIgnored(e);
207+
Throwable lastException;
208+
while (true) {
209+
try {
210+
V value = isTrue.apply(input);
211+
if (value != null && (Boolean.class != value.getClass() || Boolean.TRUE.equals(value))) {
212+
return value;
244213
}
245214

246-
// Check the timeout after evaluating the function to ensure conditions
247-
// with a zero timeout can succeed.
248-
if (end.isBefore(clock.instant())) {
249-
String message = messageSupplier != null ? messageSupplier.get() : null;
215+
// Clear the last exception; if another retry or timeout exception would
216+
// be caused by a false or null value, the last exception is not the
217+
// cause of the timeout.
218+
lastException = null;
219+
} catch (Throwable e) {
220+
lastException = propagateIfNotIgnored(e);
221+
}
250222

251-
String timeoutMessage = String.format(
252-
"Expected condition failed: %s (tried for %d second(s) with %d milliseconds interval)",
253-
message == null ? "waiting for " + isTrue : message,
254-
timeout.getSeconds(), interval.toMillis());
255-
throw timeoutException(timeoutMessage, lastException);
256-
}
223+
// Check the timeout after evaluating the function to ensure conditions
224+
// with a zero timeout can succeed.
225+
if (end.isBefore(clock.instant())) {
226+
String message = messageSupplier != null ?
227+
messageSupplier.get() : null;
257228

258-
try {
259-
sleeper.sleep(interval);
260-
} catch (InterruptedException e) {
261-
Thread.currentThread().interrupt();
262-
throw new WebDriverException(e);
263-
}
229+
String timeoutMessage = String.format(
230+
"Expected condition failed: %s (tried for %d second(s) with %d milliseconds interval)",
231+
message == null ? "waiting for " + isTrue : message,
232+
timeout.getSeconds(), interval.toMillis());
233+
throw timeoutException(timeoutMessage, lastException);
264234
}
265-
};
266-
}
267235

268-
/** This timeout is somewhat arbitrary. */
269-
private long deriveSafeTimeout() {
270-
return this.timeout.toMillis() + this.interval.toMillis();
236+
try {
237+
sleeper.sleep(interval);
238+
} catch (InterruptedException e) {
239+
Thread.currentThread().interrupt();
240+
throw new WebDriverException(e);
241+
}
242+
}
271243
}
272244

273245
private Throwable propagateIfNotIgnored(Throwable e) {

java/client/test/org/openqa/selenium/support/ui/FluentWaitTest.java

-19
Original file line numberDiff line numberDiff line change
@@ -259,25 +259,6 @@ protected RuntimeException timeoutException(String message, Throwable lastExcept
259259
.satisfies(expected -> assertThat(sentinelException).isSameAs(expected));
260260
}
261261

262-
@Test
263-
public void timeoutWhenConditionMakesNoProgress() {
264-
265-
when(mockClock.instant()).thenReturn(EPOCH, EPOCH.plusMillis(2500));
266-
when(mockCondition.apply(mockDriver)).then(invocation -> {
267-
while (true) {
268-
// it gets into an endless loop and makes no progress.
269-
}
270-
});
271-
272-
FluentWait<WebDriver> wait = new FluentWait<>(mockDriver, mockClock, mockSleeper)
273-
.withTimeout(Duration.ofSeconds(0))
274-
.pollingEvery(Duration.ofSeconds(2));
275-
276-
assertThatExceptionOfType(org.openqa.selenium.TimeoutException.class)
277-
.isThrownBy(() -> wait.until(mockCondition))
278-
.satisfies(actual -> assertThat(actual.getMessage()).startsWith("Supplied function might have stalled"));
279-
}
280-
281262
private static class TestException extends RuntimeException {
282263

283264
}

0 commit comments

Comments
 (0)