|
20 | 20 | klm,1,""" |
21 | 21 |
|
22 | 22 |
|
| 23 | +def _is_valid_uuid_v4(id_string: str) -> bool: |
| 24 | + """Helper function to validate that a string is a valid UUID v4""" |
| 25 | + try: |
| 26 | + parsed_uuid = uuid.UUID(id_string) |
| 27 | + return parsed_uuid.version == 4 |
| 28 | + except (ValueError, AttributeError): |
| 29 | + return False |
| 30 | + |
| 31 | + |
23 | 32 | def test_ping(test_client: Client): |
24 | 33 | assert test_client.ping() is True |
25 | 34 |
|
@@ -388,41 +397,75 @@ def test_role_setting_works(test_client: Client, test_config: TestConfig): |
388 | 397 | assert res.result_rows == [([role_limited],)] |
389 | 398 |
|
390 | 399 |
|
391 | | -# pylint: disable=protected-access |
392 | | -def test_autogenerate_query_id(test_client: Client, test_table_engine: str, test_config: TestConfig): |
393 | | - def _is_valid_uuid_v4_string(id_string: str) -> bool: |
394 | | - parsed_uuid = uuid.UUID(id_string) |
395 | | - return parsed_uuid.version == 4 |
396 | | - |
| 400 | +def test_query_id_autogeneration(test_client: Client, test_table_engine: str): |
| 401 | + """Test that query_id is auto-generated for query(), command(), and insert() methods""" |
397 | 402 | result = test_client.query("SELECT 1") |
398 | | - assert _is_valid_uuid_v4_string(result.query_id) |
| 403 | + assert _is_valid_uuid_v4(result.query_id) |
399 | 404 |
|
400 | | - manual_query_id = "test_manual_query_id_12345" |
401 | | - result = test_client.query("SELECT 2", settings={"query_id": manual_query_id}) |
402 | | - assert result.query_id == manual_query_id |
| 405 | + summary = test_client.command("DROP TABLE IF EXISTS test_query_id_nonexistent") |
| 406 | + assert _is_valid_uuid_v4(summary.query_id()) |
403 | 407 |
|
404 | | - summary = test_client.command("DROP TABLE IF EXISTS does_not_exist") |
405 | | - assert _is_valid_uuid_v4_string(summary.query_id()) |
| 408 | + test_client.command("DROP TABLE IF EXISTS test_query_id_insert") |
| 409 | + test_client.command(f"CREATE TABLE test_query_id_insert (id UInt32) ENGINE {test_table_engine} ORDER BY id") |
| 410 | + summary = test_client.insert("test_query_id_insert", [[1], [2], [3]], column_names=["id"]) |
| 411 | + assert _is_valid_uuid_v4(summary.query_id()) |
| 412 | + test_client.command("DROP TABLE test_query_id_insert") |
| 413 | + |
| 414 | + |
| 415 | +def test_query_id_manual_override(test_client: Client): |
| 416 | + """Test that manually specified query_id is respected and not overwritten""" |
| 417 | + manual_query_id = "test_manual_query_id_override" |
| 418 | + result = test_client.query("SELECT 1", settings={"query_id": manual_query_id}) |
| 419 | + assert result.query_id == manual_query_id |
406 | 420 |
|
407 | | - test_client.command("DROP TABLE IF EXISTS test_autogen_query_id") |
408 | | - test_client.command(f"CREATE TABLE test_autogen_query_id (id UInt32) ENGINE {test_table_engine} ORDER BY id") |
409 | | - summary = test_client.insert("test_autogen_query_id", [[1], [2], [3]], column_names=["id"]) |
410 | | - assert _is_valid_uuid_v4_string(summary.query_id()) |
411 | | - test_client.command("DROP TABLE test_autogen_query_id") |
412 | 421 |
|
413 | | - # Create client with autogenerate_query_id disabled |
| 422 | +# pylint: disable=protected-access |
| 423 | +def test_query_id_disabled(test_config: TestConfig): |
| 424 | + """Test that autogenerate_query_id=False works correctly""" |
414 | 425 | client_no_autogen = create_client( |
415 | 426 | host=test_config.host, |
416 | 427 | port=test_config.port, |
417 | 428 | username=test_config.username, |
418 | 429 | password=test_config.password, |
419 | 430 | autogenerate_query_id=False, |
420 | 431 | ) |
421 | | - result = client_no_autogen.query("SELECT 4") |
422 | | - # Even with autogen disabled the server generates a query_id |
423 | | - # so we still expect a query_id in the result, it's just generated by the server... |
424 | | - # not sure how to verify that specifically though. |
425 | | - assert _is_valid_uuid_v4_string(result.query_id) |
426 | 432 |
|
427 | | - # We can verify that the setting on the client is False though |
428 | 433 | assert client_no_autogen._autogenerate_query_id is False |
| 434 | + |
| 435 | + # Even with autogen disabled, server generates a query_id |
| 436 | + result = client_no_autogen.query("SELECT 1") |
| 437 | + assert _is_valid_uuid_v4(result.query_id) |
| 438 | + |
| 439 | + client_no_autogen.close() |
| 440 | + |
| 441 | + |
| 442 | +def test_query_id_in_query_logs(test_client: Client, test_config: TestConfig): |
| 443 | + """Test that query_id appears in ClickHouse's system.query_log for observability""" |
| 444 | + if test_config.cloud: |
| 445 | + pytest.skip("Skipping query_log test in cloud environment") |
| 446 | + |
| 447 | + def check_in_logs(test_query_id): |
| 448 | + max_retries = 30 |
| 449 | + for _ in range(max_retries): |
| 450 | + log_result = test_client.query( |
| 451 | + f"SELECT query_id FROM system.query_log WHERE query_id = '{test_query_id}' AND " "event_time > now() - 30 LIMIT 1" |
| 452 | + ) |
| 453 | + |
| 454 | + if len(log_result.result_set) > 0: |
| 455 | + assert log_result.result_set[0][0] == test_query_id |
| 456 | + return |
| 457 | + |
| 458 | + sleep(0.1) |
| 459 | + |
| 460 | + # If we get here, query_id never appeared in logs |
| 461 | + pytest.fail(f"query_id '{test_query_id}' did not appear in system.query_log after {max_retries * 0.1}s") |
| 462 | + |
| 463 | + # Manual override check |
| 464 | + test_query_id_manual = "test_query_id_in_logs" |
| 465 | + test_client.query("SELECT 1 as num", settings={"query_id": test_query_id_manual}) |
| 466 | + check_in_logs(test_query_id_manual) |
| 467 | + |
| 468 | + # Autogen check |
| 469 | + result = test_client.query("SELECT 2 as num") |
| 470 | + test_query_id_auto = result.query_id |
| 471 | + check_in_logs(test_query_id_auto) |
0 commit comments