mirror of
https://github.com/hanzoai/datastore.git
synced 2026-09-26 13:55:07 +00:00
Fix two issues causing flaky failures in `test_keeper_java_client`: 1. `test_remove_watches`: The Java watcher was counting all event types including asynchronous `PersistentWatchRemoved` notifications generated by the ZK 3.8 client when `removeAllWatches` succeeds. This caused a race between the EventThread delivering the removal event and the main thread capturing `countBefore`. Fix: filter to only count `NodeDataChanged` events. 2. `test_addwatch` (and all tests): The Java client resolved `localhost` to IPv6 `[::1]` first, but the Docker container's Keeper was not reachable on IPv6, causing `Connection refused`. The 10s connect timeout expired before the client retried on IPv4. Fix: use the container IP via `cluster.get_instance_ip` instead of `localhost`, matching the pattern used by `test_paimon_rest_catalog`. https://s3.amazonaws.com/clickhouse-test-reports/json.html?REF=master&sha=d67a6f693a4deabb3f90936c12c35cd5ced61bf3&name_0=MasterCI&name_1=Integration%20tests%20%28amd_binary%2C%203%2F5%29 https://s3.amazonaws.com/clickhouse-test-reports/json.html?REF=master&sha=4fe25262e1c78bd7b61df6ca18df0fd1586742b1&name_0=MasterCI&name_1=Integration%20tests%20%28amd_binary%2C%202%2F5%29 Co-Authored-By: Claude Opus 4.6 <[email protected]>
115 lines
3.3 KiB
Python
115 lines
3.3 KiB
Python
"""
|
|
Test ClickHouse Keeper compatibility with the Java ZooKeeper client.
|
|
|
|
Specifically tests all watch-related request types that require correct
|
|
response serialization:
|
|
- addWatch (OpCode 106): PERSISTENT and PERSISTENT_RECURSIVE modes
|
|
- checkWatches (OpCode 17): verify watch existence
|
|
- removeWatches (OpCode 18): remove all watches of a type
|
|
- setWatches (OpCode 101): re-establish watches (data/exist/child)
|
|
- setWatches2 (OpCode 105): re-establish watches including persistent
|
|
|
|
See https://github.com/ClickHouse/ClickHouse/issues/98079
|
|
"""
|
|
|
|
import os
|
|
|
|
import pytest
|
|
|
|
from helpers import keeper_utils
|
|
from helpers.cluster import ClickHouseCluster, run_and_check
|
|
|
|
SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
|
|
|
|
cluster = ClickHouseCluster(__file__)
|
|
node = cluster.add_instance(
|
|
"node",
|
|
main_configs=["configs/keeper_config.xml"],
|
|
stay_alive=True,
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def started_cluster():
|
|
try:
|
|
cluster.start()
|
|
keeper_utils.wait_until_connected(cluster, node)
|
|
yield cluster
|
|
finally:
|
|
cluster.shutdown()
|
|
|
|
|
|
def run_java_test(test_name):
|
|
"""Copy JAR to container and run a specific Java test."""
|
|
instance_id = cluster.get_instance_docker_id("node")
|
|
instance_ip = cluster.get_instance_ip("node")
|
|
jar_path = os.path.join(SCRIPT_DIR, "java_client", "keeper-java-client-test.jar")
|
|
|
|
run_and_check(
|
|
[
|
|
"docker cp {local} {cont_id}:{dist}".format(
|
|
local=jar_path,
|
|
cont_id=instance_id,
|
|
dist="/tmp/keeper-java-client-test.jar",
|
|
)
|
|
],
|
|
shell=True,
|
|
)
|
|
|
|
result = run_and_check(
|
|
[
|
|
'docker exec {cont_id} bash -lc "java -jar /tmp/keeper-java-client-test.jar {ip}:9181 {test}"'.format(
|
|
cont_id=instance_id,
|
|
ip=instance_ip,
|
|
test=test_name,
|
|
)
|
|
],
|
|
shell=True,
|
|
)
|
|
|
|
print(result)
|
|
assert "FAIL" not in result, f"Java test '{test_name}' had failures:\n{result}"
|
|
assert "Results:" in result, f"Java test '{test_name}' did not produce results:\n{result}"
|
|
|
|
|
|
def test_addwatch(started_cluster):
|
|
"""Test addWatch with PERSISTENT and PERSISTENT_RECURSIVE modes.
|
|
|
|
This is the primary regression test for issue #98079: the Java ZooKeeper
|
|
client expects an ErrorResponse body (4-byte error code) in the addWatch
|
|
response. Without it, the client gets EOFException and disconnects.
|
|
"""
|
|
run_java_test("addWatch")
|
|
|
|
|
|
def test_check_watches(started_cluster):
|
|
"""Test checkWatches (OpCode 17): verify a watch exists on a path.
|
|
|
|
The server sends no body for this response (just ReplyHeader).
|
|
"""
|
|
run_java_test("checkWatches")
|
|
|
|
|
|
def test_remove_watches(started_cluster):
|
|
"""Test removeWatches (OpCode 18): remove all watches of a given type.
|
|
|
|
The server sends no body for this response (just ReplyHeader).
|
|
"""
|
|
run_java_test("removeWatches")
|
|
|
|
|
|
def test_set_watches(started_cluster):
|
|
"""Test setWatches (OpCode 101): data/exist/child watch lists.
|
|
|
|
The server sends no body for this response (just ReplyHeader).
|
|
"""
|
|
run_java_test("setWatches")
|
|
|
|
|
|
def test_set_watches2(started_cluster):
|
|
"""Test setWatches2 (OpCode 105): watches including persistent watches.
|
|
|
|
The server sends no body for this response (just ReplyHeader).
|
|
"""
|
|
run_java_test("setWatches2")
|