Project

General

Profile

Download (13.9 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* From spring-security-oauth
3
*
4
* Apache License
5
* Version 2.0, January 2004
6
*/
7
package eu.etaxonomy.cdm.remote.server;
8

    
9

    
10
import java.io.IOException;
11
import java.io.UnsupportedEncodingException;
12
import java.net.HttpURLConnection;
13
import java.net.URI;
14
import java.net.URISyntaxException;
15
import java.net.URLDecoder;
16
import java.util.Arrays;
17
import java.util.HashMap;
18
import java.util.Map;
19

    
20
import org.apache.commons.logging.Log;
21
import org.apache.commons.logging.LogFactory;
22
import org.junit.Assume;
23
import org.junit.internal.AssumptionViolatedException;
24
import org.junit.rules.MethodRule;
25
import org.junit.runners.model.FrameworkMethod;
26
import org.junit.runners.model.Statement;
27
import org.springframework.http.HttpEntity;
28
import org.springframework.http.HttpHeaders;
29
import org.springframework.http.HttpMethod;
30
import org.springframework.http.HttpStatus;
31
import org.springframework.http.MediaType;
32
import org.springframework.http.ResponseEntity;
33
import org.springframework.http.client.ClientHttpRequest;
34
import org.springframework.http.client.ClientHttpResponse;
35
import org.springframework.http.client.SimpleClientHttpRequestFactory;
36
import org.springframework.util.FileCopyUtils;
37
import org.springframework.util.LinkedMultiValueMap;
38
import org.springframework.util.MultiValueMap;
39
import org.springframework.web.client.RequestCallback;
40
import org.springframework.web.client.ResponseErrorHandler;
41
import org.springframework.web.client.ResponseExtractor;
42
import org.springframework.web.client.RestClientException;
43
import org.springframework.web.client.RestTemplate;
44
import org.springframework.web.util.UriTemplate;
45
import org.springframework.web.util.UriUtils;
46

    
47
/**
48
 * <p>
49
 * A rule that prevents integration tests from failing if the server application is not running or not accessible. If
50
 * the server is not running in the background all the tests here will simply be skipped because of a violated
51
 * assumption (showing as successful). Usage:
52
 * </p>
53
 *
54
 * <pre>
55
 * &#064;Rule public static BrokerRunning brokerIsRunning = BrokerRunning.isRunning();
56
 *
57
 * &#064;Test public void testSendAndReceive() throws Exception { // ... test using RabbitTemplate etc. }
58
 * </pre>
59
 * <p>
60
 * The rule can be declared as static so that it only has to check once for all tests in the enclosing test case, but
61
 * there isn't a lot of overhead in making it non-static.
62
 * </p>
63
 *
64
 * @see Assume
65
 * @see AssumptionViolatedException
66
 *
67
 * @author Dave Syer
68
 *
69
 */
70
public class ServerRunning implements MethodRule {
71

    
72
    /**
73
     *
74
     */
75
    private static final String CONNECT_TEST_PATH = "/classification.json";
76

    
77
    private static Log logger = LogFactory.getLog(ServerRunning.class);
78

    
79
    // Static so that we only test once on failure: speeds up test suite
80
    private static Map<Integer, Boolean> serverOnline = new HashMap<Integer, Boolean>();
81

    
82
    // Static so that we only test once on failure
83
    private static Map<Integer, Boolean> serverOffline = new HashMap<Integer, Boolean>();
84

    
85
    private final boolean assumeOnline;
86

    
87
    private static int DEFAULT_PORT = 8080;
88

    
89
    private static String DEFAULT_HOST = "localhost";
90

    
91
    private int port;
92

    
93
    private String hostName = DEFAULT_HOST;
94

    
95
    private RestTemplate client;
96

    
97
    /**
98
     * @return a new rule that assumes an existing running broker
99
     */
100
    public static ServerRunning isRunning() {
101
        return new ServerRunning(true);
102
    }
103

    
104
    /**
105
     * @return a new rule that assumes there is no existing broker
106
     */
107
    public static ServerRunning isNotRunning() {
108
        return new ServerRunning(false);
109
    }
110

    
111
    private ServerRunning(boolean assumeOnline) {
112
        this.assumeOnline = assumeOnline;
113
        setPort(DEFAULT_PORT);
114
    }
115

    
116
    /**
117
     * @param port the port to set
118
     */
119
    public void setPort(int port) {
120
        this.port = port;
121
        if (!serverOffline.containsKey(port)) {
122
            serverOffline.put(port, true);
123
        }
124
        if (!serverOnline.containsKey(port)) {
125
            serverOnline.put(port, true);
126
        }
127
        client = getRestTemplate();
128
    }
129

    
130
    /**
131
     * @param hostName the hostName to set
132
     */
133
    public void setHostName(String hostName) {
134
        this.hostName = hostName;
135
    }
136

    
137
    @Override
138
    public Statement apply(final Statement base, FrameworkMethod method, Object target) {
139

    
140
        // Check at the beginning, so this can be used as a static field
141
        if (assumeOnline) {
142
            Assume.assumeTrue(serverOnline.get(port));
143
        } else {
144
            Assume.assumeTrue(serverOffline.get(port));
145
        }
146

    
147
        RestTemplate client = new RestTemplate();
148
        boolean followRedirects = HttpURLConnection.getFollowRedirects();
149
        HttpURLConnection.setFollowRedirects(false);
150
        boolean online = false;
151
        try {
152
            client.getForEntity(new UriTemplate(getUrl(CONNECT_TEST_PATH)).toString(), String.class);
153
            online = true;
154
            logger.info("Basic connectivity test passed");
155
        } catch (RestClientException e) {
156
            logger.warn(String.format(
157
                    "Not executing tests because basic connectivity test failed for hostName=%s, port=%d", hostName,
158
                    port), e);
159
            if (assumeOnline) {
160
                Assume.assumeNoException(e);
161
            }
162
        } finally {
163
            HttpURLConnection.setFollowRedirects(followRedirects);
164
            if (online) {
165
                serverOffline.put(port, false);
166
                if (!assumeOnline) {
167
                    Assume.assumeTrue(serverOffline.get(port));
168
                }
169

    
170
            } else {
171
                serverOnline.put(port, false);
172
            }
173
        }
174

    
175
        return new Statement() {
176

    
177
            @Override
178
            public void evaluate() throws Throwable {
179
                try {
180
                    postForStatus("/oauth/uncache_approvals", new LinkedMultiValueMap<String, String>());
181
                    base.evaluate();
182
                } finally {
183
                    postForStatus("/oauth/cache_approvals", new LinkedMultiValueMap<String, String>());
184
                }
185

    
186
            }
187
        };
188

    
189
    }
190

    
191
    public String getBaseUrl() {
192
        return "http://" + hostName + ":" + port;
193
    }
194

    
195
    public String getUrl(String path) {
196
        if (path.startsWith("http:")) {
197
            return path;
198
        }
199
        if (!path.startsWith("/")) {
200
            path = "/" + path;
201
        }
202
        return "http://" + hostName + ":" + port + path;
203
    }
204

    
205
    public ResponseEntity<String> postForString(String path, MultiValueMap<String, String> formData) {
206
        HttpHeaders headers = new HttpHeaders();
207
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_FORM_URLENCODED));
208
        return client.exchange(getUrl(path), HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(formData,
209
                headers), String.class);
210
    }
