* Adding rbac module

* Adding rbac syntax tests
This commit is contained in:
Vitaliy Zakaznikov 2020-07-21 13:51:02 -04:00
parent b26de8d2d1
commit 644ccd33cb
54 changed files with 11200 additions and 0 deletions

View File

View File

@ -0,0 +1,6 @@
<yandex>
<timezone>Europe/Moscow</timezone>
<listen_host replace="replace">0.0.0.0</listen_host>
<path>/var/lib/clickhouse/</path>
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
</yandex>

View File

@ -0,0 +1,17 @@
<yandex>
<shutdown_wait_unfinished>3</shutdown_wait_unfinished>
<logger>
<level>trace</level>
<log>/var/log/clickhouse-server/log.log</log>
<errorlog>/var/log/clickhouse-server/log.err.log</errorlog>
<size>1000M</size>
<count>10</count>
<stderr>/var/log/clickhouse-server/stderr.log</stderr>
<stdout>/var/log/clickhouse-server/stdout.log</stdout>
</logger>
<part_log>
<database>system</database>
<table>part_log</table>
<flush_interval_milliseconds>500</flush_interval_milliseconds>
</part_log>
</yandex>

View File

@ -0,0 +1,5 @@
<?xml version="1.0"?>
<yandex>
<https_port>8443</https_port>
<tcp_port_secure>9440</tcp_port_secure>
</yandex>

View File

@ -0,0 +1,85 @@
<?xml version="1.0"?>
<yandex>
<remote_servers>
<replicated_cluster>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>clickhouse1</host>
<port>9000</port>
</replica>
<replica>
<host>clickhouse2</host>
<port>9000</port>
</replica>
<replica>
<host>clickhouse3</host>
<port>9000</port>
</replica>
</shard>
</replicated_cluster>
<replicated_cluster_secure>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>clickhouse1</host>
<port>9440</port>
<secure>1</secure>
</replica>
<replica>
<host>clickhouse2</host>
<port>9440</port>
<secure>1</secure>
</replica>
<replica>
<host>clickhouse3</host>
<port>9440</port>
<secure>1</secure>
</replica>
</shard>
</replicated_cluster_secure>
<sharded_cluster>
<shard>
<replica>
<host>clickhouse1</host>
<port>9000</port>
</replica>
</shard>
<shard>
<replica>
<host>clickhouse2</host>
<port>9000</port>
</replica>
</shard>
<shard>
<replica>
<host>clickhouse3</host>
<port>9000</port>
</replica>
</shard>
</sharded_cluster>
<sharded_cluster_secure>
<shard>
<replica>
<host>clickhouse1</host>
<port>9440</port>
<secure>1</secure>
</replica>
</shard>
<shard>
<replica>
<host>clickhouse2</host>
<port>9440</port>
<secure>1</secure>
</replica>
</shard>
<shard>
<replica>
<host>clickhouse3</host>
<port>9440</port>
<secure>1</secure>
</replica>
</shard>
</sharded_cluster_secure>
</remote_servers>
</yandex>

View File

@ -0,0 +1,17 @@
<yandex>
<openSSL>
<server>
<certificateFile>/etc/clickhouse-server/ssl/server.crt</certificateFile>
<privateKeyFile>/etc/clickhouse-server/ssl/server.key</privateKeyFile>
<verificationMode>none</verificationMode>
<cacheSessions>true</cacheSessions>
</server>
<client>
<cacheSessions>true</cacheSessions>
<verificationMode>none</verificationMode>
<invalidCertificateHandler>
<name>AcceptCertificateHandler</name>
</invalidCertificateHandler>
</client>
</openSSL>
</yandex>

View File

@ -0,0 +1,20 @@
<yandex>
<storage_configuration>
<disks>
<default>
<keep_free_space_bytes>1024</keep_free_space_bytes>
</default>
</disks>
<policies>
<default>
<volumes>
<default>
<disk>default</disk>
</default>
</volumes>
</default>
</policies>
</storage_configuration>
</yandex>

View File

@ -0,0 +1,10 @@
<?xml version="1.0"?>
<yandex>
<zookeeper>
<node index="1">
<host>zookeeper</host>
<port>2181</port>
</node>
<session_timeout_ms>15000</session_timeout_ms>
</zookeeper>
</yandex>

View File

@ -0,0 +1,436 @@
<?xml version="1.0"?>
<!--
NOTE: User and query level settings are set up in "users.xml" file.
-->
<yandex>
<logger>
<!-- Possible levels: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger.h#L105 -->
<level>trace</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
<size>1000M</size>
<count>10</count>
<!-- <console>1</console> --> <!-- Default behavior is autodetection (log to console if not daemon mode and is tty) -->
</logger>
<!--display_name>production</display_name--> <!-- It is the name that will be shown in the client -->
<http_port>8123</http_port>
<tcp_port>9000</tcp_port>
<!-- For HTTPS and SSL over native protocol. -->
<!--
<https_port>8443</https_port>
<tcp_port_secure>9440</tcp_port_secure>
-->
<!-- Used with https_port and tcp_port_secure. Full ssl options list: https://github.com/ClickHouse-Extras/poco/blob/master/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h#L71 -->
<openSSL>
<server> <!-- Used for https server AND secure tcp port -->
<!-- openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /etc/clickhouse-server/server.key -out /etc/clickhouse-server/server.crt -->
<certificateFile>/etc/clickhouse-server/server.crt</certificateFile>
<privateKeyFile>/etc/clickhouse-server/server.key</privateKeyFile>
<!-- openssl dhparam -out /etc/clickhouse-server/dhparam.pem 4096 -->
<dhParamsFile>/etc/clickhouse-server/dhparam.pem</dhParamsFile>
<verificationMode>none</verificationMode>
<loadDefaultCAFile>true</loadDefaultCAFile>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
</server>
<client> <!-- Used for connecting to https dictionary source -->
<loadDefaultCAFile>true</loadDefaultCAFile>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
<!-- Use for self-signed: <verificationMode>none</verificationMode> -->
<invalidCertificateHandler>
<!-- Use for self-signed: <name>AcceptCertificateHandler</name> -->
<name>RejectCertificateHandler</name>
</invalidCertificateHandler>
</client>
</openSSL>
<!-- Default root page on http[s] server. For example load UI from https://tabix.io/ when opening http://localhost:8123 -->
<!--
<http_server_default_response><![CDATA[<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>]]></http_server_default_response>
-->
<!-- Port for communication between replicas. Used for data exchange. -->
<interserver_http_port>9009</interserver_http_port>
<!-- Hostname that is used by other replicas to request this server.
If not specified, than it is determined analoguous to 'hostname -f' command.
This setting could be used to switch replication to another network interface.
-->
<!--
<interserver_http_host>example.yandex.ru</interserver_http_host>
-->
<!-- Listen specified host. use :: (wildcard IPv6 address), if you want to accept connections both with IPv4 and IPv6 from everywhere. -->
<!-- <listen_host>::</listen_host> -->
<!-- Same for hosts with disabled ipv6: -->
<!-- <listen_host>0.0.0.0</listen_host> -->
<!-- Default values - try listen localhost on ipv4 and ipv6: -->
<!--
<listen_host>::1</listen_host>
<listen_host>127.0.0.1</listen_host>
-->
<!-- Don't exit if ipv6 or ipv4 unavailable, but listen_host with this protocol specified -->
<!-- <listen_try>0</listen_try> -->
<!-- Allow listen on same address:port -->
<!-- <listen_reuse_port>0</listen_reuse_port> -->
<!-- <listen_backlog>64</listen_backlog> -->
<max_connections>4096</max_connections>
<keep_alive_timeout>3</keep_alive_timeout>
<!-- Maximum number of concurrent queries. -->
<max_concurrent_queries>100</max_concurrent_queries>
<!-- Set limit on number of open files (default: maximum). This setting makes sense on Mac OS X because getrlimit() fails to retrieve
correct maximum value. -->
<!-- <max_open_files>262144</max_open_files> -->
<!-- Size of cache of uncompressed blocks of data, used in tables of MergeTree family.
In bytes. Cache is single for server. Memory is allocated only on demand.
Cache is used when 'use_uncompressed_cache' user setting turned on (off by default).
Uncompressed cache is advantageous only for very short queries and in rare cases.
-->
<uncompressed_cache_size>8589934592</uncompressed_cache_size>
<!-- Approximate size of mark cache, used in tables of MergeTree family.
In bytes. Cache is single for server. Memory is allocated only on demand.
You should not lower this value.
-->
<mark_cache_size>5368709120</mark_cache_size>
<!-- Path to data directory, with trailing slash. -->
<path>/var/lib/clickhouse/</path>
<!-- Path to temporary data for processing hard queries. -->
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
<!-- Directory with user provided files that are accessible by 'file' table function. -->
<user_files_path>/var/lib/clickhouse/user_files/</user_files_path>
<!-- Path to folder where users and roles created by SQL commands are stored. -->
<access_control_path>/var/lib/clickhouse/access/</access_control_path>
<!-- Path to configuration file with users, access rights, profiles of settings, quotas. -->
<users_config>users.xml</users_config>
<!-- Default profile of settings. -->
<default_profile>default</default_profile>
<!-- System profile of settings. This settings are used by internal processes (Buffer storage, Distibuted DDL worker and so on). -->
<!-- <system_profile>default</system_profile> -->
<!-- Default database. -->
<default_database>default</default_database>
<!-- Server time zone could be set here.
Time zone is used when converting between String and DateTime types,
when printing DateTime in text formats and parsing DateTime from text,
it is used in date and time related functions, if specific time zone was not passed as an argument.
Time zone is specified as identifier from IANA time zone database, like UTC or Africa/Abidjan.
If not specified, system time zone at server startup is used.
Please note, that server could display time zone alias instead of specified name.
Example: W-SU is an alias for Europe/Moscow and Zulu is an alias for UTC.
-->
<!-- <timezone>Europe/Moscow</timezone> -->
<!-- You can specify umask here (see "man umask"). Server will apply it on startup.
Number is always parsed as octal. Default umask is 027 (other users cannot read logs, data files, etc; group can only read).
-->
<!-- <umask>022</umask> -->
<!-- Perform mlockall after startup to lower first queries latency
and to prevent clickhouse executable from being paged out under high IO load.
Enabling this option is recommended but will lead to increased startup time for up to a few seconds.
-->
<mlock_executable>false</mlock_executable>
<!-- Configuration of clusters that could be used in Distributed tables.
https://clickhouse.yandex/docs/en/table_engines/distributed/
-->
<remote_servers incl="clickhouse_remote" >
<!-- Test only shard config for testing distributed storage -->
<test_shard_localhost>
<shard>
<replica>
<host>localhost</host>
<port>9000</port>
</replica>
</shard>
</test_shard_localhost>
<test_cluster_two_shards_localhost>
<shard>
<replica>
<host>localhost</host>
<port>9000</port>
</replica>
</shard>
<shard>
<replica>
<host>localhost</host>
<port>9000</port>
</replica>
</shard>
</test_cluster_two_shards_localhost>
<test_shard_localhost_secure>
<shard>
<replica>
<host>localhost</host>
<port>9440</port>
<secure>1</secure>
</replica>
</shard>
</test_shard_localhost_secure>
<test_unavailable_shard>
<shard>
<replica>
<host>localhost</host>
<port>9000</port>
</replica>
</shard>
<shard>
<replica>
<host>localhost</host>
<port>1</port>
</replica>
</shard>
</test_unavailable_shard>
</remote_servers>
<!-- If element has 'incl' attribute, then for it's value will be used corresponding substitution from another file.
By default, path to file with substitutions is /etc/metrika.xml. It could be changed in config in 'include_from' element.
Values for substitutions are specified in /yandex/name_of_substitution elements in that file.
-->
<!-- ZooKeeper is used to store metadata about replicas, when using Replicated tables.
Optional. If you don't use replicated tables, you could omit that.
See https://clickhouse.yandex/docs/en/table_engines/replication/
-->
<zookeeper incl="zookeeper" optional="true" />
<!-- Substitutions for parameters of replicated tables.
Optional. If you don't use replicated tables, you could omit that.
See https://clickhouse.yandex/docs/en/table_engines/replication/#creating-replicated-tables
-->
<macros incl="macros" optional="true" />
<!-- Reloading interval for embedded dictionaries, in seconds. Default: 3600. -->
<builtin_dictionaries_reload_interval>3600</builtin_dictionaries_reload_interval>
<!-- Maximum session timeout, in seconds. Default: 3600. -->
<max_session_timeout>3600</max_session_timeout>
<!-- Default session timeout, in seconds. Default: 60. -->
<default_session_timeout>60</default_session_timeout>
<!-- Sending data to Graphite for monitoring. Several sections can be defined. -->
<!--
interval - send every X second
root_path - prefix for keys
hostname_in_path - append hostname to root_path (default = true)
metrics - send data from table system.metrics
events - send data from table system.events
asynchronous_metrics - send data from table system.asynchronous_metrics
-->
<!--
<graphite>
<host>localhost</host>
<port>42000</port>
<timeout>0.1</timeout>
<interval>60</interval>
<root_path>one_min</root_path>
<hostname_in_path>true</hostname_in_path>
<metrics>true</metrics>
<events>true</events>
<asynchronous_metrics>true</asynchronous_metrics>
</graphite>
<graphite>
<host>localhost</host>
<port>42000</port>
<timeout>0.1</timeout>
<interval>1</interval>
<root_path>one_sec</root_path>
<metrics>true</metrics>
<events>true</events>
<asynchronous_metrics>false</asynchronous_metrics>
</graphite>
-->
<!-- Query log. Used only for queries with setting log_queries = 1. -->
<query_log>
<!-- What table to insert data. If table is not exist, it will be created.
When query log structure is changed after system update,
then old table will be renamed and new table will be created automatically.
-->
<database>system</database>
<table>query_log</table>
<!--
PARTITION BY expr https://clickhouse.yandex/docs/en/table_engines/custom_partitioning_key/
Example:
event_date
toMonday(event_date)
toYYYYMM(event_date)
toStartOfHour(event_time)
-->
<partition_by>toYYYYMM(event_date)</partition_by>
<!-- Interval of flushing data. -->
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
</query_log>
<!-- Trace log. Stores stack traces collected by query profilers.
See query_profiler_real_time_period_ns and query_profiler_cpu_time_period_ns settings. -->
<trace_log>
<database>system</database>
<table>trace_log</table>
<partition_by>toYYYYMM(event_date)</partition_by>
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
</trace_log>
<!-- Query thread log. Has information about all threads participated in query execution.
Used only for queries with setting log_query_threads = 1. -->
<query_thread_log>
<database>system</database>
<table>query_thread_log</table>
<partition_by>toYYYYMM(event_date)</partition_by>
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
</query_thread_log>
<!-- Uncomment if use part log.
Part log contains information about all actions with parts in MergeTree tables (creation, deletion, merges, downloads).
<part_log>
<database>system</database>
<table>part_log</table>
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
</part_log>
-->
<!-- Uncomment to write text log into table.
Text log contains all information from usual server log but stores it in structured and efficient way.
<text_log>
<database>system</database>
<table>text_log</table>
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
</text_log>
-->
<!-- Parameters for embedded dictionaries, used in Yandex.Metrica.
See https://clickhouse.yandex/docs/en/dicts/internal_dicts/
-->
<!-- Path to file with region hierarchy. -->
<!-- <path_to_regions_hierarchy_file>/opt/geo/regions_hierarchy.txt</path_to_regions_hierarchy_file> -->
<!-- Path to directory with files containing names of regions -->
<!-- <path_to_regions_names_files>/opt/geo/</path_to_regions_names_files> -->
<!-- Configuration of external dictionaries. See:
https://clickhouse.yandex/docs/en/dicts/external_dicts/
-->
<dictionaries_config>*_dictionary.xml</dictionaries_config>
<!-- Uncomment if you want data to be compressed 30-100% better.
Don't do that if you just started using ClickHouse.
-->
<compression incl="compression">
<!--
<!- - Set of variants. Checked in order. Last matching case wins. If nothing matches, lz4 will be used. - ->
<case>
<!- - Conditions. All must be satisfied. Some conditions may be omitted. - ->
<min_part_size>10000000000</min_part_size> <!- - Min part size in bytes. - ->
<min_part_size_ratio>0.01</min_part_size_ratio> <!- - Min size of part relative to whole table size. - ->
<!- - What compression method to use. - ->
<method>zstd</method>
</case>
-->
</compression>
<!-- Allow to execute distributed DDL queries (CREATE, DROP, ALTER, RENAME) on cluster.
Works only if ZooKeeper is enabled. Comment it if such functionality isn't required. -->
<distributed_ddl>
<!-- Path in ZooKeeper to queue with DDL queries -->
<path>/clickhouse/task_queue/ddl</path>
<!-- Settings from this profile will be used to execute DDL queries -->
<!-- <profile>default</profile> -->
</distributed_ddl>
<!-- Settings to fine tune MergeTree tables. See documentation in source code, in MergeTreeSettings.h -->
<!--
<merge_tree>
<max_suspicious_broken_parts>5</max_suspicious_broken_parts>
</merge_tree>
-->
<!-- Protection from accidental DROP.
If size of a MergeTree table is greater than max_table_size_to_drop (in bytes) than table could not be dropped with any DROP query.
If you want do delete one table and don't want to restart clickhouse-server, you could create special file <clickhouse-path>/flags/force_drop_table and make DROP once.
By default max_table_size_to_drop is 50GB; max_table_size_to_drop=0 allows to DROP any tables.
The same for max_partition_size_to_drop.
Uncomment to disable protection.
-->
<!-- <max_table_size_to_drop>0</max_table_size_to_drop> -->
<!-- <max_partition_size_to_drop>0</max_partition_size_to_drop> -->
<!-- Example of parameters for GraphiteMergeTree table engine -->
<graphite_rollup_example>
<pattern>
<regexp>click_cost</regexp>
<function>any</function>
<retention>
<age>0</age>
<precision>3600</precision>
</retention>
<retention>
<age>86400</age>
<precision>60</precision>
</retention>
</pattern>
<default>
<function>max</function>
<retention>
<age>0</age>
<precision>60</precision>
</retention>
<retention>
<age>3600</age>
<precision>300</precision>
</retention>
<retention>
<age>86400</age>
<precision>3600</precision>
</retention>
</default>
</graphite_rollup_example>
<!-- Directory in <clickhouse-path> containing schema files for various input formats.
The directory will be created if it doesn't exist.
-->
<format_schema_path>/var/lib/clickhouse/format_schemas/</format_schema_path>
<!-- Uncomment to disable ClickHouse internal DNS caching. -->
<!-- <disable_internal_dns_cache>1</disable_internal_dns_cache> -->
</yandex>

View File

@ -0,0 +1,8 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEAua92DDli13gJ+//ZXyGaggjIuidqB0crXfhUlsrBk9BV1hH3i7fR
XGP9rUdk2ubnB3k2ejBStL5oBrkHm9SzUFSQHqfDjLZjKoUpOEmuDc4cHvX1XTR5
Pr1vf5cd0yEncJWG5W4zyUB8k++SUdL2qaeslSs+f491HBLDYn/h8zCgRbBvxhxb
9qeho1xcbnWeqkN6Kc9bgGozA16P9NLuuLttNnOblkH+lMBf42BSne/TWt3AlGZf
slKmmZcySUhF8aKfJnLKbkBCFqOtFRh8zBA9a7g+BT/lSANATCDPaAk1YVih2EKb
dpc3briTDbRsiqg2JKMI7+VdULY9bh3EawIBAg==
-----END DH PARAMETERS-----

View File

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIC/TCCAeWgAwIBAgIJANjx1QSR77HBMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAgFw0xODA3MzAxODE2MDhaGA8yMjkyMDUxNDE4MTYwOFow
FDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAs9uSo6lJG8o8pw0fbVGVu0tPOljSWcVSXH9uiJBwlZLQnhN4SFSFohfI
4K8U1tBDTnxPLUo/V1K9yzoLiRDGMkwVj6+4+hE2udS2ePTQv5oaMeJ9wrs+5c9T
4pOtlq3pLAdm04ZMB1nbrEysceVudHRkQbGHzHp6VG29Fw7Ga6YpqyHQihRmEkTU
7UCYNA+Vk7aDPdMS/khweyTpXYZimaK9f0ECU3/VOeG3fH6Sp2X6FN4tUj/aFXEj
sRmU5G2TlYiSIUMF2JPdhSihfk1hJVALrHPTU38SOL+GyyBRWdNcrIwVwbpvsvPg
pryMSNxnpr0AK0dFhjwnupIv5hJIOQIDAQABo1AwTjAdBgNVHQ4EFgQUjPLb3uYC
kcamyZHK4/EV8jAP0wQwHwYDVR0jBBgwFoAUjPLb3uYCkcamyZHK4/EV8jAP0wQw
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAM/ocuDvfPus/KpMVD51j
4IdlU8R0vmnYLQ+ygzOAo7+hUWP5j0yvq4ILWNmQX6HNvUggCgFv9bjwDFhb/5Vr
85ieWfTd9+LTjrOzTw4avdGwpX9G+6jJJSSq15tw5ElOIFb/qNA9O4dBiu8vn03C
L/zRSXrARhSqTW5w/tZkUcSTT+M5h28+Lgn9ysx4Ff5vi44LJ1NnrbJbEAIYsAAD
+UA+4MBFKx1r6hHINULev8+lCfkpwIaeS8RL+op4fr6kQPxnULw8wT8gkuc8I4+L
P9gg/xDHB44T3ADGZ5Ib6O0DJaNiToO6rnoaaxs0KkotbvDWvRoxEytSbXKoYjYp
0g==
-----END CERTIFICATE-----

