/
CucumberRestTestContext.java
207 lines (173 loc) · 6.38 KB
/
CucumberRestTestContext.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package tech.jhipster.lite.cucumber.rest;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.spi.json.JsonProvider;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.function.Function;
import net.minidev.json.JSONArray;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.api.Assertions;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StreamUtils;
public final class CucumberRestTestContext {
private static final Deque<RestQuery> queries = new ConcurrentLinkedDeque<>();
private static final JsonProvider jsonReader = Configuration.defaultConfiguration().addOptions(Option.SUPPRESS_EXCEPTIONS).jsonProvider();
private CucumberRestTestContext() {}
public static void addResponse(HttpRequest request, ClientHttpResponse response, ClientHttpRequestExecution execution, byte[] body) {
queries.addFirst(new RestQuery(request, response, execution, body));
}
public static Object getElement(String jsonPath) {
return lastQuery().response().map(toElement(jsonPath)).orElse(null);
}
public static Object getElement(String uri, String jsonPath) {
return queries
.stream()
.filter(query -> query.response.isPresent() && StringUtils.isNotBlank(query.response.get()))
.filter(query -> query.forUri(uri))
.findFirst()
.flatMap(response -> response.response.map(toElement(jsonPath)))
.orElse(null);
}
public static List<String> getResponseHeader(String header) {
return Collections.unmodifiableList(lastQuery().responseHeaders().get(header));
}
public static int countEntries(String jsonPath) {
return lastQuery().response().map(toEntriesCount(jsonPath)).orElse(0);
}
private static Function<String, Integer> toEntriesCount(String jsonPath) {
return response -> {
Object element;
try {
element = JsonPath.read(jsonReader.parse(response), jsonPath);
} catch (PathNotFoundException e) {
return 0;
}
if (!(element instanceof JSONArray array)) {
return 1;
}
if (array.isEmpty()) {
return 0;
}
return array.size();
};
}
private static Function<String, Object> toElement(String jsonPath) {
return response -> {
try {
return JsonPath.read(jsonReader.parse(response), jsonPath);
} catch (PathNotFoundException e) {
return null;
}
};
}
public static HttpStatus getStatus() {
return lastQuery().status();
}
public static String getUri() {
return lastQuery().uri();
}
public static Optional<String> getResponse() {
return lastQuery().response();
}
public static void reset() {
queries.clear();
}
public static void retry() {
lastQuery().retry();
}
private static RestQuery lastQuery() {
try {
return queries.getFirst();
} catch (NoSuchElementException e) {
throw new AssertionError("Can't get last query: empty queries");
}
}
private static class RestQuery {
private static final String URI_MATCHER = ".*\\/%s(\\/[\\w-]*\\/?)?";
private final HttpRequest request;
private final String uri;
private final HttpStatus status;
private final Optional<String> response;
private final HttpHeaders responseHeaders;
private final ClientHttpRequestExecution execution;
private final byte[] body;
public RestQuery(HttpRequest request, ClientHttpResponse response, ClientHttpRequestExecution execution, byte[] body) {
this.request = request;
try {
uri = URLDecoder.decode(request.getURI().toString(), StandardCharsets.UTF_8.displayName());
responseHeaders = response.getHeaders();
status = (HttpStatus) response.getStatusCode();
} catch (IOException e) {
throw new AssertionError(e.getMessage(), e);
}
this.response = readResponse(response);
this.execution = execution;
this.body = body;
}
private Optional<String> readResponse(ClientHttpResponse response) {
try {
return Optional.of(StreamUtils.copyToString(response.getBody(), Charset.defaultCharset()));
} catch (Exception e) {
return Optional.empty();
}
}
public String uri() {
return uri;
}
private HttpStatus status() {
return status;
}
private Optional<String> response() {
return response;
}
private HttpHeaders responseHeaders() {
return responseHeaders;
}
/**
* Matches the supplied URI respecting REST principles.
*
* <pre>
* true = "/api/working-folders".forUri("working-folders")
* true = "/api/working-folders/".forUri("working-folders")
* true = "/api/working-folders/e47df162-f397".forUri("working-folders")
* true = "/api/working-folders/e47df162-f397/".forUri("working-folders")
* false = "/api/working-folders/e47df162-f397/commentaries".forUri("working-folders")
* false = "/api/working-folders/e47df162-f397/commentaries/".forUri("working-folders")
* false = "/api/working-folders/e47df162-f397/commentaries/955eea5e-9fbf".forUri("working-folders")
* false = "/api/working-folders/e47df162-f397/commentaries/955eea5e-9fbf/".forUri("working-folders")
* </pre>
*
* @param uri
* name of a REST resource, such as "working-folders"
*/
private boolean forUri(String uri) {
if (!uri.matches("[\\w-]+")) {
Assertions.fail("URI should be the name of a REST resource");
}
return this.uri.matches(String.format(URI_MATCHER, uri));
}
private void retry() {
try {
ClientHttpResponse response = execution.execute(request, body);
addResponse(request, response, execution, body);
} catch (IOException e) {
throw new AssertionError("Error while retrying last call: " + e.getMessage(), e);
}
}
}
}