mirror of
https://github.com/hanzoai/datastore.git
synced 2026-09-26 13:55:07 +00:00
Configures ruff via [tool.ruff] in pyproject.toml and wires it into the existing style-test job in ci/jobs/check_style.py. The initial rule set is narrow on purpose - only rules whose every hit is a real bug or unreachable reference: - F402 import-shadowed-by-loop-var - F522/F523 unused .format args - F601 duplicate dict-literal keys - F632 is comparison with a literal - F811 redefinition of an unused name (silently shadowed tests, duplicate route handlers, etc.) - F821 undefined name (the PR #105159 class - undefined variable inside an f-string evaluated only on an error/diagnostic branch, masking the original failure with NameError) Stylistic rules (F401, F541, F841, F403, F405) are intentionally left off for follow-up cleanups so the initial signal is bug-class only. Bugs found and fixed by the initial run: F821 (same pattern as PR #105159): - ci/jobs/scripts/check_ci.py - commit_status_data referenced in an exception branch but never assigned - tests/fuzz/runner.py - PIPE referenced without `from subprocess import PIPE` - tests/integration/test_backup_restore_on_cluster_with_checksum_data_file_name/test.py - os.path.join with os not imported - tests/integration/test_database_iceberg/test.py - BASE_URL_DOCKER typo for BASE_URL - tests/integration/test_keeper_remove_acl/test.py - node_zk referenced in a finally cleanup that was unreachable; the bare except silently swallowed the NameError on every run - tests/integration/test_storage_delta_disks/test.py - missing `from helpers.config_cluster import minio_secret_key` F811 silently-shadowed tests (later def overwrites earlier): - test_disk_types::test_different_types - test_storage_s3::test_empty_file - test_executable_table_function - one of the two same-named functions renamed to test_executable_storage_* - test_storage_delta::test_partition_columns_3 - second def renamed to test_partition_columns_jumbled F811 dead route handler: - test_merge_tree_s3_failover endpoint had two `def fail_request`; the throttle one was unreachable, renamed to throttle_request F601 duplicate dict-literal keys with divergent values in test_storage_s3_queue/test_5.py - same setting specified twice with different values; cleaned up to make the intended value explicit F522/F523 .format-string drift - templates updated without dropping the corresponding args (test_jbod_ha, test_manipulate_statistics, test_mysql_protocol, test_storage_kafka, helpers/dictionary) F632 `assert error is ""` -> `==` in test_allow_feature_tier F402 loop variable named `field` shadowing `from dataclasses import field` in praktika/issue.py Plus auto-fixed duplicate imports across CI scripts and integration tests. Two cases use `# noqa: F821` for legitimate self-referential type annotations (TypeVar bound and nested dataclass forward reference) in praktika/utils.py and praktika/gh.py. Reference: https://github.com/ClickHouse/ClickHouse/pull/105159 Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
321 lines
12 KiB
Python
321 lines
12 KiB
Python
import pytest
|
|
|
|
from helpers.cluster import ClickHouseCluster
|
|
|
|
cluster = ClickHouseCluster(__file__)
|
|
instance = cluster.add_instance(
|
|
"instance",
|
|
main_configs=["configs/allow_feature_tier.xml"],
|
|
user_configs=[
|
|
"configs/users.d/users.xml",
|
|
],
|
|
stay_alive=True,
|
|
)
|
|
|
|
feature_tier_path = "/etc/clickhouse-server/config.d/allow_feature_tier.xml"
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def start_cluster():
|
|
try:
|
|
cluster.start()
|
|
yield cluster
|
|
finally:
|
|
cluster.shutdown()
|
|
|
|
|
|
def get_current_tier_value(instance):
|
|
query_with_current_tier_value = (
|
|
"SELECT value FROM system.server_settings where name = 'allow_feature_tier'"
|
|
)
|
|
return instance.query(query_with_current_tier_value).strip()
|
|
|
|
|
|
def test_allow_feature_tier_in_general_settings(start_cluster):
|
|
# We use these settings as an example. If it fails in the future because you've changed the tier of the setting
|
|
# please change it to another setting in the same tier. If there is none, feel free to comment out the test for that tier
|
|
query_with_experimental_setting = (
|
|
"SELECT 1 SETTINGS allow_experimental_time_series_table=1"
|
|
)
|
|
query_with_beta_setting = "SELECT 1 SETTINGS allow_experimental_lightweight_update=1"
|
|
|
|
assert "0" == get_current_tier_value(instance)
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
query_with_experimental_setting
|
|
)
|
|
assert error == ""
|
|
assert "1" == output.strip()
|
|
|
|
# Disable experimental settings
|
|
instance.replace_in_config(feature_tier_path, "0", "1")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "1" == get_current_tier_value(instance)
|
|
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
query_with_experimental_setting
|
|
)
|
|
assert output == ""
|
|
assert "Changes to EXPERIMENTAL settings are disabled" in error
|
|
|
|
output, error = instance.query_and_get_answer_with_error(query_with_beta_setting)
|
|
assert error == ""
|
|
assert "1" == output.strip()
|
|
|
|
# Disable experimental and beta settings
|
|
instance.replace_in_config(feature_tier_path, "1", "2")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "2" == get_current_tier_value(instance)
|
|
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
query_with_experimental_setting
|
|
)
|
|
assert output == ""
|
|
assert "Changes to EXPERIMENTAL settings are disabled" in error
|
|
|
|
output, error = instance.query_and_get_answer_with_error(query_with_beta_setting)
|
|
assert output == ""
|
|
assert "Changes to BETA settings are disabled" in error
|
|
|
|
# Leave the server as it was
|
|
instance.replace_in_config(feature_tier_path, "2", "0")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "0" == get_current_tier_value(instance)
|
|
|
|
|
|
def test_allow_feature_tier_in_mergetree_settings(start_cluster):
|
|
assert "0" == get_current_tier_value(instance)
|
|
instance.query("DROP TABLE IF EXISTS test_experimental")
|
|
|
|
# Disable experimental settings
|
|
instance.replace_in_config(feature_tier_path, "0", "1")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "1" == get_current_tier_value(instance)
|
|
|
|
query_with_experimental_mergetree_setting = """
|
|
CREATE TABLE test_experimental (uid String, version UInt32, is_deleted UInt8)
|
|
ENGINE = ReplacingMergeTree(version, is_deleted)
|
|
ORDER by (uid)
|
|
SETTINGS allow_experimental_replacing_merge_with_cleanup=1;
|
|
"""
|
|
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
query_with_experimental_mergetree_setting
|
|
)
|
|
assert output == ""
|
|
assert "Changes to EXPERIMENTAL settings are disabled" in error
|
|
|
|
# Go back
|
|
instance.replace_in_config(feature_tier_path, "1", "0")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "0" == get_current_tier_value(instance)
|
|
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
query_with_experimental_mergetree_setting
|
|
)
|
|
assert output == ""
|
|
assert error == ""
|
|
|
|
output = instance.query(
|
|
"SELECT engine_full FROM system.tables WHERE name = 'test_experimental'"
|
|
)
|
|
assert "allow_experimental_replacing_merge_with_cleanup" in output
|
|
|
|
# We now disable experimental settings and restart the server to confirm it boots correctly
|
|
instance.replace_in_config(feature_tier_path, "0", "1")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "1" == get_current_tier_value(instance)
|
|
|
|
instance.restart_clickhouse()
|
|
|
|
# After the reboot the table will be there
|
|
output = instance.query(
|
|
"SELECT engine_full FROM system.tables WHERE name = 'test_experimental'"
|
|
)
|
|
assert "allow_experimental_replacing_merge_with_cleanup" in output
|
|
|
|
# Creating a different table should not be possible
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"""
|
|
CREATE TABLE test_experimental_new (uid String, version UInt32, is_deleted UInt8)
|
|
ENGINE = ReplacingMergeTree(version, is_deleted)
|
|
ORDER by (uid)
|
|
SETTINGS allow_experimental_replacing_merge_with_cleanup=1;
|
|
"""
|
|
)
|
|
assert output == ""
|
|
assert "Changes to EXPERIMENTAL settings are disabled" in error
|
|
|
|
# Creating a different table and altering its settings to enable experimental should not be possible either
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"""
|
|
CREATE TABLE test_experimental_new (uid String, version UInt32, is_deleted UInt8)
|
|
ENGINE = ReplacingMergeTree(version, is_deleted)
|
|
ORDER by (uid);
|
|
"""
|
|
)
|
|
assert output == ""
|
|
assert error == ""
|
|
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"""
|
|
ALTER TABLE test_experimental_new MODIFY setting allow_experimental_replacing_merge_with_cleanup=1
|
|
"""
|
|
)
|
|
assert output == ""
|
|
assert "Changes to EXPERIMENTAL settings are disabled" in error
|
|
instance.query("DROP TABLE IF EXISTS test_experimental_new")
|
|
|
|
instance.replace_in_config(feature_tier_path, "1", "0")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "0" == get_current_tier_value(instance)
|
|
instance.query("DROP TABLE IF EXISTS test_experimental")
|
|
|
|
|
|
def test_allow_feature_tier_in_mergetree_settings_with_old_compatibility(start_cluster):
|
|
assert "0" == get_current_tier_value(instance)
|
|
instance.query("DROP TABLE IF EXISTS test_experimental")
|
|
|
|
# Disable experimental settings
|
|
instance.replace_in_config(feature_tier_path, "0", "1")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "1" == get_current_tier_value(instance)
|
|
|
|
basic_merge_tree_query = """
|
|
create table b (a Int64) ENGINE=MergeTree() order by a;
|
|
"""
|
|
|
|
output, error = instance.query_and_get_answer_with_error(basic_merge_tree_query)
|
|
assert output == ""
|
|
assert error == ""
|
|
|
|
# Go back
|
|
instance.replace_in_config(feature_tier_path, "1", "0")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "0" == get_current_tier_value(instance)
|
|
instance.query("DROP TABLE IF EXISTS b")
|
|
|
|
|
|
def test_allow_feature_tier_in_user(start_cluster):
|
|
instance.query("DROP USER IF EXISTS user_experimental")
|
|
assert "0" == get_current_tier_value(instance)
|
|
|
|
# Disable experimental settings
|
|
instance.replace_in_config(feature_tier_path, "0", "1")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "1" == get_current_tier_value(instance)
|
|
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"CREATE USER user_experimental IDENTIFIED WITH no_password SETTINGS allow_experimental_time_series_table = 1"
|
|
)
|
|
assert output == ""
|
|
assert "Changes to EXPERIMENTAL settings are disabled" in error
|
|
|
|
# Go back to normal and create the user to restart the server and verify it works
|
|
instance.replace_in_config(feature_tier_path, "1", "0")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "0" == get_current_tier_value(instance)
|
|
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"CREATE USER user_experimental IDENTIFIED WITH no_password SETTINGS allow_experimental_time_series_table = 1"
|
|
)
|
|
assert output == ""
|
|
assert error == ""
|
|
|
|
# Default user = 0
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"SELECT value FROM system.settings WHERE name = 'allow_experimental_time_series_table'"
|
|
)
|
|
assert output.strip() == "0"
|
|
assert error == ""
|
|
|
|
# New user = 1
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"SELECT value FROM system.settings WHERE name = 'allow_experimental_time_series_table'",
|
|
user="user_experimental",
|
|
)
|
|
assert output.strip() == "1"
|
|
assert error == ""
|
|
|
|
# Change back to block experimental features and restart to confirm everything is working as expected (only new changes are blocked)
|
|
instance.replace_in_config(feature_tier_path, "0", "1")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "1" == get_current_tier_value(instance)
|
|
|
|
instance.restart_clickhouse()
|
|
|
|
# Default user = 0
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"SELECT value FROM system.settings WHERE name = 'allow_experimental_time_series_table'"
|
|
)
|
|
assert output.strip() == "0"
|
|
assert error == ""
|
|
|
|
# New user = 1
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"SELECT value FROM system.settings WHERE name = 'allow_experimental_time_series_table'",
|
|
user="user_experimental",
|
|
)
|
|
assert output.strip() == "1"
|
|
assert error == ""
|
|
|
|
# But note that they can't change the value either
|
|
# 1 - 1 => OK
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"SELECT 1 SETTINGS allow_experimental_time_series_table=1",
|
|
user="user_experimental",
|
|
)
|
|
assert output.strip() == "1"
|
|
assert error == ""
|
|
# 1 - 0 => KO
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"SELECT 1 SETTINGS allow_experimental_time_series_table=0",
|
|
user="user_experimental",
|
|
)
|
|
assert output == ""
|
|
assert "Changes to EXPERIMENTAL settings are disabled" in error
|
|
|
|
instance.replace_in_config(feature_tier_path, "1", "0")
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "0" == get_current_tier_value(instance)
|
|
instance.query("DROP USER IF EXISTS user_experimental")
|
|
|
|
|
|
def test_it_is_possible_to_enable_experimental_settings_in_default_profile(
|
|
start_cluster,
|
|
):
|
|
# You can disable changing experimental settings but changing the default value via global config file is ok
|
|
# It will just make the default value different and block changes
|
|
instance.replace_in_config(feature_tier_path, "0", "2")
|
|
|
|
# Change default user config
|
|
instance.replace_in_config(
|
|
"/etc/clickhouse-server/users.d/users.xml",
|
|
"allow_experimental_time_series_table>.",
|
|
"allow_experimental_time_series_table>1",
|
|
)
|
|
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "2" == get_current_tier_value(instance)
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"SELECT value FROM system.settings WHERE name = 'allow_experimental_time_series_table'"
|
|
)
|
|
assert output.strip() == "1"
|
|
assert error == ""
|
|
|
|
# But it won't be possible to change it
|
|
output, error = instance.query_and_get_answer_with_error(
|
|
"SELECT 1 SETTINGS allow_experimental_time_series_table=0"
|
|
)
|
|
assert output == ""
|
|
assert "Changes to EXPERIMENTAL settings are disabled" in error
|
|
|
|
instance.replace_in_config(feature_tier_path, "2", "0")
|
|
instance.replace_in_config(
|
|
"/etc/clickhouse-server/users.d/users.xml",
|
|
"allow_experimental_time_series_table>.",
|
|
"allow_experimental_time_series_table>0",
|
|
)
|
|
|
|
instance.query("SYSTEM RELOAD CONFIG")
|
|
assert "0" == get_current_tier_value(instance)
|