001/*
002 * (C) Copyright 2018 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *    http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Kevin Leturc <kleturc@nuxeo.com>
018 */
019package org.nuxeo.jaxrs.test;
020
021import java.util.Collections;
022import java.util.HashMap;
023import java.util.Map;
024import java.util.Map.Entry;
025import java.util.function.Function;
026
027import org.junit.rules.TestRule;
028import org.junit.runner.Description;
029import org.junit.runners.model.Statement;
030
031import com.google.common.base.Splitter;
032import com.sun.jersey.api.client.Client;
033import com.sun.jersey.api.client.ClientResponse;
034import com.sun.jersey.api.client.WebResource;
035
036/**
037 * @since 10.1
038 */
039public class HttpClientTestRule implements TestRule {
040
041    public static final String APPLICATION_JSON_NXENTITY = "application/json+nxentity";
042
043    public static final String ADMINISTRATOR = "Administrator";
044
045    private final String url;
046
047    private final String username;
048
049    private final String password;
050
051    private final String accept;
052
053    private final Map<String, String> headers;
054
055    protected Client client;
056
057    protected WebResource service;
058
059    private HttpClientTestRule(Builder builder) {
060        this.url = builder.url;
061        this.username = builder.username;
062        this.password = builder.password;
063        this.accept = builder.accept;
064        this.headers = builder.headers;
065    }
066
067    @Override
068    public Statement apply(Statement base, Description description) {
069        return new Statement() {
070
071            @Override
072            public void evaluate() throws Throwable {
073                starting(description);
074                try {
075                    base.evaluate();
076                } finally {
077                    finished(description);
078                }
079            }
080        };
081    }
082
083    protected void starting(Description description) {
084        client = JerseyClientHelper.clientBuilder().setCredentials(username, password).build();
085        service = client.resource(url);
086    }
087
088    protected void finished(Description description) {
089        client.destroy();
090    }
091
092    public CloseableClientResponse get(String path) {
093        return execute(path, builder -> builder.get(ClientResponse.class));
094    }
095
096    public CloseableClientResponse post(String path, Object data) {
097        return execute(path, builder -> builder.post(ClientResponse.class, data));
098    }
099
100    public CloseableClientResponse put(String path, Object data) {
101        return execute(path, builder -> builder.put(ClientResponse.class, data));
102    }
103
104    public CloseableClientResponse delete(String path) {
105        return execute(path, builder -> builder.delete(ClientResponse.class));
106    }
107
108    protected CloseableClientResponse execute(String path, Function<WebResource.Builder, ClientResponse> invoker) {
109        // extract queryParams from path
110        Map<String, String> queryParams = Collections.emptyMap();
111        int interrogationIdx = path.indexOf('?');
112        if (interrogationIdx >= 0) {
113            queryParams = Splitter.on('&').withKeyValueSeparator('=').split(path.substring(interrogationIdx + 1));
114            path = path.substring(0, interrogationIdx);
115        }
116        WebResource webResource = service.path(path);
117        for (Entry<String, String> entry : queryParams.entrySet()) {
118            webResource = webResource.queryParam(entry.getKey(), entry.getValue());
119        }
120        WebResource.Builder builder = webResource.accept(accept);
121        headers.forEach(builder::header);
122        return invoker.andThen(CloseableClientResponse::of).apply(builder);
123    }
124
125    /**
126     * The http client test rule builder. This builder is used to pass default parameters to client and requests.
127     */
128    public static class Builder {
129
130        private String url;
131
132        private String username;
133
134        private String password;
135
136        private String accept;
137
138        private Map<String, String> headers;
139
140        public Builder() {
141            this.url = System.getProperty("nuxeoURL", "http://localhost:8080/nuxeo").replaceAll("/$", "");
142            this.username = null;
143            this.password = null;
144            this.accept = APPLICATION_JSON_NXENTITY;
145            this.headers = new HashMap<>();
146        }
147
148        public Builder url(String url) {
149            this.url = url;
150            return this;
151        }
152
153        public Builder adminCredentials() {
154            return credentials(ADMINISTRATOR, ADMINISTRATOR);
155        }
156
157        public Builder credentials(String username, String password) {
158            this.username = username;
159            this.password = password;
160            return this;
161        }
162
163        public Builder accept(String accept) {
164            this.accept = accept;
165            return this;
166        }
167
168        public Builder header(String key, String value) {
169            headers.put(key, value);
170            return this;
171        }
172
173        public HttpClientTestRule build() {
174            return new HttpClientTestRule(this);
175        }
176
177    }
178
179}