|
26 | 26 | import org.apache.iotdb.itbase.category.LocalStandaloneIT; |
27 | 27 | import org.apache.iotdb.itbase.category.RemoteIT; |
28 | 28 | import org.apache.iotdb.itbase.env.BaseEnv; |
| 29 | +import org.apache.iotdb.rpc.TSStatusCode; |
29 | 30 |
|
30 | 31 | import com.fasterxml.jackson.databind.ObjectMapper; |
31 | 32 | import com.google.gson.JsonObject; |
|
52 | 53 | import java.sql.ResultSet; |
53 | 54 | import java.sql.SQLException; |
54 | 55 | import java.sql.Statement; |
| 56 | +import java.time.ZoneId; |
| 57 | +import java.time.ZonedDateTime; |
55 | 58 | import java.util.ArrayList; |
56 | 59 | import java.util.Base64; |
57 | 60 | import java.util.List; |
@@ -2354,4 +2357,130 @@ public void queryDateAndBlobV2(CloseableHttpClient httpClient) { |
2354 | 2357 | } |
2355 | 2358 | } |
2356 | 2359 | } |
| 2360 | + |
| 2361 | + @Test |
| 2362 | + public void testQueryWithValidTimeZoneHeaderV2() { |
| 2363 | + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); |
| 2364 | + try { |
| 2365 | + HttpPost insertPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/insertTablet"); |
| 2366 | + String insertJson = |
| 2367 | + "{\"timestamps\":[1774713387626],\"measurements\":[\"s3\"],\"data_types\":[\"INT32\"],\"values\":[[11]],\"is_aligned\":false,\"device\":\"root.sg25\"}"; |
| 2368 | + insertPost.setEntity(new StringEntity(insertJson, Charset.defaultCharset())); |
| 2369 | + try (CloseableHttpResponse resp = executeWithRetry(insertPost, httpClient)) { |
| 2370 | + assertEquals(200, resp.getStatusLine().getStatusCode()); |
| 2371 | + } |
| 2372 | + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); |
| 2373 | + httpPost.setHeader("X-TimeZone", "Europe/Warsaw"); |
| 2374 | + String sql = |
| 2375 | + "{\"sql\":\"SELECT count(s3) FROM root.sg25 GROUP BY ([2026-03-28T00:00:00, 2026-03-29T00:00:00), 1d)\"}"; |
| 2376 | + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); |
| 2377 | + CloseableHttpResponse response = httpClient.execute(httpPost); |
| 2378 | + assertEquals(200, response.getStatusLine().getStatusCode()); |
| 2379 | + String message = EntityUtils.toString(response.getEntity(), "utf-8"); |
| 2380 | + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); |
| 2381 | + assertTrue(result.has("timestamps")); |
| 2382 | + assertTrue(result.getAsJsonArray("timestamps").size() > 0); |
| 2383 | + long expectedTimestamp = |
| 2384 | + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("Europe/Warsaw")) |
| 2385 | + .toInstant() |
| 2386 | + .toEpochMilli(); |
| 2387 | + assertEquals(expectedTimestamp, result.getAsJsonArray("timestamps").get(0).getAsLong()); |
| 2388 | + } catch (IOException e) { |
| 2389 | + fail(e.getMessage()); |
| 2390 | + } finally { |
| 2391 | + try { |
| 2392 | + httpClient.close(); |
| 2393 | + } catch (IOException e) { |
| 2394 | + } |
| 2395 | + } |
| 2396 | + } |
| 2397 | + |
| 2398 | + @Test |
| 2399 | + public void testNonQueryWithValidTimeZoneHeaderV2() throws Exception { |
| 2400 | + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); |
| 2401 | + try { |
| 2402 | + nonQueryWithTimeZone( |
| 2403 | + httpClient, |
| 2404 | + "{\"sql\":\"CREATE TIMESERIES root.sg.d1.s1 WITH DATATYPE=INT32\"}", |
| 2405 | + "Europe/Warsaw"); |
| 2406 | + nonQueryWithTimeZone( |
| 2407 | + httpClient, |
| 2408 | + "{\"sql\":\"INSERT INTO root.sg.d1(time, s1) VALUES (2026-03-28T00:00:00, 123)\"}", |
| 2409 | + "Europe/Warsaw"); |
| 2410 | + |
| 2411 | + HttpPost queryPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); |
| 2412 | + queryPost.setEntity( |
| 2413 | + new StringEntity("{\"sql\":\"SELECT s1 FROM root.sg.d1\"}", StandardCharsets.UTF_8)); |
| 2414 | + try (CloseableHttpResponse resp = httpClient.execute(queryPost)) { |
| 2415 | + String message = EntityUtils.toString(resp.getEntity(), StandardCharsets.UTF_8); |
| 2416 | + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); |
| 2417 | + long expected = |
| 2418 | + ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0, ZoneId.of("Europe/Warsaw")) |
| 2419 | + .toInstant() |
| 2420 | + .toEpochMilli(); |
| 2421 | + assertEquals(expected, result.getAsJsonArray("timestamps").get(0).getAsLong()); |
| 2422 | + } |
| 2423 | + } finally { |
| 2424 | + try { |
| 2425 | + httpClient.close(); |
| 2426 | + } catch (IOException e) { |
| 2427 | + } |
| 2428 | + } |
| 2429 | + } |
| 2430 | + |
| 2431 | + @Test |
| 2432 | + public void testQueryWithInvalidTimeZoneHeaderV2() { |
| 2433 | + CloseableHttpClient httpClient = HttpClientBuilder.create().build(); |
| 2434 | + try { |
| 2435 | + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/query"); |
| 2436 | + httpPost.setHeader("X-TimeZone", "Invalid/Zone"); |
| 2437 | + String sql = "{\"sql\":\"SELECT s3 FROM root.sg25\"}"; |
| 2438 | + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); |
| 2439 | + CloseableHttpResponse response = executeWithRetry(httpPost, httpClient); |
| 2440 | + assertEquals(400, response.getStatusLine().getStatusCode()); |
| 2441 | + String message = EntityUtils.toString(response.getEntity(), "utf-8"); |
| 2442 | + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); |
| 2443 | + assertEquals(TSStatusCode.ILLEGAL_PARAMETER.getStatusCode(), result.get("code").getAsInt()); |
| 2444 | + assertTrue(result.get("message").getAsString().contains("Invalid time zone")); |
| 2445 | + } catch (IOException e) { |
| 2446 | + fail(e.getMessage()); |
| 2447 | + } finally { |
| 2448 | + try { |
| 2449 | + httpClient.close(); |
| 2450 | + } catch (IOException e) { |
| 2451 | + } |
| 2452 | + } |
| 2453 | + } |
| 2454 | + |
| 2455 | + private void nonQueryWithTimeZone(CloseableHttpClient httpClient, String json, String timeZone) { |
| 2456 | + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/nonQuery"); |
| 2457 | + httpPost.setHeader("X-TimeZone", timeZone); |
| 2458 | + httpPost.setEntity(new StringEntity(json, StandardCharsets.UTF_8)); |
| 2459 | + try (CloseableHttpResponse response = executeWithRetry(httpPost, httpClient)) { |
| 2460 | + String message = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8); |
| 2461 | + JsonObject result = JsonParser.parseString(message).getAsJsonObject(); |
| 2462 | + assertEquals(200, result.get("code").getAsInt()); |
| 2463 | + } catch (IOException e) { |
| 2464 | + fail(e.getMessage()); |
| 2465 | + } |
| 2466 | + } |
| 2467 | + |
| 2468 | + private CloseableHttpResponse executeWithRetry(HttpPost httpPost, CloseableHttpClient httpClient) |
| 2469 | + throws IOException { |
| 2470 | + CloseableHttpResponse response = null; |
| 2471 | + for (int i = 0; i < 30; i++) { |
| 2472 | + try { |
| 2473 | + response = httpClient.execute(httpPost); |
| 2474 | + break; |
| 2475 | + } catch (Exception e) { |
| 2476 | + if (i == 29) throw e; |
| 2477 | + try { |
| 2478 | + Thread.sleep(1000); |
| 2479 | + } catch (InterruptedException ex) { |
| 2480 | + throw new RuntimeException(ex); |
| 2481 | + } |
| 2482 | + } |
| 2483 | + } |
| 2484 | + return response; |
| 2485 | + } |
2357 | 2486 | } |
0 commit comments