211

    
212
    public ResponseEntity<Void> postForStatus(String path, MultiValueMap<String, String> formData) {
213
        return postForStatus(path, new HttpHeaders(), formData);
214
    }
215

    
216
    public ResponseEntity<Void> postForStatus(String path, HttpHeaders headers, MultiValueMap<String, String> formData) {
217
        HttpHeaders actualHeaders = new HttpHeaders();
218
        actualHeaders.putAll(headers);
219
        actualHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
220
        return client.exchange(getUrl(path), HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(formData,
221
                actualHeaders), (Class<Void>)null);
222
    }
223

    
224
    public HttpHeaders postForHeaders(String path, MultiValueMap<String, String> formData) {
225
        return postForHeaders(path, formData, null);
226
    }
227

    
228
    public HttpHeaders postForHeaders(String path, MultiValueMap<String, String> formData, final HttpHeaders headers) {
229

    
230
        RequestCallback requestCallback = new NullRequestCallback();
231
        if (headers != null) {
232
            requestCallback = new RequestCallback() {
233
                @Override
234
                public void doWithRequest(ClientHttpRequest request) throws IOException {
235
                    request.getHeaders().putAll(headers);
236
                }
237
            };
238
        }
239

    
240
        StringBuilder builder = new StringBuilder(getUrl(path));
241
        if (!path.contains("?")) {
242
            builder.append("?");
243
        } else {
244
            builder.append("&");
245
        }
246
        for (String key : formData.keySet()) {
247
            for (String value : formData.get(key)) {
248
                builder.append(key + "=" + value);
249
                builder.append("&");
250
            }
251
        }
252
        builder.deleteCharAt(builder.length() - 1);
253
        return client.execute(builder.toString(), HttpMethod.POST, requestCallback,
254
                new ResponseExtractor<HttpHeaders>() {
255
                    @Override
256
                    public HttpHeaders extractData(ClientHttpResponse response) throws IOException {
257
                        return response.getHeaders();
258
                    }
259
                });
260
    }
