Skip to content

Commit 337e431

Browse files
committed
Extract common browser lifecycle code and test rules into a single rule
This means that there's a lot less inside the junit 4 test base, and that's a Good Thing.
1 parent 61b0583 commit 337e431

File tree

8 files changed

+312
-202
lines changed

8 files changed

+312
-202
lines changed

java/client/test/org/openqa/selenium/environment/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ java_library(
5555
"//java/server/src/org/openqa/selenium/grid/web",
5656
"//java/server/src/org/openqa/selenium/netty/server",
5757
artifact("com.google.guava:guava"),
58+
artifact("org.assertj:assertj-core"),
5859
artifact("org.eclipse.jetty:jetty-http"),
5960
artifact("org.eclipse.jetty:jetty-server"),
6061
artifact("org.eclipse.jetty:jetty-servlet"),

java/client/test/org/openqa/selenium/environment/GlobalTestEnvironment.java

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
import java.util.function.Supplier;
2121

22+
import static org.assertj.core.api.Assertions.assertThat;
23+
2224
/**
2325
* Used to hold a TestEnvironment in a static class-level field.
2426
*/
@@ -39,6 +41,7 @@ public static synchronized TestEnvironment getOrCreate(
3941
if (environment == null) {
4042
try {
4143
environment = startThisIfNothingIsAlreadyRunning.get();
44+
environment.assertIsValid();
4245
} catch (Exception e) {
4346
throw new RuntimeException(e);
4447
}

java/client/test/org/openqa/selenium/environment/TestEnvironment.java

+9
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,18 @@
1919

2020
import org.openqa.selenium.environment.webserver.AppServer;
2121

22+
import static org.assertj.core.api.Assertions.assertThat;
23+
2224
public interface TestEnvironment {
2325

2426
AppServer getAppServer();
2527

2628
void stop();
29+
30+
default void assertIsValid() {
31+
String hostName = getAppServer().getHostName();
32+
String alternateHostName = getAppServer().getAlternateHostName();
33+
34+
assertThat(hostName).isNotEqualTo(alternateHostName);
35+
}
2736
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Licensed to the Software Freedom Conservancy (SFC) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The SFC licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.openqa.selenium.environment.webserver;
19+
20+
import org.openqa.selenium.grid.web.PathResource;
21+
import org.openqa.selenium.grid.web.ResourceHandler;
22+
import org.openqa.selenium.remote.http.HttpHandler;
23+
import org.openqa.selenium.remote.http.HttpRequest;
24+
import org.openqa.selenium.remote.http.HttpResponse;
25+
import org.openqa.selenium.remote.http.Routable;
26+
27+
import java.io.UncheckedIOException;
28+
import java.nio.file.Path;
29+
30+
import static org.openqa.selenium.build.InProject.locate;
31+
32+
public class CommonWebResources implements Routable {
33+
34+
private final Routable delegate;
35+
36+
public CommonWebResources() {
37+
Path common = locate("common/src/web").toAbsolutePath();
38+
delegate = new ResourceHandler(new PathResource(common));
39+
}
40+
41+
@Override
42+
public boolean matches(HttpRequest req) {
43+
return delegate.matches(req);
44+
}
45+
46+
@Override
47+
public HttpResponse execute(HttpRequest req) throws UncheckedIOException {
48+
return delegate.execute(req);
49+
}
50+
}

java/client/test/org/openqa/selenium/environment/webserver/NettyAppServer.java

+2-8
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
import org.openqa.selenium.grid.config.MapConfig;
2222
import org.openqa.selenium.grid.server.BaseServerOptions;
2323
import org.openqa.selenium.grid.server.Server;
24-
import org.openqa.selenium.grid.web.PathResource;
25-
import org.openqa.selenium.grid.web.ResourceHandler;
2624
import org.openqa.selenium.internal.Require;
2725
import org.openqa.selenium.json.Json;
2826
import org.openqa.selenium.net.PortProber;
@@ -38,13 +36,11 @@
3836
import java.io.UncheckedIOException;
3937
import java.net.MalformedURLException;
4038
import java.net.URL;
41-
import java.nio.file.Path;
4239

4340
import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
4441
import static com.google.common.net.MediaType.JSON_UTF_8;
4542
import static java.nio.charset.StandardCharsets.UTF_8;
4643
import static java.util.Collections.singletonMap;
47-
import static org.openqa.selenium.build.InProject.locate;
4844
import static org.openqa.selenium.remote.http.Contents.bytes;
4945
import static org.openqa.selenium.remote.http.Contents.string;
5046
import static org.openqa.selenium.remote.http.Route.get;
@@ -69,13 +65,11 @@ public NettyAppServer(HttpHandler handler) {
6965
}
7066

7167
private static Route emulateJettyAppServer() {
72-
Path common = locate("common/src/web").toAbsolutePath();
73-
7468
return Route.combine(
75-
new ResourceHandler(new PathResource(common)),
69+
new CommonWebResources(),
7670
get("/encoding").to(EncodingHandler::new),
7771
matching(req -> req.getUri().startsWith("/page/")).to(PageHandler::new),
78-
get("/redirect").to(() -> new RedirectHandler()),
72+
get("/redirect").to(RedirectHandler::new),
7973
get("/sleep").to(SleepingHandler::new),
8074
post("/upload").to(UploadHandler::new));
8175
}

java/client/test/org/openqa/selenium/testing/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ java_library(
3232
"JUnit4TestBase.java",
3333
"Pages.java",
3434
"Safely.java",
35+
"SeleniumTestRule.java",
3536
"SeleniumTestRunner.java",
3637
"StaticResources.java",
3738
"TearDownFixture.java",

java/client/test/org/openqa/selenium/testing/JUnit4TestBase.java

+10-194
Original file line numberDiff line numberDiff line change
@@ -20,38 +20,23 @@
2020
import org.junit.Before;
2121
import org.junit.BeforeClass;
2222
import org.junit.Rule;
23-
import org.junit.rules.RuleChain;
24-
import org.junit.rules.TestRule;
25-
import org.junit.rules.TestWatcher;
26-
import org.junit.runner.Description;
2723
import org.junit.runner.RunWith;
28-
import org.junit.runners.model.Statement;
2924
import org.openqa.selenium.Capabilities;
3025
import org.openqa.selenium.WebDriver;
3126
import org.openqa.selenium.environment.GlobalTestEnvironment;
3227
import org.openqa.selenium.environment.InProcessTestEnvironment;
3328
import org.openqa.selenium.environment.TestEnvironment;
3429
import org.openqa.selenium.environment.webserver.AppServer;
35-
import org.openqa.selenium.remote.RemoteWebDriver;
3630
import org.openqa.selenium.support.ui.Wait;
37-
import org.openqa.selenium.support.ui.WebDriverWait;
38-
import org.openqa.selenium.testing.drivers.Browser;
39-
import org.openqa.selenium.testing.drivers.WebDriverBuilder;
4031

41-
import java.time.Duration;
42-
import java.util.logging.Logger;
43-
import java.util.stream.Stream;
44-
45-
import static org.assertj.core.api.Assertions.assertThat;
4632
import static org.assertj.core.api.Assumptions.assumeThat;
4733

4834
@RunWith(SeleniumTestRunner.class)
4935
public abstract class JUnit4TestBase {
5036

51-
private static final Logger logger = Logger.getLogger(JUnit4TestBase.class.getName());
52-
private static final ThreadLocal<WebDriver> storedDriver = new ThreadLocal<>();
37+
@Rule
38+
public SeleniumTestRule seleniumTestRule = new SeleniumTestRule();
5339

54-
private final Browser current = Browser.detect();
5540
protected TestEnvironment environment;
5641
protected AppServer appServer;
5742
protected Pages pages;
@@ -71,187 +56,18 @@ public void prepareEnvironment() {
7156

7257
pages = new Pages(appServer);
7358

74-
String hostName = environment.getAppServer().getHostName();
75-
String alternateHostName = environment.getAppServer().getAlternateHostName();
76-
77-
assertThat(hostName).isNotEqualTo(alternateHostName);
78-
}
79-
80-
@Rule
81-
public TestRule chain = RuleChain
82-
.outerRule(new TraceMethodNameRule())
83-
.around(new ManageDriverRule())
84-
.around(new SwitchToTopRule())
85-
.around(new NotYetImplementedRule());
86-
87-
private static class TraceMethodNameRule extends TestWatcher {
88-
@Override
89-
protected void starting(Description description) {
90-
super.starting(description);
91-
logger.info(">>> Starting " + description);
92-
}
93-
94-
@Override
95-
protected void finished(Description description) {
96-
super.finished(description);
97-
logger.info("<<< Finished " + description);
98-
}
99-
}
100-
101-
private class ManageDriverRule extends TestWatcher {
102-
@Override
103-
protected void starting(Description description) {
104-
super.starting(description);
105-
NoDriverBeforeTest killSharedDriver = description.getAnnotation(NoDriverBeforeTest.class);
106-
if (killSharedDriver != null && current.matches(killSharedDriver.value())) {
107-
System.out.println("Destroying driver before test " + description);
108-
removeDriver();
109-
return;
110-
}
111-
NeedsFreshDriver annotation = description.getAnnotation(NeedsFreshDriver.class);
112-
if (annotation != null && current.matches(annotation.value())) {
113-
System.out.println("Restarting driver before test " + description);
114-
removeDriver();
115-
}
116-
try {
117-
createDriver();
118-
} catch (Exception e) {
119-
throw new RuntimeException("Exception creating driver", e);
120-
}
121-
}
122-
123-
@Override
124-
protected void succeeded(Description description) {
125-
super.finished(description);
126-
NoDriverAfterTest annotation = description.getAnnotation(NoDriverAfterTest.class);
127-
if (annotation != null && !annotation.failedOnly() && current.matches(annotation.value())) {
128-
System.out.println("Restarting driver after succeeded test " + description);
129-
removeDriver();
130-
}
131-
}
132-
133-
@Override
134-
protected void failed(Throwable e, Description description) {
135-
super.finished(description);
136-
NoDriverAfterTest annotation = description.getAnnotation(NoDriverAfterTest.class);
137-
if (annotation != null && current.matches(annotation.value())) {
138-
System.out.println("Restarting driver after failed test " + description);
139-
removeDriver();
140-
}
141-
}
142-
}
143-
144-
private class SwitchToTopRule extends TestWatcher {
145-
@Override
146-
protected void finished(Description description) {
147-
super.finished(description);
148-
SwitchToTopAfterTest annotation = description.getAnnotation(SwitchToTopAfterTest.class);
149-
if (annotation != null) {
150-
driver.switchTo().defaultContent();
151-
}
152-
}
153-
}
154-
155-
private class NotYetImplementedRule implements TestRule {
156-
157-
private boolean notImplemented(NotYetImplementedList list) {
158-
return list != null && list.value().length > 0 && notImplemented(Stream.of(list.value()));
159-
}
160-
161-
private boolean notImplemented(NotYetImplemented single) {
162-
return single != null && notImplemented(Stream.of(single));
163-
}
164-
165-
private boolean notImplemented(Stream<NotYetImplemented> nyi) {
166-
return nyi.anyMatch(driver -> current.matches(driver.value()));
167-
}
168-
169-
@Override
170-
public Statement apply(final Statement base, final Description description) {
171-
if (notImplemented(description.getAnnotation(NotYetImplementedList.class)) ||
172-
notImplemented(description.getAnnotation(NotYetImplemented.class))) {
173-
return new Statement() {
174-
@Override
175-
public void evaluate() throws Throwable {
176-
Exception toBeThrown = null;
177-
try {
178-
base.evaluate();
179-
toBeThrown = new Exception(String.format(
180-
"%s.%s is marked as not yet implemented with %s but already works!",
181-
description.getTestClass().getSimpleName(), description.getMethodName(), current));
182-
}
183-
catch (final Throwable e) {
184-
// expected
185-
}
186-
if (toBeThrown != null) {
187-
throw toBeThrown;
188-
}
189-
}
190-
};
191-
192-
} else {
193-
return base;
194-
}
195-
}
196-
}
197-
198-
private void createDriver() {
199-
logger.info("CREATING DRIVER");
200-
driver = actuallyCreateDriver();
201-
logger.info("CREATED " + driver);
202-
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
203-
shortWait = new WebDriverWait(driver, Duration.ofSeconds(5));
59+
driver = seleniumTestRule.getDriver();
60+
wait = seleniumTestRule::waitUntil;
61+
shortWait = seleniumTestRule::shortWaitUntil;
20462
}
20563

20664
public void createNewDriver(Capabilities capabilities) {
207-
removeDriver();
208-
driver = actuallyCreateDriver(capabilities);
209-
wait = new WebDriverWait(driver, Duration.ofSeconds(10));
210-
shortWait = new WebDriverWait(driver, Duration.ofSeconds(5));
65+
driver = seleniumTestRule.createNewDriver(capabilities);
66+
wait = seleniumTestRule::waitUntil;
67+
shortWait = seleniumTestRule::shortWaitUntil;
21168
}
21269

213-
private static WebDriver actuallyCreateDriver() {
214-
WebDriver driver = storedDriver.get();
215-
216-
if (driver == null ||
217-
(driver instanceof RemoteWebDriver && ((RemoteWebDriver)driver).getSessionId() == null)) {
218-
StaticResources.ensureAvailable();
219-
driver = new WebDriverBuilder().get();
220-
storedDriver.set(driver);
221-
}
222-
return storedDriver.get();
70+
public void removeDriver() {
71+
seleniumTestRule.removeDriver();
22372
}
224-
225-
private static WebDriver actuallyCreateDriver(Capabilities capabilities) {
226-
WebDriver driver = storedDriver.get();
227-
228-
if (driver == null ||
229-
(driver instanceof RemoteWebDriver && ((RemoteWebDriver)driver).getSessionId() == null)) {
230-
StaticResources.ensureAvailable();
231-
driver = new WebDriverBuilder().get(capabilities);
232-
storedDriver.set(driver);
233-
}
234-
return storedDriver.get();
235-
}
236-
237-
public static void removeDriver() {
238-
if (Boolean.getBoolean("webdriver.singletestsuite.leaverunning")) {
239-
return;
240-
}
241-
242-
WebDriver current = storedDriver.get();
243-
244-
if (current == null) {
245-
return;
246-
}
247-
248-
try {
249-
current.quit();
250-
} catch (RuntimeException ignored) {
251-
// fall through
252-
}
253-
254-
storedDriver.remove();
255-
}
256-
25773
}

0 commit comments

Comments
 (0)