View File

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCz25KjqUkbyjyn
DR9tUZW7S086WNJZxVJcf26IkHCVktCeE3hIVIWiF8jgrxTW0ENOfE8tSj9XUr3L
OguJEMYyTBWPr7j6ETa51LZ49NC/mhox4n3Cuz7lz1Pik62WreksB2bThkwHWdus
TKxx5W50dGRBsYfMenpUbb0XDsZrpimrIdCKFGYSRNTtQJg0D5WTtoM90xL+SHB7
JOldhmKZor1/QQJTf9U54bd8fpKnZfoU3i1SP9oVcSOxGZTkbZOViJIhQwXYk92F
KKF+TWElUAusc9NTfxI4v4bLIFFZ01ysjBXBum+y8+CmvIxI3GemvQArR0WGPCe6
ki/mEkg5AgMBAAECggEATrbIBIxwDJOD2/BoUqWkDCY3dGevF8697vFuZKIiQ7PP
TX9j4vPq0DfsmDjHvAPFkTHiTQXzlroFik3LAp+uvhCCVzImmHq0IrwvZ9xtB43f
7Pkc5P6h1l3Ybo8HJ6zRIY3TuLtLxuPSuiOMTQSGRL0zq3SQ5DKuGwkz+kVjHXUN
MR2TECFwMHKQ5VLrC+7PMpsJYyOMlDAWhRfUalxC55xOXTpaN8TxNnwQ8K2ISVY5
212Jz/a4hn4LdwxSz3Tiu95PN072K87HLWx3EdT6vW4Ge5P/A3y+smIuNAlanMnu
plHBRtpATLiTxZt/n6npyrfQVbYjSH7KWhB8hBHtaQKBgQDh9Cq1c/KtqDtE0Ccr
/r9tZNTUwBE6VP+3OJeKdEdtsfuxjOCkS1oAjgBJiSDOiWPh1DdoDeVZjPKq6pIu
Mq12OE3Doa8znfCXGbkSzEKOb2unKZMJxzrz99kXt40W5DtrqKPNb24CNqTiY8Aa
CjtcX+3weat82VRXvph6U8ltMwKBgQDLxjiQQzNoY7qvg7CwJCjf9qq8jmLK766g
1FHXopqS+dTxDLM8eJSRrpmxGWJvNeNc1uPhsKsKgotqAMdBUQTf7rSTbt4MyoH5
bUcRLtr+0QTK9hDWMOOvleqNXha68vATkohWYfCueNsC60qD44o8RZAS6UNy3ENq
cM1cxqe84wKBgQDKkHutWnooJtajlTxY27O/nZKT/HA1bDgniMuKaz4R4Gr1PIez
on3YW3V0d0P7BP6PWRIm7bY79vkiMtLEKdiKUGWeyZdo3eHvhDb/3DCawtau8L2K
GZsHVp2//mS1Lfz7Qh8/L/NedqCQ+L4iWiPnZ3THjjwn3CoZ05ucpvrAMwKBgB54
nay039MUVq44Owub3KDg+dcIU62U+cAC/9oG7qZbxYPmKkc4oL7IJSNecGHA5SbU
2268RFdl/gLz6tfRjbEOuOHzCjFPdvAdbysanpTMHLNc6FefJ+zxtgk9sJh0C4Jh
vxFrw9nTKKzfEl12gQ1SOaEaUIO0fEBGbe8ZpauRAoGAMAlGV+2/K4ebvAJKOVTa
dKAzQ+TD2SJmeR1HZmKDYddNqwtZlzg3v4ZhCk4eaUmGeC1Bdh8MDuB3QQvXz4Dr
vOIP4UVaOr+uM+7TgAgVnP4/K6IeJGzUDhX93pmpWhODfdu/oojEKVcpCojmEmS1
KCBtmIrQLqzMpnBpLNuSY+Q=
-----END PRIVATE KEY-----

View File

@ -0,0 +1,133 @@
<?xml version="1.0"?>
<yandex>
<!-- Profiles of settings. -->
<profiles>
<!-- Default settings. -->
<default>
<!-- Maximum memory usage for processing single query, in bytes. -->
<max_memory_usage>10000000000</max_memory_usage>
<!-- Use cache of uncompressed blocks of data. Meaningful only for processing many of very short queries. -->
<use_uncompressed_cache>0</use_uncompressed_cache>
<!-- How to choose between replicas during distributed query processing.
random - choose random replica from set of replicas with minimum number of errors
nearest_hostname - from set of replicas with minimum number of errors, choose replica
with minimum number of different symbols between replica's hostname and local hostname
(Hamming distance).
in_order - first live replica is chosen in specified order.
first_or_random - if first replica one has higher number of errors, pick a random one from replicas with minimum number of errors.
-->
<load_balancing>random</load_balancing>
</default>
<!-- Profile that allows only read queries. -->
<readonly>
<readonly>1</readonly>
</readonly>
</profiles>
<!-- Users and ACL. -->
<users>
<!-- If user name was not specified, 'default' user is used. -->
<default>
<!-- Password could be specified in plaintext or in SHA256 (in hex format).
If you want to specify password in plaintext (not recommended), place it in 'password' element.
Example: <password>qwerty</password>.
Password could be empty.
If you want to specify SHA256, place it in 'password_sha256_hex' element.
Example: <password_sha256_hex>65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5</password_sha256_hex>
Restrictions of SHA256: impossibility to connect to ClickHouse using MySQL JS client (as of July 2019).
If you want to specify double SHA1, place it in 'password_double_sha1_hex' element.
Example: <password_double_sha1_hex>e395796d6546b1b65db9d665cd43f0e858dd4303</password_double_sha1_hex>
How to generate decent password:
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d '-'
In first line will be password and in second - corresponding SHA256.
How to generate double SHA1:
Execute: PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | openssl dgst -sha1 -binary | openssl dgst -sha1
In first line will be password and in second - corresponding double SHA1.
-->
<password></password>
<!-- List of networks with open access.
To open access from everywhere, specify:
<ip>::/0</ip>
To open access only from localhost, specify:
<ip>::1</ip>
<ip>127.0.0.1</ip>
Each element of list has one of the following forms:
<ip> IP-address or network mask. Examples: 213.180.204.3 or 10.0.0.1/8 or 10.0.0.1/255.255.255.0
2a02:6b8::3 or 2a02:6b8::3/64 or 2a02:6b8::3/ffff:ffff:ffff:ffff::.
<host> Hostname. Example: server01.yandex.ru.
To check access, DNS query is performed, and all received addresses compared to peer address.
<host_regexp> Regular expression for host names. Example, ^server\d\d-\d\d-\d\.yandex\.ru$
To check access, DNS PTR query is performed for peer address and then regexp is applied.
Then, for result of PTR query, another DNS query is performed and all received addresses compared to peer address.
Strongly recommended that regexp is ends with $
All results of DNS requests are cached till server restart.
-->
<networks incl="networks" replace="replace">
<ip>::/0</ip>
</networks>
<!-- Settings profile for user. -->
<profile>default</profile>
<!-- Quota for user. -->
<quota>default</quota>
<!-- Allow access management -->
<access_management>1</access_management>
<!-- Example of row level security policy. -->
<!-- <databases>
<test>
<filtered_table1>
<filter>a = 1</filter>
</filtered_table1>
<filtered_table2>
<filter>a + b &lt; 1 or c - d &gt; 5</filter>
</filtered_table2>
</test>
</databases> -->
</default>
<!-- Example of user with readonly access. -->
<!-- <readonly>
<password></password>
<networks incl="networks" replace="replace">
<ip>::1</ip>
<ip>127.0.0.1</ip>
</networks>
<profile>readonly</profile>
<quota>default</quota>
</readonly> -->
</users>
<!-- Quotas. -->
<quotas>
<!-- Name of quota. -->
<default>
<!-- Limits for time interval. You could specify many intervals with different limits. -->
<interval>
<!-- Length of interval. -->
<duration>3600</duration>
<!-- No limits. Just calculate resource usage for time interval. -->
<queries>0</queries>
<errors>0</errors>
<result_rows>0</result_rows>
<read_rows>0</read_rows>
<execution_time>0</execution_time>
</interval>
</default>
</quotas>
</yandex>

View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<yandex>
<macros>
<replica>clickhouse1</replica>
<shard>01</shard>
<shard2>01</shard2>
</macros>
</yandex>

View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<yandex>
<macros>
<replica>clickhouse2</replica>
<shard>01</shard>
<shard2>02</shard2>
</macros>
</yandex>

View File

@ -0,0 +1,8 @@
<?xml version="1.0"?>
<yandex>
<macros>
<replica>clickhouse3</replica>
<shard>01</shard>
<shard2>03</shard2>
</macros>
</yandex>

View File

@ -0,0 +1,28 @@
version: '2.3'
services:
clickhouse:
image: yandex/clickhouse-integration-test
expose:
- "9000"
- "9009"
- "8123"
volumes:
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/config.d:/etc/clickhouse-server/config.d"
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/users.d/:/etc/clickhouse-server/users.d"
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/ssl:/etc/clickhouse-server/ssl"
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/config.xml:/etc/clickhouse-server/config.xml"
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse/users.xml:/etc/clickhouse-server/users.xml"
- "${CLICKHOUSE_TESTS_SERVER_BIN_PATH:-/usr/bin/clickhouse}:/usr/bin/clickhouse"
- "${CLICKHOUSE_TESTS_ODBC_BRIDGE_BIN_PATH:-/usr/bin/clickhouse-odbc-bridge}:/usr/bin/clickhouse-odbc-bridge"
entrypoint: bash -c "clickhouse server --config-file=/etc/clickhouse-server/config.xml --log-file=/var/log/clickhouse-server/clickhouse-server.log --errorlog-file=/var/log/clickhouse-server/clickhouse-server.err.log"
healthcheck:
test: clickhouse client --query='select 1'
interval: 3s
timeout: 2s
retries: 40
start_period: 2s
cap_add:
- SYS_PTRACE
security_opt:
- label:disable

View File

@ -0,0 +1,63 @@
version: '2.3'
services:
zookeeper:
extends:
file: zookeeper-service.yml
service: zookeeper
clickhouse1:
extends:
file: clickhouse-service.yml
service: clickhouse
hostname: clickhouse1
volumes:
- "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse1/database/:/var/lib/clickhouse/"
- "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse1/logs/:/var/log/clickhouse-server/"
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse1/config.d:/etc/clickhouse-server/config.d"
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse1/users.d:/etc/clickhouse-server/users.d"
depends_on:
zookeeper:
condition: service_healthy
clickhouse2:
extends:
file: clickhouse-service.yml
service: clickhouse
hostname: clickhouse2
volumes:
- "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse2/database/:/var/lib/clickhouse/"
- "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse2/logs/:/var/log/clickhouse-server/"
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse2/config.d:/etc/clickhouse-server/config.d"
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse2/users.d:/etc/clickhouse-server/users.d"
depends_on:
zookeeper:
condition: service_healthy
clickhouse3:
extends:
file: clickhouse-service.yml
service: clickhouse
hostname: clickhouse3
volumes:
- "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse3/database/:/var/lib/clickhouse/"
- "${CLICKHOUSE_TESTS_DIR}/_instances/clickhouse3/logs/:/var/log/clickhouse-server/"
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse3/config.d:/etc/clickhouse-server/config.d"
- "${CLICKHOUSE_TESTS_DIR}/configs/clickhouse3/users.d:/etc/clickhouse-server/users.d"
depends_on:
zookeeper:
condition: service_healthy
# dummy service which does nothing, but allows to postpone
# 'docker-compose up -d' till all dependecies will go healthy
all_services_ready:
image: hello-world
depends_on:
clickhouse1:
condition: service_healthy
clickhouse2:
condition: service_healthy
clickhouse3:
condition: service_healthy
zookeeper:
condition: service_healthy

View File

@ -0,0 +1,18 @@
version: '2.3'
services:
zookeeper:
image: zookeeper:3.4.12
expose:
- "2181"
environment:
ZOO_TICK_TIME: 500
ZOO_MY_ID: 1
healthcheck:
test: echo stat | nc localhost 2181
interval: 3s
timeout: 2s
retries: 5
start_period: 2s
security_opt:
- label:disable

View File

@ -0,0 +1,61 @@
#!/usr/bin/env python3
import sys
from testflows.core import *
append_path(sys.path, "..")
from helpers.cluster import Cluster
from helpers.argparser import argparser
from rbac.requirements import *
issue_12507 = "https://github.com/ClickHouse/ClickHouse/issues/12507"
issue_12510 = "https://github.com/ClickHouse/ClickHouse/issues/12510"
issue_12600 = "https://github.com/ClickHouse/ClickHouse/issues/12600"
xfails = {
"syntax/show create quota/I show create quota current":
[(Fail, "https://github.com/ClickHouse/ClickHouse/issues/12495")],
"syntax/create role/I create role that already exists, throws exception":
[(Fail, issue_12510)],
"syntax/create user/I create user with if not exists, user does exist":
[(Fail, issue_12507)],
"syntax/create row policy/I create row policy if not exists, policy does exist":
[(Fail, issue_12507)],
"syntax/create quota/I create quota if not exists, quota does exist":
[(Fail, issue_12507)],
"syntax/create role/I create role if not exists, role does exist":
[(Fail, issue_12507)],
"syntax/create settings profile/I create settings profile if not exists, profile does exist":
[(Fail, issue_12507)],
"syntax/grant privilege/grant privileges/privilege='dictGet', on=('db0.table0', 'db0.*', '*.*', 'tb0', '*'), allow_introspection=False":
[(Fail, issue_12600)],
"syntax/grant privilege/grant privileges/privilege='CREATE', on=('db0.table0', 'db0.*', '*.*', 'tb0', '*'), allow_introspection=False":
[(Fail, issue_12600)],
"syntax/grant privilege/grant privileges/privilege='DROP', on=('db0.table0', 'db0.*', '*.*', 'tb0', '*'), allow_introspection=False":
[(Fail, issue_12600)],
"syntax/grant privilege/grant privileges/privilege='TRUNCATE', on=('db0.table0', 'db0.*', '*.*', 'tb0', '*'), allow_introspection=False":
[(Fail, issue_12600)],
"syntax/grant privilege/grant privileges/privilege='OPTIMIZE', on=('db0.table0', 'db0.*', '*.*', 'tb0', '*'), allow_introspection=False":
[(Fail, issue_12600)],
"syntax/grant privilege/grant privileges/privilege='SYSTEM', on=('db0.table0', 'db0.*', '*.*', 'tb0', '*'), allow_introspection=False":
[(Fail, issue_12600)],
}
@TestModule
@ArgumentParser(argparser)
@XFails(xfails)
@Name("rbac")
def regression(self, local, clickhouse_binary_path):
"""RBAC regression.
"""
nodes = {
"clickhouse":
("clickhouse1", "clickhouse2", "clickhouse3")
}
with Cluster(local, clickhouse_binary_path, nodes=nodes) as cluster:
self.context.cluster = cluster
Feature(run=load("rbac.tests.syntax.feature", "feature"), flags=TE)
if main():
regression()

View File

@ -0,0 +1 @@
from .requirements import *

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
## Syntax
# Errors: not found
not_found = "Exception: There is no {type} `{name}` in [disk, users.xml]."
def user_not_found_in_disk(name):
return (192,not_found.format(type="user",name=name))
def role_not_found_in_disk(name):
return (255,not_found.format(type="role",name=name))
def settings_profile_not_found_in_disk(name):
return (180,not_found.format(type="settings profile",name=name))
def quota_not_found_in_disk(name):
return (199,not_found.format(type="quota",name=name))
def row_policy_not_found_in_disk(name):
return (11,not_found.format(type="row policy",name=name))
# Errors: cannot_rename
cannot_rename = "Exception: {type} `{name}`: cannot rename to `{name_new}` because {type} `{name_new}` already exists in [disk]."
cannot_rename_exitcode = 237
def cannot_rename_user(name,name_new):
return (cannot_rename_exitcode, cannot_rename.format(type="user", name=name, name_new=name_new))
def cannot_rename_role(name,name_new):
return (cannot_rename_exitcode, cannot_rename.format(type="role", name=name, name_new=name_new))
def cannot_rename_settings_profile(name,name_new):
return (cannot_rename_exitcode, cannot_rename.format(type="settings profile", name=name, name_new=name_new))
def cannot_rename_quota(name,name_new):
return (cannot_rename_exitcode, cannot_rename.format(type="quota", name=name, name_new=name_new))
def cannot_rename_row_policy(name,name_new):
return (cannot_rename_exitcode, cannot_rename.format(type="row policy", name=name, name_new=name_new))
# Errors: cannot insert
cannot_insert = "Exception: {type} `{name}`: cannot insert because {type} `{name}` already exists in [disk]."
cannot_insert_exitcode = 237
def cannot_insert_user(name):
return (cannot_insert_exitcode, cannot_insert.format(type="user",name=name))
def cannot_insert_role(name):
return (cannot_insert_exitcode, cannot_insert.format(type="role",name=name))
def cannot_insert_settings_profile(name):
return (cannot_insert_exitcode, cannot_insert.format(type="settings profile",name=name))
def cannot_insert_quota(name):
return (cannot_insert_exitcode, cannot_insert.format(type="quota",name=name))
def cannot_insert_row_policy(name):
return (cannot_insert_exitcode, cannot_insert.format(type="row policy",name=name))
# Error: default is readonly
default_readonly_exitcode = 239
cannot_remove_default = "Exception: Cannot remove {type} `default` from [users.xml] because this storage is readonly"
def cannot_update_default():
return (default_readonly_exitcode, "Exception: Cannot update user `default` in [users.xml] because this storage is readonly")
def cannot_remove_user_default():
return (default_readonly_exitcode, cannot_remove_default.format(type="user"))
def cannot_remove_settings_profile_default():
return (default_readonly_exitcode, cannot_remove_default.format(type="settings profile"))
def cannot_remove_quota_default():
return (default_readonly_exitcode, cannot_remove_default.format(type="quota"))
# Other syntax errors
def unknown_setting(setting):
return (115, f"Exception: Unknown setting {setting}.")
def cluster_not_found(cluster):
return (170, f"Exception: Requested cluster '{cluster}' not found.")

View File

