|
27 | 27 | import org.apache.iotdb.itbase.category.LocalStandaloneIT; |
28 | 28 | import org.apache.iotdb.itbase.category.RemoteIT; |
29 | 29 | import org.apache.iotdb.itbase.env.BaseEnv; |
| 30 | +import org.apache.iotdb.rpc.TSStatusCode; |
30 | 31 |
|
31 | 32 | import com.fasterxml.jackson.databind.ObjectMapper; |
32 | 33 | import com.google.gson.JsonObject; |
|
55 | 56 | import java.sql.ResultSetMetaData; |
56 | 57 | import java.sql.SQLException; |
57 | 58 | import java.sql.Statement; |
| 59 | +import java.time.ZoneId; |
| 60 | +import java.time.ZonedDateTime; |
58 | 61 | import java.util.ArrayList; |
59 | 62 | import java.util.Base64; |
60 | 63 | import java.util.List; |
@@ -2391,4 +2394,130 @@ public void queryDateAndBlobV2(CloseableHttpClient httpClient) { |
2391 | 2394 | } |
2392 | 2395 | } |
2393 | 2396 | } |
| 2397 | + |
| 2398 | + @Test |
| 2399 | + public void testQueryWithValidTimeZoneHeaderV2() { |
| 2400 | + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); |
| 2401 | + try { |
| 2402 | + HttpPost insertPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/insertTablet"); |
| 2403 | + String insertJson = |
| 2404 | + "{\"timestamps\":[1774713387626],\"measurements\":[\"s3\"],\"data_types\":[\"INT32\"],\"values\":[[11]],\"is_aligned\":false,\"device\":\"root.sg25\"}"; |
| 2405 | + insertPost.setEntity(new StringEntity(insertJson, Charset.defaultCharset())); |
| 2406 | + try (CloseableHttpResponse resp = executeWithRetry(insertPost, httpClient)) { |
| 2407 | + assertEquals(200, resp.getStatusLine().getStatusCode()); |
| 2408 | + } |
| 2409 | + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); |
| 2410 | + httpPost.setHeader("X-TimeZone", "Europe/Warsaw"); |
| 2411 | + String sql = |
| 2412 | + "{\"sql\":\"SELECT count(s3) FROM root.sg25 GROUP BY ([2026-03-28T00:00:00, 2026-03-29T00:00:00), 1d)\"}"; |
| 2413 | + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); |
| 2414 | + CloseableHttpResponse response = httpClient.execute(httpPost); |
| 2415 | + assertEquals(200, response.getStatusLine().getStatusCode()); |
| 2416 | + String message = EntityUtils.toString(response.getEntity(), "utf-8"); |
| 2417 | + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); |
| 2418 | + assertTrue(result.has("timestamps")); |
| 2419 | + assertTrue(result.getAsJsonArray("timestamps").size() > 0); |
| 2420 | + long expectedTimestamp = |
| 2421 | + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("Europe/Warsaw")) |
| 2422 | + .toInstant() |
| 2423 | + .toEpochMilli(); |
| 2424 | + assertEquals(expectedTimestamp, result.getAsJsonArray("timestamps").get(0).getAsLong()); |
| 2425 | + } catch (IOException e) { |
| 2426 | + fail(e.getMessage()); |
| 2427 | + } finally { |
| 2428 | + try { |
| 2429 | + httpClient.close(); |
| 2430 | + } catch (IOException e) { |
| 2431 | + } |
| 2432 | + } |
| 2433 | + } |
| 2434 | + |
| 2435 | + @Test |
| 2436 | + public void testNonQueryWithValidTimeZoneHeaderV2() throws Exception { |
| 2437 | + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); |
| 2438 | + try { |
| 2439 | + nonQueryWithTimeZone( |
| 2440 | + httpClient, |
| 2441 | + "{\"sql\":\"CREATE TIMESERIES root.sg.d1.s1 WITH DATATYPE=INT32\"}", |
| 2442 | + "Europe/Warsaw"); |
| 2443 | + nonQueryWithTimeZone( |
| 2444 | + httpClient, |
| 2445 | + "{\"sql\":\"INSERT INTO root.sg.d1(time, s1) VALUES (2026-03-28T00:00:00, 123)\"}", |
| 2446 | + "Europe/Warsaw"); |
| 2447 | + |
| 2448 | + HttpPost queryPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); |
| 2449 | + queryPost.setEntity( |
| 2450 | + new StringEntity("{\"sql\":\"SELECT s1 FROM root.sg.d1\"}", StandardCharsets.UTF_8)); |
| 2451 | + try (CloseableHttpResponse resp = httpClient.execute(queryPost)) { |
| 2452 | + String message = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); |
| 2453 | + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); |
| 2454 | + long expected = |
| 2455 | + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("Europe/Warsaw")) |
| 2456 | + .toInstant() |
| 2457 | + .toEpochMilli(); |
| 2458 | + assertEquals(expected, result.getAsJsonArray("timestamps").get(0).getAsLong()); |
| 2459 | + } |
| 2460 | + } finally { |
| 2461 | + try { |
| 2462 | + httpClient.close(); |
| 2463 | + } catch (IOException e) { |
| 2464 | + } |
| 2465 | + } |
| 2466 | + } |
| 2467 | + |
| 2468 | + @Test |
| 2469 | + public void testQueryWithInvalidTimeZoneHeaderV2() { |
| 2470 | + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); |
| 2471 | + try { |
| 2472 | + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); |
| 2473 | + httpPost.setHeader("X-TimeZone", "Invalid/Zone"); |
| 2474 | + String sql = "{\"sql\":\"SELECT s3 FROM root.sg25\"}"; |
| 2475 | + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); |
| 2476 | + CloseableHttpResponse response = executeWithRetry(httpPost, httpClient); |
| 2477 | + assertEquals(400, response.getStatusLine().getStatusCode()); |
| 2478 | + String message = EntityUtils.toString(response.getEntity(), "utf-8"); |
| 2479 | + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); |
| 2480 | + assertEquals(TSStatusCode.ILLEGAL_PARAMETER.getStatusCode(), result.get("code").getAsInt()); |
| 2481 | + assertTrue(result.get("message").getAsString().contains("Invalid time zone")); |
| 2482 | + } catch (IOException e) { |
| 2483 | + fail(e.getMessage()); |
| 2484 | + } finally { |
| 2485 | + try { |
| 2486 | + httpClient.close(); |
| 2487 | + } catch (IOException e) { |
| 2488 | + } |
| 2489 | + } |
| 2490 | + } |
| 2491 | + |
| 2492 | + private void nonQueryWithTimeZone(CloseableHttpClient httpClient, String json, String timeZone) { |
| 2493 | + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/nonQuery"); |
| 2494 | + httpPost.setHeader("X-TimeZone", timeZone); |
| 2495 | + httpPost.setEntity(new StringEntity(json, StandardCharsets.UTF_8)); |
| 2496 | + try (CloseableHttpResponse response = executeWithRetry(httpPost, httpClient)) { |
| 2497 | + String message = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); |
| 2498 | + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); |
| 2499 | + assertEquals(200, result.get("code").getAsInt()); |
| 2500 | + } catch (IOException e) { |
| 2501 | + fail(e.getMessage()); |
| 2502 | + } |
| 2503 | + } |
| 2504 | + |
| 2505 | + private CloseableHttpResponse executeWithRetry(HttpPost httpPost, CloseableHttpClient httpClient) |
| 2506 | + throws IOException { |
| 2507 | + CloseableHttpResponse response = null; |
| 2508 | + for (int i = 0; i < 30; i++) { |
| 2509 | + try { |
| 2510 | + response = httpClient.execute(httpPost); |
| 2511 | + break; |
| 2512 | + } catch (Exception e) { |
| 2513 | + if (i == 29) throw e; |
| 2514 | + try { |
| 2515 | + Thread.sleep(1000); |
| 2516 | + } catch (InterruptedException ex) { |
| 2517 | + throw new RuntimeException(ex); |
| 2518 | + } |
| 2519 | + } |
| 2520 | + } |
| 2521 | + return response; |
| 2522 | + } |
2394 | 2523 | } |
0 commit comments