-
-
Notifications
You must be signed in to change notification settings - Fork 184
Expand file tree
/
Copy pathWebServerTestCase.java
More file actions
282 lines (247 loc) · 9.74 KB
/
WebServerTestCase.java
File metadata and controls
282 lines (247 loc) · 9.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/*
* Copyright (c) 2002-2026 Gargoyle Software Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.htmlunit;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
import java.net.URL;
import java.nio.charset.Charset;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.jetty.server.Server;
import org.htmlunit.WebDriverTestCase.MockWebConnectionServlet;
import org.htmlunit.html.HtmlPage;
import org.htmlunit.util.JettyServerUtils;
import org.htmlunit.util.MimeType;
import org.junit.jupiter.api.AfterEach;
import jakarta.servlet.Servlet;
/**
* A WebTestCase which starts a local server, and doesn't use WebDriver.
* <p>
* <b>Note that {@link WebDriverTestCase} should be used unless HtmlUnit-specific feature
* is needed and Selenium does not support it.</b>
*
* @author Ahmed Ashour
* @author Marc Guillemot
* @author Ronald Brill
*/
public abstract class WebServerTestCase extends WebTestCase {
public enum SSLVariant {
NONE,
INSECURE,
SELF_SIGNED
}
/** Timeout used when waiting for successful bind. */
public static final int BIND_TIMEOUT = 1000;
private Server server_;
private static Server STATIC_SERVER_;
private WebClient webClient_;
private CollectingAlertHandler alertHandler_ = new CollectingAlertHandler();
/**
* Starts the web server on the default {@link #PORT}.
* The given resourceBase is used to be the ROOT directory that serves the default context.
* <p><b>Don't forget to stop the returned HttpServer after the test</b>
*
* @param resourceBase the base of resources for the default context
* @throws Exception if the test fails
*/
protected void startWebServer(final String resourceBase) throws Exception {
if (server_ != null) {
throw new IllegalStateException("startWebServer() can not be called twice");
}
server_ = JettyServerUtils.startWebServer(PORT, resourceBase, null, null, isBasicAuthentication(), getSSLVariant());
}
/**
* Starts the web server on the default {@link #PORT}.
* The given resourceBase is used to be the ROOT directory that serves the default context.
* <p><b>Don't forget to stop the returned HttpServer after the test</b>
*
* @param resourceBase the base of resources for the default context
* @param servlets map of {String, Class} pairs: String is the path spec, while class is the class
* @throws Exception if the test fails
*/
protected void startWebServer(final String resourceBase,
final Map<String, Class<? extends Servlet>> servlets) throws Exception {
if (server_ != null) {
throw new IllegalStateException("startWebServer() can not be called twice");
}
server_ = JettyServerUtils.startWebServer(PORT, resourceBase, servlets, null, false, SSLVariant.NONE);
}
/**
* Performs post-test deconstruction.
* @throws Exception if an error occurs
*/
@AfterEach
public void tearDown() throws Exception {
JettyServerUtils.stopServer(server_);
server_ = null;
stopWebServer();
}
/**
* Defines the provided string as response for the provided URL and loads it using the currently
* configured browser version. Finally it extracts the captured alerts and verifies them.
* @param html the HTML to use
* @param url the URL to use to load the page
* @return the page
* @throws Exception if something goes wrong
*/
protected final HtmlPage loadPageWithAlerts(final String html, final URL url)
throws Exception {
return loadPageWithAlerts(html, url, Duration.ofSeconds(0));
}
/**
* Same as {@link #loadPageWithAlerts(String, URL)}, but configuring the max wait time.
* @param html the HTML to use
* @param url the URL to use to load the page
* @param maxWaitTime to wait to get the alerts (in ms)
* @return the page
* @throws Exception if something goes wrong
*/
protected final HtmlPage loadPageWithAlerts(final String html, final URL url, final Duration maxWaitTime)
throws Exception {
alertHandler_.clear();
expandExpectedAlertsVariables(URL_FIRST);
final String[] expectedAlerts = getExpectedAlerts();
final HtmlPage page = loadPage(html, url);
List<String> actualAlerts = getCollectedAlerts(page);
final long maxWait = System.currentTimeMillis() + maxWaitTime.toMillis();
while (actualAlerts.size() < expectedAlerts.length && System.currentTimeMillis() < maxWait) {
Thread.sleep(30);
actualAlerts = getCollectedAlerts(page);
}
assertEquals(expectedAlerts, getCollectedAlerts(page));
return page;
}
/**
* Defines the provided string as response for the default URL and loads it using the currently
* configured browser version.
* @param html the HTML to use
* @return the page
* @throws Exception if something goes wrong
*/
protected final HtmlPage loadPage(final String html) throws Exception {
return loadPage(html, URL_FIRST);
}
/**
* Same as {@link #loadPage(String)}... but defining the default URL.
* @param html the HTML to use
* @param url the url to use to load the page
* @return the page
* @throws Exception if something goes wrong
*/
protected final HtmlPage loadPage(final String html, final URL url) throws Exception {
return loadPage(html, url, MimeType.TEXT_HTML, ISO_8859_1);
}
/**
* Same as {@link #loadPage(String, URL)}... but defining content type and charset as well.
* @param html the HTML to use
* @param url the url to use to load the page
* @param contentType the content type to return
* @param charset the charset
* @return the page
* @throws Exception if something goes wrong
*/
private HtmlPage loadPage(final String html, final URL url,
final String contentType, final Charset charset) throws Exception {
final MockWebConnection mockWebConnection = getMockWebConnection();
mockWebConnection.setResponse(url, html, contentType, charset);
startWebServer(mockWebConnection);
return getWebClient().getPage(url);
}
/**
* Starts the web server delivering response from the provided connection.
* @param mockConnection the sources for responses
* @throws Exception if a problem occurs
*/
protected void startWebServer(final MockWebConnection mockConnection) throws Exception {
if (STATIC_SERVER_ == null) {
final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
servlets.put("/*", MockWebConnectionServlet.class);
STATIC_SERVER_ = JettyServerUtils.startWebServer(PORT, "./", servlets, null, isBasicAuthentication(), getSSLVariant());
}
MockWebConnectionServlet.setMockconnection(mockConnection);
}
/**
* Stops the WebServer.
* @throws Exception if it fails
*/
protected static void stopWebServer() throws Exception {
JettyServerUtils.stopServer(STATIC_SERVER_);
STATIC_SERVER_ = null;
}
/**
* Loads the provided URL serving responses from {@link #getMockWebConnection()}
* and verifies that the captured alerts are correct.
* @param url the URL to use to load the page
* @return the web driver
* @throws Exception if something goes wrong
*/
protected final HtmlPage loadPageWithAlerts(final URL url) throws Exception {
alertHandler_.clear();
expandExpectedAlertsVariables(url);
final String[] expectedAlerts = getExpectedAlerts();
startWebServer(getMockWebConnection());
final HtmlPage page = getWebClient().getPage(url);
assertEquals(expectedAlerts, getCollectedAlerts(page));
return page;
}
/**
* Returns the collected alerts.
* @param page the page
* @return the alerts
*/
protected List<String> getCollectedAlerts(final HtmlPage page) {
return alertHandler_.getCollectedAlerts();
}
/**
* Returns whether to use basic authentication for all resources or not.
* The default implementation returns false.
* @return whether to use basic authentication or not
*/
protected boolean isBasicAuthentication() {
return false;
}
/**
* @return the {@link SSLVariant} to be used
*/
public SSLVariant getSSLVariant() {
return SSLVariant.NONE;
}
/**
* Returns the WebClient instance for the current test with the current {@link BrowserVersion}.
* @return a WebClient with the current {@link BrowserVersion}
*/
protected WebClient getWebClient() {
if (webClient_ == null) {
webClient_ = new WebClient(getBrowserVersion());
webClient_.setAlertHandler(alertHandler_);
}
return webClient_;
}
/**
* Cleanup after a test.
*/
@Override
@AfterEach
public void releaseResources() {
super.releaseResources();
if (webClient_ != null) {
webClient_.close();
webClient_.getCookieManager().clearCookies();
}
webClient_ = null;
alertHandler_ = null;
}
}