|
1 | 1 | package org.heigit.ors.benchmark; |
2 | 2 |
|
3 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; |
| 4 | +import com.fasterxml.jackson.core.type.TypeReference; |
4 | 5 | import io.gatling.javaapi.core.PopulationBuilder; |
5 | 6 | import io.gatling.javaapi.core.ScenarioBuilder; |
6 | 7 | import io.gatling.javaapi.core.Session; |
|
11 | 12 | import org.slf4j.LoggerFactory; |
12 | 13 |
|
13 | 14 | import java.util.ArrayList; |
| 15 | +import java.util.HashMap; |
14 | 16 | import java.util.List; |
15 | 17 | import java.util.Map; |
16 | 18 | import java.util.concurrent.atomic.AtomicInteger; |
@@ -116,7 +118,6 @@ private String formatScenarioName(MatrixModes mode, String profile, boolean isPa |
116 | 118 | * |
117 | 119 | * @param name descriptive name for the scenario |
118 | 120 | * @param sourceFile path to CSV file containing test coordinates |
119 | | - * @param config test configuration parameters |
120 | 121 | * @param mode matrix calculation mode to test |
121 | 122 | * @param profile routing profile to test |
122 | 123 | * @return ScenarioBuilder configured for matrix testing |
@@ -156,117 +157,78 @@ private static HttpRequestActionBuilder createRequest(String name, MatrixModes m |
156 | 157 | String profile) { |
157 | 158 | return http(name) |
158 | 159 | .post("/v2/matrix/" + profile) |
| 160 | + .header("Accept", "application/json;charset=UTF-8") |
159 | 161 | .body(StringBody(session -> createRequestBody(session, mode))) |
160 | 162 | .asJson() |
161 | 163 | .check(status().is(200)); |
162 | 164 | } |
163 | 165 |
|
164 | 166 | /** |
165 | 167 | * Creates the JSON request body for matrix API calls from CSV session data. |
166 | | - * |
| 168 | + * |
167 | 169 | * @param session Gatling session containing CSV row data |
168 | 170 | * @param mode matrix calculation mode providing additional parameters |
169 | 171 | * @return JSON string representation of the request body |
170 | | - * @throws RequestBodyCreationException if JSON serialization fails |
| 172 | + * @throws RequestBodyCreationException if JSON serialization fails or data is missing |
171 | 173 | */ |
172 | 174 | static String createRequestBody(Session session, MatrixModes mode) { |
173 | 175 | try { |
174 | | - // Get the data from the CSV row |
175 | | - String coordinatesStr = (String) session.get("coordinates"); |
176 | | - String sourcesStr = (String) session.get("sources"); |
177 | | - String destinationsStr = (String) session.get("destinations"); |
178 | | - |
179 | | - Map<String, Object> requestBody = new java.util.HashMap<>(Map.of( |
180 | | - "locations", parseCoordinatesFromString(coordinatesStr), |
181 | | - "sources", parseIntegerArrayFromString(sourcesStr), |
182 | | - "destinations", parseIntegerArrayFromString(destinationsStr))); |
183 | | - |
184 | | - requestBody.putAll(mode.getRequestParams()); |
185 | | - return objectMapper.writeValueAsString(requestBody); |
186 | | - } catch (JsonProcessingException e) { |
187 | | - throw new RequestBodyCreationException("Failed to create request body", e); |
188 | | - } |
189 | | - } |
190 | | - |
191 | | - /** |
192 | | - * Parses coordinate pairs from CSV string format to nested list structure. |
193 | | - * |
194 | | - * Converts strings like "[[8.695556, 49.392701], [8.684623, 49.398284]]" |
195 | | - * into List<List<Double>> format expected by the matrix API. |
196 | | - * |
197 | | - * @param coordinatesStr string representation of coordinate array from CSV |
198 | | - * @return list of coordinate pairs as [longitude, latitude] arrays |
199 | | - * @throws RequestBodyCreationException if parsing fails or format is invalid |
200 | | - */ |
201 | | - static List<List<Double>> parseCoordinatesFromString(String coordinatesStr) { |
202 | | - try { |
203 | | - if (coordinatesStr == null || coordinatesStr.trim().isEmpty()) { |
204 | | - throw new RequestBodyCreationException("Coordinates string is null or empty"); |
| 176 | + // 1) Retrieve the raw feeder values. Gatling will give us a List<String> for each column. |
| 177 | + @SuppressWarnings("unchecked") |
| 178 | + List<String> coordsList = (List<String>) session.get("coordinates"); |
| 179 | + @SuppressWarnings("unchecked") |
| 180 | + List<String> sourcesList = (List<String>) session.get("sources"); |
| 181 | + @SuppressWarnings("unchecked") |
| 182 | + List<String> destsList = (List<String>) session.get("destinations"); |
| 183 | + |
| 184 | + // 2) Fail fast if any column is missing or empty |
| 185 | + if (coordsList == null || coordsList.isEmpty()) { |
| 186 | + throw new RequestBodyCreationException("'coordinates' field is missing or empty in session"); |
205 | 187 | } |
206 | | - |
207 | | - // Remove quotes if present |
208 | | - String cleaned = coordinatesStr.trim(); |
209 | | - if (cleaned.startsWith("\"") && cleaned.endsWith("\"")) { |
210 | | - cleaned = cleaned.substring(1, cleaned.length() - 1); |
| 188 | + if (sourcesList == null || sourcesList.isEmpty()) { |
| 189 | + throw new RequestBodyCreationException("'sources' field is missing or empty in session"); |
211 | 190 | } |
212 | | - |
213 | | - // Remove outer brackets |
214 | | - cleaned = cleaned.substring(2, cleaned.length() - 2); |
215 | | - String[] coordinatePairs = cleaned.split("\\], \\["); |
216 | | - |
217 | | - List<List<Double>> locations = new ArrayList<>(); |
218 | | - for (String pair : coordinatePairs) { |
219 | | - String[] values = pair.split(", "); |
220 | | - if (values.length != 2) { |
221 | | - throw new RequestBodyCreationException("Invalid coordinate pair: " + pair); |
222 | | - } |
223 | | - double lon = Double.parseDouble(values[0]); |
224 | | - double lat = Double.parseDouble(values[1]); |
225 | | - locations.add(List.of(lon, lat)); |
226 | | - } |
227 | | - return locations; |
228 | | - } catch (Exception e) { |
229 | | - throw new RequestBodyCreationException("Failed to parse coordinates: " + coordinatesStr, e); |
230 | | - } |
231 | | - } |
232 | | - |
233 | | - /** |
234 | | - * Parses integer arrays from CSV string format. |
235 | | - * |
236 | | - * Converts strings like "[0, 1, 2]" into List<Integer> format |
237 | | - * for sources and destinations parameters. |
238 | | - * |
239 | | - * @param arrayStr string representation of integer array from CSV |
240 | | - * @return list of integers |
241 | | - * @throws RequestBodyCreationException if parsing fails or format is invalid |
242 | | - */ |
243 | | - static List<Integer> parseIntegerArrayFromString(String arrayStr) { |
244 | | - try { |
245 | | - if (arrayStr == null || arrayStr.trim().isEmpty()) { |
246 | | - throw new RequestBodyCreationException("Array string is null or empty"); |
247 | | - } |
248 | | - |
249 | | - // Remove quotes if present |
250 | | - String cleaned = arrayStr.trim(); |
251 | | - if (cleaned.startsWith("\"") && cleaned.endsWith("\"")) { |
252 | | - cleaned = cleaned.substring(1, cleaned.length() - 1); |
| 191 | + if (destsList == null || destsList.isEmpty()) { |
| 192 | + throw new RequestBodyCreationException("'destinations' field is missing or empty in session"); |
253 | 193 | } |
254 | 194 |
|
255 | | - // Remove brackets |
256 | | - cleaned = cleaned.substring(1, cleaned.length() - 1); |
| 195 | + // 3) The first element of each List<String> is the actual JSON‐style value. |
| 196 | + String coordinatesJson = coordsList.get(0); |
| 197 | + String sourcesJson = sourcesList.get(0); |
| 198 | + String destsJson = destsList.get(0); |
| 199 | + |
| 200 | + logger.debug( |
| 201 | + "Raw CSV values → coordinatesJson: {}, sourcesJson: {}, destsJson: {}", |
| 202 | + coordinatesJson, sourcesJson, destsJson |
| 203 | + ); |
| 204 | + |
| 205 | + // 4) Let Jackson parse "[[lon, lat], [lon, lat], …]" into List<List<Double>> |
| 206 | + List<List<Double>> locations = objectMapper.readValue( |
| 207 | + coordinatesJson, new TypeReference<List<List<Double>>>() {} |
| 208 | + ); |
| 209 | + |
| 210 | + // 5) Similarly parse "[0, 1, 2]" into List<Integer> |
| 211 | + List<Integer> sources = objectMapper.readValue( |
| 212 | + sourcesJson, new TypeReference<List<Integer>>() {} |
| 213 | + ); |
| 214 | + List<Integer> destinations = objectMapper.readValue( |
| 215 | + destsJson, new TypeReference<List<Integer>>() {} |
| 216 | + ); |
| 217 | + |
| 218 | + // 6) Build the request body map and merge in any extra params from MatrixModes |
| 219 | + Map<String, Object> requestBody = new HashMap<>(Map.of( |
| 220 | + "locations", locations, |
| 221 | + "sources", sources, |
| 222 | + "destinations", destinations |
| 223 | + )); |
| 224 | + requestBody.putAll(mode.getRequestParams()); |
257 | 225 |
|
258 | | - if (cleaned.trim().isEmpty()) { |
259 | | - return new ArrayList<>(); |
260 | | - } |
| 226 | + // 7) Serialize to JSON and return |
| 227 | + return objectMapper.writeValueAsString(requestBody); |
261 | 228 |
|
262 | | - String[] values = cleaned.split(", "); |
263 | | - List<Integer> result = new ArrayList<>(); |
264 | | - for (String value : values) { |
265 | | - result.add(Integer.parseInt(value.trim())); |
266 | | - } |
267 | | - return result; |
268 | | - } catch (Exception e) { |
269 | | - throw new RequestBodyCreationException("Failed to parse integer array: " + arrayStr, e); |
| 229 | + } catch (JsonProcessingException e) { |
| 230 | + // Jackson failed to parse or serialize |
| 231 | + throw new RequestBodyCreationException("Failed to serialize request body to JSON", e); |
270 | 232 | } |
271 | 233 | } |
272 | 234 | } |
0 commit comments