@ -0,0 +1,206 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors
@TestFeature
@Name("alter quota")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check alter quota query syntax.
```sql
ALTER QUOTA [IF EXISTS] name [ON CLUSTER cluster_name]
[RENAME TO new_name]
[KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}]
[FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY | MONTH}
{MAX { {QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number } [,...] |
NO LIMITS | TRACKING ONLY} [,...]]
[TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
```
"""
node = self.context.cluster.node(node)
def cleanup_quota(quota):
with Given(f"I ensure that quota {quota} does not exist"):
node.query(f"DROP QUOTA IF EXISTS {quota}")
try:
with Given("I have a quota, a user, and a role"):
node.query(f"CREATE QUOTA quota0")
node.query(f"CREATE USER user0")
node.query(f"CREATE ROLE role0")
with Scenario("I alter quota with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter("1.0")]):
with When("I alter quota"):
node.query("ALTER QUOTA quota0")
with Scenario("I alter quota that does not exist, throws an exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter("1.0")]):
quota = "quota1"
cleanup_quota(quota)
with When(f"I alter quota {quota}, which does not exist"):
exitcode, message = errors.quota_not_found_in_disk(name=quota)
node.query(f"ALTER QUOTA {quota}", exitcode=exitcode, message=message)
del quota
with Scenario("I alter quota with if exists, quota does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_IfExists("1.0")]):
node.query("ALTER QUOTA IF EXISTS quota0")
with Scenario("I alter quota with if exists, quota does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_IfExists("1.0")]):
quota = "quota1"
cleanup_quota(quota)
with When(f"I alter quota {quota}, which does not exist, with IF EXISTS"):
node.query(f"ALTER QUOTA IF EXISTS {quota}")
del quota
with Scenario("I alter quota using rename, target available", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Rename("1.0")]):
node.query("ALTER QUOTA quota0 RENAME TO quota0")
with Scenario("I alter quota using rename, target unavailable", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Rename("1.0")]):
new_quota = "quota1"
try:
with Given(f"Ensure target name {new_quota} is NOT available"):
node.query(f"CREATE QUOTA IF NOT EXISTS {new_quota}")
with When(f"I try to rename to {new_quota}"):
exitcode, message = errors.cannot_rename_quota(name="quota0", name_new=new_quota)
node.query(f"ALTER QUOTA quota0 RENAME TO {new_quota}", exitcode=exitcode, message=message)
finally:
with Finally(f"I cleanup target name {new_quota}"):
node.query(f"DROP QUOTA IF EXISTS {new_quota}")
del new_quota
keys = ['none', 'user name', 'ip address', 'client key', 'client key or user name', 'client key or ip address']
for key in keys:
with Scenario(f"I alter quota keyed by {key}", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_KeyedBy("1.0"),
RQ_SRS_006_RBAC_Quota_Alter_KeyedByOptions("1.0")]):
with When("I alter quota with a key"):
node.query(f"ALTER QUOTA quota0 KEYED BY '{key}'")
with Scenario("I alter quota for randomized interval", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Interval_Randomized("1.0")]):
with When("I alter quota on a randomized interval"):
node.query("ALTER QUOTA quota0 FOR RANDOMIZED INTERVAL 1 DAY NO LIMITS")
intervals = ['SECOND', 'MINUTE', 'HOUR', 'DAY', 'MONTH']
for i, interval in enumerate(intervals):
with Scenario(f"I alter quota for interval {interval}", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Interval("1.0")]):
with When(f"I alter quota for {interval}"):
node.query(f"ALTER QUOTA quota0 FOR INTERVAL 1 {interval} NO LIMITS")
constraints = ['MAX QUERIES', 'MAX ERRORS', 'MAX RESULT ROWS',
'MAX RESULT BYTES', 'MAX READ ROWS', 'MAX READ BYTES', 'MAX EXECUTION TIME',
'NO LIMITS', 'TRACKING ONLY']
for i, constraint in enumerate(constraints):
with Scenario(f"I alter quota for {constraint.lower()}", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Queries("1.0"),
RQ_SRS_006_RBAC_Quota_Alter_Errors("1.0"),
RQ_SRS_006_RBAC_Quota_Alter_ResultRows("1.0"),
RQ_SRS_006_RBAC_Quota_Alter_ReadRows("1.0"),
RQ_SRS_006_RBAC_Quota_ALter_ResultBytes("1.0"),
RQ_SRS_006_RBAC_Quota_Alter_ReadBytes("1.0"),
RQ_SRS_006_RBAC_Quota_Alter_ExecutionTime("1.0"),
RQ_SRS_006_RBAC_Quota_Alter_NoLimits("1.0"),
RQ_SRS_006_RBAC_Quota_Alter_TrackingOnly("1.0")]):
with When("I alter quota for a constraint"):
node.query(f"ALTER QUOTA quota0 FOR INTERVAL 1 DAY {constraint}{' 1024' if constraint.startswith('MAX') else ''}")
with Scenario("I create quota for multiple constraints", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Interval("1.0"),
RQ_SRS_006_RBAC_Quota_Alter_Queries("1.0")]):
node.query("ALTER QUOTA quota0 \
FOR INTERVAL 1 DAY NO LIMITS, \
FOR INTERVAL 2 DAY MAX QUERIES 124, \
FOR INTERVAL 1 MONTH TRACKING ONLY")
with Scenario("I alter quota to assign to one role", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Assignment("1.0")]):
with When("I alter quota to a role"):
node.query("ALTER QUOTA quota0 TO role0")
with Scenario("I alter quota to assign to role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Assignment("1.0")]):
role = "role1"
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I alter a quota, assign to role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"ALTER QUOTA quota0 TO {role}", exitcode=exitcode, message=message)
del role
with Scenario("I alter quota to assign to all except role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Assignment("1.0")]):
role = "role1"
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I alter a quota, assign to all except role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"ALTER QUOTA quota0 TO ALL EXCEPT {role}", exitcode=exitcode, message=message)
del role
with Scenario("I alter quota to assign to one role and one user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Assignment("1.0")]):
with When("I alter quota to a role and a user"):
node.query("ALTER QUOTA quota0 TO role0, user0")
with Scenario("I alter quota assigned to none", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Assignment_None("1.0")]):
with When("I alter quota to none"):
node.query("ALTER QUOTA quota0 TO NONE")
with Scenario("I alter quota to assign to all", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Assignment_All("1.0")]):
with When("I alter quota to all"):
node.query("ALTER QUOTA quota0 TO ALL")
with Scenario("I alter quota to assign to all except one role", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Assignment_Except("1.0")]):
with When("I alter quota to all except one role"):
node.query("ALTER QUOTA quota0 TO ALL EXCEPT role0")
with Scenario("I alter quota to assign to all except multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Assignment_Except("1.0")]):
with When("I alter quota to all except one multiple roles"):
node.query("ALTER QUOTA quota0 TO ALL EXCEPT role0, user0")
with Scenario("I alter quota on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Cluster("1.0")]):
try:
with Given("I have a quota on a cluster"):
node.query("CREATE QUOTA quota1 ON CLUSTER sharded_cluster")
with When("I run alter quota command on a cluster"):
node.query("ALTER QUOTA quota1 ON CLUSTER sharded_cluster")
with And("I run alter quota command on a cluster with a key"):
node.query("ALTER QUOTA quota1 ON CLUSTER sharded_cluster KEYED BY 'none'")
with And("I run alter quota command on a cluster with an interval"):
node.query("ALTER QUOTA quota1 ON CLUSTER sharded_cluster FOR INTERVAL 1 DAY TRACKING ONLY")
with And("I run alter quota command on a cluster for all"):
node.query("ALTER QUOTA quota1 ON CLUSTER sharded_cluster TO ALL")
finally:
with Finally("I drop the quota"):
node.query("DROP QUOTA IF EXISTS quota1 ON CLUSTER sharded_cluster")
with Scenario("I alter quota on nonexistent cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Alter_Cluster("1.0")]):
with When("I run alter quota on a cluster"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("ALTER QUOTA quota0 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)
finally:
with Finally("I drop the quota and all the users and roles"):
node.query(f"DROP QUOTA IF EXISTS quota0")
node.query(f"DROP USER IF EXISTS user0")
node.query(f"DROP ROLE IF EXISTS role0")

View File

@ -0,0 +1,196 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("alter role")
def feature(self, node="clickhouse1"):
"""Check alter role query syntax.
```sql
ALTER ROLE [IF EXISTS] name [ON CLUSTER cluster_name]
[RENAME TO new_name]
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def setup(role, profile=None):
try:
with Given("I have a role"):
node.query(f"CREATE ROLE OR REPLACE {role}")
if profile != None: #create profile when name is given
with Given("And I have a profile"):
node.query(f"CREATE SETTINGS PROFILE OR REPLACE {profile}")
yield
finally:
with Finally("I drop the role"):
node.query(f"DROP ROLE IF EXISTS {role}")
if profile != "":
with Finally("I drop the profile"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}")
def cleanup_role(role):
with Given(f"I ensure that role {role} does not exist"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Scenario("I alter role with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter("1.0")]):
with setup("role0"):
with When("I alter role"):
node.query("ALTER ROLE role0")
with Scenario("I alter role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter("1.0")]):
role = "role0"
cleanup_role(role)
with When(f"I alter role {role} that does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"ALTER ROLE {role}", exitcode=exitcode, message=message)
del role
with Scenario("I alter role if exists, role does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_IfExists("1.0")]):
with setup("role1"):
with When("I alter role with if exists"):
node.query("ALTER ROLE IF EXISTS role1")
with Scenario("I alter role if exists, role does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_IfExists("1.0")]):
role = "role0"
cleanup_role(role)
with When(f"I alter role {role} that does not exist"):
node.query(f"ALTER ROLE IF EXISTS {role}")
del role
with Scenario("I alter role on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Cluster("1.0")]):
try:
with Given("I have a role on a cluster"):
node.query("CREATE ROLE role1 ON CLUSTER sharded_cluster")
with When("I run alter role on a cluster"):
node.query("ALTER ROLE role1 ON CLUSTER sharded_cluster")
with And("I rename role on a cluster"):
node.query("ALTER ROLE role1 ON CLUSTER sharded_cluster RENAME TO role2")
with And("I alter role with settings on a cluster"):
node.query("ALTER ROLE role2 ON CLUSTER sharded_cluster SETTINGS max_memory_usage=10000000 READONLY")
finally:
with Finally("I drop the role"):
node.query("DROP ROLE IF EXISTS role1,role2 ON CLUSTER sharded_cluster")
with Scenario("I alter role on nonexistent cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Cluster("1.0")]):
with When("I run alter role on a cluster"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("ALTER ROLE role1 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)
with Scenario("I alter role to rename, new name is available", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Rename("1.0")]):
with setup("role2"):
new_role = "role3"
try:
with Given(f"Ensure target name {new_role} is available"):
node.query(f"DROP ROLE IF EXISTS {new_role}")
with When(f"I try to rename to {new_role}"):
node.query(f"ALTER ROLE role2 RENAME TO {new_role}")
finally:
with Finally(f"I cleanup new name {new_role}"):
node.query(f"DROP ROLE IF EXISTS {new_role}")
del new_role
with Scenario("I alter role to rename, new name is not available, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Rename("1.0")]):
with setup("role2a"):
new_role = "role3a"
try:
with Given(f"Ensure target name {new_role} is NOT available"):
node.query(f"CREATE ROLE IF NOT EXISTS {new_role}")
with When(f"I try to rename to {new_role}"):
exitcode, message = errors.cannot_rename_role(name="role2a", name_new=new_role)
node.query(f"ALTER ROLE role2a RENAME TO {new_role}", exitcode=exitcode, message=message)
finally:
with Finally(f"I cleanup target name {new_role}"):
node.query(f"DROP ROLE IF EXISTS {new_role}")
del new_role
with Scenario("I alter role settings profile", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]):
with setup("role4"):
with When("I alter role with settings profile"):
node.query("ALTER ROLE role4 SETTINGS PROFILE default, max_memory_usage=10000000 READONLY")
with Scenario("I alter role settings profile, profile does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]):
with setup("role4a"):
with Given("I ensure profile profile0 does not exist"):
node.query("DROP SETTINGS PROFILE IF EXISTS profile0")
with When("I alter role with settings profile that does not exist"):
exitcode, message = errors.settings_profile_not_found_in_disk("profile0")
node.query("ALTER ROLE role4a SETTINGS PROFILE profile0", exitcode=exitcode, message=message)
with Scenario("I alter role settings profile multiple", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]):
with setup("role4b", profile="profile0"):
with When("I alter role with multiple profiles"):
node.query("ALTER ROLE role4b SETTINGS PROFILE default, PROFILE profile0, \
max_memory_usage=10000000 READONLY")
with Scenario("I alter role settings without profile", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]):
with setup("role5"):
with When("I alter role with settings and no profile"):
node.query("ALTER ROLE role5 SETTINGS max_memory_usage=10000000 READONLY")
with Scenario("I alter role settings, variable does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]):
with setup("role5a"):
with When("I alter role using settings and nonexistent value"):
exitcode, message = errors.unknown_setting("fake_setting")
node.query("ALTER ROLE role5a SETTINGS fake_setting = 100000001", exitcode=exitcode, message=message)
with Scenario("I alter role settings without profile multiple", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]):
with setup("role6"):
with When("I alter role with multiple settings and no profile"):
node.query("ALTER ROLE role6 SETTINGS max_memory_usage=10000000 READONLY, \
max_rows_to_read MIN 20 MAX 25")
with Scenario("I alter role settings with multiple profiles multiple variables", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]):
with setup("role7", profile="profile1"):
with When("I alter role with multiple settings and profiles"):
node.query("ALTER ROLE role7 SETTINGS PROFILE default, PROFILE profile1, \
max_memory_usage=10000000 READONLY, max_rows_to_read MIN 20 MAX 25")
with Scenario("I alter role settings readonly", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]):
with setup("role8"):
with When("I alter role with readonly"):
node.query("ALTER ROLE role8 SETTINGS max_memory_usage READONLY")
with Scenario("I alter role settings writable", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]):
with setup("role9"):
with When("I alter role with writable"):
node.query("ALTER ROLE role9 SETTINGS max_memory_usage WRITABLE")
with Scenario("I alter role settings min, with and without = sign", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]):
with setup("role10"):
with When("I set min, no equals"):
node.query("ALTER ROLE role10 SETTINGS max_memory_usage MIN 200")
with When("I set min, yes equals"):
node.query("ALTER ROLE role10 SETTINGS max_memory_usage MIN = 200")
with Scenario("I alter role settings max, with and without = sign", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Alter_Settings("1.0")]):
with setup("role11"):
with When("I set max, no equals"):
node.query("ALTER ROLE role11 SETTINGS max_memory_usage MAX 2000")
with When("I set max, yes equals"):
node.query("ALTER ROLE role11 SETTINGS max_memory_usage MAX = 200")

View File

@ -0,0 +1,244 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("alter row policy")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check alter row policy query syntax.
```sql
ALTER [ROW] POLICY [IF EXISTS] name [ON CLUSTER cluster_name] ON [database.]table
[RENAME TO new_name]
[AS {PERMISSIVE | RESTRICTIVE}]
[FOR SELECT]
[USING {condition | NONE}][,...]
[TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(policy):
try:
with Given("I have a row policy"):
node.query(f"CREATE ROW POLICY {policy} ON default.foo")
yield
finally:
with Finally("I drop the row policy"):
node.query(f"DROP ROW POLICY IF EXISTS {policy} ON default.foo")
def cleanup_policy(policy):
with Given(f"I ensure that policy {policy} does not exist"):
node.query(f"DROP ROW POLICY IF EXISTS {policy} ON default.foo")
try:
with Given("I have a table and some roles"):
node.query(f"CREATE TABLE default.foo (x UInt64, y String) Engine=Memory")
node.query(f"CREATE ROLE role0")
node.query(f"CREATE ROLE role1")
with Scenario("I alter row policy with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy0"):
with When("I alter row policy"):
node.query("ALTER ROW POLICY policy0 ON default.foo")
with Scenario("I alter row policy using short syntax with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy1"):
with When("I alter row policy short form"):
node.query("ALTER POLICY policy1 ON default.foo")
with Scenario("I alter row policy, does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
policy = "policy2"
cleanup_policy(policy)
with When(f"I alter row policy {policy} that doesn't exist"):
exitcode, message = errors.row_policy_not_found_in_disk(name=f"{policy} ON default.foo")
node.query(f"ALTER ROW POLICY {policy} ON default.foo", exitcode=exitcode, message=message)
del policy
with Scenario("I alter row policy if exists", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_IfExists("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy2"):
with When("I alter row policy using if exists"):
node.query("ALTER ROW POLICY IF EXISTS policy2 ON default.foo")
with Scenario("I alter row policy if exists, policy does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_IfExists("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
policy = "policy2"
cleanup_policy(policy)
with When(f"I alter row policy {policy} that doesn't exist"):
node.query(f"ALTER ROW POLICY IF EXISTS {policy} ON default.foo")
del policy
with Scenario("I alter row policy to rename, target available", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Rename("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy3"):
with When("I alter row policy with rename"):
node.query("ALTER ROW POLICY policy3 ON default.foo RENAME TO policy3")
with Scenario("I alter row policy to rename, target unavailable", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Rename("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy3"):
new_policy = "policy4"
try:
with Given(f"Ensure target name {new_policy} is NOT available"):
node.query(f"CREATE ROW POLICY IF NOT EXISTS {new_policy} ON default.foo")
with When(f"I try to rename to {new_policy}"):
exitcode, message = errors.cannot_rename_row_policy(name="policy3 ON default.foo",
name_new=f"{new_policy} ON default.foo")
node.query(f"ALTER ROW POLICY policy3 ON default.foo RENAME TO {new_policy}", exitcode=exitcode, message=message)
finally:
with Finally(f"I cleanup target name {new_policy}"):
node.query(f"DROP ROW POLICY IF EXISTS {new_policy} ON default.foo")
del new_policy
with Scenario("I alter row policy to permissive", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Permissive("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy4"):
with When("I alter row policy as permissive"):
node.query("ALTER ROW POLICY policy4 ON default.foo AS PERMISSIVE")
with Scenario("I alter row policy to restrictive", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Access_Restrictive("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy5"):
with When("I alter row policy as restrictive"):
node.query("ALTER ROW POLICY policy5 ON default.foo AS RESTRICTIVE")
with Scenario("I alter row policy for select", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_ForSelect("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy6"):
with When("I alter row policy using for select"):
node.query("ALTER ROW POLICY policy6 ON default.foo FOR SELECT USING x > 10")
with Scenario("I alter row policy using condition", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Condition("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy6"):
with When("I alter row policy wtih condition"):
node.query("ALTER ROW POLICY policy6 ON default.foo USING x > 10")
with Scenario("I alter row policy using condition none", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Condition_None("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy7"):
with When("I alter row policy using no condition"):
node.query("ALTER ROW POLICY policy7 ON default.foo USING NONE")
with Scenario("I alter row policy to one role", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy8"):
with When("I alter row policy to a role"):
node.query("ALTER ROW POLICY policy8 ON default.foo TO role0")
with Scenario("I alter row policy to assign to role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment("1.0")]):
role = "role2"
with cleanup("policy8a"):
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I alter a row policy, assign to role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"ALTER ROW POLICY policy8a ON default.foo TO {role}", exitcode=exitcode, message=message)
del role
with Scenario("I alter row policy to assign to all excpet role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment("1.0")]):
role = "role2"
with cleanup("policy8a"):
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I alter a row policy, assign to all except role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"ALTER ROW POLICY policy8a ON default.foo TO ALL EXCEPT {role}", exitcode=exitcode, message=message)
del role
with Scenario("I alter row policy assigned to multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy9"):
with When("I alter row policy to multiple roles"):
node.query("ALTER ROW POLICY policy9 ON default.foo TO role0, role1")
with Scenario("I alter row policy assigned to all", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_All("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy10"):
with When("I alter row policy to all"):
node.query("ALTER ROW POLICY policy10 ON default.foo TO ALL")
with Scenario("I alter row policy assigned to all except one role", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_AllExcept("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy11"):
with When("I alter row policy to all except"):
node.query("ALTER ROW POLICY policy11 ON default.foo TO ALL EXCEPT role0")
with Scenario("I alter row policy assigned to all except multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_AllExcept("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy12"):
with When("I alter row policy to all except multiple roles"):
node.query("ALTER ROW POLICY policy12 ON default.foo TO ALL EXCEPT role0, role1")
with Scenario("I alter row policy assigned to none", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_Assignment_None("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with cleanup("policy12"):
with When("I alter row policy to no assignment"):
node.query("ALTER ROW POLICY policy12 ON default.foo TO NONE")
# Official syntax: ON CLUSTER cluster_name ON database.table
# Working syntax: both orderings of ON CLUSTER and TABLE clauses work
with Scenario("I alter row policy on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_OnCluster("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
try:
with Given("I have a row policy"):
node.query("CREATE ROW POLICY policy13 ON CLUSTER sharded_cluster ON default.foo")
with When("I run alter row policy command"):
node.query("ALTER ROW POLICY policy13 ON CLUSTER sharded_cluster ON default.foo")
finally:
with Finally("I drop the row policy"):
node.query("DROP ROW POLICY IF EXISTS policy13 ON CLUSTER sharded_cluster ON default.foo")
with Scenario("I alter row policy on fake cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_OnCluster("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
with When("I run alter row policy command"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("ALTER ROW POLICY policy13 ON CLUSTER fake_cluster ON default.foo", exitcode=exitcode, message=message)
with Scenario("I alter row policy on cluster after table", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Alter_OnCluster("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Alter_On("1.0")]):
try:
with Given("I have a row policy"):
node.query("CREATE ROW POLICY policy14 ON default.foo ON CLUSTER sharded_cluster")
with When("I run create row policy command"):
node.query("ALTER ROW POLICY policy14 ON default.foo ON CLUSTER sharded_cluster")
finally:
with Finally("I drop the row policy"):
node.query("DROP ROW POLICY IF EXISTS policy14 ON default.foo ON CLUSTER sharded_cluster")
finally:
with Finally("I drop the table and the roles"):
node.query(f"DROP TABLE IF EXISTS default.foo")
node.query(f"DROP ROLE IF EXISTS role0, role1")

View File

@ -0,0 +1,232 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("alter settings profile")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check alter settings profile query syntax.
```sql
ALTER SETTINGS PROFILE [IF EXISTS] name
[ON CLUSTER cluster_name]
[RENAME TO new_name]
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | INHERIT 'profile_name'] [,...]
[TO {user_or_role [,...] | NONE | ALL | ALL EXCEPT user_or_role [,...]]}
```
"""
node = self.context.cluster.node(node)
def cleanup_profile(profile):
with Given(f"I ensure that profile {profile} does not exist"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}")
try:
with Given("I have a profile and some users and roles"):
node.query(f"CREATE SETTINGS PROFILE profile0")
node.query(f"CREATE USER user0")
node.query(f"CREATE ROLE role0")
with Scenario("I alter settings profile with no options", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter("1.0")]):
with When("I alter settings profile"):
node.query("ALTER SETTINGS PROFILE profile0")
with Scenario("I alter settings profile short form", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter("1.0")]):
with When("I short form alter settings profile"):
node.query("ALTER PROFILE profile0")
with Scenario("I alter settings profile that does not exist, throws exception", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter("1.0")]):
profile = "profile1"
cleanup_profile(profile)
with When(f"I alter settings profile {profile} that doesn't exist"):
exitcode, message = errors.settings_profile_not_found_in_disk(name=profile)
node.query(f"ALTER SETTINGS PROFILE {profile}", exitcode=exitcode, message=message)
del profile
with Scenario("I alter settings profile if exists", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_IfExists("1.0")]):
with When("I alter settings profile using if exists"):
node.query("ALTER SETTINGS PROFILE IF EXISTS profile0")
with Scenario("I alter settings profile if exists, profile does not exist", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_IfExists("1.0")]):
profile = "profile1"
cleanup_profile(profile)
with When(f"I alter settings profile {profile} using if exists"):
node.query(f"ALTER SETTINGS PROFILE IF EXISTS {profile}")
del profile
with Scenario("I alter settings profile to rename, target available", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_Rename("1.0")]):
with When("I alter settings profile by renaming it"):
node.query("ALTER SETTINGS PROFILE profile0 RENAME TO profile0")
with Scenario("I alter settings profile to rename, target unavailable", flags=TE, requirements=[RQ_SRS_006_RBAC_SettingsProfile_Alter_Rename("1.0")]):
new_profile = "profile1"
try:
with Given(f"Ensure target name {new_profile} is NOT available"):
node.query(f"CREATE SETTINGS PROFILE IF NOT EXISTS {new_profile}")
with When(f"I try to rename to {new_profile}"):
exitcode, message = errors.cannot_rename_settings_profile(name="profile0", name_new=new_profile)
node.query(f"ALTER SETTINGS PROFILE profile0 RENAME TO {new_profile}", exitcode=exitcode, message=message)
finally:
with Finally(f"I cleanup target name {new_profile}"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {new_profile}")
del new_profile
with Scenario("I alter settings profile with a setting value", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables("1.0"),
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Value("1.0")]):
with When("I alter settings profile using settings"):
node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage = 100000001")
with Scenario("I alter settings profile with a setting value, does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables("1.0"),
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Value("1.0")]):
with When("I alter settings profile using settings and nonexistent value"):
exitcode, message = errors.unknown_setting("fake_setting")
node.query("ALTER SETTINGS PROFILE profile0 SETTINGS fake_setting = 100000001", exitcode=exitcode, message=message)
with Scenario("I alter settings profile with a min setting value", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints("1.0")]):
with When("I alter settings profile using 2 minimum formats"):
node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage MIN 100000001")
node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage MIN = 100000001")
with Scenario("I alter settings profile with a max setting value", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints("1.0")]):
with When("I alter settings profile using 2 maximum formats"):
node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage MAX 100000001")
node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage MAX = 100000001")
with Scenario("I alter settings profile with min and max setting values", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints("1.0")]):
with When("I alter settings profile with both min and max"):
node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage MIN 100000001 MAX 200000001")
with Scenario("I alter settings profile with a readonly setting", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints("1.0")]):
with When("I alter settings profile with with readonly"):
node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage READONLY")
with Scenario("I alter settings profile with a writable setting", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Constraints("1.0")]):
with When("I alter settings profile with writable"):
node.query("ALTER SETTINGS PROFILE profile0 SETTINGS max_memory_usage WRITABLE")
with Scenario("I alter settings profile with inherited settings", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_Inherit("1.0")]):
with When("I alter settings profile with inherit"):
node.query("ALTER SETTINGS PROFILE profile0 SETTINGS INHERIT 'default'")
with Scenario("I alter settings profile with inherit, parent profile does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_Inherit("1.0")]):
profile = "profile3"
with Given(f"I ensure that profile {profile} does not exist"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}")
with When("I alter settings profile inherit from nonexistant parent"):
exitcode, message = errors.settings_profile_not_found_in_disk(profile)
node.query(f"ALTER PROFILE profile0 SETTINGS INHERIT {profile}", exitcode=exitcode, message=message)
del profile
with Scenario("I alter settings profile with multiple settings", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables("1.0"),
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Value("1.0")]):
with When("I alter settings profile with multiple settings"):
node.query("ALTER SETTINGS PROFILE profile0"
" SETTINGS max_memory_usage = 100000001"
" SETTINGS max_memory_usage_for_user = 100000001")
with Scenario("I alter settings profile with multiple settings short form", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables("1.0"),
RQ_SRS_006_RBAC_SettingsProfile_Alter_Variables_Value("1.0")]):
with When("I alter settings profile with short form multiple settings"):
node.query("ALTER SETTINGS PROFILE profile0"
" SETTINGS max_memory_usage = 100000001,"
" max_memory_usage_for_user = 100000001")
with Scenario("I alter settings profile assigned to one role", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment("1.0")]):
with When("I alter settings profile with assignment to role"):
node.query("ALTER SETTINGS PROFILE profile0 TO role0")
with Scenario("I alter settings profile to assign to role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment("1.0")]):
role = "role1"
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I alter a settings profile, assign to role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"ALTER SETTINGS PROFILE profile0 TO {role}", exitcode=exitcode, message=message)
del role
with Scenario("I alter settings profile to assign to all except role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment("1.0")]):
role = "role1"
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I alter a settings profile, assign to all except role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"ALTER SETTINGS PROFILE profile0 TO ALL EXCEPT {role}", exitcode=exitcode, message=message)
del role
with Scenario("I alter settings profile assigned to multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment("1.0")]):
with When("I alter settings profile with assignment to multiple roles"):
node.query("ALTER SETTINGS PROFILE profile0 TO role0, user0")
with Scenario("I alter settings profile assigned to all", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_All("1.0")]):
with When("I alter settings profile with assignment to all"):
node.query("ALTER SETTINGS PROFILE profile0 TO ALL")
with Scenario("I alter settings profile assigned to all except one role", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_AllExcept("1.0")]):
with When("I alter settings profile with assignment to all except a role"):
node.query("ALTER SETTINGS PROFILE profile0 TO ALL EXCEPT role0")
with Scenario("I alter settings profile assigned to all except multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_AllExcept("1.0")]):
with When("I alter settings profile with assignmentto all except multiple roles"):
node.query("ALTER SETTINGS PROFILE profile0 TO ALL EXCEPT role0, user0")
with Scenario("I alter settings profile assigned to none", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_None("1.0")]):
with When("I alter settings profile with assignment to none"):
node.query("ALTER SETTINGS PROFILE profile0 TO NONE")
with Scenario("I alter settings profile on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_OnCluster("1.0")]):
try:
with Given("I have a settings profile on cluster"):
node.query("CREATE SETTINGS PROFILE profile1 ON CLUSTER sharded_cluster")
with When("I run alter settings profile command"):
node.query("ALTER SETTINGS PROFILE profile1 ON CLUSTER sharded_cluster")
with And("I alter settings profile with settings"):
node.query("ALTER SETTINGS PROFILE profile1 ON CLUSTER sharded_cluster SETTINGS max_memory_usage = 100000001")
with And("I alter settings profile with inherit"):
node.query("ALTER SETTINGS PROFILE profile1 ON CLUSTER sharded_cluster SETTINGS INHERIT 'default'")
with And("I alter settings profile to all"):
node.query("ALTER SETTINGS PROFILE profile1 ON CLUSTER sharded_cluster TO ALL")
finally:
with Finally("I drop the settings profile"):
node.query("DROP SETTINGS PROFILE IF EXISTS profile1 ON CLUSTER sharded_cluster")
with Scenario("I alter settings profile on fake cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Alter_Assignment_OnCluster("1.0")]):
with When("I run alter settings profile command"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("ALTER SETTINGS PROFILE profile1 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)
finally:
with Finally("I drop the profile and all the users and roles"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS profile0")
node.query(f"DROP USER IF EXISTS user0")
node.query(f"DROP ROLE IF EXISTS role0")

View File

@ -0,0 +1,324 @@
import hashlib
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("alter user")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check alter user query syntax.
```sql
ALTER USER [IF EXISTS] name [ON CLUSTER cluster_name]
[RENAME TO new_name]
[IDENTIFIED [WITH {PLAINTEXT_PASSWORD|SHA256_PASSWORD|DOUBLE_SHA1_PASSWORD}] BY {'password'|'hash'}]
[[ADD|DROP] HOST {LOCAL | NAME 'name' | REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
[DEFAULT ROLE role [,...] | ALL | ALL EXCEPT role [,...] ]
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def setup(user):
try:
with Given("I have a user"):
node.query(f"CREATE USER OR REPLACE {user}")
yield
finally:
with Finally("I drop the user", flags=TE):
node.query(f"DROP USER IF EXISTS {user}")
with Scenario("I alter user, base command", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter("1.0")]):
with setup("user0"):
with When("I alter user"):
node.query("ALTER USER user0")
with Scenario("I alter user that does not exist without if exists, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter("1.0")]):
with When("I run alter user command, expecting error 192"):
exitcode, message = errors.user_not_found_in_disk(name="user0")
node.query(f"ALTER USER user0",exitcode=exitcode, message=message)
with Scenario("I alter user with if exists", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_IfExists("1.0")]):
with setup("user0"):
with When(f"I alter user with if exists"):
node.query(f"ALTER USER IF EXISTS user0")
with Scenario("I alter user that does not exist with if exists", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_IfExists("1.0")]):
user = "user0"
with Given("I don't have a user"):
node.query(f"DROP USER IF EXISTS {user}")
with When(f"I alter user {user} with if exists"):
node.query(f"ALTER USER IF EXISTS {user}")
del user
with Scenario("I alter user on a cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Cluster("1.0")]):
with Given("I have a user on a cluster"):
node.query("CREATE USER OR REPLACE user0 ON CLUSTER sharded_cluster")
with When("I alter user on a cluster"):
node.query("ALTER USER user0 ON CLUSTER sharded_cluster")
with Finally("I drop user from cluster"):
node.query("DROP USER IF EXISTS user0 ON CLUSTER sharded_cluster")
with Scenario("I alter user on a fake cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Cluster("1.0")]):
with When("I alter user on a fake cluster"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("ALTER USER user0 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)
with Scenario("I alter user to rename, target available", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Rename("1.0")]):
with setup("user15"):
with When("I alter user name"):
node.query("ALTER USER user15 RENAME TO user15")
with Scenario("I alter user to rename, target unavailable", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Rename("1.0")]):
with setup("user15"):
new_user = "user16"
try:
with Given(f"Ensure target name {new_user} is NOT available"):
node.query(f"CREATE USER IF NOT EXISTS {new_user}")
with When(f"I try to rename to {new_user}"):
exitcode, message = errors.cannot_rename_user(name="user15", name_new=new_user)
node.query(f"ALTER USER user15 RENAME TO {new_user}", exitcode=exitcode, message=message)
finally:
with Finally(f"I cleanup target name {new_user}"):
node.query(f"DROP USER IF EXISTS {new_user}")
del new_user
with Scenario("I alter user password plaintext password", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Password_PlainText("1.0")]):
with setup("user1"):
with When("I alter user with plaintext password"):
node.query("ALTER USER user1 IDENTIFIED WITH PLAINTEXT_PASSWORD BY 'mypassword'", step=When)
with Scenario("I alter user password to sha256", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Password_Sha256Password("1.0")]):
with setup("user2"):
with When("I alter user with sha256_password"):
password = hashlib.sha256("mypassword".encode("utf-8")).hexdigest()
node.query(f"ALTER USER user2 IDENTIFIED WITH SHA256_PASSWORD BY '{password}'",step=When)
with Scenario("I alter user password to double_sha1_password", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Password_DoubleSha1Password("1.0")]):
with setup("user3"):
with When("I alter user with double_sha1_password"):
def hash(password):
return hashlib.sha1(password.encode("utf-8")).hexdigest()
password = hash(hash("mypassword"))
node.query(f"ALTER USER user3 IDENTIFIED WITH DOUBLE_SHA1_PASSWORD BY '{password}'", step=When)
with Scenario("I alter user host local", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Host_Local("1.0")]):
with setup("user4"):
with When("I alter user with host local"):
node.query("ALTER USER user4 HOST LOCAL")
with Scenario("I alter user host name", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Host_Name("1.0")]):
with setup("user5"):
with When("I alter user with host name"):
node.query("ALTER USER user5 HOST NAME 'localhost', NAME 'clickhouse.com'")
with Scenario("I alter user host regexp", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Host_Regexp("1.0")]):
with setup("user6"):
with When("I alter user with host regexp"):
node.query("ALTER USER user6 HOST REGEXP 'lo..*host', 'lo*host'")
with Scenario("I alter user host ip", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Host_IP("1.0")]):
with setup("user7"):
with When("I alter user with host ip"):
node.query("ALTER USER user7 HOST IP '127.0.0.1', IP '127.0.0.2'")
with Scenario("I alter user host like", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Host_Like("1.0")]):
with setup("user8"):
with When("I alter user with host like"):
node.query("ALTER USER user8 HOST LIKE '%.clickhouse.com'")
with Scenario("I alter user host any", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Host_Any("1.0")]):
with setup("user9"):
with When("I alter user with host any"):
node.query("ALTER USER user9 HOST ANY")
with Scenario("I alter user host many hosts", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Host_Like("1.0")]):
with setup("user11"):
with When("I alter user with multiple hosts"):
node.query("ALTER USER user11 HOST LIKE '%.clickhouse.com', \
IP '127.0.0.2', NAME 'localhost', REGEXP 'lo*host'")
with Scenario("I alter user default role set to none", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Host_None("1.0")]):
with setup("user12"):
with When("I alter user with default role none"):
node.query("ALTER USER user12 DEFAULT ROLE NONE")
with Scenario("I alter user default role set to all", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_DefaultRole_All("1.0")]):
with setup("user13"):
with When("I alter user with all roles set to default"):
node.query("ALTER USER user13 DEFAULT ROLE ALL")
@contextmanager
def setup_role(role):
try:
with Given(f"I have a role {role}"):
node.query(f"CREATE ROLE OR REPLACE {role}")
yield
finally:
with Finally(f"I drop the role {role}", flags=TE):
node.query(f"DROP ROLE IF EXISTS {role}")
with Scenario("I alter user default role", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_DefaultRole("1.0")]):
with setup("user14"), setup_role("role2"):
with Given("I have a user with a role"):
node.query("GRANT role2 TO user14")
with When("I alter user default role"):
node.query("ALTER USER user14 DEFAULT ROLE role2")
with Scenario("I alter user default role, setting default role", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_DefaultRole("1.0")]):
with setup("user14a"), setup_role("default"):
with Given("I grant default role to the user"):
node.query("GRANT default TO user14a")
with When("I alter user default role"):
node.query("ALTER USER user14a DEFAULT ROLE default")
with Scenario("I alter user default role, role doesn't exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_DefaultRole("1.0")]):
with setup("user12"):
role = "role0"
with Given(f"I ensure that role {role} does not exist"):
node.query(f"DROP ROLE IF EXISTS {role}")
with When(f"I alter user with default role {role}"):
exitcode, message = errors.role_not_found_in_disk(role)
node.query(f"ALTER USER user12 DEFAULT ROLE {role}",exitcode=exitcode, message=message)
del role
with Scenario("I alter user default role, all except role doesn't exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_DefaultRole("1.0")]):
with setup("user12"):
role = "role0"
with Given(f"I ensure that role {role} does not exist"):
node.query(f"DROP ROLE IF EXISTS {role}")
with When(f"I alter user with default role {role}"):
exitcode, message = errors.role_not_found_in_disk(role)
node.query(f"ALTER USER user12 DEFAULT ROLE ALL EXCEPT {role}",exitcode=exitcode, message=message)
del role
with Scenario("I alter user default role multiple", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_DefaultRole("1.0")]):
with setup("user15"), setup_role("second"), setup_role("third"):
with Given("I have a user with multiple roles"):
node.query("GRANT second,third TO user15")
with When("I alter user default role to second, third"):
node.query("ALTER USER user15 DEFAULT ROLE second, third")
with Scenario("I alter user default role set to all except", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_DefaultRole_AllExcept("1.0")]):
with setup("user16"), setup_role("second"):
with Given("I have a user with a role"):
node.query("GRANT second TO user16")
with When("I alter user default role"):
node.query("ALTER USER user16 DEFAULT ROLE ALL EXCEPT second")
with Scenario("I alter user default role multiple all except", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_DefaultRole_AllExcept("1.0")]):
with setup("user17"), setup_role("second"), setup_role("third"):
with Given("I have a user with multiple roles"):
node.query("GRANT second,third TO user17")
with When("I alter user default role to all except second"):
node.query("ALTER USER user17 DEFAULT ROLE ALL EXCEPT second")
with Scenario("I alter user settings profile", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Settings("1.0"), \
RQ_SRS_006_RBAC_User_Alter_Settings_Profile("1.0")]):
with setup("user18"):
try:
with Given("I have a profile"):
node.query(f"CREATE SETTINGS PROFILE profile10")
with When("I alter user with settings and set profile to profile1"):
node.query("ALTER USER user18 SETTINGS PROFILE profile10, max_memory_usage = 100 MIN 0 MAX 1000 READONLY")
finally:
with Finally("I drop the profile"):
node.query(f"DROP SETTINGS PROFILE profile10")
with Scenario("I alter user settings profile, fake profile, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Settings("1.0"),
RQ_SRS_006_RBAC_User_Alter_Settings_Profile("1.0")]):
with setup("user18a"):
profile = "profile0"
with Given(f"I ensure that profile {profile} does not exist"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}")
with When(f"I alter user with Settings and set profile to fake profile {profile}"):
exitcode, message = errors.settings_profile_not_found_in_disk(profile)
node.query("ALTER USER user18a SETTINGS PROFILE profile0", exitcode=exitcode, message=message)
del profile
with Scenario("I alter user settings with a fake setting, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Settings("1.0")]):
with setup("user18b"):
with When("I alter settings profile using settings and nonexistent value"):
exitcode, message = errors.unknown_setting("fake_setting")
node.query("ALTER USER user18b SETTINGS fake_setting = 100000001", exitcode=exitcode, message=message)
with Scenario("I alter user settings without profile (no equals)", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Settings("1.0"),
RQ_SRS_006_RBAC_User_Alter_Settings_Min("1.0"),
RQ_SRS_006_RBAC_User_Alter_Settings_Max("1.0")]):
with setup("user19"):
with When("I alter user with settings without profile using no equals"):
node.query("ALTER USER user19 SETTINGS max_memory_usage=10000000 MIN 100000 MAX 1000000000 READONLY")
#equals sign (=) syntax verify
with Scenario("I alter user settings without profile (yes equals)", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Settings("1.0"),
RQ_SRS_006_RBAC_User_Alter_Settings_Min("1.0"),
RQ_SRS_006_RBAC_User_Alter_Settings_Max("1.0")]):
with setup("user20"):
with When("I alter user with settings without profile using equals"):
node.query("ALTER USER user20 SETTINGS max_memory_usage=10000000 MIN=100000 MAX=1000000000 READONLY")
#Add requirement to host: add/drop
with Scenario("I alter user to add host", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Host_AddDrop("1.0")]):
with setup("user21"):
with When("I alter user by adding local host"):
node.query("ALTER USER user21 ADD HOST LOCAL")
with And("I alter user by adding no host"):
node.query("ALTER USER user21 ADD HOST NONE")
with And("I alter user by adding host like"):
node.query("ALTER USER user21 ADD HOST LIKE 'local%'")
with And("I alter user by adding host ip"):
node.query("ALTER USER user21 ADD HOST IP '127.0.0.1'")
with And("I alter user by adding host name"):
node.query("ALTER USER user21 ADD HOST NAME 'localhost'")
with Scenario("I alter user to remove host", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Alter_Host_AddDrop("1.0")]):
with setup("user22"):
with When("I alter user by removing local host"):
node.query("ALTER USER user22 DROP HOST LOCAL")
with And("I alter user by removing no host"):
node.query("ALTER USER user22 DROP HOST NONE")
with And("I alter user by removing like host"):
node.query("ALTER USER user22 DROP HOST LIKE 'local%'")
with And("I alter user by removing host ip"):
node.query("ALTER USER user22 DROP HOST IP '127.0.0.1'")
with And("I alter user by removing host name"):
node.query("ALTER USER user22 DROP HOST NAME 'localhost'")

View File

@ -0,0 +1,227 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("create quota")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check create quota query syntax.
```sql
CREATE QUOTA [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name]
[KEYED BY {'none' | 'user name' | 'ip address' | 'client key' | 'client key or user name' | 'client key or ip address'}]
[FOR [RANDOMIZED] INTERVAL number {SECOND | MINUTE | HOUR | DAY}
{MAX { {QUERIES | ERRORS | RESULT ROWS | RESULT BYTES | READ ROWS | READ BYTES | EXECUTION TIME} = number } [,...] |
NO LIMITS | TRACKING ONLY} [,...]]
[TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(quota):
try:
with Given("I ensure the quota does not already exist"):
node.query(f"DROP QUOTA IF EXISTS {quota}")
yield
finally:
with Finally("I drop the quota"):
node.query(f"DROP QUOTA IF EXISTS {quota}")
def create_quota(quota):
with And(f"I ensure I do have quota {quota}"):
node.query(f"CREATE QUOTA OR REPLACE {quota}")
try:
with Given("I have a user and a role"):
node.query(f"CREATE USER user0")
node.query(f"CREATE ROLE role0")
with Scenario("I create quota with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create("1.0")]):
with cleanup("quota0"):
with When("I create a quota with no options"):
node.query("CREATE QUOTA quota0")
with Scenario("I create quota that already exists, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create("1.0")]):
quota = "quota0"
with cleanup(quota):
create_quota(quota)
with When(f"I create a quota {quota} that already exists without IF EXISTS, throws exception"):
exitcode, message = errors.cannot_insert_quota(name=quota)
node.query(f"CREATE QUOTA {quota}", exitcode=exitcode, message=message)
del quota
with Scenario("I create quota if not exists, quota does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_IfNotExists("1.0")]):
quota = "quota1"
with cleanup(quota):
with When(f"I create a quota {quota} with if not exists"):
node.query(f"CREATE QUOTA IF NOT EXISTS {quota}")
del quota
with Scenario("I create quota if not exists, quota does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_IfNotExists("1.0")]):
quota = "quota1"
with cleanup(quota):
create_quota(quota)
with When(f"I create a quota {quota} with if not exists"):
node.query(f"CREATE QUOTA IF NOT EXISTS {quota}")
del quota
with Scenario("I create quota or replace, quota does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Replace("1.0")]):
quota = "quota2"
with cleanup(quota):
with When(f"I create a quota {quota} with or replace"):
node.query(f"CREATE QUOTA OR REPLACE {quota}")
del quota
with Scenario("I create quota or replace, quota does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Replace("1.0")]):
quota = "quota2"
with cleanup(quota):
create_quota(quota)
with When(f"I create a quota {quota} with or replace"):
node.query(f"CREATE QUOTA OR REPLACE {quota}")
del quota
keys = ['none', 'user name', 'ip address', 'client key', 'client key or user name', 'client key or ip address']
for i, key in enumerate(keys):
with Scenario(f"I create quota keyed by {key}", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_KeyedBy("1.0"),
RQ_SRS_006_RBAC_Quota_Create_KeyedByOptions("1.0")]):
name = f'quota{3 + i}'
with cleanup(name):
with When(f"I create a quota with {key}"):
node.query(f"CREATE QUOTA {name} KEYED BY '{key}'")
with Scenario("I create quota for randomized interval", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Interval_Randomized("1.0")]):
with cleanup("quota9"):
with When("I create a quota for randomized interval"):
node.query("CREATE QUOTA quota9 FOR RANDOMIZED INTERVAL 1 DAY NO LIMITS")
intervals = ['SECOND', 'MINUTE', 'HOUR', 'DAY', 'MONTH']
for i, interval in enumerate(intervals):
with Scenario(f"I create quota for interval {interval}", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Interval("1.0")]):
name = f'quota{10 + i}'
with cleanup(name):
with When(f"I create a quota for {interval} interval"):
node.query(f"CREATE QUOTA {name} FOR INTERVAL 1 {interval} NO LIMITS")
constraints = ['MAX QUERIES', 'MAX ERRORS', 'MAX RESULT ROWS',
'MAX RESULT BYTES', 'MAX READ ROWS', 'MAX READ BYTES', 'MAX EXECUTION TIME',
'NO LIMITS', 'TRACKING ONLY']
for i, constraint in enumerate(constraints):
with Scenario(f"I create quota for {constraint.lower()}", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Queries("1.0"),
RQ_SRS_006_RBAC_Quota_Create_Errors("1.0"),
RQ_SRS_006_RBAC_Quota_Create_ResultRows("1.0"),
RQ_SRS_006_RBAC_Quota_Create_ResultBytes("1.0"),
RQ_SRS_006_RBAC_Quota_Create_ReadRows("1.0"),
RQ_SRS_006_RBAC_Quota_Create_ReadBytes("1.0"),
RQ_SRS_006_RBAC_Quota_Create_ExecutionTime("1.0"),
RQ_SRS_006_RBAC_Quota_Create_NoLimits("1.0"),
RQ_SRS_006_RBAC_Quota_Create_TrackingOnly("1.0")]):
name = f'quota{15 + i}'
with cleanup(name):
with When(f"I create quota for {constraint.lower()}"):
node.query(f"CREATE QUOTA {name} FOR INTERVAL 1 DAY {constraint}{' 1024' if constraint.startswith('MAX') else ''}")
with Scenario("I create quota for multiple constraints", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Interval("1.0"),
RQ_SRS_006_RBAC_Quota_Create_Queries("1.0")]):
with cleanup("quota23"):
with When(f"I create quota for multiple constraints"):
node.query('CREATE QUOTA quota23 \
FOR INTERVAL 1 DAY NO LIMITS, \
FOR INTERVAL 2 DAY MAX QUERIES 124, \
FOR INTERVAL 1 HOUR TRACKING ONLY')
with Scenario("I create quota assigned to one role", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Assignment("1.0")]):
with cleanup("quota24"):
with When("I create quota for role"):
node.query("CREATE QUOTA quota24 TO role0")
with Scenario("I create quota to assign to role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Assignment("1.0")]):
role = "role1"
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I create a quota, assign to role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"CREATE QUOTA quota0 TO {role}", exitcode=exitcode, message=message)
del role
with Scenario("I create quota to assign to all except role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Assignment("1.0")]):
role = "role1"
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I create a quota, assign to all except role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"CREATE QUOTA quota0 TO ALL EXCEPT {role}", exitcode=exitcode, message=message)
del role
with Scenario("I create quota assigned to no role", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Assignment_None("1.0")]):
with When("I create quota for no role"):
node.query("CREATE QUOTA quota24 TO NONE")
with Scenario("I create quota assigned to multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Assignment("1.0")]):
with cleanup("quota25"):
with When("I create quota for multiple roles"):
node.query("CREATE QUOTA quota25 TO role0, user0")
with Scenario("I create quota assigned to all", flags=TE,requirements=[
RQ_SRS_006_RBAC_Quota_Create_Assignment_All("1.0")]):
with cleanup("quota26"):
with When("I create quota for all"):
node.query("CREATE QUOTA quota26 TO ALL")
with Scenario("I create quota assigned to all except one role", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Assignment_Except("1.0")]):
with cleanup("quota27"):
with When("I create quota for all except one role"):
node.query("CREATE QUOTA quota27 TO ALL EXCEPT role0")
with Scenario("I create quota assigned to all except multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Assignment_Except("1.0")]):
with cleanup("quota28"):
with When("I create quota for all except multiple roles"):
node.query("CREATE QUOTA quota28 TO ALL EXCEPT role0, user0")
with Scenario("I create quota on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Cluster("1.0")]):
try:
with When("I run create quota command on cluster"):
node.query("CREATE QUOTA quota29 ON CLUSTER sharded_cluster")
with When("I run create quota command on cluster, keyed"):
node.query("CREATE QUOTA OR REPLACE quota29 ON CLUSTER sharded_cluster KEYED BY 'none'")
with When("I run create quota command on cluster, interval"):
node.query("CREATE QUOTA OR REPLACE quota29 ON CLUSTER sharded_cluster FOR INTERVAL 1 DAY TRACKING ONLY")
with When("I run create quota command on cluster, assign"):
node.query("CREATE QUOTA OR REPLACE quota29 ON CLUSTER sharded_cluster TO ALL")
finally:
with Finally("I drop the quota from cluster"):
node.query("DROP QUOTA IF EXISTS quota29 ON CLUSTER sharded_cluster")
with Scenario("I create quota on nonexistent cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Create_Cluster("1.0")]):
with When("I run create quota on a cluster"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("CREATE QUOTA quota0 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)
finally:
with Finally("I drop all the users and roles"):
node.query(f"DROP USER IF EXISTS user0")
node.query(f"DROP ROLE IF EXISTS role0")

View File

@ -0,0 +1,122 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("create role")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check create role query syntax.
```sql
CREATE ROLE [IF NOT EXISTS | OR REPLACE] name
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(role):
try:
with Given("I ensure the role doesn't already exist"):
node.query(f"DROP ROLE IF EXISTS {role}")
yield
finally:
with Finally("I drop the role"):
node.query(f"DROP ROLE IF EXISTS {role}")
def create_role(role):
with Given(f"I ensure I do have role {role}"):
node.query(f"CREATE ROLE OR REPLACE {role}")
with Scenario("I create role with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Create("1.0")]):
with cleanup("role0"):
with When("I create role"):
node.query("CREATE ROLE role0")
with Scenario("I create role that already exists, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Create("1.0")]):
role = "role0"
with cleanup(role):
with When(f"I create role {role}"):
exitcode, message = errors.cannot_insert_role(name=role)
node.query(f"CREATE ROLE {role}", exitcode=exitcode, message=message)
del role
with Scenario("I create role if not exists, role does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Create_IfNotExists("1.0")]):
role = "role1"
with cleanup(role):
with When(f"I create role {role} with if not exists"):
node.query(f"CREATE ROLE IF NOT EXISTS {role}")
del role
with Scenario("I create role if not exists, role does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Create_IfNotExists("1.0")]):
role = "role1"
with cleanup(role):
create_role(role)
with When(f"I create role {role} with if not exists"):
node.query(f"CREATE ROLE IF NOT EXISTS {role}")
del role
with Scenario("I create role or replace, role does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Create_Replace("1.0")]):
role = "role2"
with cleanup(role):
with When(f"I create role {role} with or replace"):
node.query(f"CREATE ROLE OR REPLACE {role}")
del role
with Scenario("I create role or replace, role does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Create_Replace("1.0")]):
role = "role2"
with cleanup(role):
create_role(role)
with When(f"I create role {role} with or replace"):
node.query(f"CREATE ROLE OR REPLACE {role}")
del role
with Scenario("I create role on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Create("1.0")]):
try:
with When("I have a role on a cluster"):
node.query("CREATE ROLE role1 ON CLUSTER sharded_cluster")
with And("I run create role or replace on a cluster"):
node.query("CREATE ROLE OR REPLACE role1 ON CLUSTER sharded_cluster")
with And("I create role with settings on a cluster"):
node.query("CREATE ROLE role2 ON CLUSTER sharded_cluster SETTINGS max_memory_usage=10000000 READONLY")
finally:
with Finally("I drop the role"):
node.query("DROP ROLE IF EXISTS role1,role2 ON CLUSTER sharded_cluster")
with Scenario("I create role on nonexistent cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Create("1.0")]):
with When("I run create role on a cluster"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("CREATE ROLE role1 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)
with Scenario("I create role with settings profile", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Create_Settings("1.0")]):
with cleanup("role3"):
with When("I create role with settings profile"):
node.query("CREATE ROLE role3 SETTINGS PROFILE default, max_memory_usage=10000000 WRITABLE")
with Scenario("I create role settings profile, fake profile, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Create_Settings("1.0")]):
with cleanup("role4a"):
with Given("I ensure profile profile0 does not exist"):
node.query("DROP SETTINGS PROFILE IF EXISTS profile0")
with When("I create role with settings profile that does not exist"):
exitcode, message = errors.settings_profile_not_found_in_disk("profile0")
node.query("CREATE ROLE role4a SETTINGS PROFILE profile0", exitcode=exitcode, message=message)
with Scenario("I create role with settings without profile", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Create_Settings("1.0")]):
with cleanup("role4"):
with When("I create role with settings without profile"):
node.query("CREATE ROLE role4 SETTINGS max_memory_usage=10000000 READONLY")

View File

@ -0,0 +1,225 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("create row policy")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check create row policy query syntax.
```sql
CREATE [ROW] POLICY [IF NOT EXISTS | OR REPLACE] policy_name [ON CLUSTER cluster_name] ON [db.]table
[AS {PERMISSIVE | RESTRICTIVE}]
[FOR SELECT]
[USING condition]
[TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(policy, on="default.foo"):
try:
with Given(f"I ensure the row policy does not already exist on {on}"):
node.query(f"DROP ROW POLICY IF EXISTS {policy} ON {on}")
yield
finally:
with Finally(f"I drop the row policy on {on}"):
node.query(f"DROP ROW POLICY IF EXISTS {policy} ON {on}")
def create_policy(policy, on="default.foo"):
with Given(f"I ensure I do have policy {policy} on {on}"):
node.query(f"CREATE ROW POLICY OR REPLACE {policy} ON {on}")
try:
with Given("I have a table and some roles"):
node.query(f"CREATE TABLE default.foo (x UInt64, y String) Engine=Memory")
node.query(f"CREATE ROLE role0")
node.query(f"CREATE ROLE role1")
with Scenario("I create row policy with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy0"):
with When("I create row policy"):
node.query("CREATE ROW POLICY policy0 ON default.foo")
with Scenario("I create row policy using short syntax with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy1"):
with When("I create row policy short form"):
node.query("CREATE POLICY policy1 ON default.foo")
with Scenario("I create row policy that already exists, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
policy = "policy0"
with cleanup(policy):
create_policy(policy)
with When(f"I create row policy {policy}"):
exitcode, message = errors.cannot_insert_row_policy(name=f"{policy} ON default.foo")
node.query(f"CREATE ROW POLICY {policy} ON default.foo", exitcode=exitcode, message=message)
del policy
with Scenario("I create row policy if not exists, policy does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_IfNotExists("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy2"):
with When("I create row policy with if not exists"):
node.query("CREATE ROW POLICY IF NOT EXISTS policy2 ON default.foo")
with Scenario("I create row policy if not exists, policy does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_IfNotExists("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
policy = "policy2"
with cleanup(policy):
create_policy(policy)
with When(f"I create row policy {policy} with if not exists"):
node.query(f"CREATE ROW POLICY IF NOT EXISTS {policy} ON default.foo")
del policy
with Scenario("I create row policy or replace, policy does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Replace("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy3"):
with When("I create row policy with or replace"):
node.query("CREATE ROW POLICY OR REPLACE policy3 ON default.foo")
with Scenario("I create row policy or replace, policy does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Replace("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
policy = "policy3"
with cleanup(policy):
create_policy(policy)
with When(f"I create row policy {policy} with or replace"):
node.query(f"CREATE ROW POLICY OR REPLACE {policy} ON default.foo")
del policy
with Scenario("I create row policy as permissive", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Access_Permissive("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy4"):
with When("I create row policy as permissive"):
node.query("CREATE ROW POLICY policy4 ON default.foo AS PERMISSIVE")
with Scenario("I create row policy as restrictive", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Access_Restrictive("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy5"):
with When("I create row policy as restrictive"):
node.query("CREATE ROW POLICY policy5 ON default.foo AS RESTRICTIVE")
with Scenario("I create row policy for select", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_ForSelect("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_Condition("1.0")]):
with cleanup("policy6"):
with When("I create row policy with for select"):
node.query("CREATE ROW POLICY policy6 ON default.foo FOR SELECT USING x > 10")
with Scenario("I create row policy using condition", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Condition("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy6"):
with When("I create row policy with condition"):
node.query("CREATE ROW POLICY policy6 ON default.foo USING x > 10")
with Scenario("I create row policy assigned to one role", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Assignment("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy7"):
with When("I create row policy for one role"):
node.query("CREATE ROW POLICY policy7 ON default.foo TO role0")
with Scenario("I create row policy to assign to role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Assignment("1.0")]):
role = "role2"
with cleanup("policy8a"):
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I create a row policy, assign to role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"CREATE ROW POLICY policy8a ON default.foo TO {role}", exitcode=exitcode, message=message)
del role
with Scenario("I create row policy to assign to all excpet role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Assignment("1.0")]):
role = "role2"
with cleanup("policy8a"):
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I create a row policy, assign to all except role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"CREATE ROW POLICY policy8a ON default.foo TO ALL EXCEPT {role}", exitcode=exitcode, message=message)
del role
with Scenario("I create row policy assigned to multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Assignment("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy8b"):
with When("I create row policy for multiple roles"):
node.query("CREATE ROW POLICY policy8b ON default.foo TO role0, role1")
with Scenario("I create row policy assigned to all", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_All("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy9"):
with When("I create row policy for all"):
node.query("CREATE ROW POLICY policy9 ON default.foo TO ALL")
with Scenario("I create row policy assigned to all except one role", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_AllExcept("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy10"):
with When("I create row policy for all except one"):
node.query("CREATE ROW POLICY policy10 ON default.foo TO ALL EXCEPT role0")
with Scenario("I create row policy assigned to all except multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_AllExcept("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy11"):
with When("I create row policy for all except multiple roles"):
node.query("CREATE ROW POLICY policy11 ON default.foo TO ALL EXCEPT role0, role1")
with Scenario("I create row policy assigned to none", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_Assignment_None("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with cleanup("policy11"):
with When("I create row policy for none"):
node.query("CREATE ROW POLICY policy11 ON default.foo TO NONE")
with Scenario("I create row policy on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_OnCluster("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
try:
with When("I run create row policy command on cluster"):
node.query("CREATE ROW POLICY policy12 ON CLUSTER sharded_cluster ON default.foo")
finally:
with Finally("I drop the row policy from cluster"):
node.query("DROP ROW POLICY IF EXISTS policy12 ON default.foo ON CLUSTER sharded_cluster")
with Scenario("I create row policy on fake cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_OnCluster("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
with When("I run create row policy command"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("CREATE ROW POLICY policy13 ON CLUSTER fake_cluster ON default.foo", exitcode=exitcode, message=message)
with Scenario("I create row policy on cluster after table", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Create_OnCluster("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Create_On("1.0")]):
try:
with When("I run create row policy command on cluster"):
node.query("CREATE ROW POLICY policy12 ON default.foo ON CLUSTER sharded_cluster")
finally:
with Finally("I drop the row policy from cluster"):
node.query("DROP ROW POLICY IF EXISTS policy12 ON default.foo ON CLUSTER sharded_cluster")
finally:
with Finally("I drop the table and the roles"):
node.query(f"DROP TABLE IF EXISTS default.foo")
node.query(f"DROP ROLE IF EXISTS role0, role1")

View File

@ -0,0 +1,254 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("create settings profile")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check create settings profile query syntax.
```sql
CREATE [SETTINGS] PROFILE [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name]
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value]
[READONLY] | [INHERIT|PROFILE 'profile_name']] [,...]
[TO {role [,...] | ALL | ALL EXCEPT role [,...]}]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(profile):
try:
with Given(f"I ensure the profile {profile} does not exist"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}")
yield
finally:
with Finally("I drop the profile"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}")
def create_profile(profile):
with Given(f"I ensure I do have profile {profile}"):
node.query(f"CREATE SETTINGS PROFILE OR REPLACE {profile}")
try:
with Given("I have a user and a role"):
node.query(f"CREATE USER user0")
node.query(f"CREATE ROLE role0")
with Scenario("I create settings profile with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create("1.0")]):
with cleanup("profile0"):
with When("I create settings profile"):
node.query("CREATE SETTINGS PROFILE profile0")
with Scenario("I create settings profile that already exists, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create("1.0")]):
profile = "profile0"
with cleanup(profile):
create_profile(profile)
with When(f"I create settings profile {profile} that already exists"):
exitcode, message = errors.cannot_insert_settings_profile(name=profile)
node.query(f"CREATE SETTINGS PROFILE {profile}", exitcode=exitcode, message=message)
del profile
with Scenario("I create settings profile if not exists, profile does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_IfNotExists("1.0")]):
with cleanup("profile1"):
with When("I create settings profile with if not exists"):
node.query("CREATE SETTINGS PROFILE IF NOT EXISTS profile1")
with Scenario("I create settings profile if not exists, profile does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_IfNotExists("1.0")]):
profile = "profile1"
with cleanup(profile):
create_profile(profile)
with When(f"I create settings profile {profile} with if not exists"):
node.query(f"CREATE SETTINGS PROFILE IF NOT EXISTS {profile}")
del profile
with Scenario("I create settings profile or replace, profile does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Replace("1.0")]):
with cleanup("profile2"):
with When("I create settings policy with or replace"):
node.query("CREATE SETTINGS PROFILE OR REPLACE profile2")
with Scenario("I create settings profile or replace, profile does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Replace("1.0")]):
with cleanup("profile2"):
create_profile("profile2")
with When("I create settings policy with or replace"):
node.query("CREATE SETTINGS PROFILE OR REPLACE profile2")
with Scenario("I create settings profile short form", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create("1.0")]):
with cleanup("profile3"):
with When("I create settings profile short form"):
node.query("CREATE PROFILE profile3")
with Scenario("I create settings profile with a setting value", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Variables("1.0"),
RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Value("1.0")]):
with cleanup("profile4"):
with When("I create settings profile with settings"):
node.query("CREATE SETTINGS PROFILE profile4 SETTINGS max_memory_usage = 100000001")
with Scenario("I create settings profile with a setting value, does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Variables("1.0"),
RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Value("1.0")]):
with When("I create settings profile using settings and nonexistent value"):
exitcode, message = errors.unknown_setting("fake_setting")
node.query("CREATE SETTINGS PROFILE profile0 SETTINGS fake_setting = 100000001", exitcode=exitcode, message=message)
with Scenario("I create settings profile with a min setting value", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]):
with cleanup("profile5"), cleanup("profile6"):
with When("I create settings profile with min setting with and without equals"):
node.query("CREATE SETTINGS PROFILE profile5 SETTINGS max_memory_usage MIN 100000001")
node.query("CREATE SETTINGS PROFILE profile6 SETTINGS max_memory_usage MIN = 100000001")
with Scenario("I create settings profile with a max setting value", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]):
with cleanup("profile7"), cleanup("profile8"):
with When("I create settings profile with max setting with and without equals"):
node.query("CREATE SETTINGS PROFILE profile7 SETTINGS max_memory_usage MAX 100000001")
node.query("CREATE SETTINGS PROFILE profile8 SETTINGS max_memory_usage MAX = 100000001")
with Scenario("I create settings profile with min and max setting values", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]):
with cleanup("profile9"):
with When("I create settings profile with min and max setting"):
node.query("CREATE SETTINGS PROFILE profile9 SETTINGS max_memory_usage MIN 100000001 MAX 200000001")
with Scenario("I create settings profile with a readonly setting", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]):
with cleanup("profile10"):
with When("I create settings profile with readonly"):
node.query("CREATE SETTINGS PROFILE profile10 SETTINGS max_memory_usage READONLY")
with Scenario("I create settings profile with a writable setting", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]):
with cleanup("profile21"):
with When("I create settings profile with writable"):
node.query("CREATE SETTINGS PROFILE profile21 SETTINGS max_memory_usage WRITABLE")
with Scenario("I create settings profile with inherited settings", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Inherit("1.0")]):
with cleanup("profile11"):
with When("I create settings profile with inherit"):
node.query("CREATE SETTINGS PROFILE profile11 SETTINGS INHERIT 'default'")
with Scenario("I create settings profile with inherit/from profile, fake profile, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Inherit("1.0")]):
profile = "profile3"
with Given(f"I ensure that profile {profile} does not exist"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}")
sources = {"INHERIT","PROFILE"}
for source in sources:
with When(f"I create settings profile {source} from nonexistant parent"):
exitcode, message = errors.settings_profile_not_found_in_disk(profile)
node.query(f"CREATE PROFILE profile0 SETTINGS {source} {profile}", exitcode=exitcode, message=message)
del profile
with Scenario("I create settings profile with inherited settings other form", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Inherit("1.0")]):
with cleanup("profile12"):
with When("I create settings profile with inherit short form"):
node.query("CREATE PROFILE profile12 SETTINGS PROFILE 'default'")
with Scenario("I create settings profile with multiple settings", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]):
with cleanup("profile13"):
with When("I create settings profile with multiple settings"):
node.query("CREATE SETTINGS PROFILE profile13"
" SETTINGS max_memory_usage = 100000001"
" SETTINGS max_memory_usage_for_user = 100000001")
with Scenario("I create settings profile with multiple settings short form", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Variables_Constraints("1.0")]):
with cleanup("profile14"):
with When("I create settings profile with multiple settings short form"):
node.query("CREATE SETTINGS PROFILE profile14"
" SETTINGS max_memory_usage = 100000001,"
" max_memory_usage_for_user = 100000001")
with Scenario("I create settings profile assigned to one role", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment("1.0")]):
with cleanup("profile15"):
with When("I create settings profile for a role"):
node.query("CREATE SETTINGS PROFILE profile15 TO role0")
with Scenario("I create settings profile to assign to role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment("1.0")]):
role = "role1"
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I create a settings profile, assign to role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"CREATE SETTINGS PROFILE profile0 TO {role}", exitcode=exitcode, message=message)
del role
with Scenario("I create settings profile to assign to all except role that does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment("1.0")]):
role = "role1"
with Given(f"I drop {role} if it exists"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Then(f"I create a settings profile, assign to all except role {role}, which does not exist"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"CREATE SETTINGS PROFILE profile0 TO ALL EXCEPT {role}", exitcode=exitcode, message=message)
del role
with Scenario("I create settings profile assigned to multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment("1.0")]):
with cleanup("profile16"):
with When("I create settings profile for multiple roles"):
node.query("CREATE SETTINGS PROFILE profile16 TO role0, user0")
with Scenario("I create settings profile assigned to all", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_All("1.0")]):
with cleanup("profile17"):
with When("I create settings profile for all"):
node.query("CREATE SETTINGS PROFILE profile17 TO ALL")
with Scenario("I create settings profile assigned to all except one role", flags=TE,requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_AllExcept("1.0")]):
with cleanup("profile18"):
with When("I create settings profile for all except one role"):
node.query("CREATE SETTINGS PROFILE profile18 TO ALL EXCEPT role0")
with Scenario("I create settings profile assigned to all except multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_AllExcept("1.0")]):
with cleanup("profile19"):
with When("I create settings profile for all except multiple roles"):
node.query("CREATE SETTINGS PROFILE profile19 TO ALL EXCEPT role0, user0")
with Scenario("I create settings profile assigned to none", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_Assignment_None("1.0")]):
with cleanup("profile22"):
with When("I create settings profile for none"):
node.query("CREATE SETTINGS PROFILE profile22 TO NONE")
with Scenario("I create settings profile on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_OnCluster("1.0")]):
try:
with When("I run create settings profile command"):
node.query("CREATE SETTINGS PROFILE profile20 ON CLUSTER sharded_cluster")
node.query("CREATE SETTINGS PROFILE OR REPLACE profile20 ON CLUSTER sharded_cluster SETTINGS max_memory_usage = 100000001")
node.query("CREATE SETTINGS PROFILE OR REPLACE profile20 ON CLUSTER sharded_cluster SETTINGS INHERIT 'default'")
node.query("CREATE SETTINGS PROFILE OR REPLACE profile20 ON CLUSTER sharded_cluster TO ALL")
finally:
with Finally("I drop the settings profile"):
node.query("DROP SETTINGS PROFILE IF EXISTS profile20 ON CLUSTER sharded_cluster")
with Scenario("I create settings profile on fake cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Create_OnCluster("1.0")]):
with When("I run create settings profile command"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("CREATE SETTINGS PROFILE profile1 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)
finally:
with Finally("I drop all the users and roles"):
node.query(f"DROP USER IF EXISTS user0")
node.query(f"DROP ROLE IF EXISTS role0")

View File

@ -0,0 +1,271 @@
import hashlib
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("create user")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check create user query syntax.
```sql
CREATE USER [IF NOT EXISTS | OR REPLACE] name [ON CLUSTER cluster_name]
[IDENTIFIED [WITH {NO_PASSWORD|PLAINTEXT_PASSWORD|SHA256_PASSWORD|SHA256_HASH|DOUBLE_SHA1_PASSWORD|DOUBLE_SHA1_HASH}] BY {'password'|'hash'}]
[HOST {LOCAL | NAME 'name' | NAME REGEXP 'name_regexp' | IP 'address' | LIKE 'pattern'} [,...] | ANY | NONE]
[DEFAULT ROLE role [,...]]
[SETTINGS variable [= value] [MIN [=] min_value] [MAX [=] max_value] [READONLY|WRITABLE] | PROFILE 'profile_name'] [,...]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(user):
try:
with Given("I ensure the user does not already exist", flags=TE):
node.query(f"DROP USER IF EXISTS {user}")
yield
finally:
with Finally("I drop the user", flags=TE):
node.query(f"DROP USER IF EXISTS {user}")
def create_user(user):
with Given(f"I ensure I do have user {user}"):
node.query(f"CREATE USER OR REPLACE {user}")
with Scenario("I create user with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create("1.0"),
RQ_SRS_006_RBAC_User_Create_Host_Default("1.0")]):
with cleanup("user0"):
with When("I create a user with no options"):
node.query("CREATE USER user0")
with Scenario("I create user that already exists, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create("1.0"),
RQ_SRS_006_RBAC_User_Create_Host_Default("1.0")]):
user = "user0"
with cleanup(user):
create_user(user)
with When(f"I create a user {user} that already exists without IF EXISTS, throws exception"):
exitcode, message = errors.cannot_insert_user(name=user)
node.query(f"CREATE USER {user}", exitcode=exitcode, message=message)
del user
with Scenario("I create user with if not exists, user does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_IfNotExists("1.0")]):
user = "user0"
with cleanup(user):
with When(f"I create a user {user} with if not exists"):
node.query(f"CREATE USER IF NOT EXISTS {user}")
del user
#Bug exists, mark as xfail
with Scenario("I create user with if not exists, user does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_IfNotExists("1.0")]):
user = "user0"
with cleanup(user):
create_user(user)
with When(f"I create a user {user} with if not exists"):
node.query(f"CREATE USER IF NOT EXISTS {user}")
del user
with Scenario("I create user or replace, user does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Replace("1.0")]):
user = "user0"
with cleanup(user):
with When(f"I create a user {user} with or replace"):
node.query(f"CREATE USER OR REPLACE {user}")
del user
with Scenario("I create user or replace, user does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Replace("1.0")]):
user = "user0"
with cleanup(user):
create_user(user)
with When(f"I create a user {user} with or replace"):
node.query(f"CREATE USER OR REPLACE {user}")
del user
with Scenario("I create user with no password", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Password_NoPassword("1.0")]):
with cleanup("user1"):
with When("I create a user with no password"):
node.query("CREATE USER user1 IDENTIFIED WITH NO_PASSWORD")
with Scenario("I create user with plaintext password", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Password_PlainText("1.0")]):
with cleanup("user1"):
with When("I create a user with plaintext password"):
node.query("CREATE USER user1 IDENTIFIED WITH PLAINTEXT_PASSWORD BY 'mypassword'")
with Scenario("I create user with sha256 password", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Password_Sha256Password("1.0")]):
with cleanup("user2"):
with When("I create a user with sha256 password"):
password = hashlib.sha256("mypassword".encode("utf-8")).hexdigest()
node.query(f"CREATE USER user2 IDENTIFIED WITH SHA256_PASSWORD BY '{password}'")
with Scenario("I create user with sha256 password using IDENTIFIED BY", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Password_Sha256Password("1.0")]):
with cleanup("user2"):
with When("I create a user with sha256 password using short form"):
password = hashlib.sha256("mypassword".encode("utf-8")).hexdigest()
node.query(f"CREATE USER user2 IDENTIFIED BY '{password}'")
with Scenario("I create user with sha256_hash password", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Password_Sha256Hash("1.0")]):
with cleanup("user3"):
with When("I create a user with sha256_hash"):
def hash(password):
return hashlib.sha256(password.encode("utf-8")).hexdigest()
password = hash(hash("mypassword"))
node.query(f"CREATE USER user3 IDENTIFIED WITH SHA256_HASH BY '{password}'")
with Scenario("I create user with double sha1 password", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Password("1.0")]):
with cleanup("user3"):
with When("I create a user with double_sha1_password"):
node.query(f"CREATE USER user3 IDENTIFIED WITH DOUBLE_SHA1_PASSWORD BY 'mypassword'")
with Scenario("I create user with double sha1 hash", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Password_DoubleSha1Hash("1.0")]):
with cleanup("user3"):
with When("I create a user with double_sha1_hash"):
def hash(password):
return hashlib.sha1(password.encode("utf-8")).hexdigest()
password = hash(hash("mypassword"))
node.query(f"CREATE USER user3 IDENTIFIED WITH DOUBLE_SHA1_HASH BY '{password}'")
with Scenario("I create user with host name", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Host_Name("1.0")]):
with cleanup("user4"):
with When("I create a user with host name"):
node.query("CREATE USER user4 HOST NAME 'localhost', NAME 'clickhouse.com'")
with Scenario("I create user with host regexp", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Host_Regexp("1.0")]):
with cleanup("user5"):
with When("I create a user with host regexp"):
node.query("CREATE USER user5 HOST REGEXP 'lo.?*host', REGEXP 'lo*host'")
with Scenario("I create user with host ip", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Host_IP("1.0")]):
with cleanup("user6"):
with When("I create a user with host ip"):
node.query("CREATE USER user6 HOST IP '127.0.0.1', IP '127.0.0.2'")
with Scenario("I create user with host like", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Host_Like("1.0")]):
with cleanup("user7"):
with When("I create a user with host like"):
node.query("CREATE USER user7 HOST LIKE 'local%'")
with Scenario("I create user with host none", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Host_None("1.0")]):
with cleanup("user7"):
with When("I create a user with host none"):
node.query("CREATE USER user7 HOST NONE")
with Scenario("I create user with host local", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Host_Local("1.0")]):
with cleanup("user7"):
with When("I create a user with host local"):
node.query("CREATE USER user7 HOST LOCAL")
with Scenario("I create user with host any", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Host_Any("1.0")]):
with cleanup("user7"):
with When("I create a user with host any"):
node.query("CREATE USER user7 HOST ANY")
with Scenario("I create user with default role set to none", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_DefaultRole_None("1.0")]):
with cleanup("user8"):
with When("I create a user with no default role"):
node.query("CREATE USER user8 DEFAULT ROLE NONE")
with Scenario("I create user with default role", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_DefaultRole("1.0")]):
with Given("I have a role"):
node.query("CREATE ROLE default")
with cleanup("user9"):
with When("I create a user with a default role"):
node.query("CREATE USER user9 DEFAULT ROLE default")
with Finally("I drop the role"):
node.query("DROP ROLE default")
with Scenario("I create user default role, role doesn't exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_DefaultRole("1.0")]):
with cleanup("user12"):
role = "role0"
with Given(f"I ensure that role {role} does not exist"):
node.query(f"DROP ROLE IF EXISTS {role}")
with When(f"I create user with default role {role}"):
exitcode, message = errors.role_not_found_in_disk(role)
node.query(f"CREATE USER user12 DEFAULT ROLE {role}",exitcode=exitcode, message=message)
del role
with Scenario("I create user default role, all except role doesn't exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_DefaultRole("1.0")]):
with cleanup("user12"):
role = "role0"
with Given(f"I ensure that role {role} does not exist"):
node.query(f"DROP ROLE IF EXISTS {role}")
with When(f"I create user with default role {role}"):
exitcode, message = errors.role_not_found_in_disk(role)
node.query(f"CREATE USER user12 DEFAULT ROLE ALL EXCEPT {role}",exitcode=exitcode, message=message)
del role
with Scenario("I create user with all roles set to default", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_DefaultRole_All("1.0")]):
with cleanup("user10"):
with When("I create a user with all roles as default"):
node.query("CREATE USER user10 DEFAULT ROLE ALL")
with Scenario("I create user with settings profile", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Settings("1.0")]):
with cleanup("user11"):
with When("I create a user with a settings profile"):
node.query("CREATE USER user11 SETTINGS PROFILE default, max_memory_usage=10000000 READONLY")
with Scenario("I create user settings profile, fake profile, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Settings("1.0")]):
with cleanup("user18a"):
profile = "profile0"
with Given(f"I ensure that profile {profile} does not exist"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}")
with When(f"I create user with Settings and set profile to fake profile {profile}"):
exitcode, message = errors.settings_profile_not_found_in_disk(profile)
node.query("CREATE USER user18a SETTINGS PROFILE profile0", exitcode=exitcode, message=message)
del profile
with Scenario("I create user settings with a fake setting, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Settings("1.0")]):
with cleanup("user18b"):
with When("I create settings profile using settings and nonexistent value"):
exitcode, message = errors.unknown_setting("fake_setting")
node.query("CREATE USER user18b SETTINGS fake_setting = 100000001", exitcode=exitcode, message=message)
with Scenario("I create user with settings without profile", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_Settings("1.0")]):
with cleanup("user12"):
with When("I create a user with settings and no profile"):
node.query("CREATE USER user12 SETTINGS max_memory_usage=10000000 READONLY")
with Scenario("I create user on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_OnCluster("1.0")]):
try:
with When("I create user on cluster"):
node.query("CREATE USER user13 ON CLUSTER sharded_cluster")
finally:
with Finally("I drop the user"):
node.query("DROP USER user13 ON CLUSTER sharded_cluster")
with Scenario("I create user on fake cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Create_OnCluster("1.0")]):
with When("I create user on fake cluster"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("CREATE USER user14 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)

View File

@ -0,0 +1,87 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("drop quota")
def feature(self, node="clickhouse1"):
"""Check drop quota query syntax.
```sql
DROP QUOTA [IF EXISTS] name [,...] [ON CLUSTER cluster_name]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(quota):
try:
with Given("I have a quota"):
node.query(f"CREATE QUOTA {quota}")
yield
finally:
with Finally("I drop the quota"):
node.query(f"DROP QUOTA IF EXISTS {quota}")
def cleanup_quota(quota):
with Given(f"I ensure that quota {quota} does not exist"):
node.query(f"DROP QUOTA IF EXISTS {quota}")
with Scenario("I drop quota with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Drop("1.0")]):
with cleanup("quota0"):
with When("I run drop quota command"):
node.query("DROP QUOTA quota0")
with Scenario("I drop quota, does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Drop("1.0")]):
quota = "quota0"
cleanup_quota(quota)
with When("I run drop quota command, throws exception"):
exitcode, message = errors.quota_not_found_in_disk(name=quota)
node.query(f"DROP QUOTA {quota}", exitcode=exitcode, message=message)
del quota
with Scenario("I drop quota if exists, quota exists", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Drop_IfExists("1.0")]):
with cleanup("quota1"):
with When("I run drop quota command"):
node.query("DROP QUOTA IF EXISTS quota1")
with Scenario("I drop quota if exists, quota does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Drop_IfExists("1.0")]):
cleanup_quota("quota2")
with When("I run drop quota command, quota does not exist"):
node.query("DROP QUOTA IF EXISTS quota2")
with Scenario("I drop default quota, throws error", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Drop("1.0")]):
with When("I drop default quota"):
exitcode, message = errors.cannot_remove_quota_default()
node.query("DROP QUOTA default", exitcode=exitcode, message=message)
with Scenario("I drop multiple quotas", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Drop("1.0")]):
with cleanup("quota2"), cleanup("quota3"):
with When("I run drop quota command"):
node.query("DROP QUOTA quota2, quota3")
with Scenario("I drop quota on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Drop_Cluster("1.0")]):
try:
with Given("I have a quota"):
node.query("CREATE QUOTA quota4 ON CLUSTER sharded_cluster")
with When("I run drop quota command"):
node.query("DROP QUOTA quota4 ON CLUSTER sharded_cluster")
finally:
with Finally("I drop the quota in case it still exists"):
node.query("DROP QUOTA IF EXISTS quota4 ON CLUSTER sharded_cluster")
with Scenario("I drop quota on fake cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_Drop_Cluster("1.0")]):
with When("I run drop quota command"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("DROP QUOTA quota5 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)

View File

@ -0,0 +1,84 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("drop role")
def feature(self, node="clickhouse1"):
"""Check drop role query syntax.
```sql
DROP ROLE [IF EXISTS] name [,...] [ON CLUSTER cluster_name]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def setup(role):
try:
with Given("I have a role"):
node.query(f"CREATE ROLE OR REPLACE {role}")
yield
finally:
with Finally("I confirm the role is dropped"):
node.query(f"DROP ROLE IF EXISTS {role}")
def cleanup_role(role):
with Given(f"I ensure that role {role} does not exist"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Scenario("I drop role with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Drop("1.0")]):
with setup("role0"):
with When("I drop role"):
node.query("DROP ROLE role0")
with Scenario("I drop role that doesn't exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Drop("1.0")]):
role = "role0"
cleanup_role(role)
with When(f"I drop role {role}"):
exitcode, message = errors.role_not_found_in_disk(name=role)
node.query(f"DROP ROLE {role}", exitcode=exitcode, message=message)
del role
with Scenario("I drop multiple roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Drop("1.0")]):
with setup("role1"), setup("role2"):
with When("I drop multiple roles"):
node.query("DROP ROLE role1, role2")
with Scenario("I drop role that does not exist, using if exists", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Drop_IfExists("1.0")]):
with When("I drop role if exists"):
node.query("DROP ROLE IF EXISTS role3")
with Scenario("I drop multiple roles where one does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Drop_IfExists("1.0")]):
with setup("role5"):
with When("I drop multiple roles where one doesnt exist"):
node.query("DROP ROLE IF EXISTS role3, role5")
with Scenario("I drop multiple roles where both do not exist", flags = TE, requirements=[
RQ_SRS_006_RBAC_Role_Drop_IfExists("1.0")]):
with Given("I ensure role does not exist"):
node.query("DROP ROLE IF EXISTS role6")
with When("I drop the nonexistant roles"):
node.query("DROP USER IF EXISTS role5, role6")
with Scenario("I drop role on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Drop_Cluster("1.0")]):
with Given("I have a role on cluster"):
node.query("CREATE ROLE role0 ON CLUSTER sharded_cluster")
with When("I drop the role from the cluster"):
node.query("DROP ROLE role0 ON CLUSTER sharded_cluster")
with Scenario("I drop role on fake cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_Drop_Cluster("1.0")]):
with When("I run drop role command"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("DROP ROLE role2 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)

View File

@ -0,0 +1,135 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("drop row policy")
def feature(self, node="clickhouse1"):
"""Check drop row policy query syntax.
```sql
DROP [ROW] POLICY [IF EXISTS] name [,...] ON [database.]table [,...] [ON CLUSTER cluster_name]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(policy, on=["default.foo"]):
try:
with Given("I have a row policy"):
for i in policy:
for j in on:
node.query(f"CREATE ROW POLICY OR REPLACE {i} ON {j}")
yield
finally:
with Finally("I drop the row policy"):
for i in policy:
for j in on:
node.query(f"DROP ROW POLICY IF EXISTS {i} ON {j}")
def cleanup_policy(policy, on="default.foo"):
with Given(f"I ensure that policy {policy} does not exist"):
node.query(f"DROP ROW POLICY IF EXISTS {policy} ON {on}")
try:
with Given("I have some tables"):
node.query(f"CREATE TABLE default.foo (x UInt64, y String) Engine=Memory")
node.query(f"CREATE TABLE default.foo2 (x UInt64, y String) Engine=Memory")
with Scenario("I drop row policy with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]):
with cleanup(["policy1"]):
with When("I drop row policy"):
node.query("DROP ROW POLICY policy1 ON default.foo")
with Scenario("I drop row policy using short syntax with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]):
with cleanup(["policy2"]):
with When("I drop row policy short form"):
node.query("DROP POLICY policy2 ON default.foo")
with Scenario("I drop row policy, does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]):
policy = "policy1"
cleanup_policy(policy)
with When("I drop row policy"):
exitcode, message = errors.row_policy_not_found_in_disk(name=f"{policy} ON default.foo")
node.query(f"DROP ROW POLICY {policy} ON default.foo", exitcode=exitcode, message=message)
del policy
with Scenario("I drop row policy if exists, policy does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Drop_IfExists("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]):
with cleanup(["policy3"]):
with When("I drop row policy if exists"):
node.query("DROP ROW POLICY IF EXISTS policy3 ON default.foo")
with Scenario("I drop row policy if exists, policy doesn't exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Drop_IfExists("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]):
cleanup_policy("policy3")
with When("I drop row policy if exists"):
node.query("DROP ROW POLICY IF EXISTS policy3 ON default.foo")
with Scenario("I drop multiple row policies", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]):
with cleanup(["policy3", "policy4"]):
with When("I drop multiple row policies"):
node.query("DROP ROW POLICY policy3, policy4 ON default.foo")
with Scenario("I drop row policy on multiple tables", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]):
with cleanup(["policy3"], ["default.foo","default.foo2"]):
with When("I drop row policy on multiple tables"):
node.query("DROP ROW POLICY policy3 ON default.foo, default.foo2")
with Scenario("I drop multiple row policies on multiple tables", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Drop("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]):
with cleanup(["policy3", "policy4"], ["default.foo","default.foo2"]):
with When("I drop the row policies from the tables"):
node.query("DROP ROW POLICY policy3 ON default.foo, policy4 ON default.foo2")
with Scenario("I drop row policy on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Drop_OnCluster("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]):
try:
with Given("I have a row policy"):
node.query("CREATE ROW POLICY policy13 ON default.foo ON CLUSTER sharded_cluster")
with When("I run drop row policy command"):
node.query("DROP ROW POLICY IF EXISTS policy13 ON CLUSTER sharded_cluster ON default.foo")
finally:
with Finally("I drop the row policy in case it still exists"):
node.query("DROP ROW POLICY IF EXISTS policy13 ON default.foo ON CLUSTER sharded_cluster")
with Scenario("I drop row policy on cluster after table", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Drop_OnCluster("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]):
try:
with Given("I have a row policy"):
node.query("CREATE ROW POLICY policy12 ON default.foo ON CLUSTER sharded_cluster")
with When("I run drop row policy command"):
node.query("DROP ROW POLICY IF EXISTS policy13 ON default.foo ON CLUSTER sharded_cluster")
finally:
with Finally("I drop the row policy in case it still exists"):
node.query("DROP ROW POLICY IF EXISTS policy12 ON default.foo ON CLUSTER sharded_cluster")
with Scenario("I drop row policy on fake cluster throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_Drop_OnCluster("1.0"),
RQ_SRS_006_RBAC_RowPolicy_Drop_On("1.0")]):
with When("I run drop row policy command"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("DROP ROW POLICY IF EXISTS policy14 ON default.foo ON CLUSTER fake_cluster",
exitcode=exitcode, message=message)
finally:
with Finally("I drop the tables"):
node.query(f"DROP TABLE IF EXISTS default.foo")
node.query(f"DROP TABLE IF EXISTS default.foo2")

View File

@ -0,0 +1,93 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("drop settings profile")
def feature(self, node="clickhouse1"):
"""Check drop settings profile query syntax.
```sql
DROP [SETTINGS] PROFILE [IF EXISTS] name [,...] [ON CLUSTER cluster_name]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(profile):
try:
with Given("I have a settings profile"):
node.query(f"CREATE SETTINGS PROFILE {profile}")
yield
finally:
with Finally("I drop the settings profile"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}")
def cleanup_profile(profile):
with Given(f"I ensure that profile {profile} does not exist"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}")
with Scenario("I drop settings profile with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Drop("1.0")]):
with cleanup("profile0"):
with When("I drop settings profile"):
node.query("DROP SETTINGS PROFILE profile0")
with Scenario("I drop settings profile, does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Drop("1.0")]):
profile = "profile0"
cleanup_profile(profile)
with When("I drop settings profile"):
exitcode, message = errors.settings_profile_not_found_in_disk(name=profile)
node.query("DROP SETTINGS PROFILE profile0", exitcode=exitcode, message=message)
del profile
with Scenario("I drop settings profile short form", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Drop("1.0")]):
with cleanup("profile1"):
with When("I drop settings profile short form"):
node.query("DROP PROFILE profile1")
with Scenario("I drop settings profile if exists, profile does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Drop_IfExists("1.0")]):
with cleanup("profile2"):
with When("I drop settings profile if exists"):
node.query("DROP SETTINGS PROFILE IF EXISTS profile2")
with Scenario("I drop settings profile if exists, profile does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Drop_IfExists("1.0")]):
cleanup_profile("profile2")
with When("I drop settings profile if exists"):
node.query("DROP SETTINGS PROFILE IF EXISTS profile2")
with Scenario("I drop default settings profile, throws error", requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Drop("1.0")]):
with When("I drop default profile"):
exitcode, message = errors.cannot_remove_settings_profile_default()
node.query("DROP SETTINGS PROFILE default", exitcode=exitcode, message=message)
with Scenario("I drop multiple settings profiles", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Drop("1.0")]):
with cleanup("profile3"), cleanup("profile4"):
with When("I drop multiple settings profiles"):
node.query("DROP SETTINGS PROFILE profile3, profile4")
with Scenario("I drop settings profile on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Drop_OnCluster("1.0")]):
try:
with Given("I have a settings profile"):
node.query("CREATE SETTINGS PROFILE profile5 ON CLUSTER sharded_cluster")
with When("I run drop settings profile command"):
node.query("DROP SETTINGS PROFILE profile5 ON CLUSTER sharded_cluster")
finally:
with Finally("I drop the profile in case it still exists"):
node.query("DROP SETTINGS PROFILE IF EXISTS profile5 ON CLUSTER sharded_cluster")
with Scenario("I drop settings profile on fake cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_Drop_OnCluster("1.0")]):
with When("I run drop settings profile command"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("DROP SETTINGS PROFILE profile6 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)

View File

@ -0,0 +1,98 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("drop user")
def feature(self, node="clickhouse1"):
"""Check drop user query syntax.
```sql
DROP USER [IF EXISTS] name [,...] [ON CLUSTER cluster_name]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def setup(user):
try:
with Given("I have a user"):
node.query(f"CREATE USER {user}")
yield
finally:
with Finally("I drop the user"):
node.query(f"DROP USER IF EXISTS {user}")
def cleanup_user(user):
with Given(f"I ensure that user {user} does not exist"):
node.query(f"DROP USER IF EXISTS {user}")
with Scenario("I drop user with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Drop("1.0")]):
with setup("user0"):
with When("I drop user"):
node.query("DROP USER user0")
with Scenario("I drop user, does not exist, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Drop("1.0")]):
user = "user0"
cleanup_user(user)
with When(f"I drop user {user}"):
exitcode, message = errors.user_not_found_in_disk(name=user)
node.query(f"DROP USER {user}", exitcode=exitcode, message=message)
del user
with Scenario("I drop multiple users", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Drop("1.0")]):
with setup("user1"), setup("user2"):
with When("I drop multiple users"):
node.query("DROP USER user1, user2")
with Scenario("I drop user if exists, user does exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Drop_IfExists("1.0")]):
with setup("user3"):
with When("I drop user that exists"):
node.query("DROP USER IF EXISTS user3")
with Scenario("I drop user if exists, user does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Drop_IfExists("1.0")]):
cleanup_user("user3")
with When("I drop nonexistant user"):
node.query("DROP USER IF EXISTS user3")
with Scenario("I drop default user, throws error", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Drop("1.0")]):
with When("I drop user"):
exitcode, message = errors.cannot_remove_user_default()
node.query("DROP USER default", exitcode=exitcode, message=message)
with Scenario("I drop multiple users where one does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Drop_IfExists("1.0")]):
with setup("user3"):
with When("I drop multiple users where one does not exist"):
node.query("DROP USER IF EXISTS user3, user4")
with Scenario("I drop multiple users where both do not exist", requirements=[
RQ_SRS_006_RBAC_User_Drop_IfExists("1.0")]):
with When("I drop the nonexistant users"):
node.query("DROP USER IF EXISTS user5, user6")
with Scenario("I drop user from specific cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Drop_OnCluster("1.0")]):
try:
with Given("I have a user on cluster"):
node.query("CREATE USER user4 ON CLUSTER sharded_cluster")
with When("I drop a user from the cluster"):
node.query("DROP USER user4 ON CLUSTER sharded_cluster")
finally:
with Finally("I make sure the user is dropped"):
node.query("DROP USER IF EXISTS user4 ON CLUSTER sharded_cluster")
with Scenario("I drop user from fake cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_Drop_OnCluster("1.0")]):
with When("I drop a user from the fake cluster"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("DROP USER user5 ON CLUSTER fake_cluster", exitcode=exitcode, message=message)

View File

@ -0,0 +1,34 @@
from testflows.core import *
@TestFeature
@Name("syntax")
def feature(self):
Feature(run=load("rbac.tests.syntax.create_user", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.alter_user", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.drop_user", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.show_create_user", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.create_role", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.alter_role", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.drop_role", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.show_create_role", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.grant_role", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.grant_privilege","feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.show_grants", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.revoke_role", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.revoke_privilege","feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.create_row_policy", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.alter_row_policy", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.drop_row_policy", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.show_create_row_policy", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.show_row_policies", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.create_quota", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.alter_quota", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.drop_quota", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.show_create_quota", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.show_quotas", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.create_settings_profile", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.alter_settings_profile", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.drop_settings_profile", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.show_create_settings_profile", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.set_default_role", "feature"), flags=TE)
Feature(run=load("rbac.tests.syntax.set_role","feature"), flags=TE)

View File

@ -0,0 +1,134 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@contextmanager
def setup(node):
try:
with Given("I have some users and roles"):
node.query("CREATE USER OR REPLACE user0 ON CLUSTER sharded_cluster")
node.query("CREATE USER OR REPLACE user1")
node.query("CREATE ROLE OR REPLACE role1")
yield
finally:
with Finally("I drop the users and roles"):
node.query("DROP USER IF EXISTS user0 ON CLUSTER sharded_cluster")
node.query("DROP USER IF EXISTS user1")
node.query("DROP ROLE IF EXISTS role1")
@TestOutline(Scenario)
@Examples("privilege on allow_introspection", [
("dictGet", ("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_DictGet("1.0"))),
("INTROSPECTION", ("*.*",), True, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_Introspection("1.0"))),
("SELECT", ("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"))),
("INSERT",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_Insert("1.0"))),
("ALTER",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_Alter("1.0"))),
("CREATE",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_Create("1.0"))),
("DROP",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_Drop("1.0"))),
("TRUNCATE",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_Truncate("1.0"))),
("OPTIMIZE",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_Optimize("1.0"))),
("SHOW",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_Show("1.0"))),
("KILL QUERY",("*.*",), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_KillQuery("1.0"))),
("ACCESS MANAGEMENT",("*.*",), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_AccessManagement("1.0"))),
("SYSTEM",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_System("1.0"))),
("SOURCES",("*.*",), False, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_Sources("1.0"))),
("ALL",("*.*",), True, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_All("1.0"))),
("ALL PRIVILEGES",("*.*",), True, Requirements(RQ_SRS_006_RBAC_Grant_Privilege_All("1.0"))), #alias for all
],)
def grant_privileges(self, privilege, on, allow_introspection, node="clickhouse1"):
grant_privilege(privilege=privilege, on=on, allow_introspection=allow_introspection, node=node)
@TestOutline(Scenario)
@Requirements(RQ_SRS_006_RBAC_Grant_Privilege_GrantOption("1.0"))
def grant_privilege(self, privilege, on, allow_introspection, node="clickhouse1"):
node = self.context.cluster.node(node)
for on_ in on:
with When(f"I grant {privilege} privilege to user on {on_}"):
with setup(node):
settings = []
if allow_introspection:
settings.append(("allow_introspection_functions", 1))
node.query("SET allow_introspection_functions = 1")
with When("I grant privilege without grant option"):
node.query(f"GRANT {privilege} ON {on_} TO user0", settings=settings)
with When("I grant privilege with grant option"):
node.query(f"GRANT {privilege} ON {on_} TO user1 WITH GRANT OPTION", settings=settings)
#grant column specific for some column 'x'
with When("I grant privilege with columns"):
node.query(f"GRANT {privilege}(x) ON {on_} TO user0", settings=settings)
@TestFeature
@Name("grant privilege")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check grant privilege syntax.
```sql
GRANT [ON CLUSTER cluster_name]
privilege {SELECT | SELECT(columns) | INSERT | ALTER | CREATE | DROP | TRUNCATE | OPTIMIZE | SHOW | KILL QUERY | ACCESS MANAGEMENT | SYSTEM | INTROSPECTION | SOURCES | dictGet | NONE |ALL [PRIVILEGES]} [, ...]
ON {*.* | database.* | database.table | * | table}
TO {user | role | CURRENT_USER} [,...]
[WITH GRANT OPTION]
```
"""
node = self.context.cluster.node(node)
Scenario(run=grant_privileges)
# with nonexistant object name, GRANT assumes type role
with Scenario("I grant privilege to role that does not exist", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]):
with Given("I ensure that role does not exist"):
node.query("DROP ROLE IF EXISTS role0")
with When("I grant privilege ON CLUSTER"):
exitcode, message = errors.role_not_found_in_disk(name="role0")
node.query("GRANT NONE TO role0", exitcode=exitcode, message=message)
with Scenario("I grant privilege ON CLUSTER", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Privilege_OnCluster("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]):
with setup(node):
with When("I grant privilege ON CLUSTER"):
node.query("GRANT ON CLUSTER sharded_cluster NONE TO user0")
with Scenario("I grant privilege on fake cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Privilege_OnCluster("1.0")]):
with setup(node):
with When("I grant privilege ON CLUSTER"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("GRANT ON CLUSTER fake_cluster NONE TO user0", exitcode=exitcode, message=message)
with Scenario("I grant privilege to multiple users and roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]):
with setup(node):
with When("I grant privilege to several users"):
node.query("GRANT NONE TO user0, user1, role1")
with Scenario("I grant privilege to current user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Privilege_ToCurrentUser("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]):
with setup(node):
with When("I grant privilege to current user"):
node.query("GRANT NONE TO CURRENT_USER", settings = [("user","user0")])
with Scenario("I grant privilege NONE to default user, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Privilege_ToCurrentUser("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]):
with setup(node):
with When("I grant privilege to current user"):
exitcode, message = errors.cannot_update_default()
node.query("GRANT NONE TO CURRENT_USER", exitcode=exitcode, message=message)
with Scenario("I grant privilege with grant option", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Privilege_GrantOption("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_None("1.0")]):
with setup(node):
with When("I grant privilege with grant option"):
node.query("GRANT NONE ON *.* TO user0 WITH GRANT OPTION")

View File

@ -0,0 +1,115 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("grant role")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check grant query syntax.
```sql
GRANT ON CLUSTER [cluster_name] role [,...] TO {user | another_role | CURRENT_USER} [,...] [WITH ADMIN OPTION]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def setup(users=0,roles=0):
try:
with Given("I have some users and roles"):
for i in range(users):
node.query(f"CREATE USER OR REPLACE user{i}")
for j in range(roles):
node.query(f"CREATE ROLE OR REPLACE role{j}")
yield
finally:
with Finally("I drop the users and roles"):
for i in range(users):
node.query(f"DROP USER IF EXISTS user{i}")
for j in range(roles):
node.query(f"DROP ROLE IF EXISTS role{j}")
with Scenario("I grant a role to a user",flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Role("1.0")]):
with setup(1,1):
with When("I grant a role"):
node.query("GRANT role0 TO user0")
with Scenario("I grant a nonexistent role to user", requirements=[
RQ_SRS_006_RBAC_Grant_Role("1.0")]):
with setup(1,0):
with When("I grant nonexistent role to a user"):
exitcode, message = errors.role_not_found_in_disk(name="role0")
node.query("GRANT role0 TO user0", exitcode=exitcode, message=message)
# with nonexistent object name, GRANT assumes type role (treats user0 as role)
with Scenario("I grant a role to a nonexistent user", requirements=[
RQ_SRS_006_RBAC_Grant_Role("1.0")]):
with setup(0,1):
with When("I grant role to a nonexistent user"):
exitcode, message = errors.role_not_found_in_disk(name="user0")
node.query("GRANT role0 TO user0", exitcode=exitcode, message=message)
with Scenario("I grant a nonexistent role to a nonexistent user", requirements=[
RQ_SRS_006_RBAC_Grant_Role("1.0")]):
with setup(0,0):
with When("I grant nonexistent role to a nonexistent user"):
exitcode, message = errors.role_not_found_in_disk(name="role0")
node.query("GRANT role0 TO user0", exitcode=exitcode, message=message)
with Scenario("I grant a role to multiple users", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Role("1.0")]):
with setup(2,1):
with When("I grant role to a multiple users"):
node.query("GRANT role0 TO user0, user1")
with Scenario("I grant multiple roles to multiple users", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Role("1.0")]):
with setup(2,2):
with When("I grant multiple roles to multiple users"):
node.query("GRANT role0, role1 TO user0, user1")
with Scenario("I grant role to current user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Role_CurrentUser("1.0")]):
with setup(1,1):
with Given("I have a user with access management privilege"):
node.query("GRANT ACCESS MANAGEMENT ON *.* TO user0")
with When("I grant role to current user"):
node.query("GRANT role0 TO CURRENT_USER", settings = [("user","user0")])
with Scenario("I grant role to default user, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Role_CurrentUser("1.0")]):
with setup(1,1):
with When("I grant role to default user"):
exitcode, message = errors.cannot_update_default()
node.query("GRANT role0 TO CURRENT_USER", exitcode=exitcode, message=message)
with Scenario("I grant role to user with admin option", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Role_AdminOption("1.0")]):
with setup(1,1):
with When("I grant role to a user with admin option"):
node.query("GRANT role0 TO user0 WITH ADMIN OPTION")
with Scenario("I grant role to user on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Role_OnCluster("1.0")]):
try:
with Given("I have a user and a role on a cluster"):
node.query("CREATE USER user0 ON CLUSTER sharded_cluster")
node.query("CREATE ROLE role0 ON CLUSTER sharded_cluster")
with When("I grant the role to the user"):
node.query("GRANT ON CLUSTER sharded_cluster role0 TO user0")
finally:
with Finally("I drop the user and role"):
node.query("DROP USER user0 ON CLUSTER sharded_cluster")
node.query("DROP ROLE role0 ON CLUSTER sharded_cluster")
with Scenario("I grant role to user on fake cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Grant_Role_OnCluster("1.0")]):
with setup(1,1):
with When("I grant the role to the user"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("GRANT ON CLUSTER fake_cluster role0 TO user0", exitcode=exitcode, message=message)

View File

@ -0,0 +1,159 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@contextmanager
def setup(node):
try:
with Given("I have some users and roles"):
node.query("CREATE USER OR REPLACE user0 ON CLUSTER sharded_cluster")
node.query("CREATE USER OR REPLACE user1")
node.query("CREATE ROLE OR REPLACE role1")
yield
finally:
with Finally("I drop the users and roles"):
node.query("DROP USER IF EXISTS user0 ON CLUSTER sharded_cluster")
node.query("DROP USER IF EXISTS user1")
node.query("DROP ROLE IF EXISTS role1")
@TestOutline(Scenario)
@Examples("privilege on allow_introspection", [
("dictGet", ("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_DictGet("1.0"))),
("INTROSPECTION", ("*.*",), True, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_Introspection("1.0"))),
("SELECT", ("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_Select("1.0"))),
("INSERT",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_Insert("1.0"))),
("ALTER",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_Alter("1.0"))),
("CREATE",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_Create("1.0"))),
("DROP",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_Drop("1.0"))),
("TRUNCATE",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_Truncate("1.0"))),
("OPTIMIZE",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_Optimize("1.0"))),
("SHOW",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_Show("1.0"))),
("KILL QUERY",("*.*",), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_KillQuery("1.0"))),
("ACCESS MANAGEMENT",("*.*",), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_AccessManagement("1.0"))),
("SYSTEM",("db0.table0","db0.*","*.*","tb0","*"), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_System("1.0"))),
("SOURCES",("*.*",), False, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_Sources("1.0"))),
("ALL",("*.*",), True, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_All("1.0"))),
("ALL PRIVILEGES",("*.*",), True, Requirements(RQ_SRS_006_RBAC_Revoke_Privilege_All("1.0"))), #alias for all
],)
def revoke_privileges(self, privilege, on, allow_introspection, node="clickhouse1"):
revoke_privilege(privilege=privilege, on=on, allow_introspection=allow_introspection, node=node)
@TestOutline(Scenario)
@Requirements([RQ_SRS_006_RBAC_Revoke_Privilege_Any("1.0") , RQ_SRS_006_RBAC_Revoke_Privilege_PrivelegeColumns("1.0")])
def revoke_privilege(self, privilege, on, allow_introspection, node="clickhouse1"):
node = self.context.cluster.node(node)
for on_ in on:
with When(f"I revoke {privilege} privilege from user on {on_}"):
with setup(node):
settings = []
if allow_introspection:
settings.append(("allow_introspection_functions", 1))
node.query("SET allow_introspection_functions = 1")
with When("I revoke privilege without columns"):
node.query(f"REVOKE {privilege} ON {on_} FROM user0", settings=settings)
#revoke column specific for some column 'x'
with When("I revoke privilege with columns"):
node.query(f"REVOKE {privilege}(x) ON {on_} FROM user0", settings=settings)
@TestFeature
@Name("revoke privilege")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check revoke privilege syntax.
```sql
REVOKE [ON CLUSTER cluster_name] privilege
[(column_name [,...])] [,...]
ON {db.table|db.*|*.*|table|*}
FROM {user | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user | CURRENT_USER} [,...]
```
"""
node = self.context.cluster.node(node)
Scenario(run=revoke_privileges)
with Scenario("I revoke privilege ON CLUSTER", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Privilege_Cluster("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]):
with setup(node):
with When("I revoke privilege ON CLUSTER"):
node.query("REVOKE ON CLUSTER sharded_cluster NONE FROM user0")
with Scenario("I revoke privilege ON fake CLUSTER, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Privilege_Cluster("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]):
with setup(node):
with When("I revoke privilege ON CLUSTER"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("REVOKE ON CLUSTER fake_cluster NONE FROM user0",
exitcode=exitcode, message=message)
with Scenario("I revoke privilege from multiple users and roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]):
with setup(node):
with When("I revoke privilege from multiple users"):
node.query("REVOKE NONE FROM user0, user1, role1")
with Scenario("I revoke privilege from current user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]):
with setup(node):
with When("I revoke privilege from current user"):
node.query("REVOKE NONE FROM CURRENT_USER", settings = [("user","user0")])
with Scenario("I revoke privilege from all users", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]):
with setup(node):
with When("I revoke privilege from all users"):
exitcode, message = errors.cannot_update_default()
node.query("REVOKE NONE FROM ALL", exitcode=exitcode,message=message)
with Scenario("I revoke privilege from default user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]):
with setup(node):
with When("I revoke privilege from default user"):
exitcode, message = errors.cannot_update_default()
node.query("REVOKE NONE FROM default", exitcode=exitcode,message=message)
#By default, ClickHouse treats unnamed object as role
with Scenario("I revoke privilege from nonexistent role, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]):
role = "role5"
with Given(f"I ensure that role {role} does not exist"):
node.query(f"DROP ROLE IF EXISTS {role}")
with When(f"I revoke privilege from nonexistent role {role}"):
exitcode, message = errors.role_not_found_in_disk(role)
node.query(f"REVOKE NONE FROM {role}", exitcode=exitcode,message=message)
with Scenario("I revoke privilege from ALL EXCEPT nonexistent role, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]):
role = "role5"
with Given(f"I ensure that role {role} does not exist"):
node.query(f"DROP ROLE IF EXISTS {role}")
with When(f"I revoke privilege from nonexistent role {role}"):
exitcode, message = errors.role_not_found_in_disk(role)
node.query(f"REVOKE NONE FROM ALL EXCEPT {role}", exitcode=exitcode,message=message)
with Scenario("I revoke privilege from all except some users and roles", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]):
with setup(node):
with When("I revoke privilege all except some users"):
node.query("REVOKE NONE FROM ALL EXCEPT default, user0, role1")
with Scenario("I revoke privilege from all except current user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_None("1.0")]):
with setup(node):
with When("I revoke privilege from all except current user"):
node.query("REVOKE NONE FROM ALL EXCEPT CURRENT_USER")

View File

@ -0,0 +1,198 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("revoke role")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check revoke query syntax.
```sql
REVOKE [ON CLUSTER cluster_name] [ADMIN OPTION FOR]
role [,...] FROM {user | role | CURRENT_USER} [,...]
| ALL | ALL EXCEPT {user_name | role_name | CURRENT_USER} [,...]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def setup(users=2,roles=2):
try:
with Given("I have some users"):
for i in range(users):
node.query(f"CREATE USER OR REPLACE user{i}")
with And("I have some roles"):
for i in range(roles):
node.query(f"CREATE ROLE OR REPLACE role{i}")
yield
finally:
with Finally("I drop the users"):
for i in range(users):
node.query(f"DROP USER IF EXISTS user{i}")
with And("I drop the roles"):
for i in range(roles):
node.query(f"DROP ROLE IF EXISTS role{i}")
with Scenario("I revoke a role from a user",flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0")]):
with setup():
with When("I revoke a role"):
node.query("REVOKE role0 FROM user0")
with Scenario("I revoke a nonexistent role from user", requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0")]):
with setup(1,0):
with When("I revoke nonexistent role from a user"):
exitcode, message = errors.role_not_found_in_disk(name="role0")
node.query("REVOKE role0 FROM user0", exitcode=exitcode, message=message)
# with nonexistent object name, REVOKE assumes type role (treats user0 as role)
with Scenario("I revoke a role from a nonexistent user", requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0")]):
with setup(0,1):
with When("I revoke role from a nonexistent user"):
exitcode, message = errors.role_not_found_in_disk(name="user0")
node.query("REVOKE role0 FROM user0", exitcode=exitcode, message=message)
# with nonexistent object name, REVOKE assumes type role (treats user0 as role)
with Scenario("I revoke a role from ALL EXCEPT nonexistent user", requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0")]):
with setup(0,1):
with When("I revoke role from a nonexistent user"):
exitcode, message = errors.role_not_found_in_disk(name="user0")
node.query("REVOKE role0 FROM ALL EXCEPT user0", exitcode=exitcode, message=message)
with Scenario("I revoke a nonexistent role from a nonexistent user", requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0")]):
with setup(0,0):
with When("I revoke nonexistent role from a nonexistent user"):
exitcode, message = errors.role_not_found_in_disk(name="role0")
node.query("REVOKE role0 FROM user0", exitcode=exitcode, message=message)
with Scenario("I revoke a role from multiple users", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0")]):
with setup():
with When("I revoke a role from multiple users"):
node.query("REVOKE role0 FROM user0, user1")
with Scenario("I revoke multiple roles from multiple users", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0")]):
with setup():
node.query("REVOKE role0, role1 FROM user0, user1")
#user is default, expect exception
with Scenario("I revoke a role from default user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0"),
RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]):
with setup():
with When("I revoke a role from default user"):
exitcode, message = errors.cannot_update_default()
node.query("REVOKE role0 FROM CURRENT_USER", exitcode=exitcode, message=message)
#user is user0
with Scenario("I revoke a role from current user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0"),
RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]):
with setup():
with When("I revoke a role from current user"):
node.query("REVOKE role0 FROM CURRENT_USER", settings = [("user","user0")])
#user is default, expect exception
with Scenario("I revoke a role from all", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0"),
RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]):
with setup():
with When("I revoke a role from all"):
exitcode, message = errors.cannot_update_default()
node.query("REVOKE role0 FROM ALL", exitcode=exitcode, message=message)
#user is default, expect exception
with Scenario("I revoke multiple roles from all", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0"),
RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]):
with setup():
with When("I revoke multiple roles from all"):
exitcode, message = errors.cannot_update_default()
node.query("REVOKE role0, role1 FROM ALL", exitcode=exitcode, message=message)
with Scenario("I revoke a role from all but current user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0"),
RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]):
with setup():
with When("I revoke a role from all except current"):
node.query("REVOKE role0 FROM ALL EXCEPT CURRENT_USER")
with Scenario("I revoke a role from all but default user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0"),
RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]):
with setup():
with When("I revoke a role from all except default"):
node.query("REVOKE role0 FROM ALL EXCEPT default",
settings = [("user","user0")])
with Scenario("I revoke multiple roles from all but default user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0"),
RQ_SRS_006_RBAC_Revoke_Role_Keywords("1.0")]):
with setup():
with When("I revoke multiple roles from all except default"):
node.query("REVOKE role0, role1 FROM ALL EXCEPT default", settings = [("user","user0")])
with Scenario("I revoke a role from a role", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0")]):
with setup():
with When("I revoke a role from a role"):
node.query("REVOKE role0 FROM role1")
with Scenario("I revoke a role from a role and a user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0")]):
with setup():
with When("I revoke a role from multiple roles"):
node.query("REVOKE role0 FROM role1, user0")
with Scenario("I revoke a role from a user on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role_Cluster("1.0")]):
with Given("I have a role and a user on a cluster"):
node.query("CREATE USER OR REPLACE user0 ON CLUSTER sharded_cluster")
node.query("CREATE ROLE OR REPLACE role0 ON CLUSTER sharded_cluster")
with When("I revoke a role from user on a cluster"):
node.query("REVOKE ON CLUSTER sharded_cluster role0 FROM user0")
with Finally("I drop the user and role"):
node.query("DROP USER IF EXISTS user0 ON CLUSTER sharded_cluster")
node.query("DROP ROLE IF EXISTS role0 ON CLUSTER sharded_cluster")
with Scenario("I revoke a role on fake cluster, throws exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role_Cluster("1.0")]):
with When("I revoke a role from user on a cluster"):
exitcode, message = errors.cluster_not_found("fake_cluster")
node.query("REVOKE ON CLUSTER fake_cluster role0 FROM user0", exitcode=exitcode, message=message)
with Scenario("I revoke multiple roles from multiple users on cluster", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0"),
RQ_SRS_006_RBAC_Revoke_Role_Cluster("1.0")]):
with Given("I have multiple roles and multiple users on a cluster"):
for i in range(2):
node.query(f"CREATE USER OR REPLACE user{i} ON CLUSTER sharded_cluster")
node.query(f"CREATE ROLE OR REPLACE role{i} ON CLUSTER sharded_cluster")
with When("I revoke multiple roles from multiple users on cluster"):
node.query("REVOKE ON CLUSTER sharded_cluster role0, role1 FROM user0, user1")
with Finally("I drop the roles and users"):
for i in range(2):
node.query(f"DROP USER IF EXISTS user{i} ON CLUSTER sharded_cluster")
node.query(f"DROP ROLE IF EXISTS role{i} ON CLUSTER sharded_cluster")
with Scenario("I revoke admin option for role from a user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_AdminOption("1.0")]):
with setup():
with When("I revoke admin option for role from a user"):
node.query("REVOKE ADMIN OPTION FOR role0 FROM user0")
with Scenario("I revoke admin option for multiple roles from multiple users", flags=TE, requirements=[
RQ_SRS_006_RBAC_Revoke_Role("1.0"),
RQ_SRS_006_RBAC_Revoke_AdminOption("1.0")]):
with setup():
with When("I revoke admin option for multiple roles from multiple users"):
node.query("REVOKE ADMIN OPTION FOR role0, role1 FROM user0, user1")

View File

@ -0,0 +1,120 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("set default role")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check set default role query syntax.
```sql
SET DEFAULT ROLE {NONE | role [,...] | ALL | ALL EXCEPT role [,...]} TO {user|CURRENT_USER} [,...]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def setup(users=2,roles=2):
try:
with Given("I have some users"):
for i in range(users):
node.query(f"CREATE USER OR REPLACE user{i}")
with And("I have some roles"):
for i in range(roles):
node.query(f"CREATE ROLE OR REPLACE role{i}")
yield
finally:
with Finally("I drop the users"):
for i in range(users):
node.query(f"DROP USER IF EXISTS user{i}")
with And("I drop the roles"):
for i in range(roles):
node.query(f"DROP ROLE IF EXISTS role{i}")
with Scenario("I set default a nonexistent role to user", requirements=[
RQ_SRS_006_RBAC_SetDefaultRole("1.0")]):
with setup(1,0):
with When("I set default nonexistent role to a user"):
exitcode, message = errors.role_not_found_in_disk(name="role0")
node.query("SET DEFAULT ROLE role0 TO user0", exitcode=exitcode, message=message)
with Scenario("I set default ALL EXCEPT a nonexistent role to user", requirements=[
RQ_SRS_006_RBAC_SetDefaultRole("1.0")]):
with setup(1,0):
with When("I set default nonexistent role to a user"):
exitcode, message = errors.role_not_found_in_disk(name="role0")
node.query("SET DEFAULT ROLE ALL EXCEPT role0 TO user0", exitcode=exitcode, message=message)
with Scenario("I set default a role to a nonexistent user", requirements=[
RQ_SRS_006_RBAC_SetDefaultRole("1.0")]):
with setup(0,1):
with When("I set default role to a nonexistent user"):
exitcode, message = errors.user_not_found_in_disk(name="user0")
node.query("SET DEFAULT ROLE role0 TO user0", exitcode=exitcode, message=message)
#in SET DEFAULT ROLE, the nonexistent user is noticed first and becomes the thrown exception
with Scenario("I set default a nonexistent role to a nonexistent user", requirements=[
RQ_SRS_006_RBAC_SetDefaultRole("1.0")]):
with setup(0,0):
with When("I set default nonexistent role to a nonexistent user"):
exitcode, message = errors.user_not_found_in_disk(name="user0")
node.query("SET DEFAULT ROLE role0 TO user0", exitcode=exitcode, message=message)
try:
with Given("I have some roles and some users"):
for i in range(2):
node.query(f"CREATE ROLE role{i}")
node.query(f"CREATE USER user{i}")
node.query(f"GRANT role0, role1 TO user0, user1")
with Scenario("I set default role for a user to none", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetDefaultRole_None("1.0")]):
with When("I set no roles default for user"):
node.query("SET DEFAULT ROLE NONE TO user0")
with Scenario("I set one default role for a user", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetDefaultRole("1.0")]):
with When("I set a default role for user "):
node.query("SET DEFAULT ROLE role0 TO user0")
with Scenario("I set one default role for user default, throws exception", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetDefaultRole("1.0")]):
with When("I set a default role for default"):
exitcode, message = errors.cannot_update_default()
node.query("SET DEFAULT ROLE role0 TO default", exitcode=exitcode, message=message)
with Scenario("I set multiple default roles for a user", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetDefaultRole("1.0")]):
with When("I set multiple default roles to user"):
node.query("SET DEFAULT ROLE role0, role1 TO user0")
with Scenario("I set multiple default roles for multiple users", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetDefaultRole("1.0")]):
with When("I set multiple default roles to multiple users"):
node.query("SET DEFAULT ROLE role0, role1 TO user0, user1")
with Scenario("I set all roles as default for a user", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetDefaultRole_All("1.0")]):
with When("I set all roles default to user"):
node.query("SET DEFAULT ROLE ALL TO user0")
with Scenario("I set all roles except one for a user", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetDefaultRole_AllExcept("1.0")]):
with When("I set all except one role default to user"):
node.query("SET DEFAULT ROLE ALL EXCEPT role0 TO user0")
with Scenario("I set default role for current user", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetDefaultRole_CurrentUser("1.0")]):
with When("I set default role to current user"):
node.query("GRANT ACCESS MANAGEMENT ON *.* TO user0")
node.query("SET DEFAULT ROLE role0 TO CURRENT_USER", settings = [("user","user0")])
finally:
with Finally("I drop the roles and users"):
for i in range(2):
node.query(f"DROP ROLE IF EXISTS role{i}")
node.query(f"DROP USER IF EXISTS user{i}")

View File

@ -0,0 +1,91 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("set role")
@Args(format_description=False)
def feature(self, node="clickhouse1"):
"""Check set role query syntax.
```
SET ROLE {DEFAULT | NONE | role [,...] | ALL | ALL EXCEPT role [,...]}
```
"""
node = self.context.cluster.node(node)
@contextmanager
def setup(roles=0):
try:
with Given("I have some roles"):
for i in range(roles):
node.query(f"CREATE ROLE role{i}")
yield
finally:
with Finally("I drop the roles"):
for i in range(roles):
node.query(f"DROP ROLE IF EXISTS role{i}")
with Scenario("I set default role for current user", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetRole_Default("1.0")]):
with When("I set default role for current user"):
node.query("SET ROLE DEFAULT")
with Scenario("I set no role for current user", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetRole_None("1.0")]):
with When("I set no role for current user"):
node.query("SET ROLE NONE")
with Scenario("I set nonexistent role, throws exception", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetRole_None("1.0")]):
with Given("I ensure that role role5 does not exist"):
node.query("DROP ROLE IF EXISTS role5")
with When("I set nonexistent role for current user"):
exitcode, message = errors.role_not_found_in_disk("role5")
node.query("SET ROLE role5", exitcode=exitcode, message=message)
with Scenario("I set nonexistent role, throws exception", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetRole_None("1.0")]):
with Given("I ensure that role role5 does not exist"):
node.query("DROP ROLE IF EXISTS role5")
with When("I set nonexistent role for current user"):
exitcode, message = errors.role_not_found_in_disk("role5")
node.query("SET ROLE ALL EXCEPT role5", exitcode=exitcode, message=message)
with Scenario("I set one role for current user", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetRole("1.0")]):
with setup(1):
with Given("I have a user"):
node.query("CREATE USER OR REPLACE user0")
with And("I grant user a role"):
node.query("GRANT role0 TO user0")
with When("I set role for the user"):
node.query("SET ROLE role0", settings = [("user","user0")])
with Finally("I drop the user"):
node.query("DROP USER user0")
with Scenario("I set multiple roles for current user", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetRole("1.0")]):
with setup(2):
with Given("I have a user"):
node.query("CREATE USER OR REPLACE user0")
with And("I grant user a role"):
node.query("GRANT role0, role1 TO user0")
with When("I set roles for the user"):
node.query("SET ROLE role0, role1", settings = [("user","user0")])
with Finally("I drop the user"):
node.query("DROP USER user0")
with Scenario("I set all roles for current user", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetRole_All("1.0")]):
with When("I set all roles for current user"):
node.query("SET ROLE ALL")
with Scenario("I set all roles except one for current user", flags = TE, requirements=[
RQ_SRS_006_RBAC_SetRole_AllExcept("1.0")]):
with setup(1):
with When("I run set role command"):
node.query("SET ROLE ALL EXCEPT role0")

View File

@ -0,0 +1,44 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
@TestFeature
@Name("show create quota")
def feature(self, node="clickhouse1"):
"""Check show create quota query syntax.
```sql
SHOW CREATE QUOTA [name | CURRENT]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(quota):
try:
with Given("I have a quota"):
node.query(f"CREATE QUOTA {quota}")
yield
finally:
with Finally("I drop the quota"):
node.query(f"DROP QUOTA IF EXISTS {quota}")
with Scenario("I show create quota", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Name("1.0")]):
with cleanup("quota0"):
with When("I run show create quota command"):
node.query("SHOW CREATE QUOTA quota0")
with Scenario("I show create quota current", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Current("1.0")]):
with cleanup("quota1"):
with When("I run show create quota command"):
node.query("SHOW CREATE QUOTA CURRENT")
with Scenario("I show create quota current short form", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_ShowCreateQuota_Current("1.0")]):
with cleanup("quota2"):
with When("I run show create quota command"):
node.query("SHOW CREATE QUOTA")

View File

@ -0,0 +1,39 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as errors
@TestFeature
@Name("show create role")
def feature(self, node="clickhouse1"):
"""Check show create role query syntax.
```sql
SHOW CREATE ROLE name
```
"""
node = self.context.cluster.node(node)
@contextmanager
def setup(role):
try:
with Given("I have a role"):
node.query(f"CREATE ROLE OR REPLACE {role}")
yield
finally:
with Finally("I drop the role"):
node.query(f"DROP ROLE IF EXISTS {role}")
with Scenario("I show create role", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_ShowCreate("1.0")]):
with setup("role0"):
with When("I run show create role command"):
node.query("SHOW CREATE ROLE role0")
with Scenario("I show create role, role doesn't exist, exception", flags=TE, requirements=[
RQ_SRS_006_RBAC_Role_ShowCreate("1.0")]):
with When("I run show create role to catch an exception"):
exitcode, message = errors.role_not_found_in_disk(name="role0")
node.query("SHOW CREATE ROLE role0", exitcode=exitcode, message=message)

View File

@ -0,0 +1,51 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
@TestFeature
@Name("show create row policy")
def feature(self, node="clickhouse1"):
"""Check show create row policy query syntax.
```sql
SHOW CREATE [ROW] POLICY name ON [database.]table
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(policy, on="default.foo"):
try:
with Given("I have a row policy"):
node.query(f"CREATE ROW POLICY {policy} ON {on}")
yield
finally:
with Finally("I drop the row policy"):
node.query(f"DROP ROW POLICY IF EXISTS {policy} ON {on}")
try:
with Given("I have a table"):
node.query(f"CREATE TABLE default.foo (x UInt64, y String) Engine=Memory")
with Scenario("I show create row policy", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy("1.0")]):
with cleanup("policy0"):
with When("I run show create row policy command"):
node.query("SHOW CREATE ROW POLICY policy0 ON default.foo")
with Scenario("I show create row policy on a table", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy_On("1.0")]):
with cleanup("policy0"):
with When("I run show create row policy command"):
node.query("SHOW CREATE ROW POLICY policy0 ON default.foo")
with Scenario("I show create row policy using short syntax on a table", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_ShowCreateRowPolicy_On("1.0")]):
with cleanup("policy1",on="foo"):
with When("I run show create row policy command"):
node.query("SHOW CREATE POLICY policy1 ON foo")
finally:
with Finally("I drop the table"):
node.query(f"DROP TABLE IF EXISTS default.foo")

View File

@ -0,0 +1,38 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
@TestFeature
@Name("show create settings profile")
def feature(self, node="clickhouse1"):
"""Check show create settings profile query syntax.
```sql
SHOW CREATE [SETTINGS] PROFILE name
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(profile):
try:
with Given("I have a settings profile"):
node.query(f"CREATE SETTINGS PROFILE {profile}")
yield
finally:
with Finally("I drop the settings profile"):
node.query(f"DROP SETTINGS PROFILE IF EXISTS {profile}")
with Scenario("I show create settings profile", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_ShowCreateSettingsProfile("1.0")]):
with cleanup("profile0"):
with When("I run show create settings profile command"):
node.query("SHOW CREATE SETTINGS PROFILE profile0")
with Scenario("I show create settings profile short form", flags=TE, requirements=[
RQ_SRS_006_RBAC_SettingsProfile_ShowCreateSettingsProfile("1.0")]):
with cleanup("profile1"):
with When("I run show create settings profile command"):
node.query("SHOW CREATE PROFILE profile1")

View File

@ -0,0 +1,37 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
@TestFeature
@Name("show create user")
def feature(self, node="clickhouse1"):
"""Check show create user query syntax.
```
SHOW CREATE USER [name | CURRENT_USER]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def setup(user):
try:
with Given("I have a user"):
node.query(f"CREATE USER {user}")
yield
finally:
with Finally("I drop the user"):
node.query(f"DROP USER IF EXISTS {user}")
with Scenario("I run show create on user with no options", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_ShowCreateUser_For("1.0")]):
with setup("user0"):
with When("I run show create user command"):
node.query("SHOW CREATE USER user0")
with Scenario("I run show create on current user", flags=TE, requirements=[
RQ_SRS_006_RBAC_User_ShowCreateUser("1.0")]):
with When("I show create the current user"):
node.query("SHOW CREATE USER CURRENT_USER")

View File

@ -0,0 +1,37 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
@TestFeature
@Name("show grants")
def feature(self, node="clickhouse1"):
"""Check show grants query syntax.
```sql
SHOW GRANTS [FOR user_or_role]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def setup(user):
try:
with Given("I have a user"):
node.query(f"CREATE USER {user}")
yield
finally:
with Finally("I drop the user"):
node.query(f"DROP USER IF EXISTS {user}")
with Scenario("I show grants for user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Show_Grants_For("1.0")]):
with setup("user0"):
with When("I run show grants command"):
node.query("SHOW GRANTS FOR user0")
with Scenario("I show grants for current user", flags=TE, requirements=[
RQ_SRS_006_RBAC_Show_Grants("1.0")]):
with When("I show grants"):
node.query("SHOW GRANTS")

View File

@ -0,0 +1,50 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
@TestFeature
@Name("show quotas")
def feature(self, node="clickhouse1"):
"""Check show quotas query syntax.
```sql
SHOW QUOTAS
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(quota):
try:
with Given("I have a quota"):
node.query(f"CREATE QUOTA OR REPLACE {quota}")
yield
finally:
with Finally("I drop the quota"):
node.query(f"DROP QUOTA IF EXISTS {quota}")
with Scenario("I show quotas", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_ShowQuotas("1.0")]):
with cleanup("quota0"), cleanup("quota1"):
with When("I run show quota command"):
node.query("SHOW QUOTAS")
with Scenario("I show quotas into outfile", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_ShowQuotas_IntoOutfile("1.0")]):
with cleanup("quota0"), cleanup("quota1"):
with When("I run show quota command"):
node.query("SHOW QUOTAS INTO OUTFILE 'quotas.txt'")
with Scenario("I show quotas with format", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_ShowQuotas_Format("1.0")]):
with cleanup("quota0"), cleanup("quota1"):
with When("I run show quota command"):
node.query("SHOW QUOTAS FORMAT TabSeparated")
with Scenario("I show quotas with settings", flags=TE, requirements=[
RQ_SRS_006_RBAC_Quota_ShowQuotas("1.0")]):
with cleanup("quota0"), cleanup("quota1"):
with When("I run show quota command"):
node.query("SHOW QUOTAS SETTINGS max_memory_usage=5")

View File

@ -0,0 +1,58 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
@TestFeature
@Name("show row policies")
def feature(self, node="clickhouse1"):
"""Check show row polices query syntax.
```sql
SHOW [ROW] POLICIES [ON [database.]table]
```
"""
node = self.context.cluster.node(node)
@contextmanager
def cleanup(policy, on="default.foo"):
try:
with Given("I have a row policy"):
node.query(f"CREATE ROW POLICY {policy} ON {on}")
yield
finally:
with Finally("I drop the row policy"):
node.query(f"DROP ROW POLICY IF EXISTS {policy} ON {on}")
try:
with Given("I have a table"):
node.query(f"CREATE TABLE default.foo (x UInt64, y String) Engine=Memory")
with Scenario("I show row policies", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies("1.0")]):
with cleanup("policy0"):
with When("I run drop row policy command"):
node.query("SHOW ROW POLICIES")
with Scenario("I show row policies using short syntax", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies("1.0")]):
with cleanup("policy1"):
with When("I run drop row policy command"):
node.query("SHOW POLICIES")
with Scenario("I show row policies on a database table", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies_On("1.0")]):
with cleanup("policy0"):
with When("I run drop row policy command"):
node.query("SHOW ROW POLICIES ON default.foo")
with Scenario("I show row policies on a table", flags=TE, requirements=[
RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies_On("1.0")]):
with cleanup("policy0"):
with When("I run drop row policy command"):
node.query("SHOW ROW POLICIES ON foo")
finally:
with Finally("I drop the table"):
node.query(f"DROP TABLE IF EXISTS default.foo")