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 ADMINISTRATOR = "Administrator";
042
043    private final String url;
044
045    private final String username;
046
047    private final String password;
048
049    private final String accept;
050
051    private final Map<String, String> headers;
052
053    protected Client client;
054
055    protected WebResource service;
056
057    private HttpClientTestRule(Builder builder) {
058        this.url = builder.url;
059        this.username = builder.username;
060        this.password = builder.password;
061        this.accept = builder.accept;
062        this.headers = builder.headers;
063    }
064
065    @Override
066    public Statement apply(Statement base, Description description) {
067        return new Statement() {
068
069            @Override
070            public void evaluate() throws Throwable {
071                starting();
072                try {
073                    base.evaluate();
074                } finally {
075                    finished();
076                }
077            }
078        };
079    }
080
081    protected void starting() {
082        client = JerseyClientHelper.clientBuilder().setCredentials(username, password).build();
083        service = client.resource(url);
084    }
085
086    protected void finished() {
087        client.destroy();
088    }
089
090    public CloseableClientResponse get(String path) {
091        return execute(path, builder -> builder.get(ClientResponse.class));
092    }
093
094    public CloseableClientResponse post(String path, Object data) {
095        return execute(path, builder -> builder.post(ClientResponse.class, data));
096    }
097
098    public CloseableClientResponse put(String path, Object data) {
099        return execute(path, builder -> builder.put(ClientResponse.class, data));
100    }
101
102    public CloseableClientResponse delete(String path) {
103        return execute(path, builder -> builder.delete(ClientResponse.class));
104    }
105
106    protected CloseableClientResponse execute(String path, Function<WebResource.Builder, ClientResponse> invoker) {
107        // extract queryParams from path
108        Map<String, String> queryParams = Collections.emptyMap();
109        int interrogationIdx = path.indexOf('?');
110        if (interrogationIdx >= 0) {
111            queryParams = Splitter.on('&').withKeyValueSeparator('=').split(path.substring(interrogationIdx + 1));
112            path = path.substring(0, interrogationIdx);
113        }
114        WebResource webResource = service.path(path);
115        for (Entry<String, String> entry : queryParams.entrySet()) {
116            webResource = webResource.queryParam(entry.getKey(), entry.getValue());
117        }
118        WebResource.Builder builder = webResource.accept(accept);
119        headers.forEach(builder::header);
120        return invoker.andThen(CloseableClientResponse::of).apply(builder);
121    }
122
123    /**
124     * The http client test rule builder. This builder is used to pass default parameters to client and requests.
125     */
126    public static class Builder {
127
128        private String url;
129
130        private String username;
131
132        private String password;
133
134        private String accept;
135
136        private Map<String, String> headers;
137
138        public Builder() {
139            this.url = System.getProperty("nuxeoURL", "http://localhost:8080/nuxeo").replaceAll("/$", "");
140            this.username = null;
141            this.password = null;
142            this.accept = null;
143            this.headers = new HashMap<>();
144        }
145
146        public Builder url(String url) {
147            this.url = url;
148            return this;
149        }
150
151        public Builder adminCredentials() {
152            return credentials(ADMINISTRATOR, ADMINISTRATOR);
153        }
154
155        public Builder credentials(String username, String password) {
156            this.username = username;
157            this.password = password;
158            return this;
159        }
160
161        public Builder accept(String accept) {
162            this.accept = accept;
163            return this;
164        }
165
166        public Builder header(String key, String value) {
167            headers.put(key, value);
168            return this;
169        }
170
171        public HttpClientTestRule build() {
172            return new HttpClientTestRule(this);
173        }
174
175    }
176
177}