Changeset 17154 in josm for trunk/test/functional
- Timestamp:
- 2020-10-11T00:39:35+02:00 (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/test/functional/org/openstreetmap/josm/tools/HttpClientTest.java
r17152 r17154 2 2 package org.openstreetmap.josm.tools; 3 3 4 import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; 5 import static com.github.tomakehurst.wiremock.client.WireMock.binaryEqualTo; 6 import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; 7 import static com.github.tomakehurst.wiremock.client.WireMock.get; 8 import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; 9 import static com.github.tomakehurst.wiremock.client.WireMock.post; 10 import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; 11 import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; 4 12 import static org.hamcrest.CoreMatchers.containsString; 5 13 import static org.hamcrest.CoreMatchers.is; … … 12 20 import java.io.BufferedReader; 13 21 import java.io.IOException; 14 import java. io.InputStream;22 import java.net.MalformedURLException; 15 23 import java.net.URL; 16 24 import java.nio.charset.StandardCharsets; 17 25 import java.util.Collections; 26 import java.util.Map; 18 27 import java.util.logging.Handler; 19 28 import java.util.logging.LogRecord; 20 29 import java.util.regex.Matcher; 21 22 import javax.json.JsonObject; 23 import javax.json.JsonReader; 24 import javax.json.spi.JsonProvider; 30 import java.util.stream.Collectors; 25 31 26 32 import org.junit.Assert; … … 32 38 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 33 39 import org.openstreetmap.josm.testutils.JOSMTestRules; 40 import org.openstreetmap.josm.tools.HttpClient.Response; 41 42 import com.github.tomakehurst.wiremock.core.WireMockConfiguration; 43 import com.github.tomakehurst.wiremock.http.HttpHeader; 44 import com.github.tomakehurst.wiremock.http.HttpHeaders; 45 import com.github.tomakehurst.wiremock.junit.WireMockRule; 46 import com.github.tomakehurst.wiremock.matching.UrlPattern; 34 47 35 48 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 36 49 37 50 /** 38 * Tests the {@link HttpClient} using the webservice <a href="https://httpbin.org/">https://httpbin.org/</a>.51 * Tests the {@link HttpClient}. 39 52 */ 40 53 public class HttpClientTest { … … 47 60 public JOSMTestRules test = new JOSMTestRules().preferences().timeout(15000); 48 61 62 /** 63 * mocked local http server 64 */ 65 @Rule 66 public WireMockRule localServer = new WireMockRule(WireMockConfiguration.options().dynamicPort()); 67 49 68 private ProgressMonitor progress; 50 69 … … 71 90 @Before 72 91 public void setUp() { 92 localServer.resetAll(); 73 93 progress = TestUtils.newTestProgressMonitor(); 74 94 captured = null; … … 83 103 @Test 84 104 public void testConstructorGetterSetter() throws IOException { 85 final HttpClient client = HttpClient.create(new URL("https://httpbin.org/")); 86 assertThat(client.getURL(), is(new URL("https://httpbin.org/"))); 105 final URL localUrl = url(""); 106 final HttpClient client = HttpClient.create(localUrl); 107 assertThat(client.getURL(), is(localUrl)); 87 108 assertThat(client.getRequestMethod(), is("GET")); 88 109 assertThat(client.getRequestHeader("Accept"), is("*/*")); … … 104 125 @Test 105 126 public void testGet() throws IOException { 106 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/get?foo=bar")).connect(progress); 127 final UrlPattern pattern = urlEqualTo("/get?foo=bar"); 128 localServer.stubFor(get(pattern).willReturn(aResponse().withStatusMessage("OK") 129 .withHeader("Content-Type", "application/json; encoding=utf-8"))); 130 final Response response = connect("/get?foo=bar"); 107 131 assertThat(response.getRequestMethod(), is("GET")); 108 132 assertThat(response.getResponseCode(), is(200)); 109 133 assertThat(response.getResponseMessage(), equalToIgnoringCase("OK")); 110 assertThat(response.getContentType(), is("application/json")); 111 assertThat(response.getHeaderField("Content-Type"), is("application/json")); 112 assertThat(response.getHeaderField("Content-TYPE"), is("application/json")); 113 assertThat(response.getHeaderFields().get("Content-Type"), is(Collections.singletonList("application/json"))); 114 assertThat(response.getHeaderFields().get("Content-TYPE"), is(Collections.singletonList("application/json"))); 115 try (InputStream in = response.getContent(); 116 JsonReader json = JsonProvider.provider().createReader(in)) { 117 final JsonObject root = json.readObject(); 118 assertThat(root.getJsonObject("args").getString("foo"), is("bar")); 119 assertThat(root.getString("url"), is("https://httpbin.org/get?foo=bar")); 120 assertThat(root.getJsonObject("headers").get("Cache-Control"), nullValue()); 121 assertThat(root.getJsonObject("headers").get("Pragma"), nullValue()); 122 } 123 } 124 125 /** 126 * Test JOSM User-Agent 134 assertThat(response.getContentType(), is("application/json; encoding=utf-8")); 135 assertThat(response.getHeaderField("Content-Type"), is("application/json; encoding=utf-8")); 136 assertThat(response.getHeaderField("Content-TYPE"), is("application/json; encoding=utf-8")); 137 assertThat(response.getHeaderFields().get("Content-Type"), is(Collections.singletonList("application/json; encoding=utf-8"))); 138 assertThat(response.getHeaderFields().get("Content-TYPE"), is(Collections.singletonList("application/json; encoding=utf-8"))); 139 localServer.verify(getRequestedFor(pattern) 140 .withQueryParam("foo", equalTo("bar")) 141 .withoutHeader("Cache-Control") 142 .withoutHeader("Pragma")); 143 } 144 145 /** 146 * Test JOSM User-Agent and the incoming request's HTTP headers. 127 147 * @throws IOException if an I/O error occurs 128 148 */ 129 149 @Test 130 150 public void testHeaders() throws IOException { 131 try (InputStream in = HttpClient.create(new URL("https://httpbin.org/headers")).connect(progress).getContent(); 132 JsonReader json = JsonProvider.provider().createReader(in)) { 133 final JsonObject headers = json.readObject().getJsonObject("headers"); 134 assertThat(headers.getString("Accept"), is("*/*")); 135 assertThat(headers.getString("Accept-Encoding"), is("gzip, deflate")); 136 assertThat(headers.getString("User-Agent"), is(Version.getInstance().getFullAgentString())); 137 } 138 } 139 140 /** 141 * Test JOSM User-Agent 142 * @throws IOException if an I/O error occurs 143 */ 144 @Test 145 public void testUserAgent() throws IOException { 146 try (InputStream in = HttpClient.create(new URL("https://httpbin.org/user-agent")).connect(progress).getContent(); 147 JsonReader json = JsonProvider.provider().createReader(in)) { 148 assertThat(json.readObject().getString("user-agent"), is(Version.getInstance().getFullAgentString())); 149 } 151 final UrlPattern pattern = urlEqualTo("/headers"); 152 localServer.stubFor(get(pattern).willReturn(aResponse())); 153 connect("/headers"); 154 localServer.verify(getRequestedFor(pattern) 155 .withHeader("Accept", equalTo("*/*")) 156 .withHeader("Accept-Encoding", equalTo("gzip, deflate")) 157 .withHeader("User-Agent", equalTo(Version.getInstance().getFullAgentString()))); 150 158 } 151 159 … … 156 164 @Test 157 165 public void testFetchUtf8Content() throws IOException { 158 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/encoding/utf8")).connect(progress); 166 localServer.stubFor(get(urlEqualTo("/encoding/utf8")) 167 .willReturn(aResponse().withBody("∀x∈ℝ: UTF-8 encoded sample plain-text file"))); 168 final Response response = connect("/encoding/utf8"); 159 169 assertThat(response.getResponseCode(), is(200)); 160 170 final String content = response.fetchContent(); … … 164 174 165 175 /** 166 * Test HTTP POST 176 * Test HTTP POST with non-empty body 167 177 * @throws IOException if an I/O error occurs 168 178 */ 169 179 @Test 170 180 public void testPost() throws IOException { 181 final UrlPattern pattern = urlEqualTo("/post"); 182 localServer.stubFor(post(pattern).willReturn(aResponse())); 171 183 final String text = "Hello World!\nGeetings from JOSM, the Java OpenStreetMap Editor"; 172 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/post"), "POST")184 final Response response = HttpClient.create(url("/post"), "POST") 173 185 .setHeader("Content-Type", "text/plain") 174 186 .setRequestBody(text.getBytes(StandardCharsets.UTF_8)) … … 176 188 .connect(progress); 177 189 assertThat(response.getResponseCode(), is(200)); 178 try (InputStream in = response.getContent(); 179 JsonReader json = JsonProvider.provider().createReader(in)) { 180 assertThat(json.readObject().getString("data"), is(text)); 181 } 182 } 183 190 assertThat(response.getRequestMethod(), is("POST")); 191 localServer.verify(postRequestedFor(pattern).withRequestBody(equalTo(text))); 192 } 193 194 /** 195 * Test HTTP POST with empty body 196 * @throws IOException if an I/O error occurs 197 */ 184 198 @Test 185 199 public void testPostZero() throws IOException { 186 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/post"), "POST") 200 final UrlPattern pattern = urlEqualTo("/post"); 201 localServer.stubFor(post(pattern).willReturn(aResponse())); 202 final byte[] bytes = "".getBytes(StandardCharsets.UTF_8); 203 final Response response = HttpClient.create(url("/post"), "POST") 187 204 .setHeader("Content-Type", "text/plain") 188 .setRequestBody( "".getBytes(StandardCharsets.UTF_8))205 .setRequestBody(bytes) 189 206 .setFinishOnCloseOutput(false) // to fix #12583, not sure if it's the best way to do it 190 207 .connect(progress); 191 208 assertThat(response.getResponseCode(), is(200)); 192 try (InputStream in = response.getContent(); 193 JsonReader json = JsonProvider.provider().createReader(in)) { 194 assertThat(json.readObject().getString("data"), is("")); 195 } 196 } 197 198 /*@Test 209 assertThat(response.getRequestMethod(), is("POST")); 210 localServer.verify(postRequestedFor(pattern).withRequestBody(binaryEqualTo(bytes))); 211 } 212 213 @Test 199 214 public void testRelativeRedirects() throws IOException { 200 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/relative-redirect/3")).connect(progress); 201 assertThat(response.getResponseCode(), is(200)); 202 assertThat(response.getContentLength() > 100, is(true)); 203 }*/ 204 205 /*@Test 215 mockRedirects(false, 3); 216 final Response response = connect("/relative-redirect/3"); 217 assertThat(response.getResponseCode(), is(200)); 218 assertThat(response.getHeaderField("foo"), is("bar")); 219 } 220 221 @Test 206 222 public void testAbsoluteRedirects() throws IOException { 207 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/absolute-redirect/3")).connect(progress); 208 assertThat(response.getResponseCode(), is(200)); 209 assertThat(response.getContentLength() > 100, is(true)); 210 }*/ 223 mockRedirects(true, 3); 224 final Response response = connect("/absolute-redirect/3"); 225 assertThat(response.getResponseCode(), is(200)); 226 assertThat(response.getHeaderField("foo"), is("bar")); 227 } 211 228 212 229 /** … … 214 231 * @throws IOException if an I/O error occurs 215 232 */ 216 /*@Test(expected = IOException.class)233 @Test(expected = IOException.class) 217 234 public void testTooMuchRedirects() throws IOException { 218 HttpClient.create(new URL("https://httpbin.org/redirect/3")).setMaxRedirects(2).connect(progress); 219 }*/ 235 mockRedirects(false, 3); 236 HttpClient.create(url("/relative-redirect/3")).setMaxRedirects(2).connect(progress); 237 } 220 238 221 239 /** … … 226 244 public void testHttp418() throws IOException { 227 245 // https://tools.ietf.org/html/rfc2324 228 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/status/418")).connect(progress); 229 assertThat(response.getResponseCode(), is(418)); 230 final String content = response.fetchContent(); 231 assertThat(content, containsString("-=[ teapot ]=-")); 232 assertThat(captured.getMessage(), containsString("-=[ teapot ]=-")); 233 assertThat(captured.getLevel(), is(Logging.LEVEL_DEBUG)); 246 final Response response = doTestHttp(418, "I'm a teapot!", "I'm a teapot!", 247 Collections.singletonMap("X-More-Info", "http://tools.ietf.org/html/rfc2324")); 248 assertThat(response.getHeaderField("X-More-Info"), is("http://tools.ietf.org/html/rfc2324")); 234 249 } 235 250 … … 241 256 public void testHttp401() throws IOException { 242 257 // https://tools.ietf.org/html/rfc2324 243 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/status/401")).connect(progress); 244 assertThat(response.getResponseCode(), is(401)); 245 assertThat(response.getResponseMessage(), equalToIgnoringCase("UNAUTHORIZED")); 246 final String content = response.fetchContent(); 247 assertThat(content, is("")); 248 assertThat(captured.getMessage(), containsString("Server did not return any body")); 249 assertThat(captured.getLevel(), is(Logging.LEVEL_DEBUG)); 258 doTestHttp(401, "UNAUTHORIZED", null); 250 259 } 251 260 … … 257 266 public void testHttp402() throws IOException { 258 267 // https://tools.ietf.org/html/rfc2324 259 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/status/402")).connect(progress); 260 assertThat(response.getResponseCode(), is(402)); 261 assertThat(response.getResponseMessage(), equalToIgnoringCase("PAYMENT REQUIRED")); 262 final String content = response.fetchContent(); 263 assertThat(content, containsString("Fuck you, pay me!")); 264 assertThat(captured.getMessage(), containsString("Fuck you, pay me!")); 265 assertThat(captured.getLevel(), is(Logging.LEVEL_DEBUG)); 268 doTestHttp(402, "PAYMENT REQUIRED", "Fuck you, pay me!"); 266 269 } 267 270 … … 273 276 public void testHttp403() throws IOException { 274 277 // https://tools.ietf.org/html/rfc2324 275 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/status/403")).connect(progress); 276 assertThat(response.getResponseCode(), is(403)); 277 assertThat(response.getResponseMessage(), equalToIgnoringCase("FORBIDDEN")); 278 final String content = response.fetchContent(); 279 assertThat(content, is("")); 280 assertThat(captured.getMessage(), containsString("Server did not return any body")); 281 assertThat(captured.getLevel(), is(Logging.LEVEL_DEBUG)); 278 doTestHttp(403, "FORBIDDEN", null); 282 279 } 283 280 … … 289 286 public void testHttp404() throws IOException { 290 287 // https://tools.ietf.org/html/rfc2324 291 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/status/404")).connect(progress); 292 assertThat(response.getResponseCode(), is(404)); 293 assertThat(response.getResponseMessage(), equalToIgnoringCase("NOT FOUND")); 294 final String content = response.fetchContent(); 295 assertThat(content, is("")); 296 assertThat(captured.getMessage(), containsString("Server did not return any body")); 297 assertThat(captured.getLevel(), is(Logging.LEVEL_DEBUG)); 288 doTestHttp(404, "NOT FOUND", null); 298 289 } 299 290 … … 305 296 public void testHttp500() throws IOException { 306 297 // https://tools.ietf.org/html/rfc2324 307 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/status/500")).connect(progress); 308 assertThat(response.getResponseCode(), is(500)); 309 assertThat(response.getResponseMessage(), equalToIgnoringCase("INTERNAL SERVER ERROR")); 310 final String content = response.fetchContent(); 311 assertThat(content, containsString("")); 312 assertThat(captured.getMessage(), containsString("Server did not return any body")); 313 assertThat(captured.getLevel(), is(Logging.LEVEL_DEBUG)); 298 doTestHttp(500, "INTERNAL SERVER ERROR", null); 314 299 } 315 300 … … 320 305 @Test 321 306 public void testRequestInTime() throws IOException { 322 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/delay/1")).setReadTimeout(2000).connect(progress); 307 mockDelay(1); 308 final Response response = HttpClient.create(url("/delay/1")).setReadTimeout(2000).connect(progress); 323 309 assertThat(response.getResponseCode(), is(200)); 324 310 } … … 330 316 @Test(expected = IOException.class) 331 317 public void testTakesTooLong() throws IOException { 332 HttpClient.create(new URL("https://httpbin.org/delay/1")).setReadTimeout(500).connect(progress); 333 } 334 335 /** 336 * Test reading Deflate-encoded data. 337 * @throws IOException if any I/O error occurs 338 */ 339 @Test 340 public void testDeflate() throws IOException { 341 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/deflate")).connect(progress); 342 assertThat(response.getResponseCode(), is(200)); 343 try (InputStream in = response.getContent(); 344 JsonReader json = JsonProvider.provider().createReader(in)) { 345 assertThat(json.readObject().getBoolean("deflated"), is(true)); 346 } 318 mockDelay(1); 319 HttpClient.create(url("/delay/1")).setReadTimeout(500).connect(progress); 347 320 } 348 321 … … 353 326 @Test 354 327 public void testGzip() throws IOException { 355 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/gzip")).connect(progress); 356 assertThat(response.getResponseCode(), is(200)); 357 try (InputStream in = response.getContent(); 358 JsonReader json = JsonProvider.provider().createReader(in)) { 359 assertThat(json.readObject().getBoolean("gzipped"), is(true)); 360 } 361 } 362 363 /** 364 * Test of {@link HttpClient.Response#uncompress} method with Gzip compression. 328 localServer.stubFor(get(urlEqualTo("/gzip")).willReturn(aResponse().withBody("foo"))); 329 final Response response = connect("/gzip"); 330 assertThat(response.getResponseCode(), is(200)); 331 assertThat(response.getContentEncoding(), is("gzip")); 332 assertThat(response.fetchContent(), is("foo")); 333 } 334 335 /** 336 * Test of {@link Response#uncompress} method with Gzip compression. 365 337 * @throws IOException if any I/O error occurs 366 338 */ … … 374 346 375 347 /** 376 * Test of {@link HttpClient.Response#uncompress} method with Bzip compression.348 * Test of {@link Response#uncompress} method with Bzip compression. 377 349 * @throws IOException if any I/O error occurs 378 350 */ … … 386 358 387 359 /** 388 * Test of {@link HttpClient.Response#uncompress} method with Bzip compression.360 * Test of {@link Response#uncompress} method with Bzip compression. 389 361 * @throws IOException if any I/O error occurs 390 362 */ … … 420 392 assertEquals("La commune demandée n'existe pas ou n'est pas accessible.", m.group(1)); 421 393 } 394 395 private void mockDelay(int seconds) { 396 localServer.stubFor(get(urlEqualTo("/delay/" + seconds)) 397 .willReturn(aResponse().withFixedDelay(1000 * seconds))); 398 } 399 400 private void mockRedirects(boolean absolute, int n) { 401 final String prefix = absolute ? "absolute" : "relative"; 402 for (int i = n; i > 0; i--) { 403 final String location = "/" + prefix + "-redirect/" + (i-1); 404 localServer.stubFor(get(urlEqualTo("/" + prefix + "-redirect/" + i)) 405 .willReturn(aResponse().withStatus(302).withHeader( 406 "Location", absolute ? localServer.url(location) : location))); 407 } 408 localServer.stubFor(get(urlEqualTo("/" + prefix + "-redirect/0")) 409 .willReturn(aResponse().withHeader("foo", "bar"))); 410 } 411 412 private Response doTestHttp(int responseCode, String message, String body) throws IOException { 413 return doTestHttp(responseCode, message, body, Collections.emptyMap()); 414 } 415 416 private Response doTestHttp(int responseCode, String message, String body, Map<String, String> headersMap) throws IOException { 417 localServer.stubFor(get(urlEqualTo("/status/" + responseCode)) 418 .willReturn(aResponse().withStatus(responseCode).withStatusMessage(message).withBody(body).withHeaders( 419 new HttpHeaders(headersMap.entrySet().stream().map( 420 e -> new HttpHeader(e.getKey(), e.getValue())).collect(Collectors.toList()))))); 421 Response response = connect("/status/" + responseCode); 422 assertThat(response.getResponseCode(), is(responseCode)); 423 assertThat(response.getResponseMessage(), equalToIgnoringCase(message)); 424 final String content = response.fetchContent(); 425 assertThat(content, is(body == null ? "" : body)); 426 assertThat(captured.getMessage(), containsString(body == null ? "Server did not return any body" : body)); 427 assertThat(captured.getLevel(), is(Logging.LEVEL_DEBUG)); 428 return response; 429 } 430 431 private Response connect(String path) throws IOException { 432 return HttpClient.create(url(path)).connect(progress); 433 } 434 435 private URL url(String path) throws MalformedURLException { 436 return new URL(localServer.url(path)); 437 } 422 438 }
Note:
See TracChangeset
for help on using the changeset viewer.