select.py: requirements cleanup + syntax update

This commit is contained in:
ritaank 2020-08-03 03:24:05 -07:00
commit 4910435f6c
37 changed files with 5328 additions and 1243 deletions

View File

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

View File

@ -8,7 +8,37 @@ 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
@ -25,6 +55,7 @@ def regression(self, local, clickhouse_binary_path):
with Cluster(local, clickhouse_binary_path, nodes=nodes) as cluster:
self.context.cluster = cluster
Feature(run=load("rbac.tests.syntax.feature", "feature"), flags=TE)
Feature(run=load("rbac.tests.privileges.feature", "feature"), flags=TE)
if main():

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
# These requirements were auto generated
# from software requirements specification (SRS)
# document by TestFlows v1.6.200723.1011705.
# document by TestFlows v1.6.200731.1222107.
# Do not edit by hand but re-generate instead
# using 'tfs requirements generate' command.
from testflows.core import Requirement
@ -316,329 +316,6 @@ RQ_SRS_006_RBAC_Role_RowPolicies = Requirement(
link=None
)
RQ_SRS_006_RBAC_Privileges_Usage = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Usage',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **usage** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Select = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Select',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **select** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_SelectColumns = Requirement(
name='RQ.SRS-006.RBAC.Privileges.SelectColumns',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **select columns** privilege\n'
'for a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Insert = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Insert',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **insert** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Delete = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Delete',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **delete** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Alter = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Alter',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **alter** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Create = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Create',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **create** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Drop = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Drop',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **drop** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_All = Requirement(
name='RQ.SRS-006.RBAC.Privileges.All',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL include in the **all** privilege the same rights\n'
'as provided by **usage**, **select**, **select columns**,\n'
'**insert**, **delete**, **alter**, **create**, and **drop** privileges.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_All_GrantRevoke = Requirement(
name='RQ.SRS-006.RBAC.Privileges.All.GrantRevoke',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **all** privileges\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_GrantOption = Requirement(
name='RQ.SRS-006.RBAC.Privileges.GrantOption',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **grant option** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_AdminOption = Requirement(
name='RQ.SRS-006.RBAC.Privileges.AdminOption',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **admin option** privilege\n'
'to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Insert = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Insert',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `INSERT INTO` statements\n'
'to be executed unless the user has the **insert** privilege for the destination table\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Select = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Select',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `SELECT` statements\n'
'to be executed unless the user has the **select** or **select columns** privilege\n'
'for the destination table either because of the explicit grant\n'
'or through one of the roles assigned to the user.\n'
'If the the user only has the **select columns**\n'
'privilege then only the specified columns SHALL be available for reading.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Create = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Create',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `CREATE` statements\n'
'to be executed unless the user has the **create** privilege for the destination database\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Alter = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Alter',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `ALTER` statements\n'
'to be executed unless the user has the **alter** privilege for the destination table\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Drop = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Drop',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `DROP` statements\n'
'to be executed unless the user has the **drop** privilege for the destination database\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Drop_Table = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Drop.Table',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `DROP TABLE` statements\n'
'to be executed unless the user has the **drop** privilege for the destination database or the table\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_GrantRevoke = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.GrantRevoke',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `GRANT` or `REVOKE` statements\n'
'to be executed unless the user has the **grant option** privilege\n'
'for the privilege of the destination table\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Use = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Use',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow the `USE` statement to be executed\n'
'unless the user has at least one of the privileges for the database\n'
'or the table inside that database\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Admin = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Admin',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any of the following statements\n'
'\n'
'* `SYSTEM`\n'
'* `SHOW`\n'
'* `ATTACH`\n'
'* `CHECK TABLE`\n'
'* `DESCRIBE TABLE`\n'
'* `DETACH`\n'
'* `EXISTS`\n'
'* `KILL QUERY`\n'
'* `KILL MUTATION`\n'
'* `OPTIMIZE`\n'
'* `RENAME`\n'
'* `TRUNCATE`\n'
'\n'
'to be executed unless the user has the **admin option** privilege\n'
'through one of the roles with **admin option** privilege assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_PartialRevokes = Requirement(
name='RQ.SRS-006.RBAC.PartialRevokes',
version='1.0',
@ -2319,52 +1996,6 @@ RQ_SRS_006_RBAC_Grant_Privilege_Select = Requirement(
link=None
)
RQ_SRS_006_RBAC_Grant_Privilege_Select_Effect = Requirement(
name='RQ.SRS-006.RBAC.Grant.Privilege.Select.Effect',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL add the **select** privilege to the specified users or roles\n'
'after the successful execution of the `GRANT SELECT` statement.\n'
'Any new operation by a user or a user that has the specified role\n'
'which requires the **select** privilege SHALL succeed.\n'
),
link=None
)
RQ_SRS_006_RBAC_Grant_Privilege_SelectColumns = Requirement(
name='RQ.SRS-006.RBAC.Grant.Privilege.SelectColumns',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting the **select columns** privilege to one or more users or roles\n'
'for a database or a table using the `GRANT SELECT(columns)` statement.\n'
),
link=None
)
RQ_SRS_006_RBAC_Grant_Privilege_SelectColumns_Effect = Requirement(
name='RQ.SRS-006.RBAC.Grant.Privilege.SelectColumns.Effect',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL add the **select columns** privilege to the specified users or roles\n'
'after the successful execution of the `GRANT SELECT(columns)` statement.\n'
'Any new operation by a user or a user that has the specified role\n'
'which requires the **select columns** privilege SHALL succeed.\n'
),
link=None
)
RQ_SRS_006_RBAC_Grant_Privilege_Insert = Requirement(
name='RQ.SRS-006.RBAC.Grant.Privilege.Insert',
version='1.0',
@ -2375,21 +2006,9 @@ RQ_SRS_006_RBAC_Grant_Privilege_Insert = Requirement(
description=(
'[ClickHouse] SHALL support granting the **insert** privilege to one or more users or roles\n'
'for a database or a table using the `GRANT INSERT` statement.\n'
),
link=None
)
RQ_SRS_006_RBAC_Grant_Privilege_Insert_Effect = Requirement(
name='RQ.SRS-006.RBAC.Grant.Privilege.Insert.Effect',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL add the **insert** privilege to the specified users or roles\n'
'after the successful execution of the `GRANT INSERT` statement.\n'
'Any new operation by a user or a user that has the specified role\n'
'When the **insert** privilege is granted to the specified users or roles\n'
'after the successful execution of the `GRANT INSERT` statement,\n'
'any new operation by a user or a user that has the specified role\n'
'which requires the **insert** privilege SHALL succeed.\n'
),
link=None
@ -2942,9 +2561,8 @@ RQ_SRS_006_RBAC_Grant_Privilege_Syntax = Requirement(
'grants explicit privileges to a user or a role.\n'
'\n'
'```sql\n'
'GRANT [ON CLUSTER cluster_name]\n'
' privilege {SELECT | SELECT(columns) | INSERT | ALTER | CREATE | DROP | TRUNCATE | OPTIMIZE | SHOW | KILL QUERY | ACCESS MANAGEMENT | SYSTEM | INTROSPECTION | SOURCES | dictGet | NONE |ALL \t[PRIVILEGES]} [, ...]\n'
' ON {*.* | database.* | database.table | * | table}\n'
'GRANT [ON CLUSTER cluster_name] privilege[(column_name [,...])] [,...]\n'
' ON {db.table|db.*|*.*|table|*}\n'
' TO {user | role | CURRENT_USER} [,...]\n'
' [WITH GRANT OPTION]\n'
'```\n'
@ -3029,22 +2647,6 @@ RQ_SRS_006_RBAC_Revoke_Privilege_Select = Requirement(
link=None
)
RQ_SRS_006_RBAC_Revoke_Privilege_Select_Effect = Requirement(
name='RQ.SRS-006.RBAC.Revoke.Privilege.Select.Effect',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL remove the **select** privilege from the specified users or roles\n'
'after the successful execution of the `REVOKE SELECT` statement.\n'
'Any new operation by a user or a user that had the specified role\n'
'which requires the **select** privilege SHALL fail if user does not have it otherwise.\n'
),
link=None
)
RQ_SRS_006_RBAC_Revoke_Privilege_Insert = Requirement(
name='RQ.SRS-006.RBAC.Revoke.Privilege.Insert',
version='1.0',
@ -3055,21 +2657,9 @@ RQ_SRS_006_RBAC_Revoke_Privilege_Insert = Requirement(
description=(
'[ClickHouse] SHALL support revoking the **insert** privilege to one or more users or roles\n'
'for a database or a table using the `REVOKE INSERT` statement.\n'
),
link=None
)
RQ_SRS_006_RBAC_Revoke_Privilege_Insert_Effect = Requirement(
name='RQ.SRS-006.RBAC.Revoke.Privilege.Insert.Effect',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL remove the **insert** privilege from the specified users or roles\n'
'after the successful execution of the `REVOKE INSERT` statement.\n'
'Any new operation by a user or a user that had the specified role\n'
'When the **insert** privilege is removed from the specified users or roles\n'
'after the successful execution of the `REVOKE INSERT` statement,\n'
'any new operation by a user or a user that had the specified role\n'
'which requires the **insert** privilege SHALL fail if user does not have it otherwise.\n'
),
link=None
@ -3664,13 +3254,6 @@ RQ_SRS_006_RBAC_Revoke_Privilege_Syntax = Requirement(
' ON {db.table|db.*|*.*|table|*}\n'
' FROM {user | CURRENT_USER} [,...] | ALL | ALL EXCEPT {user | CURRENT_USER} [,...]\n'
'```\n'
'<!-- old syntax, for reference -->\n'
'<!-- ```sql\n'
'REVOKE [GRANT OPTION FOR]\n'
' {USAGE | SELECT | SELECT(columns) | INSERT | DELETE | ALTER | CREATE | DROP | ALL [PRIVILEGES]} [, ...]\n'
' ON {*.* | database.* | database.table | * | table}\n'
' FROM user_or_role [, user_or_role ...]\n'
'``` -->\n'
),
link=None
)
@ -6192,3 +5775,509 @@ RQ_SRS_006_RBAC_RowPolicy_ShowRowPolicies_Syntax = Requirement(
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Usage = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Usage',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **usage** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Select = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Select',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support changing access to the **select** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
'Any `SELECT INTO` statements SHALL not to be executed, unless the user\n'
'has the **select** privilege for the destination table\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Select_Grant = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Select.Grant',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting **select** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Select_Revoke = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Select.Revoke',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support revoking **select** privilege\n'
'for a database or a specific table to one or more **users** or **roles**\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Select_Column = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Select.Column',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **select** privilege\n'
'for one or more specified columns in a table to one or more **users** or **roles**.\n'
'Any `SELECT INTO` statements SHALL not to be executed, unless the user\n'
'has the **select** privilege for the destination column\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Select_Cluster = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Select.Cluster',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **select** privilege\n'
'on a specified cluster to one or more **users** or **roles**.\n'
'Any `SELECT INTO` statements SHALL succeed only on nodes where\n'
'the table exists and privilege was granted.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Select_GrantOption = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Select.GrantOption',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting **select** privilege\n'
'for a database or a specific table to one or more **users** or **roles**\n'
'with a `GRANT OPTION` clause. User with **grant option** privilege SHALL be able to\n'
'change access to the **select** privilege by another user or role\n'
'on the same or smaller scope that they have access to.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Select_GrantOption_Grant = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Select.GrantOption.Grant',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support a user with **grant option** privilege\n'
'granting **select** privilege to other **users** or **roles** on the same\n'
'or smaller scope that they have access to. Any `SELECT INTO` statements SHALL succeed\n'
'when done by a user with privilege granted by a user with `GRANT OPTION`,\n'
'either directly or through an assigned role.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Select_GrantOption_Revoke = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Select.GrantOption.Revoke',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support a user with **grant option** privilege\n'
'revoking **select** privilege from other **users** or **roles** on the same\n'
'or smaller scope that they have access to. Any `SELECT INTO` statements SHALL fail\n'
'when done by a user with privilege revoke by a user with `GRANT OPTION`,\n'
'either directly or through an assigned role, unless they have access otherwise.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Insert = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Insert',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support changing access to the **insert** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
'Any `INSERT INTO` statements SHALL not to be executed, unless the user\n'
'has the **insert** privilege for the destination table\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Insert_Grant = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Insert.Grant',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting **insert** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Insert_Revoke = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Insert.Revoke',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support revoking **insert** privilege\n'
'for a database or a specific table to one or more **users** or **roles**\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Insert_Column = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Insert.Column',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **insert** privilege\n'
'for one or more specified columns in a table to one or more **users** or **roles**.\n'
'Any `INSERT INTO` statements SHALL not to be executed, unless the user\n'
'has the **insert** privilege for the destination column\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Insert_Cluster = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Insert.Cluster',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **insert** privilege\n'
'on a specified cluster to one or more **users** or **roles**.\n'
'Any `INSERT INTO` statements SHALL succeed only on nodes where\n'
'the table exists and privilege was granted.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Insert_GrantOption = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Insert.GrantOption',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting **insert** privilege\n'
'for a database or a specific table to one or more **users** or **roles**\n'
'with a `GRANT OPTION` clause. User with **grant option** privilege SHALL be able to\n'
'change access to the **insert** privilege by another user or role\n'
'on the same or smaller scope that they have access to.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Insert_GrantOption_Grant = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Insert.GrantOption.Grant',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support a user with **grant option** privilege\n'
'granting **insert** privilege to other **users** or **roles** on the same\n'
'or smaller scope that they have access to. Any `INSERT INTO` statements SHALL succeed\n'
'when done by a user with privilege granted by a user with `GRANT OPTION`,\n'
'either directly or through an assigned role.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Insert_GrantOption_Revoke = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Insert.GrantOption.Revoke',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support a user with **grant option** privilege\n'
'revoking **insert** privilege from other **users** or **roles** on the same\n'
'or smaller scope that they have access to. Any `INSERT INTO` statements SHALL fail\n'
'when done by a user with privilege revoke by a user with `GRANT OPTION`,\n'
'either directly or through an assigned role, unless they have access otherwise.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Delete = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Delete',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **delete** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Alter = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Alter',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **alter** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Create = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Create',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **create** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_Drop = Requirement(
name='RQ.SRS-006.RBAC.Privileges.Drop',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **drop** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_All = Requirement(
name='RQ.SRS-006.RBAC.Privileges.All',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL include in the **all** privilege the same rights\n'
'as provided by **usage**, **select**, **select columns**,\n'
'**insert**, **delete**, **alter**, **create**, and **drop** privileges.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_All_GrantRevoke = Requirement(
name='RQ.SRS-006.RBAC.Privileges.All.GrantRevoke',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **all** privileges\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_GrantOption = Requirement(
name='RQ.SRS-006.RBAC.Privileges.GrantOption',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **grant option** privilege\n'
'for a database or a specific table to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_Privileges_AdminOption = Requirement(
name='RQ.SRS-006.RBAC.Privileges.AdminOption',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL support granting or revoking **admin option** privilege\n'
'to one or more **users** or **roles**.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Create = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Create',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `CREATE` statements\n'
'to be executed unless the user has the **create** privilege for the destination database\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Alter = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Alter',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `ALTER` statements\n'
'to be executed unless the user has the **alter** privilege for the destination table\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Drop = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Drop',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `DROP` statements\n'
'to be executed unless the user has the **drop** privilege for the destination database\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Drop_Table = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Drop.Table',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `DROP TABLE` statements\n'
'to be executed unless the user has the **drop** privilege for the destination database or the table\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_GrantRevoke = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.GrantRevoke',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any `GRANT` or `REVOKE` statements\n'
'to be executed unless the user has the **grant option** privilege\n'
'for the privilege of the destination table\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Use = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Use',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow the `USE` statement to be executed\n'
'unless the user has at least one of the privileges for the database\n'
'or the table inside that database\n'
'either because of the explicit grant or through one of the roles assigned to the user.\n'
),
link=None
)
RQ_SRS_006_RBAC_RequiredPrivileges_Admin = Requirement(
name='RQ.SRS-006.RBAC.RequiredPrivileges.Admin',
version='1.0',
priority=None,
group=None,
type=None,
uid=None,
description=(
'[ClickHouse] SHALL not allow any of the following statements\n'
'\n'
'* `SYSTEM`\n'
'* `SHOW`\n'
'* `ATTACH`\n'
'* `CHECK TABLE`\n'
'* `DESCRIBE TABLE`\n'
'* `DETACH`\n'
'* `EXISTS`\n'
'* `KILL QUERY`\n'
'* `KILL MUTATION`\n'
'* `OPTIMIZE`\n'
'* `RENAME`\n'
'* `TRUNCATE`\n'
'\n'
'to be executed unless the user has the **admin option** privilege\n'
'through one of the roles with **admin option** privilege assigned to the user.\n'
),
link=None
)

View File

@ -3,5 +3,4 @@ from testflows.core import *
@TestFeature
@Name("privileges")
def feature(self):
Feature(run=load("rbac.tests.privileges.insert", "feature"), flags=TE)
Feature(run=load("rbac.tests.privileges.select", "feature"), flags=TE)

View File

@ -12,8 +12,6 @@ table_types = {
"CollapsingMergeTree": "CREATE TABLE {name} (d Date, a String, b UInt8, x String, y Int8, z UInt32) ENGINE = CollapsingMergeTree(d, (a, b), 111, y);"
}
exitcode, message = errors.not_enough_privileges(name="user0")
@contextmanager
def table(node, name, table_type="MergeTree"):
try:
@ -44,70 +42,47 @@ def role(node, role):
with Finally("I drop the role"):
node.query(f"DROP ROLE IF EXISTS {role}")
def input_output_equality_check(node, user, input_columns="d", input_data="2020-01-01"):
"""
ensures that selecting some data from a specified user on some table gives the desired
result. The desired result is specified from input_columns and input_data
"""
data_list = [x.strip("'") for x in input_data.split(",")]
input_dict = dict(zip(input_columns.split(","), data_list))
output_dict = json.loads(node.query(f"select {input_columns} from merge_tree format JSONEachRow",
settings = [("user", user)]).output)
output_dict = {k:str(v) for (k,v) in output_dict.items()}
return input_dict == output_dict
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0")
)
def without_privilege(self, table_type, node=None):
"""Check that user without select privilege on a table is not able to select on that table."""
"""Check that user without select privilege on a table is not able to select on that table.
"""
if node is None:
node = self.context.node
with table(node, "merge_tree", table_type):
with user(node, "user0"):
with When("I run SELECT without privilege"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query("SELECT * FROM merge_tree", settings = [("user","user0")],
exitcode=exitcode, message=message)
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select_Effect("1.0")
RQ_SRS_006_RBAC_Privileges_Select_Grant("1.0"),
)
def user_with_privilege(self, table_type, node=None):
"""Check that user can select from a table on which they have select privilege."""
"""Check that user can select from a table on which they have select privilege.
"""
if node is None:
node = self.context.node
with table(node, "merge_tree", table_type):
with Given("I have some data inserted into table"):
node.query("INSERT INTO merge_tree (d) VALUES ('2020-01-01')")
with user(node, "user88"):
pass
with user(node, "user0"):
with When("I grant privilege"):
node.query("GRANT SELECT ON merge_tree TO user0")
with And("I use SELECT"):
node.query("SELECT d FROM merge_tree", settings = [("user","user0")])
with Then("I check the SELECT call output is correct"):
assert input_output_equality_check(node, "user0"), error()
with Then("I verify SELECT command"):
user_select = node.query("SELECT d FROM merge_tree", settings = [("user","user0")])
default = node.query("SELECT d FROM merge_tree")
assert user_select.output == default.output, error()
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_On_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_From_Effect("1.0")
RQ_SRS_006_RBAC_Privileges_Select_Revoke("1.0"),
)
def user_with_revoked_privilege(self, table_type, node=None):
"""
Check that user is unable to select from a table after select privilege
"""Check that user is unable to select from a table after select privilege
on that table has been revoked from the user.
"""
if node is None:
@ -119,25 +94,19 @@ def user_with_revoked_privilege(self, table_type, node=None):
with And("I revoke privilege"):
node.query("REVOKE SELECT ON merge_tree FROM user0")
with And("I use SELECT, throws exception"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query("SELECT * FROM merge_tree", settings = [("user","user0")],
exitcode=exitcode, message=message)
@TestScenario
def user_with_privilege_on_columns(self, table_type):
Scenario(run=user_column_privileges,
examples=Examples("grant_columns revoke_columns select_columns_fail select_columns_pass data_pass table_type",
[tuple(list(row)+[table_type]) for row in user_column_privileges.examples]))
@TestOutline(Scenario)
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_PrivelegeColumns("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_PrivelegeColumns_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_On_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_From_Effect("1.0")
RQ_SRS_006_RBAC_Privileges_Select_Column("1.0"),
)
@Examples("grant_columns revoke_columns select_columns_fail select_columns_pass data_pass", [
("d", "d", "x", "d", '\'2020-01-01\''),
@ -145,9 +114,8 @@ def user_with_revoked_privilege(self, table_type, node=None):
("d,a,b", "d,a,b", "x", "d,b", '\'2020-01-01\',9'),
("d,a,b", "b", "y", "d,a,b", '\'2020-01-01\',\'woo\',9')
])
def user_with_privilege_on_columns(self, grant_columns, select_columns_pass, data_pass, table_type, revoke_columns=None, select_columns_fail=None, node=None):
"""
Check that user is able to select on granted columns
def user_column_privileges(self, grant_columns, select_columns_pass, data_pass, table_type, revoke_columns=None, select_columns_fail=None, node=None):
"""Check that user is able to select on granted columns
and unable to select on not granted or revoked columns.
"""
if node is None:
@ -159,28 +127,26 @@ def user_with_privilege_on_columns(self, grant_columns, select_columns_pass, dat
node.query(f"GRANT SELECT({grant_columns}) ON merge_tree TO user0")
if select_columns_fail is not None:
with And("I select from not granted column"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query(f"SELECT ({select_columns_fail}) FROM merge_tree",
settings = [("user","user0")], exitcode=exitcode, message=message)
with Then("I select from granted column and check result"):
assert input_output_equality_check(node, "user0", input_columns=select_columns_pass, input_data=data_pass), error()
with Then("I select from granted column, verify correct result"):
user_select = node.query("SELECT d FROM merge_tree", settings = [("user","user0")])
default = node.query("SELECT d FROM merge_tree")
assert user_select.output == default.output
if revoke_columns is not None:
with When("I revoke select privilege for columns from user"):
node.query(f"REVOKE SELECT({revoke_columns}) ON merge_tree FROM user0")
with And("I select from revoked columns"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query(f"SELECT ({select_columns_pass}) FROM merge_tree", settings = [("user","user0")], exitcode=exitcode, message=message)
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select_Effect("1.0")
RQ_SRS_006_RBAC_Privileges_Select_Grant("1.0"),
)
def role_with_privilege(self, table_type, node=None):
"""
Check that user can select from a table after it is granted a role that
"""Check that user can select from a table after it is granted a role that
has the select privilege for that table.
"""
if node is None:
@ -194,23 +160,17 @@ def role_with_privilege(self, table_type, node=None):
node.query("GRANT SELECT ON merge_tree TO role0")
with And("I grant role to the user"):
node.query("GRANT role0 TO user0")
with Then("I check that SELECT call output is correct"):
assert input_output_equality_check(node, "user0"), error()
with Then("I verify SELECT command"):
user_select = node.query("SELECT d FROM merge_tree", settings = [("user","user0")])
default = node.query("SELECT d FROM merge_tree")
assert user_select.output == default.output, error()
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_On_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_From_Effect("1.0")
RQ_SRS_006_RBAC_Privileges_Select_Revoke("1.0"),
)
def role_with_revoked_privilege(self, table_type, node=None):
"""
Check that user with a role that has select privilege on a table is unable
"""Check that user with a role that has select privilege on a table is unable
to select from that table after select privilege has been revoked from the role.
"""
if node is None:
@ -224,23 +184,13 @@ def role_with_revoked_privilege(self, table_type, node=None):
with And("I revoke privilege from the role"):
node.query("REVOKE SELECT ON merge_tree FROM role0")
with And("I select from the table"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query("SELECT * FROM merge_tree", settings = [("user","user0")],
exitcode=exitcode, message=message)
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Role("1.0"),
RQ_SRS_006_RBAC_Revoke_Role_Effect("1.0")
)
def user_with_revoked_role(self, table_type, node=None):
"""
Check that user with a role that has select privilege on a table is unable to
"""Check that user with a role that has select privilege on a table is unable to
select from that table after the role with select privilege has been revoked from the user.
"""
if node is None:
@ -254,25 +204,19 @@ def user_with_revoked_role(self, table_type, node=None):
with And("I revoke the role from the user"):
node.query("REVOKE role0 FROM user0")
with And("I select from the table"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query("SELECT * FROM merge_tree", settings = [("user","user0")],
exitcode=exitcode, message=message)
@TestScenario
def role_with_privilege_on_columns(self, table_type):
Scenario(run=role_column_privileges,
examples=Examples("grant_columns revoke_columns select_columns_fail select_columns_pass data_pass table_type",
[tuple(list(row)+[table_type]) for row in role_column_privileges.examples]))
@TestOutline(Scenario)
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_PrivelegeColumns("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_PrivelegeColumns_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_On_Effect("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_From("1.0"),
RQ_SRS_006_RBAC_Revoke_Privilege_From_Effect("1.0")
RQ_SRS_006_RBAC_Privileges_Select_Column("1.0"),
)
@Examples("grant_columns revoke_columns select_columns_fail select_columns_pass data_pass", [
("d", "d", "x", "d", '\'2020-01-01\''),
@ -280,9 +224,8 @@ def user_with_revoked_role(self, table_type, node=None):
("d,a,b", "d,a,b", "x", "d,b", '\'2020-01-01\',9'),
("d,a,b", "b", "y", "d,a,b", '\'2020-01-01\',\'woo\',9')
])
def role_with_privilege_on_columns(self, grant_columns, select_columns_pass, data_pass, table_type, revoke_columns=None, select_columns_fail=None, node=None):
"""
Check that user is able to select from granted columns and unable
def role_column_privileges(self, grant_columns, select_columns_pass, data_pass, table_type, revoke_columns=None, select_columns_fail=None, node=None):
"""Check that user is able to select from granted columns and unable
to select from not granted or revoked columns.
"""
if node is None:
@ -297,29 +240,27 @@ def role_with_privilege_on_columns(self, grant_columns, select_columns_pass, dat
node.query("GRANT role0 TO user0")
if select_columns_fail is not None:
with And("I select from not granted column"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query(f"SELECT ({select_columns_fail}) FROM merge_tree",
settings = [("user","user0")], exitcode=exitcode, message=message)
with Then("I select from granted column and check result"):
assert input_output_equality_check(node, "user0", input_columns=select_columns_pass, input_data=data_pass), error()
with Then("I verify SELECT command"):
user_select = node.query("SELECT d FROM merge_tree", settings = [("user","user0")])
default = node.query("SELECT d FROM merge_tree")
assert user_select.output == default.output, error()
if revoke_columns is not None:
with When("I revoke select privilege for columns from role"):
node.query(f"REVOKE SELECT({revoke_columns}) ON merge_tree FROM role0")
with And("I select from revoked columns"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query(f"SELECT ({select_columns_pass}) FROM merge_tree",
settings = [("user","user0")], exitcode=exitcode, message=message)
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Privileges_Select_GrantOption_Grant("1.0"),
)
def user_with_privilege_on_cluster(self, table_type, node=None):
"""
Check that user is able to select from a table with
"""Check that user is able to select from a table with
privilege granted on a cluster.
"""
if node is None:
@ -332,24 +273,20 @@ def user_with_privilege_on_cluster(self, table_type, node=None):
node.query("CREATE USER OR REPLACE user0 ON CLUSTER sharded_cluster")
with When("I grant select privilege on a cluster"):
node.query("GRANT ON CLUSTER sharded_cluster SELECT ON merge_tree TO user0")
with Then("I check that SELECT call output is correct"):
assert input_output_equality_check(node, "user0"), error()
with Then("I verify SELECT command"):
user_select = node.query("SELECT d FROM merge_tree", settings = [("user","user0")])
default = node.query("SELECT d FROM merge_tree")
assert user_select.output == default.output, error()
finally:
with Finally("I drop the user"):
node.query("DROP USER user0 ON CLUSTER sharded_cluster")
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Privileges_Select_GrantOption_Grant("1.0"),
)
def user_with_privilege_from_user_with_grant_option(self, table_type, node=None):
"""
Check that user is able to select from a table when granted privilege
"""Check that user is able to select from a table when granted privilege
from another user with grant option.
"""
if node is None:
@ -362,21 +299,17 @@ def user_with_privilege_from_user_with_grant_option(self, table_type, node=None)
node.query("GRANT SELECT ON merge_tree TO user0 WITH GRANT OPTION")
with And("I grant privilege to another user via grant option"):
node.query("GRANT SELECT ON merge_tree TO user1", settings = [("user","user0")])
with Then("I check that SELECT call output is correct"):
assert input_output_equality_check(node, "user1"), error()
with Then("I verify SELECT command"):
user_select = node.query("SELECT d FROM merge_tree", settings = [("user","user1")])
default = node.query("SELECT d FROM merge_tree")
assert user_select.output == default.output, error()
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Privileges_Select_GrantOption_Grant("1.0"),
)
def role_with_privilege_from_user_with_grant_option(self, table_type, node=None):
"""
Check that user is able to select from a table when granted a role with
"""Check that user is able to select from a table when granted a role with
select privilege that was granted by another user with grant option.
"""
if node is None:
@ -391,21 +324,17 @@ def role_with_privilege_from_user_with_grant_option(self, table_type, node=None)
node.query("GRANT SELECT ON merge_tree TO role0", settings = [("user","user0")])
with And("I grant the role to another user"):
node.query("GRANT role0 TO user1")
with Then("I check that SELECT call output is correct"):
assert input_output_equality_check(node, "user1"), error()
with Then("I verify SELECT command"):
user_select = node.query("SELECT d FROM merge_tree", settings = [("user","user1")])
default = node.query("SELECT d FROM merge_tree")
assert user_select.output == default.output, error()
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Privileges_Select_GrantOption_Grant("1.0"),
)
def user_with_privilege_from_role_with_grant_option(self, table_type, node=None):
"""
Check that user is able to select from a table when granted privilege from
"""Check that user is able to select from a table when granted privilege from
a role with grant option
"""
if node is None:
@ -420,21 +349,17 @@ def user_with_privilege_from_role_with_grant_option(self, table_type, node=None)
node.query("GRANT role0 TO user0")
with And("I grant privilege to a user via grant option"):
node.query("GRANT SELECT ON merge_tree TO user1", settings = [("user","user0")])
with Then("I check that SELECT call output is correct"):
assert input_output_equality_check(node, "user1"), error()
with Then("I verify SELECT command"):
user_select = node.query("SELECT d FROM merge_tree", settings = [("user","user1")])
default = node.query("SELECT d FROM merge_tree")
assert user_select.output == default.output, error()
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select_Effect("1.0"),
RQ_SRS_006_RBAC_Privileges_Select_GrantOption_Grant("1.0"),
)
def role_with_privilege_from_role_with_grant_option(self, table_type, node=None):
"""
Check that a user is able to select from a table with a role that was
"""Check that a user is able to select from a table with a role that was
granted privilege by another role with grant option
"""
if node is None:
@ -451,22 +376,18 @@ def role_with_privilege_from_role_with_grant_option(self, table_type, node=None)
node.query("GRANT SELECT ON merge_tree TO role1", settings = [("user","user0")])
with And("I grant the second role to another user"):
node.query("GRANT role1 TO user1")
with Then("I check that SELECT call output is correct"):
assert input_output_equality_check(node, "user1"), error()
with Then("I verify SELECT command"):
user_select = node.query("SELECT d FROM merge_tree", settings = [("user","user1")])
default = node.query("SELECT d FROM merge_tree")
assert user_select.output == default.output, error()
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_Privileges_GrantOption("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To_Effect("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_PrivilegeColumns("1.0"),
RQ_SRS_006_RBAC_Privileges_Select_GrantOption_Revoke("1.0"),
)
def revoke_privilege_from_user_via_user_with_grant_option(self, table_type, node=None):
"""Check that user is unable to revoke a column they don't have access to from a user."""
"""Check that user is unable to revoke a column they don't have access to from a user.
"""
if node is None:
node = self.context.node
with table(node, "merge_tree", table_type):
@ -474,22 +395,17 @@ def revoke_privilege_from_user_via_user_with_grant_option(self, table_type, node
with When("I grant privilege with grant option to user"):
node.query("GRANT SELECT(d) ON merge_tree TO user0 WITH GRANT OPTION")
with Then("I revoke privilege on a column the user with grant option does not have access to"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query("REVOKE SELECT(b) ON merge_tree FROM user1", settings=[("user","user0")],
exitcode=exitcode, message=message)
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_Privileges_GrantOption("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To_Effect("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_PrivilegeColumns("1.0"),
RQ_SRS_006_RBAC_Privileges_Select_GrantOption_Revoke("1.0"),
)
def revoke_privilege_from_role_via_user_with_grant_option(self, table_type, node=None):
"""Check that user is unable to revoke a column they dont have acces to from a role."""
"""Check that user is unable to revoke a column they dont have acces to from a role.
"""
if node is None:
node = self.context.node
with table(node, "merge_tree", table_type):
@ -497,22 +413,17 @@ def revoke_privilege_from_role_via_user_with_grant_option(self, table_type, node
with When("I grant privilege with grant option to user"):
node.query("GRANT SELECT(d) ON merge_tree TO user0 WITH GRANT OPTION")
with Then("I revoke privilege on a column the user with grant option does not have access to"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query("REVOKE SELECT(b) ON merge_tree FROM role0", settings=[("user","user0")],
exitcode=exitcode, message=message)
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_Privileges_GrantOption("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To_Effect("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_PrivilegeColumns("1.0"),
RQ_SRS_006_RBAC_Privileges_Select_GrantOption_Revoke("1.0"),
)
def revoke_privilege_from_user_via_role_with_grant_option(self, table_type, node=None):
"""Check that user with a role is unable to revoke a column they dont have acces to from a user."""
"""Check that user with a role is unable to revoke a column they dont have acces to from a user.
"""
if node is None:
node = self.context.node
with table(node, "merge_tree", table_type):
@ -522,22 +433,17 @@ def revoke_privilege_from_user_via_role_with_grant_option(self, table_type, node
with And("I grant the role to a user"):
node.query("GRANT role0 TO user0")
with Then("I revoke privilege on a column the user with grant option does not have access to"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query("REVOKE SELECT(b) ON merge_tree FROM user1", settings=[("user","user0")],
exitcode=exitcode, message=message)
@TestScenario
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
RQ_SRS_006_RBAC_Privileges_GrantOption("1.0"),
RQ_SRS_006_RBAC_RequiredPrivileges_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_To_Effect("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_On("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_Select("1.0"),
RQ_SRS_006_RBAC_Grant_Privilege_PrivilegeColumns("1.0"),
RQ_SRS_006_RBAC_Privileges_Select_GrantOption_Revoke("1.0"),
)
def revoke_privilege_from_role_via_role_with_grant_option(self, table_type, node=None):
"""Check that user with a role is unable to revoke a column they dont have acces to from a role."""
"""Check that user with a role is unable to revoke a column they dont have acces to from a role.
"""
if node is None:
node = self.context.node
with table(node, "merge_tree", table_type):
@ -547,10 +453,14 @@ def revoke_privilege_from_role_via_role_with_grant_option(self, table_type, node
with And("I grant the role to a user"):
node.query("GRANT role0 TO user0")
with Then("I revoke privilege on a column the user with grant option does not have access to"):
exitcode, message = errors.not_enough_privileges(name="user0")
node.query("REVOKE SELECT(b) ON merge_tree FROM role1", settings=[("user","user0")],
exitcode=exitcode, message=message)
@TestOutline(Feature)
@Requirements(
RQ_SRS_006_RBAC_Privileges_Select("1.0"),
)
@Examples("table_type", [
(key,) for key in table_types.keys()
])
@ -561,15 +471,11 @@ def feature(self, table_type, node="clickhouse1"):
Scenario(test=without_privilege)(table_type=table_type)
Scenario(test=user_with_privilege)(table_type=table_type)
Scenario(test=user_with_revoked_privilege)(table_type=table_type)
Scenario(run=user_with_privilege_on_columns,
examples=Examples("grant_columns revoke_columns select_columns_fail select_columns_pass data_pass table_type",
[tuple(list(row)+[table_type]) for row in user_with_privilege_on_columns.examples]))
Scenario(test=user_with_privilege_on_columns)(table_type=table_type)
Scenario(test=role_with_privilege)(table_type=table_type)
Scenario(test=role_with_revoked_privilege)(table_type=table_type)
Scenario(test=user_with_revoked_role)(table_type=table_type)
Scenario(run=role_with_privilege_on_columns,
examples=Examples("grant_columns revoke_columns select_columns_fail select_columns_pass data_pass table_type",
[tuple(list(row)+[table_type]) for row in role_with_privilege_on_columns.examples]))
Scenario(test=role_with_privilege_on_columns)(table_type=table_type)
Scenario(test=user_with_privilege_on_cluster)(table_type=table_type)
Scenario(test=user_with_privilege_from_user_with_grant_option)(table_type=table_type)
Scenario(test=role_with_privilege_from_user_with_grant_option)(table_type=table_type)

View File

View File

@ -0,0 +1,206 @@
from contextlib import contextmanager
from testflows.core import *
from rbac.requirements import *
import rbac.tests.errors as 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")