261

    
262
    public ResponseEntity<String> postForString(String path, HttpHeaders headers, MultiValueMap<String, String> formData) {
263
        HttpHeaders actualHeaders = new HttpHeaders();
264
        actualHeaders.putAll(headers);
265
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_FORM_URLENCODED));
266
        return client.exchange(getUrl(path), HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(formData,
267
                headers), String.class);
268
    }
269

    
270
    public ResponseEntity<String> getForString(String path, final HttpHeaders headers) {
271
        return client.exchange(getUrl(path), HttpMethod.GET, new HttpEntity<Void>((Void) null, headers), String.class);
272
    }
273

    
274
    public ResponseEntity<String> getForString(String path) {
275
        return getForString(path, new HttpHeaders());
276
    }
277

    
278
    public String getForRedirect(String path, final HttpHeaders headers) {
279
        ResponseEntity<Void> response = client.exchange(getUrl(path), HttpMethod.GET, new HttpEntity<Void>((Void) null,
280
                headers), Void.class);
281
        URI location = response.getHeaders().getLocation();
282
        try {
283
            return URLDecoder.decode(location.toString(), "UTF-8");
284
        } catch (UnsupportedEncodingException e) {
285
            throw new IllegalStateException("Could not decode URL", e);
286
        }
287
    }
288

    
289
    public HttpStatus getStatusCode(String path, final HttpHeaders headers) {
290
        RequestCallback requestCallback = new NullRequestCallback();
291
        if (headers != null) {
292
            requestCallback = new RequestCallback() {
293
                @Override
294
                public void doWithRequest(ClientHttpRequest request) throws IOException {
295
                    request.getHeaders().putAll(headers);
296
                }
297
            };
298
        }
299
        return client.execute(getUrl(path), HttpMethod.GET, requestCallback,
300
                new ResponseExtractor<ResponseEntity<Void>>() {
301
                    @Override
302
                    public ResponseEntity<Void> extractData(ClientHttpResponse response) throws IOException {
303
                        FileCopyUtils.copyToByteArray(response.getBody());
304
                        return new ResponseEntity<Void>(response.getStatusCode());
305
                    }
306
                }).getStatusCode();
307
    }
308

    
309
    public HttpStatus getStatusCode(String path) {
310
        return getStatusCode(getUrl(path), null);
311
    }
312

    
313
    public RestTemplate getRestTemplate() {
314
        RestTemplate client = new RestTemplate();
315
        client.setRequestFactory(new SimpleClientHttpRequestFactory() {
316
            @Override
317
            protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
318
                super.prepareConnection(connection, httpMethod);
319
                connection.setInstanceFollowRedirects(false);
320
            }
321
        });
322
        client.setErrorHandler(new ResponseErrorHandler() {
323
            // Pass errors through in response entity for status code analysis
324
            @Override
325
            public boolean hasError(ClientHttpResponse response) throws IOException {
326
                return false;
327
            }
328

    
329
            @Override
330
            public void handleError(ClientHttpResponse response) throws IOException {
331
            }
332
        });
333
        return client;
334
    }
335

    
336
    public UriBuilder buildUri(String url) {
337
        return UriBuilder.fromUri(url.startsWith("http:") ? url : getUrl(url));
338
    }
339

    
340
    private static final class NullRequestCallback implements RequestCallback {
341
        @Override
342
        public void doWithRequest(ClientHttpRequest request) throws IOException {
343
        }
344
    }
345

    
346
    public static class UriBuilder {
347

    
348
        private final String url;
349
        private MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
350

    
351
        public UriBuilder(String url) {
352
            this.url = url;
353
        }
354

    
355
        public static UriBuilder fromUri(String url) {
356
            return new UriBuilder(url);
357
        }
358

    
359
        public UriBuilder queryParam(String key, String value) {
360
            params.add(key, value);
361
            return this;
362
        }
363

    
364
        public URI build() {
365
            StringBuilder builder = new StringBuilder(url);
366
            try {
367
                if (!params.isEmpty()) {
368
                    builder.append("?");
369
                    boolean first = true;
370
                    for (String key : params.keySet()) {
371
                        if (!first) {
372
                            builder.append("&");
373
                        } else {
374
                            first = false;
375
                        }
376
                        for (String value : params.get(key)) {
377
                            builder.append(key + "=" + UriUtils.encodeQueryParam(value, "UTF-8"));
378
                        }
379
                    }
380
                }
381
                return new URI(builder.toString());
382
            } catch (UnsupportedEncodingException ex) {
383
                // should not happen, UTF-8 is always supported
384
                throw new IllegalStateException(ex);
385
            } catch (URISyntaxException ex) {
386
                throw new IllegalArgumentException("Could not create URI from [" + builder + "]: " + ex, ex);
387
            }
388
        }
389
    }
390
}
(1-1/2)