diff --git a/tests/config/config.d/storage_conf.xml b/tests/config/config.d/storage_conf.xml index f046b9c31dce..1f80b8ae05a4 100644 --- a/tests/config/config.d/storage_conf.xml +++ b/tests/config/config.d/storage_conf.xml @@ -112,7 +112,13 @@ default - s3_disk + + + s3_disk + 0 + diff --git a/tests/integration/test_hedged_requests/test.py b/tests/integration/test_hedged_requests/test.py index 1aafc1aadafa..6c53ef01a5d4 100644 --- a/tests/integration/test_hedged_requests/test.py +++ b/tests/integration/test_hedged_requests/test.py @@ -7,6 +7,7 @@ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from helpers.cluster import ClickHouseCluster +from helpers.network import PartitionManager from helpers.test_tools import TSV cluster = ClickHouseCluster(__file__) @@ -429,28 +430,46 @@ def test_async_connect(started_cluster): Distributed('test_cluster_connect', 'default', 'test_hedged')""" ) - NODES["node"].query( - "SELECT hostName(), id FROM distributed_connect ORDER BY id LIMIT 1 SETTINGS prefer_localhost_replica = 0, connect_timeout_with_failover_ms=5000, async_query_sending_for_remote=0, max_threads=1, max_distributed_connections=1" - ) - check_changing_replica_events(2) - check_if_query_sending_was_not_suspended() - - # Restart server to reset connection pool state - NODES["node"].restart_clickhouse() + # The first replica of each shard in test_cluster_connect is an unreachable + # address (129.0.0.1 / 129.0.0.2). Silently drop the initiator's packets to + # them so the connect always stalls and is preempted by the + # hedged_connection_timeout_ms timer (the path HedgedRequestsChangeReplica + # counts). Otherwise, on slow builds the connect can fail fast (host + # unreachable), switching the replica through the connection-failure path, + # which does not increment that event. + with PartitionManager() as pm: + for unreachable_ip in ("129.0.0.1", "129.0.0.2"): + pm.add_rule( + { + "instance": NODES["node"], + "chain": "OUTPUT", + "destination": unreachable_ip, + "action": "DROP", + } + ) - attempt = 0 - while attempt < 100: NODES["node"].query( - "SELECT hostName(), id FROM distributed_connect ORDER BY id LIMIT 1 SETTINGS prefer_localhost_replica = 0, connect_timeout_with_failover_ms=5000, async_query_sending_for_remote=1, max_threads=1, max_distributed_connections=1" + "SELECT hostName(), id FROM distributed_connect ORDER BY id LIMIT 1 SETTINGS prefer_localhost_replica = 0, connect_timeout_with_failover_ms=5000, async_query_sending_for_remote=0, max_threads=1, max_distributed_connections=1" ) - check_changing_replica_events(2) - if check_if_query_sending_was_suspended(): - break + check_if_query_sending_was_not_suspended() - attempt += 1 + # Restart server to reset connection pool state + NODES["node"].restart_clickhouse() - assert attempt < 100 + attempt = 0 + while attempt < 100: + NODES["node"].query( + "SELECT hostName(), id FROM distributed_connect ORDER BY id LIMIT 1 SETTINGS prefer_localhost_replica = 0, connect_timeout_with_failover_ms=5000, async_query_sending_for_remote=1, max_threads=1, max_distributed_connections=1" + ) + + check_changing_replica_events(2) + if check_if_query_sending_was_suspended(): + break + + attempt += 1 + + assert attempt < 100 NODES["node"].query("DROP TABLE distributed_connect") diff --git a/tests/integration/test_keeper_auth/test.py b/tests/integration/test_keeper_auth/test.py index 68a1c95e7d5c..ebf78ab4d6b3 100644 --- a/tests/integration/test_keeper_auth/test.py +++ b/tests/integration/test_keeper_auth/test.py @@ -61,6 +61,22 @@ def zk_stop_and_close(zk): zk.close() +# ZooKeeper checks delete against the PARENT's ACL, and its setACL leaves the +# outstanding change record carrying the old ACL (duplicate() copies acl verbatim +# and updates only stat.aversion), so a delete issued right after a widening +# setACL can still be authorized against the pre-setACL ACL and get NoAuthError. +def zk_delete_after_acl_change(zk, path, timeout=30.0): + deadline = time.monotonic() + timeout + while True: + try: + zk.delete(path) + return + except NoAuthError: + if time.monotonic() >= deadline: + raise + time.sleep(0.1) + + @pytest.mark.parametrize(("get_zk"), [get_genuine_zk, get_fake_zk]) def test_remove_acl(started_cluster, get_zk): auth_connection = None @@ -412,7 +428,9 @@ def test_partial_auth(started_cluster, get_zk): ) auth_connection.set_acls("/test_partial_acl_delete", acls=[acl]) auth_connection.set_acls("/test_partial_acl_delete/subnode", acls=[acl]) - auth_connection.delete("/test_partial_acl_delete/subnode") + zk_delete_after_acl_change(auth_connection, "/test_partial_acl_delete/subnode") + # Authorized against "/", whose ACL this test never touches, so a + # NoAuthError here would be a real problem: do not retry it. auth_connection.delete("/test_partial_acl_delete") zk_stop_and_close(auth_connection) diff --git a/tests/integration/test_named_collections_encrypted2/test.py b/tests/integration/test_named_collections_encrypted2/test.py index aaa0d7989982..b7e29e127b4c 100644 --- a/tests/integration/test_named_collections_encrypted2/test.py +++ b/tests/integration/test_named_collections_encrypted2/test.py @@ -62,6 +62,7 @@ def wait_not_exists(node, collection, timeout=10): def check_encrypted(zk, collection): + zk.sync(ZK_PATH) content = zk.get(f"{ZK_PATH}/{collection}.sql")[0] assert content[:3] == b"ENC" return content @@ -717,6 +718,7 @@ def test_new_replica_encrypted_data_integrity(stopped_node3): password='P@ssw0rd!Complex#123' """) + zk.sync(ZK_PATH) content = zk.get(f"{ZK_PATH}/encrypted_coll.sql")[0] assert content[:3] == b"ENC" assert b"super_secret_api_key_12345" not in content diff --git a/tests/integration/test_replication_credentials/test.py b/tests/integration/test_replication_credentials/test.py index e1ce61067d94..44df4ccd4f15 100644 --- a/tests/integration/test_replication_credentials/test.py +++ b/tests/integration/test_replication_credentials/test.py @@ -46,13 +46,13 @@ def same_credentials_cluster(): def test_same_credentials(same_credentials_cluster): node1.query("insert into test_table values ('2017-06-16', 111, 0)") - time.sleep(1) + node2.query("SYSTEM SYNC REPLICA test_table", timeout=60) assert node1.query("SELECT id FROM test_table order by id") == "111\n" assert node2.query("SELECT id FROM test_table order by id") == "111\n" node2.query("insert into test_table values ('2017-06-17', 222, 1)") - time.sleep(1) + node1.query("SYSTEM SYNC REPLICA test_table", timeout=60) assert node1.query("SELECT id FROM test_table order by id") == "111\n222\n" assert node2.query("SELECT id FROM test_table order by id") == "111\n222\n" @@ -85,13 +85,13 @@ def no_credentials_cluster(): def test_no_credentials(no_credentials_cluster): node3.query("insert into test_table values ('2017-06-18', 111, 0)") - time.sleep(1) + node4.query("SYSTEM SYNC REPLICA test_table", timeout=60) assert node3.query("SELECT id FROM test_table order by id") == "111\n" assert node4.query("SELECT id FROM test_table order by id") == "111\n" node4.query("insert into test_table values ('2017-06-19', 222, 1)") - time.sleep(1) + node3.query("SYSTEM SYNC REPLICA test_table", timeout=60) assert node3.query("SELECT id FROM test_table order by id") == "111\n222\n" assert node4.query("SELECT id FROM test_table order by id") == "111\n222\n" diff --git a/tests/integration/test_s3_table_functions/test.py b/tests/integration/test_s3_table_functions/test.py index b2dfddb23ebd..ec565de617ca 100644 --- a/tests/integration/test_s3_table_functions/test.py +++ b/tests/integration/test_s3_table_functions/test.py @@ -78,14 +78,25 @@ def test_s3_table_functions(started_cluster): def test_s3_table_functions_timeouts(started_cluster): """ - Test with timeout limit of 1200ms. - This should raise an Exception and pass. + A 1200ms network delay must make the S3 write time out and raise. """ + # Make the S3 request timeout (not the connect timeout) the single failure mechanism: + # disable adaptive timeouts and keep the connect timeout above the delay, so the write + # can only fail via s3_request_timeout_ms. This exercises the send/receive idleness + # timeout that applies to every attempt on both fresh and reused (pooled keep-alive) + # connections, which is the path that was silently not timing out before. + timeout_settings = { + **settings, + "s3_use_adaptive_timeouts": "0", + "s3_connect_timeout_ms": "10000", + "s3_request_timeout_ms": "500", + } + with PartitionManager() as pm: pm.add_network_delay(node, 1200) - with pytest.raises(QueryRuntimeException): + with pytest.raises(QueryRuntimeException, match="Timeout"): node.query( """ INSERT INTO FUNCTION s3 @@ -98,5 +109,5 @@ def test_s3_table_functions_timeouts(started_cluster): ) SELECT * FROM numbers(1000000) """, - settings=settings, + settings=timeout_settings, ) diff --git a/tests/integration/test_storage_kafka/test_batch_fast.py b/tests/integration/test_storage_kafka/test_batch_fast.py index c9705f2eafdb..5608582281f5 100644 --- a/tests/integration/test_storage_kafka/test_batch_fast.py +++ b/tests/integration/test_storage_kafka/test_batch_fast.py @@ -2081,10 +2081,19 @@ def test_kafka_flush_by_time(kafka_cluster, create_query_generator): cancel = threading.Event() + # Reuse one producer: `k.kafka_produce` opens a new connection per call, + # and a single broker-version probe there can cost seconds, which is + # enough to miss the row count asserted below. + producer = k.get_kafka_producer( + kafka_cluster.kafka_port, k.producer_serializer, retries=15 + ) + def produce(): while not cancel.is_set(): - messages = [json.dumps({"key": 0, "value": 0})] - k.kafka_produce(kafka_cluster, topic_name, messages) + producer.send( + topic=topic_name, value=json.dumps({"key": 0, "value": 0}) + ) + producer.flush() time.sleep(0.8) kafka_thread = threading.Thread(target=produce) @@ -2102,6 +2111,7 @@ def produce(): cancel.set() kafka_thread.join() + producer.close() instance.query(f""" DROP TABLE test.{kafka_table}_consumer; diff --git a/tests/integration/test_storage_kafka/test_batch_slow_0.py b/tests/integration/test_storage_kafka/test_batch_slow_0.py index 03e7297aa3dd..6f6393f0bd00 100644 --- a/tests/integration/test_storage_kafka/test_batch_slow_0.py +++ b/tests/integration/test_storage_kafka/test_batch_slow_0.py @@ -301,7 +301,6 @@ def test_kafka_formats_with_broken_message(kafka_cluster, create_query_generator data_prefix = data_prefix + [""] if format_opts.get("printable", False) == False: raw_message = "hex(_raw_message)" - k.kafka_produce(kafka_cluster, topic_name, data_prefix + data_sample) create_query = create_query_generator( f"kafka_{format_name}", "id Int64, blockNo UInt16, val1 String, val2 Float32, val3 UInt8", @@ -313,6 +312,10 @@ def test_kafka_formats_with_broken_message(kafka_cluster, create_query_generator "kafka_flush_interval_ms": 1000, }, ) + # Create both materialized views, then detach/re-attach the Kafka table, + # before producing any message. Creating the first view starts the + # streaming loop, so producing earlier lets the loop consume and commit + # the broken message before the errors view is attached, leaving it empty. instance.query( f""" DROP TABLE IF EXISTS test.kafka_{format_name}; @@ -328,8 +331,12 @@ def test_kafka_formats_with_broken_message(kafka_cluster, create_query_generator CREATE MATERIALIZED VIEW test.kafka_errors_{format_name}_mv ENGINE=MergeTree ORDER BY tuple() AS SELECT {raw_message} as raw_message, _error as error, _topic as topic, _partition as partition, _offset as offset FROM test.kafka_{format_name} WHERE length(_error) > 0; + + DETACH TABLE test.kafka_{format_name}; + ATTACH TABLE test.kafka_{format_name}; """ ) + k.kafka_produce(kafka_cluster, topic_name, data_prefix + data_sample) raw_expected = """\ 0 0 AM 0.5 1 {topic_name} 0 {offset_0} diff --git a/tests/integration/test_tcp_handler_connection_limits/test.py b/tests/integration/test_tcp_handler_connection_limits/test.py index ef9a35f40f2a..ac9ec0a4eddd 100644 --- a/tests/integration/test_tcp_handler_connection_limits/test.py +++ b/tests/integration/test_tcp_handler_connection_limits/test.py @@ -1,6 +1,5 @@ import pytest import subprocess -import time from helpers.cluster import ClickHouseCluster cluster = ClickHouseCluster(__file__) @@ -14,11 +13,6 @@ def started_cluster(): finally: cluster.shutdown() -@pytest.fixture(scope="module", autouse=True) -def stabilize_container(started_cluster): - """Wait for container startup processes to complete before running tests""" - time.sleep(1) - def execute_queries_persistent_connection(queries): """Execute multiple queries through a single persistent clickhouse-client connection""" proc = subprocess.Popen( @@ -34,17 +28,19 @@ def execute_queries_persistent_connection(queries): return stdout, stderr -def get_connection_done_count(): - try: - log_result = node.exec_in_container( - ["grep", "-c", "Done processing connection", "/var/log/clickhouse-server/clickhouse-server.log"] - ) - return int(log_result.strip()) - except Exception: - return 0 +def get_limit_closed_count(reason): + """Count the connections that the server closed because a limit was reached. + + Counting every closed connection instead would be racy: the readiness probe of + `cluster.start` connects to the port and closes it without sending any data, and the + server accepts that connection only once it starts serving, which can happen after the + test has already sampled the initial count. Connections closed for other reasons never + report a limit, so counting only those keeps the assertion exact. + """ + return int(node.count_in_log(f"Closing connection due to limits: {reason}").strip()) def test_query_count_limit(started_cluster): - initial_count = get_connection_done_count() + initial_count = get_limit_closed_count("queries=") queries = ["SELECT 1;", "SELECT 2;", "SELECT 3;", "SELECT 4;", "SELECT 5;"] stdout, stderr = execute_queries_persistent_connection(queries) @@ -53,11 +49,11 @@ def test_query_count_limit(started_cluster): assert "4" not in stdout and "5" not in stdout assert "TCP_CONNECTION_LIMIT_REACHED" in stderr - final_count = get_connection_done_count() + final_count = get_limit_closed_count("queries=") assert final_count == initial_count + 1, f"Expected exactly 1 connection closure, got {final_count - initial_count}" def test_time_limit(started_cluster): - initial_count = get_connection_done_count() + initial_count = get_limit_closed_count("elapsed=") queries = ["SELECT sleep(3);", "SELECT 1;", "SELECT 2;"] stdout, stderr = execute_queries_persistent_connection(queries) @@ -65,5 +61,5 @@ def test_time_limit(started_cluster): assert "1" not in stdout and "2" not in stdout assert "TCP_CONNECTION_LIMIT_REACHED" in stderr - final_count = get_connection_done_count() + final_count = get_limit_closed_count("elapsed=") assert final_count == initial_count + 1, f"Expected exactly 1 connection closure, got {final_count - initial_count}" diff --git a/tests/queries/0_stateless/01184_long_insert_values_huge_strings.sh b/tests/queries/0_stateless/01184_long_insert_values_huge_strings.sh index 8d41c32467d2..0973bf5d17d2 100755 --- a/tests/queries/0_stateless/01184_long_insert_values_huge_strings.sh +++ b/tests/queries/0_stateless/01184_long_insert_values_huge_strings.sh @@ -17,7 +17,8 @@ done; wait $CLICKHOUSE_CLIENT -q "select count() from huge_strings" -$CLICKHOUSE_CLIENT -q "select sum(l = length(s)) from huge_strings" -$CLICKHOUSE_CLIENT -q "select sum(h = cityHash64(s)) from huge_strings" +# Pin `max_threads`: each read stream holds its own buffer for a ~9 MB row of `s`, so the randomized 32-thread draw exceeds `max_memory_usage`. +$CLICKHOUSE_CLIENT -q "select sum(l = length(s)) from huge_strings SETTINGS max_threads = 3" +$CLICKHOUSE_CLIENT -q "select sum(h = cityHash64(s)) from huge_strings SETTINGS max_threads = 3" $CLICKHOUSE_CLIENT -q "drop table huge_strings" diff --git a/tests/queries/0_stateless/01661_extract_all_groups_throw_fast.sql b/tests/queries/0_stateless/01661_extract_all_groups_throw_fast.sql index afb6866a0df5..f16e83a6d0f5 100644 --- a/tests/queries/0_stateless/01661_extract_all_groups_throw_fast.sql +++ b/tests/queries/0_stateless/01661_extract_all_groups_throw_fast.sql @@ -1,2 +1,4 @@ -SELECT repeat('abcdefghijklmnopqrstuvwxyz', number * 100) AS haystack, extractAllGroupsHorizontal(haystack, '(\\w)') AS matches FROM numbers(1023); -- { serverError TOO_LARGE_ARRAY_SIZE } +-- 1001 matches in one row exceeds `regexp_max_matches_per_row` (default 1000) and trips the fast-throw. +-- The low `max_memory_usage` also guards against regressing to a huge fixture that could hit MEMORY_LIMIT_EXCEEDED first. +SELECT extractAllGroupsHorizontal(materialize(repeat('a', 1001)), '(\\w)') FORMAT Null SETTINGS max_memory_usage = 100000000; -- { serverError TOO_LARGE_ARRAY_SIZE } SELECT count(extractAllGroupsHorizontal(materialize('a'), '(a)')) FROM numbers(1000000) FORMAT Null; -- shouldn't fail diff --git a/tests/queries/0_stateless/02040_clickhouse_benchmark_query_id_pass_through.sh b/tests/queries/0_stateless/02040_clickhouse_benchmark_query_id_pass_through.sh index 59538534fa71..6d084cfd9858 100755 --- a/tests/queries/0_stateless/02040_clickhouse_benchmark_query_id_pass_through.sh +++ b/tests/queries/0_stateless/02040_clickhouse_benchmark_query_id_pass_through.sh @@ -6,6 +6,11 @@ CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) query_id="${CLICKHOUSE_DATABASE}_$$" benchmark_args=( + # A loaded runner can take longer than the default 10 s handshake_timeout_ms + # to send Hello; the benchmark then exits without running a query and + # query_log has 0 rows instead of 3. + --connect_timeout 60 + --handshake_timeout_ms 60000 --iterations 1 --log_queries 1 --query_id "$query_id" diff --git a/tests/queries/0_stateless/02423_ddl_for_opentelemetry.sh b/tests/queries/0_stateless/02423_ddl_for_opentelemetry.sh index 0dc7b7500797..ef1bff5d47d6 100755 --- a/tests/queries/0_stateless/02423_ddl_for_opentelemetry.sh +++ b/tests/queries/0_stateless/02423_ddl_for_opentelemetry.sh @@ -39,17 +39,31 @@ function check_span() extra_condition="" fi - ret=$(${CLICKHOUSE_CLIENT} -q " - SYSTEM FLUSH LOGS opentelemetry_span_log; - - SELECT count() - FROM system.opentelemetry_span_log - WHERE finish_date >= yesterday() - AND lower(hex(trace_id)) = '${2}' - AND operation_name like '${3}' - ${extra_condition};") - - if [ $ret = $1 ]; then + # A span is enqueued into the async opentelemetry_span_log only when its holder is + # destroyed, and the TCPHandler holder is destroyed after the client already has its + # answer, so a single flush+count can legitimately read a short count. Retry while the + # count is below the expectation; a non-numeric result (client or flush error) breaks + # out immediately, and the sleep budget is shared by the whole test so a genuinely + # broken assertion cannot multiply the added wall time by the number of call sites. + for _ in {1..30}; do + ret=$(${CLICKHOUSE_CLIENT} -q " + SYSTEM FLUSH LOGS opentelemetry_span_log; + + SELECT count() + FROM system.opentelemetry_span_log + WHERE finish_date >= yesterday() + AND lower(hex(trace_id)) = '${2}' + AND operation_name like '${3}' + ${extra_condition};") + + [[ "$ret" =~ ^[0-9]+$ ]] || break + [[ "$ret" -ge "$1" ]] && break + [[ "${span_poll_sleeps_left:-0}" -gt 0 ]] || break + span_poll_sleeps_left=$((span_poll_sleeps_left - 1)) + sleep 1 + done + + if [ "$ret" = "$1" ]; then echo 1 else echo "[operation_name like '${3}' ${extra_condition}]=$ret, expected: ${1}" @@ -79,6 +93,9 @@ cluster_name=$($CLICKHOUSE_CLIENT -q "select if(engine = 'Replicated', name, 'te # # Only format_version 4 enables the tracing # +# Total number of 1-second sleeps check_span may spend waiting for spans to be enqueued. +span_poll_sleeps_left=15 + for ddl_version in 3 4; do # Echo a separator so that the reference file is more clear for reading echo "===ddl_format_version ${ddl_version}====" diff --git a/tests/queries/0_stateless/02465_limit_trivial_max_rows_to_read.sql b/tests/queries/0_stateless/02465_limit_trivial_max_rows_to_read.sql index 700a54044271..2b6302292b2a 100644 --- a/tests/queries/0_stateless/02465_limit_trivial_max_rows_to_read.sql +++ b/tests/queries/0_stateless/02465_limit_trivial_max_rows_to_read.sql @@ -15,7 +15,10 @@ SELECT number FROM numbers(30) LIMIT 21; -- { serverError TOO_MANY_ROWS } SELECT number FROM numbers(30) LIMIT 1; SELECT number FROM numbers(5); -SELECT a FROM t_max_rows_to_read LIMIT 1; +-- Under parallel replicas this read is split into per-replica mark ranges, so an +-- ORDER-less LIMIT 1 may legally return any row (CI saw 32, the first row of the +-- second task). Project a constant: only `max_rows_to_read` is measured here. +SELECT 0 FROM t_max_rows_to_read LIMIT 1; SELECT a FROM t_max_rows_to_read LIMIT 11 offset 11; -- { serverError TOO_MANY_ROWS } SELECT a FROM t_max_rows_to_read WHERE a > 50 LIMIT 1; -- { serverError TOO_MANY_ROWS } diff --git a/tests/queries/0_stateless/02559_add_parts.reference b/tests/queries/0_stateless/02559_add_parts.reference index 50bd3725056e..845bf13dd8d9 100644 --- a/tests/queries/0_stateless/02559_add_parts.reference +++ b/tests/queries/0_stateless/02559_add_parts.reference @@ -1,4 +1,4 @@ 0 0 0 1 1 2 2 2 4 -2 1 2 +1 diff --git a/tests/queries/0_stateless/02559_add_parts.sql b/tests/queries/0_stateless/02559_add_parts.sql index 9f4e85a32589..b8f427a90537 100644 --- a/tests/queries/0_stateless/02559_add_parts.sql +++ b/tests/queries/0_stateless/02559_add_parts.sql @@ -16,5 +16,7 @@ SELECT parts, active_parts,total_marks FROM system.tables WHERE name = 'check_sy INSERT INTO check_system_tables VALUES (1, 2, 1); SELECT parts, active_parts,total_marks FROM system.tables WHERE name = 'check_system_tables' AND database = currentDatabase(); ALTER TABLE check_system_tables DETACH PARTITION 1; -SELECT parts, active_parts,total_marks FROM system.tables WHERE name = 'check_system_tables' AND database = currentDatabase(); +-- `parts` and `total_marks` count Outdated parts too, and reclamation after DETACH is best-effort, +-- so only `active_parts` is well defined here. +SELECT active_parts FROM system.tables WHERE name = 'check_system_tables' AND database = currentDatabase(); DROP TABLE IF EXISTS check_system_tables; diff --git a/tests/queries/0_stateless/02703_max_local_read_bandwidth.sh b/tests/queries/0_stateless/02703_max_local_read_bandwidth.sh index fb7f47613c1d..9a049fd34d7f 100755 --- a/tests/queries/0_stateless/02703_max_local_read_bandwidth.sh +++ b/tests/queries/0_stateless/02703_max_local_read_bandwidth.sh @@ -11,8 +11,10 @@ $CLICKHOUSE_CLIENT -m -q " create table data (key UInt64 CODEC(NONE)) engine=MergeTree() order by tuple() settings min_bytes_for_wide_part=1e9; " -# reading 1e6*8 bytes with 1M bandwith it should take (8-1)/1=7 seconds -$CLICKHOUSE_CLIENT -q "insert into data select * from numbers(1e6)" +# Reading 2e5*8 bytes at 160000 B/s takes 1.6e6/160000-1 = 9 seconds (-1 is the 1s token burst). +# The throttler only sleeps while the arrival rate exceeds the cap, so the cap must stay far +# below the natural read rate or the sleep assertion flaps on loaded runners. +$CLICKHOUSE_CLIENT -q "insert into data select * from numbers(2e5)" read_methods=( read @@ -25,14 +27,14 @@ read_methods=( ) for read_method in "${read_methods[@]}"; do query_id=$(random_str 10) - $CLICKHOUSE_CLIENT --query_id "$query_id" -q "select * from data format Null settings max_local_read_bandwidth='1M', local_filesystem_read_method='$read_method'" + $CLICKHOUSE_CLIENT --query_id "$query_id" -q "select * from data format Null settings max_local_read_bandwidth=160000, local_filesystem_read_method='$read_method'" $CLICKHOUSE_CLIENT -m -q " SYSTEM FLUSH LOGS query_log; SELECT '$read_method', query_duration_ms >= 7e3, - ProfileEvents['ReadBufferFromFileDescriptorReadBytes'] > 8e6, - ProfileEvents['QueryLocalReadThrottlerBytes'] > 8e6, + ProfileEvents['ReadBufferFromFileDescriptorReadBytes'] > 1.5e6, + ProfileEvents['QueryLocalReadThrottlerBytes'] > 1.5e6, ProfileEvents['QueryLocalReadThrottlerSleepMicroseconds'] > 7e6*0.5 FROM system.query_log WHERE event_date >= yesterday() AND event_time >= now() - 600 AND current_database = '$CLICKHOUSE_DATABASE' AND query_id = '$query_id' AND type != 'QueryStart' diff --git a/tests/queries/0_stateless/03100_lwu_15_future_reads.sh b/tests/queries/0_stateless/03100_lwu_15_future_reads.sh index 3c74ff76ba0d..518dce65dde0 100755 --- a/tests/queries/0_stateless/03100_lwu_15_future_reads.sh +++ b/tests/queries/0_stateless/03100_lwu_15_future_reads.sh @@ -26,7 +26,11 @@ $CLICKHOUSE_CLIENT --query " ORDER BY id SETTINGS enable_block_number_column = 1, - enable_block_offset_column = 1; + enable_block_offset_column = 1, + -- The test checks the number of rows in patch parts at the end. + -- Once the patches are applied, the cleanup thread is free to drop them, + -- so keep them around to make the last query deterministic. + remove_unused_patch_parts = 0; INSERT INTO t_lwu_future_reads SELECT number, number FROM numbers(1000); SYSTEM ENABLE FAILPOINT $failpoint_name; diff --git a/tests/queries/0_stateless/03356_analyzer_unused_scalar_subquery.sql b/tests/queries/0_stateless/03356_analyzer_unused_scalar_subquery.sql index cb8594046ad0..90242ab22a2d 100644 --- a/tests/queries/0_stateless/03356_analyzer_unused_scalar_subquery.sql +++ b/tests/queries/0_stateless/03356_analyzer_unused_scalar_subquery.sql @@ -1,16 +1,31 @@ +-- An unused scalar subquery or an unused `WITH` expression must not be evaluated, +-- so `throwIf` never fires. This is checked with `throwIf` rather than with a +-- timeout, because a timeout makes the test flaky on a loaded machine. + set enable_analyzer = 1; WITH ( - SELECT sleepEachRow(3) + SELECT throwIf(1) ) AS res SELECT * FROM system.one -FORMAT Null -SETTINGS max_execution_time = 2; +FORMAT Null; -WITH sleepEachRow(3) AS res +WITH throwIf(1) AS res SELECT * FROM system.one -FORMAT Null -SETTINGS max_execution_time = 2; +FORMAT Null; + +-- But it is evaluated when it is actually used. +WITH ( + SELECT throwIf(1) + ) AS res +SELECT res +FROM system.one +FORMAT Null; -- { serverError FUNCTION_THROW_IF_VALUE_IS_NON_ZERO } + +WITH throwIf(1) AS res +SELECT res +FROM system.one +FORMAT Null; -- { serverError FUNCTION_THROW_IF_VALUE_IS_NON_ZERO } diff --git a/tests/queries/0_stateless/03394_distributed_shuffle_join_with_aggregation.sql b/tests/queries/0_stateless/03394_distributed_shuffle_join_with_aggregation.sql index cdf868a409fc..9f196df7108b 100644 --- a/tests/queries/0_stateless/03394_distributed_shuffle_join_with_aggregation.sql +++ b/tests/queries/0_stateless/03394_distributed_shuffle_join_with_aggregation.sql @@ -14,6 +14,10 @@ INSERT INTO test SELECT 'path_' || number::String, 'en', number FROM numbers(5); INSERT INTO test SELECT 'path_' || (number%3)::String, 'de', number%4 FROM numbers(10); SET query_plan_join_swap_table = 0; +SET query_plan_optimize_join_order_randomize = 0; -- Pinned because the test asserts on join plan/order +-- Pinned because the test asserts that the runtime join filter is built; the default threshold +-- skips it when the probe side is estimated to be tiny. +SET join_runtime_filter_min_probe_rows = 0; SET optimize_move_to_prewhere = 1, diff --git a/tests/queries/0_stateless/03394_distributed_shuffle_join_with_in.sql b/tests/queries/0_stateless/03394_distributed_shuffle_join_with_in.sql index 6e7680024dc9..655401b1ec40 100644 --- a/tests/queries/0_stateless/03394_distributed_shuffle_join_with_in.sql +++ b/tests/queries/0_stateless/03394_distributed_shuffle_join_with_in.sql @@ -14,6 +14,10 @@ INSERT INTO test SELECT 'path_' || number::String, 'en', number FROM numbers(5); INSERT INTO test SELECT 'path_' || (number%3)::String, 'de', number%4 FROM numbers(10); SET query_plan_join_swap_table = 0; +SET query_plan_optimize_join_order_randomize = 0; -- Pinned because the test asserts on join plan/order +-- Pinned because the test asserts that the runtime join filter is built; the default threshold +-- skips it when the probe side is estimated to be tiny. +SET join_runtime_filter_min_probe_rows = 0; SET