source: josm/trunk/test/functional/org/openstreetmap/josm/tools/HttpClientTest.java@ 16633

Last change on this file since 16633 was 16633, checked in by simon04, 4 years ago

see #16567 - Fix deprecations related to JUnit 5 (in HttpClientTest)

  • Property svn:eol-style set to native
File size: 18.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import static org.hamcrest.CoreMatchers.containsString;
5import static org.hamcrest.CoreMatchers.is;
6import static org.hamcrest.CoreMatchers.nullValue;
7import static org.hamcrest.MatcherAssert.assertThat;
8import static org.junit.Assert.assertEquals;
9import static org.junit.Assert.assertTrue;
10
11import java.io.BufferedReader;
12import java.io.IOException;
13import java.io.InputStream;
14import java.net.URL;
15import java.nio.charset.StandardCharsets;
16import java.util.Collections;
17import java.util.logging.Handler;
18import java.util.logging.LogRecord;
19import java.util.regex.Matcher;
20
21import javax.json.JsonObject;
22import javax.json.JsonReader;
23import javax.json.spi.JsonProvider;
24
25import org.junit.Assert;
26import org.junit.Before;
27import org.junit.Rule;
28import org.junit.Test;
29import org.openstreetmap.josm.TestUtils;
30import org.openstreetmap.josm.data.Version;
31import org.openstreetmap.josm.gui.progress.ProgressMonitor;
32import org.openstreetmap.josm.testutils.JOSMTestRules;
33
34import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
35
36/**
37 * Tests the {@link HttpClient} using the webservice <a href="https://httpbin.org/">https://httpbin.org/</a>.
38 */
39public class HttpClientTest {
40
41 /**
42 * Setup test
43 */
44 @Rule
45 @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
46 public JOSMTestRules test = new JOSMTestRules().preferences().timeout(15000);
47
48 private ProgressMonitor progress;
49
50 private LogRecord captured;
51 private final Handler handler = new Handler() {
52
53 @Override
54 public void publish(LogRecord record) {
55 captured = record;
56 }
57
58 @Override
59 public void flush() {
60 }
61
62 @Override
63 public void close() throws SecurityException {
64 }
65 };
66
67 /**
68 * Setup test.
69 */
70 @Before
71 public void setUp() {
72 progress = TestUtils.newTestProgressMonitor();
73 captured = null;
74 Logging.getLogger().addHandler(handler);
75 Logging.getLogger().setLevel(Logging.LEVEL_DEBUG);
76 }
77
78 /**
79 * Test constructor, getters and setters
80 * @throws IOException if an I/O error occurs
81 */
82 @Test
83 public void testConstructorGetterSetter() throws IOException {
84 final HttpClient client = HttpClient.create(new URL("https://httpbin.org/"));
85 assertThat(client.getURL(), is(new URL("https://httpbin.org/")));
86 assertThat(client.getRequestMethod(), is("GET"));
87 assertThat(client.getRequestHeader("Accept"), is("*/*"));
88 client.setAccept("text/html");
89 assertThat(client.getRequestHeader("Accept"), is("text/html"));
90 assertThat(client.getRequestHeader("ACCEPT"), is("text/html"));
91 client.setHeaders(Collections.singletonMap("foo", "bar"));
92 assertThat(client.getRequestHeader("foo"), is("bar"));
93 client.setHeaders(Collections.singletonMap("foo", "baz"));
94 assertThat(client.getRequestHeader("foo"), is("baz"));
95 client.setHeaders(Collections.singletonMap("foo", (String) null));
96 assertThat(client.getRequestHeader("foo"), nullValue());
97 }
98
99 /**
100 * Test HTTP GET
101 * @throws IOException if an I/O error occurs
102 */
103 @Test
104 public void testGet() throws IOException {
105 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/get?foo=bar")).connect(progress);
106 assertThat(response.getRequestMethod(), is("GET"));
107 assertThat(response.getResponseCode(), is(200));
108 assertThat(response.getResponseMessage(), is("OK"));
109 assertThat(response.getContentType(), is("application/json"));
110 assertThat(response.getHeaderField("Content-Type"), is("application/json"));
111 assertThat(response.getHeaderField("Content-TYPE"), is("application/json"));
112 assertThat(response.getHeaderFields().get("Content-Type"), is(Collections.singletonList("application/json")));
113 assertThat(response.getHeaderFields().get("Content-TYPE"), is(Collections.singletonList("application/json")));
114 try (InputStream in = response.getContent();
115 JsonReader json = JsonProvider.provider().createReader(in)) {
116 final JsonObject root = json.readObject();
117 assertThat(root.getJsonObject("args").getString("foo"), is("bar"));
118 assertThat(root.getString("url"), is("https://httpbin.org/get?foo=bar"));
119 assertThat(root.getJsonObject("headers").get("Cache-Control"), nullValue());
120 assertThat(root.getJsonObject("headers").get("Pragma"), nullValue());
121 }
122 }
123
124 /**
125 * Test JOSM User-Agent
126 * @throws IOException if an I/O error occurs
127 */
128 @Test
129 public void testHeaders() throws IOException {
130 try (InputStream in = HttpClient.create(new URL("https://httpbin.org/headers")).connect(progress).getContent();
131 JsonReader json = JsonProvider.provider().createReader(in)) {
132 final JsonObject headers = json.readObject().getJsonObject("headers");
133 assertThat(headers.getString("Accept"), is("*/*"));
134 assertThat(headers.getString("Accept-Encoding"), is("gzip, deflate"));
135 assertThat(headers.getString("User-Agent"), is(Version.getInstance().getFullAgentString()));
136 }
137 }
138
139 /**
140 * Test JOSM User-Agent
141 * @throws IOException if an I/O error occurs
142 */
143 @Test
144 public void testUserAgent() throws IOException {
145 try (InputStream in = HttpClient.create(new URL("https://httpbin.org/user-agent")).connect(progress).getContent();
146 JsonReader json = JsonProvider.provider().createReader(in)) {
147 assertThat(json.readObject().getString("user-agent"), is(Version.getInstance().getFullAgentString()));
148 }
149 }
150
151 /**
152 * Test UTF-8 encoded content
153 * @throws IOException if an I/O error occurs
154 */
155 @Test
156 public void testFetchUtf8Content() throws IOException {
157 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/encoding/utf8")).connect(progress);
158 assertThat(response.getResponseCode(), is(200));
159 final String content = response.fetchContent();
160 assertThat(content, containsString("UTF-8 encoded sample plain-text file"));
161 assertThat(content, containsString("\u2200x\u2208\u211d:"));
162 }
163
164 /**
165 * Test HTTP POST
166 * @throws IOException if an I/O error occurs
167 */
168 @Test
169 public void testPost() throws IOException {
170 final String text = "Hello World!\nGeetings from JOSM, the Java OpenStreetMap Editor";
171 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/post"), "POST")
172 .setHeader("Content-Type", "text/plain")
173 .setRequestBody(text.getBytes(StandardCharsets.UTF_8))
174 .setFinishOnCloseOutput(false) // to fix #12583, not sure if it's the best way to do it
175 .connect(progress);
176 assertThat(response.getResponseCode(), is(200));
177 try (InputStream in = response.getContent();
178 JsonReader json = JsonProvider.provider().createReader(in)) {
179 assertThat(json.readObject().getString("data"), is(text));
180 }
181 }
182
183 @Test
184 public void testPostZero() throws IOException {
185 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/post"), "POST")
186 .setHeader("Content-Type", "text/plain")
187 .setRequestBody("".getBytes(StandardCharsets.UTF_8))
188 .setFinishOnCloseOutput(false) // to fix #12583, not sure if it's the best way to do it
189 .connect(progress);
190 assertThat(response.getResponseCode(), is(200));
191 try (InputStream in = response.getContent();
192 JsonReader json = JsonProvider.provider().createReader(in)) {
193 assertThat(json.readObject().getString("data"), is(""));
194 }
195 }
196
197 @Test
198 public void testRelativeRedirects() throws IOException {
199 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/relative-redirect/3")).connect(progress);
200 assertThat(response.getResponseCode(), is(200));
201 assertThat(response.getContentLength() > 100, is(true));
202 }
203
204 @Test
205 public void testAbsoluteRedirects() throws IOException {
206 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/absolute-redirect/3")).connect(progress);
207 assertThat(response.getResponseCode(), is(200));
208 assertThat(response.getContentLength() > 100, is(true));
209 }
210
211 /**
212 * Test maximum number of redirections.
213 * @throws IOException if an I/O error occurs
214 */
215 @Test(expected = IOException.class)
216 public void testTooMuchRedirects() throws IOException {
217 HttpClient.create(new URL("https://httpbin.org/redirect/3")).setMaxRedirects(2).connect(progress);
218 }
219
220 /**
221 * Test HTTP error 418
222 * @throws IOException if an I/O error occurs
223 */
224 @Test
225 public void testHttp418() throws IOException {
226 // https://tools.ietf.org/html/rfc2324
227 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/status/418")).connect(progress);
228 assertThat(response.getResponseCode(), is(418));
229 assertThat(response.getResponseMessage(), is("I'M A TEAPOT"));
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));
234 }
235
236 /**
237 * Test HTTP error 401
238 * @throws IOException if an I/O error occurs
239 */
240 @Test
241 public void testHttp401() throws IOException {
242 // 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(), is("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));
250 }
251
252 /**
253 * Test HTTP error 402
254 * @throws IOException if an I/O error occurs
255 */
256 @Test
257 public void testHttp402() throws IOException {
258 // 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(), is("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));
266 }
267
268 /**
269 * Test HTTP error 403
270 * @throws IOException if an I/O error occurs
271 */
272 @Test
273 public void testHttp403() throws IOException {
274 // 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(), is("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));
282 }
283
284 /**
285 * Test HTTP error 404
286 * @throws IOException if an I/O error occurs
287 */
288 @Test
289 public void testHttp404() throws IOException {
290 // 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(), is("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));
298 }
299
300 /**
301 * Test HTTP error 500
302 * @throws IOException if an I/O error occurs
303 */
304 @Test
305 public void testHttp500() throws IOException {
306 // 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(), is("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));
314 }
315
316 /**
317 * Checks that a slow request is well handled if it completes before the timeout.
318 * @throws IOException if any I/O error occurs
319 */
320 @Test
321 public void testRequestInTime() throws IOException {
322 final HttpClient.Response response = HttpClient.create(new URL("https://httpbin.org/delay/1")).setReadTimeout(2000).connect(progress);
323 assertThat(response.getResponseCode(), is(200));
324 }
325
326 /**
327 * Checks that a slow request results in the expected exception if it exceeds the timeout.
328 * @throws IOException always
329 */
330 @Test(expected = IOException.class)
331 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 }
347 }
348
349 /**
350 * Test reading Gzip-encoded data.
351 * @throws IOException if any I/O error occurs
352 */
353 @Test
354 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.
365 * @throws IOException if any I/O error occurs
366 */
367 @Test
368 public void testOpenUrlGzip() throws IOException {
369 final URL url = new URL("https://www.openstreetmap.org/trace/1613906/data");
370 try (BufferedReader x = HttpClient.create(url).connect().uncompress(true).getContentReader()) {
371 Assert.assertTrue(x.readLine().startsWith("<?xml version="));
372 }
373 }
374
375 /**
376 * Test of {@link HttpClient.Response#uncompress} method with Bzip compression.
377 * @throws IOException if any I/O error occurs
378 */
379 @Test
380 public void testOpenUrlBzip() throws IOException {
381 final URL url = new URL("https://www.openstreetmap.org/trace/785544/data");
382 try (BufferedReader x = HttpClient.create(url).connect().uncompress(true).getContentReader()) {
383 Assert.assertTrue(x.readLine().startsWith("<?xml version="));
384 }
385 }
386
387 /**
388 * Test of {@link HttpClient.Response#uncompress} method with Bzip compression.
389 * @throws IOException if any I/O error occurs
390 */
391 @Test
392 public void testTicket9660() throws IOException {
393 final URL url = new URL("http://www.openstreetmap.org/trace/1350010/data");
394 try (BufferedReader x = HttpClient.create(url).connect()
395 .uncompress(true).uncompressAccordingToContentDisposition(true).getContentReader()) {
396 Assert.assertTrue(x.readLine().startsWith("<?xml version="));
397 }
398 }
399
400 /**
401 * Test that error message sent by Tomcat can be parsed.
402 */
403 @Test
404 public void testTomcatErrorMessage() {
405 Matcher m = HttpClient.getTomcatErrorMatcher(
406 "<html><head><title>Apache Tomcat/DGFiP - Rapport d''erreur</title><style><!--"+
407 "H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} "+
408 "H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} "+
409 "H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} "+
410 "BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} "+
411 "B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} "+
412 "P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}"+
413 "A {color : black;}A.name {color : black;}HR {color : #525D76;}"+
414 "--></style> </head><body><h1>Etat HTTP 400 - La commune demandée n'existe pas ou n'est pas accessible.</h1>"+
415 "<HR size=\"1\" noshade=\"noshade\">"+
416 "<p><b>type</b> Rapport d''état</p><p><b>message</b> <u>La commune demandée n'existe pas ou n'est pas accessible.</u></p>"+
417 "<p><b>description</b> <u>La requête envoyée par le client était syntaxiquement incorrecte.</u></p>"+
418 "<HR size=\"1\" noshade=\"noshade\"><h3>Apache Tomcat/DGFiP</h3></body></html>");
419 assertTrue(m.matches());
420 assertEquals("La commune demandée n'existe pas ou n'est pas accessible.", m.group(1));
421 }
422}
Note: See TracBrowser for help on using the repository browser.