View Javadoc
1   package net.avcompris.commons3.web.it.utils;
2   
3   import static com.google.common.base.Preconditions.checkState;
4   import static com.google.common.collect.Maps.newHashMap;
5   import static io.restassured.RestAssured.given;
6   import static net.avcompris.commons3.api.tests.ControllerContextUtils.extractControllerContext;
7   import static net.avcompris.commons3.api.tests.TestsSpec.HttpMethod.DELETE;
8   import static net.avcompris.commons3.api.tests.TestsSpec.HttpMethod.GET;
9   import static net.avcompris.commons3.api.tests.TestsSpec.HttpMethod.POST;
10  import static net.avcompris.commons3.api.tests.TestsSpec.HttpMethod.PUT;
11  import static net.avcompris.commons3.web.it.utils.ExpressionUtils.process;
12  import static net.avcompris.commons3.web.it.utils.JSONUtils.parseJSON;
13  import static org.apache.commons.lang3.StringUtils.isBlank;
14  import static org.apache.commons.lang3.StringUtils.substringAfter;
15  import static org.apache.commons.lang3.StringUtils.substringBefore;
16  
17  import java.io.IOException;
18  import java.util.Map;
19  
20  import javax.annotation.Nullable;
21  
22  import org.apache.commons.lang3.NotImplementedException;
23  import org.json.simple.parser.JSONParser;
24  import org.junit.jupiter.api.BeforeEach;
25  
26  import com.google.common.collect.ImmutableMap;
27  
28  import io.restassured.response.Response;
29  import io.restassured.specification.RequestSpecification;
30  import net.avcompris.commons3.api.tests.AbstractApiTest;
31  import net.avcompris.commons3.api.tests.TestsSpec.AuthenticationSpec;
32  import net.avcompris.commons3.api.tests.TestsSpec.Data;
33  import net.avcompris.commons3.api.tests.TestsSpec.HttpMethod;
34  import net.avcompris.commons3.api.tests.TestsSpec.TestSpec;
35  import net.avcompris.commons3.web.AbstractController;
36  
37  public abstract class AbstractWebApiTest extends AbstractApiTest {
38  
39  	private String baseURL;
40  
41  	private final Map<Class<? extends AbstractController>, String> moreRestAssured = newHashMap();
42  
43  	protected AbstractWebApiTest(final TestSpec spec, //
44  			@Nullable final String superadminAuthorization) {
45  
46  		super(spec, superadminAuthorization);
47  
48  		final Class<? extends AbstractWebApiTest> clazz = this.getClass();
49  
50  		final RestAssured restAssuredAnnotation = clazz.getAnnotation(RestAssured.class);
51  
52  		checkState(restAssuredAnnotation != null, //
53  				"Class should be annotated with @RestAssured: %s", clazz.getName());
54  
55  		try {
56  
57  			baseURL = process(restAssuredAnnotation.value());
58  
59  		} catch (final IOException e) {
60  
61  			throw new RuntimeException(e);
62  		}
63  	}
64  
65  	@Override
66  	protected final StepExecutionResult execute(final int stepIndex, final StepExecution step) throws Exception {
67  
68  		final String uri = step.getPath();
69  
70  		final HttpMethod httpMethod = step.getHttpMethod();
71  
72  		final String baseURL = moreRestAssured.entrySet().stream()
73  
74  				.filter(entry -> extractControllerContext(httpMethod, uri, entry.getKey()) != null)
75  
76  				.map(entry -> entry.getValue())
77  
78  				.findFirst().orElse(null);
79  
80  		AbstractWebTest.setUpRestAssured(baseURL != null ? baseURL : this.baseURL);
81  
82  		final RequestSpecification request = given();
83  
84  		final AuthenticationSpec authenticationSpec = step.getAuthentication();
85  
86  		if (authenticationSpec != null) {
87  
88  			request.header("Authorization", superadminAuthorization);
89  		}
90  
91  		final String path;
92  		final Map<String, String> queryParams;
93  
94  		if (uri.contains("?")) {
95  
96  			path = substringBefore(uri, "?");
97  
98  			final String query = substringAfter(uri, "?");
99  
100 			if (query.contains("&")) {
101 				throw new NotImplementedException("uri: " + uri);
102 			}
103 
104 			queryParams = ImmutableMap.<String, String>builder().put( //
105 					substringBefore(query, "="), //
106 					substringAfter(query, "=").replace('+', ' ') //
107 			).build();
108 
109 		} else {
110 
111 			path = uri;
112 			queryParams = null;
113 		}
114 
115 		final Response response;
116 
117 		if (httpMethod == GET) {
118 
119 			if (queryParams != null) {
120 
121 				request.queryParams(queryParams);
122 			}
123 
124 			response = request
125 
126 					.when().get(path);
127 
128 		} else if (httpMethod == POST) {
129 
130 			final Map<String, Object> map = newHashMap();
131 
132 			for (final Data data : step.getData()) {
133 
134 				map.put(data.getName(), data.getValue());
135 			}
136 
137 			response = request
138 
139 					.header("Content-Type", "application/json")
140 
141 					.body(map)
142 
143 					.when().post(path);
144 
145 		} else if (httpMethod == PUT) {
146 
147 			final Map<String, Object> map = newHashMap();
148 
149 			for (final Data data : step.getData()) {
150 
151 				map.put(data.getName(), data.getValue());
152 			}
153 
154 			response = request
155 
156 					.header("Content-Type", "application/json")
157 
158 					.body(map)
159 
160 					.when().put(path);
161 
162 		} else if (httpMethod == DELETE) {
163 
164 			response = request
165 
166 					.when().delete(path);
167 
168 		} else {
169 
170 			throw new NotImplementedException("httpMethod: " + httpMethod);
171 		}
172 
173 		response.then();
174 
175 		final int statusCode = response.then().extract().statusCode();
176 
177 		final String resultAsString = response.then().extract().asString();
178 
179 		final Class<?> returnType = step.getReturnType();
180 
181 		final Object dataBean;
182 
183 		if (returnType == null && isBlank(resultAsString)) {
184 
185 			dataBean = null;
186 
187 		} else if (returnType == null) {
188 
189 			dataBean = new JSONParser().parse(resultAsString);
190 
191 		} else {
192 
193 			dataBean = parseJSON(resultAsString, returnType);
194 		}
195 
196 		return new StepExecutionResult(statusCode, dataBean);
197 	}
198 
199 	/**
200 	 * Use the "@RestAssured" annotation set on the test class (e.g. AppInfoTest) to
201 	 * retrieve the env property to use for the API baseURL (e.g.
202 	 * "customers.baseURL"), and then call
203 	 * {@link AbstractWebTest#setUpRestAssured(String)}
204 	 */
205 	@BeforeEach
206 	public final void setUpRestAssured() throws Exception {
207 
208 		AbstractWebTest.setUpRestAssured(baseURL);
209 	}
210 
211 	protected final void moreRestAssured(final String expression,
212 			final Class<? extends AbstractController> controllerClass0) {
213 
214 		try {
215 
216 			moreRestAssured.putIfAbsent(controllerClass0, process(expression));
217 
218 		} catch (final IOException e) {
219 
220 			throw new RuntimeException(e);
221 		}
222 	}
223 }