|
61 | 61 | model, |
62 | 62 | ) |
63 | 63 | from sqlmesh.core.model.common import parse_expression |
64 | | -from sqlmesh.core.model.kind import ModelKindName, _model_kind_validator |
| 64 | +from sqlmesh.core.model.kind import _ModelKind, ModelKindName, _model_kind_validator |
65 | 65 | from sqlmesh.core.model.seed import CsvSettings |
66 | 66 | from sqlmesh.core.node import IntervalUnit, _Node |
67 | 67 | from sqlmesh.core.signal import signal |
@@ -11804,90 +11804,235 @@ def my_macro(evaluator): |
11804 | 11804 | assert model.render_query_or_raise().sql() == 'SELECT 3 AS "c"' |
11805 | 11805 |
|
11806 | 11806 |
|
11807 | | -def test_grants_validation_symbolic_model_error(): |
11808 | | - with pytest.raises(ValidationError, match=r".*grants cannot be set for EXTERNAL.*"): |
11809 | | - create_sql_model( |
11810 | | - "db.table", |
11811 | | - parse_one("SELECT 1 AS id"), |
11812 | | - kind="EXTERNAL", |
11813 | | - grants={"select": ["user1", "user2"], "insert": ["admin_user"]}, |
11814 | | - ) |
| 11807 | +@pytest.mark.parametrize( |
| 11808 | + "kind", |
| 11809 | + [ |
| 11810 | + "FULL", |
| 11811 | + "VIEW", |
| 11812 | + SeedKind(path="test.csv"), |
| 11813 | + IncrementalByTimeRangeKind(time_column="ds"), |
| 11814 | + IncrementalByUniqueKeyKind(unique_key="id"), |
| 11815 | + ], |
| 11816 | +) |
| 11817 | +def test_grants_valid_model_kinds(kind: t.Union[str, _ModelKind]): |
| 11818 | + model = create_sql_model( |
| 11819 | + "db.table", |
| 11820 | + parse_one("SELECT 1 AS id"), |
| 11821 | + kind=kind, |
| 11822 | + grants={"select": ["user1", "user2"], "insert": ["admin_user"]}, |
| 11823 | + ) |
| 11824 | + assert model.grants == {"select": ["user1", "user2"], "insert": ["admin_user"]} |
11815 | 11825 |
|
11816 | 11826 |
|
11817 | | -def test_grants_validation_embedded_model_error(): |
11818 | | - with pytest.raises(ValidationError, match=r".*grants cannot be set for EMBEDDED.*"): |
| 11827 | +@pytest.mark.parametrize( |
| 11828 | + "kind", |
| 11829 | + [ |
| 11830 | + "EXTERNAL", |
| 11831 | + "EMBEDDED", |
| 11832 | + ], |
| 11833 | +) |
| 11834 | +def test_grants_invalid_model_kind_errors(kind: str): |
| 11835 | + with pytest.raises(ValidationError, match=rf".*grants cannot be set for {kind}.*"): |
11819 | 11836 | create_sql_model( |
11820 | 11837 | "db.table", |
11821 | 11838 | parse_one("SELECT 1 AS id"), |
11822 | | - kind="EMBEDDED", |
| 11839 | + kind=kind, |
11823 | 11840 | grants={"select": ["user1"], "insert": ["admin_user"]}, |
11824 | 11841 | ) |
11825 | 11842 |
|
11826 | 11843 |
|
11827 | | -def test_grants_validation_valid_seed_model(): |
| 11844 | +def test_grants_validation_no_grants(): |
| 11845 | + model = create_sql_model("db.table", parse_one("SELECT 1 AS id"), kind="FULL") |
| 11846 | + assert model.grants is None |
| 11847 | + |
| 11848 | + |
| 11849 | +def test_grants_validation_empty_grantees(): |
11828 | 11850 | model = create_sql_model( |
11829 | | - "db.table", |
11830 | | - parse_one("SELECT 1 AS id"), |
11831 | | - kind=SeedKind(path="test.csv"), |
11832 | | - grants={"select": ["user1"], "insert": ["admin_user"]}, |
| 11851 | + "db.table", parse_one("SELECT 1 AS id"), kind="FULL", grants={"select": []} |
11833 | 11852 | ) |
11834 | | - assert model.grants == {"select": ["user1"], "insert": ["admin_user"]} |
| 11853 | + assert model.grants == {"select": []} |
11835 | 11854 |
|
11836 | 11855 |
|
11837 | | -def test_grants_validation_valid_materialized_model(): |
| 11856 | +def test_grants_single_value_conversions(): |
| 11857 | + expressions = d.parse(f""" |
| 11858 | + MODEL ( |
| 11859 | + name test.nested_arrays, |
| 11860 | + kind FULL, |
| 11861 | + grants ( |
| 11862 | + 'select' = "user1", update = user2 |
| 11863 | + ) |
| 11864 | + ); |
| 11865 | + SELECT 1 as id |
| 11866 | + """) |
| 11867 | + model = load_sql_based_model(expressions) |
| 11868 | + assert model.grants == {"select": ["user1"], "update": ["user2"]} |
| 11869 | + |
11838 | 11870 | model = create_sql_model( |
11839 | 11871 | "db.table", |
11840 | 11872 | parse_one("SELECT 1 AS id"), |
11841 | 11873 | kind="FULL", |
11842 | | - grants={"select": ["user1", "user2"], "insert": ["admin_user"]}, |
| 11874 | + grants={"select": "user1", "insert": 123}, |
11843 | 11875 | ) |
11844 | | - assert model.grants == {"select": ["user1", "user2"], "insert": ["admin_user"]} |
| 11876 | + assert model.grants == {"select": ["user1"], "insert": ["123"]} |
11845 | 11877 |
|
11846 | 11878 |
|
11847 | | -def test_grants_validation_valid_view_model(): |
11848 | | - model = create_sql_model( |
11849 | | - "db.table", parse_one("SELECT 1 AS id"), kind="VIEW", grants={"select": ["user1", "user2"]} |
| 11879 | +@pytest.mark.parametrize( |
| 11880 | + "grantees", |
| 11881 | + [ |
| 11882 | + "('user1', ('user2', 'user3'), 'user4')", |
| 11883 | + "('user1', ['user2', 'user3'], user4)", |
| 11884 | + "['user1', ['user2', user3], 'user4']", |
| 11885 | + "[user1, ('user2', \"user3\"), 'user4']", |
| 11886 | + ], |
| 11887 | +) |
| 11888 | +def test_grants_array_flattening(grantees: str): |
| 11889 | + expressions = d.parse(f""" |
| 11890 | + MODEL ( |
| 11891 | + name test.nested_arrays, |
| 11892 | + kind FULL, |
| 11893 | + grants ( |
| 11894 | + 'select' = {grantees} |
| 11895 | + ) |
| 11896 | + ); |
| 11897 | + SELECT 1 as id |
| 11898 | + """) |
| 11899 | + model = load_sql_based_model(expressions) |
| 11900 | + assert model.grants == {"select": ["user1", "user2", "user3", "user4"]} |
| 11901 | + |
| 11902 | + |
| 11903 | +def test_grants_macro_var_resolved(): |
| 11904 | + expressions = d.parse(""" |
| 11905 | + MODEL ( |
| 11906 | + name test.macro_grants, |
| 11907 | + kind FULL, |
| 11908 | + grants ( |
| 11909 | + 'select' = @VAR('readers'), |
| 11910 | + 'insert' = @VAR('writers') |
| 11911 | + ) |
| 11912 | + ); |
| 11913 | + SELECT 1 as id |
| 11914 | + """) |
| 11915 | + model = load_sql_based_model( |
| 11916 | + expressions, variables={"readers": ["user1", "user2"], "writers": "admin"} |
11850 | 11917 | ) |
11851 | | - assert model.grants == {"select": ["user1", "user2"]} |
| 11918 | + assert model.grants == { |
| 11919 | + "select": ["user1", "user2"], |
| 11920 | + "insert": ["admin"], |
| 11921 | + } |
11852 | 11922 |
|
11853 | 11923 |
|
11854 | | -def test_grants_validation_valid_incremental_model(): |
11855 | | - model = create_sql_model( |
11856 | | - "db.table", |
11857 | | - parse_one("SELECT 1 AS id, CURRENT_TIMESTAMP AS ts"), |
11858 | | - kind=IncrementalByTimeRangeKind(time_column="ts"), |
11859 | | - grants={"select": ["user1"], "update": ["admin_user"]}, |
| 11924 | +def test_grants_macro_var_in_array_flattening(): |
| 11925 | + expressions = d.parse(""" |
| 11926 | + MODEL ( |
| 11927 | + name test.macro_in_array, |
| 11928 | + kind FULL, |
| 11929 | + grants ( |
| 11930 | + 'select' = ['user1', @VAR('admins'), 'user3'] |
| 11931 | + ) |
| 11932 | + ); |
| 11933 | + SELECT 1 as id |
| 11934 | + """) |
| 11935 | + |
| 11936 | + model = load_sql_based_model(expressions, variables={"admins": ["admin1", "admin2"]}) |
| 11937 | + assert model.grants == {"select": ["user1", "admin1", "admin2", "user3"]} |
| 11938 | + |
| 11939 | + model2 = load_sql_based_model(expressions, variables={"admins": "super_admin"}) |
| 11940 | + assert model2.grants == {"select": ["user1", "super_admin", "user3"]} |
| 11941 | + |
| 11942 | + |
| 11943 | +def test_grants_dynamic_permission_names(): |
| 11944 | + expressions = d.parse(""" |
| 11945 | + MODEL ( |
| 11946 | + name test.dynamic_keys, |
| 11947 | + kind FULL, |
| 11948 | + grants ( |
| 11949 | + @VAR('read_perm') = ['user1', 'user2'], |
| 11950 | + @VAR('write_perm') = ['admin'] |
| 11951 | + ) |
| 11952 | + ); |
| 11953 | + SELECT 1 as id |
| 11954 | + """) |
| 11955 | + model = load_sql_based_model( |
| 11956 | + expressions, variables={"read_perm": "select", "write_perm": "insert"} |
11860 | 11957 | ) |
11861 | | - assert model.grants == {"select": ["user1"], "update": ["admin_user"]} |
| 11958 | + assert model.grants == {"select": ["user1", "user2"], "insert": ["admin"]} |
11862 | 11959 |
|
11863 | 11960 |
|
11864 | | -def test_grants_validation_no_grants(): |
11865 | | - model = create_sql_model("db.table", parse_one("SELECT 1 AS id"), kind="FULL") |
11866 | | - assert model.grants is None |
| 11961 | +def test_grants_unresolved_macro_errors(): |
| 11962 | + expressions1 = d.parse(""" |
| 11963 | + MODEL (name test.bad1, kind FULL, grants ('select' = @VAR('undefined'))); |
| 11964 | + SELECT 1 as id |
| 11965 | + """) |
| 11966 | + with pytest.raises(ConfigError, match=r"Invalid grants configuration for 'select': NULL value"): |
| 11967 | + load_sql_based_model(expressions1) |
11867 | 11968 |
|
| 11969 | + expressions2 = d.parse(""" |
| 11970 | + MODEL (name test.bad2, kind FULL, grants (@VAR('undefined') = ['user'])); |
| 11971 | + SELECT 1 as id |
| 11972 | + """) |
| 11973 | + with pytest.raises(ConfigError, match=r"Invalid grants configuration.*NULL value"): |
| 11974 | + load_sql_based_model(expressions2) |
11868 | 11975 |
|
11869 | | -def test_grants_validation_empty_grantees(): |
11870 | | - model = create_sql_model( |
| 11976 | + expressions3 = d.parse(""" |
| 11977 | + MODEL (name test.bad3, kind FULL, grants ('select' = ['user', @VAR('undefined')])); |
| 11978 | + SELECT 1 as id |
| 11979 | + """) |
| 11980 | + with pytest.raises(ConfigError, match=r"Invalid grants configuration for 'select': NULL value"): |
| 11981 | + load_sql_based_model(expressions3) |
| 11982 | + |
| 11983 | + |
| 11984 | +def test_grants_mixed_types_conversion(): |
| 11985 | + expressions = d.parse(""" |
| 11986 | + MODEL ( |
| 11987 | + name test.mixed_types, |
| 11988 | + kind FULL, |
| 11989 | + grants ( |
| 11990 | + 'select' = ['user1', 123, admin_role, 'user2'] |
| 11991 | + ) |
| 11992 | + ); |
| 11993 | + SELECT 1 as id |
| 11994 | + """) |
| 11995 | + model = load_sql_based_model(expressions) |
| 11996 | + assert model.grants == {"select": ["user1", "123", "admin_role", "user2"]} |
| 11997 | + |
| 11998 | + |
| 11999 | +def test_grants_empty_values(): |
| 12000 | + model1 = create_sql_model( |
11871 | 12001 | "db.table", parse_one("SELECT 1 AS id"), kind="FULL", grants={"select": []} |
11872 | 12002 | ) |
11873 | | - assert model.grants == {"select": []} |
| 12003 | + assert model1.grants == {"select": []} |
11874 | 12004 |
|
| 12005 | + model2 = create_sql_model("db.table", parse_one("SELECT 1 AS id"), kind="FULL") |
| 12006 | + assert model2.grants is None |
11875 | 12007 |
|
11876 | | -def test_grants_table_type_view(): |
11877 | | - model = create_sql_model("test_view", parse_one("SELECT 1 as id"), kind="VIEW") |
11878 | | - assert model.grants_table_type == DataObjectType.VIEW |
11879 | 12008 |
|
| 12009 | +def test_grants_backward_compatibility(): |
11880 | 12010 | model = create_sql_model( |
11881 | | - "test_mv", parse_one("SELECT 1 as id"), kind=ViewKind(materialized=True) |
| 12011 | + "db.table", |
| 12012 | + parse_one("SELECT 1 AS id"), |
| 12013 | + kind="FULL", |
| 12014 | + grants={ |
| 12015 | + "select": ["user1", "user2"], |
| 12016 | + "insert": ["admin"], |
| 12017 | + "roles/bigquery.dataViewer": ["user:data_eng@company.com"], |
| 12018 | + }, |
11882 | 12019 | ) |
11883 | | - assert model.grants_table_type == DataObjectType.MATERIALIZED_VIEW |
11884 | | - |
11885 | | - |
11886 | | -def test_grants_table_type_table(): |
11887 | | - model = create_sql_model("test_table", parse_one("SELECT 1 as id"), kind="FULL") |
11888 | | - assert model.grants_table_type == DataObjectType.TABLE |
| 12020 | + assert model.grants == { |
| 12021 | + "select": ["user1", "user2"], |
| 12022 | + "insert": ["admin"], |
| 12023 | + "roles/bigquery.dataViewer": ["user:data_eng@company.com"], |
| 12024 | + } |
11889 | 12025 |
|
11890 | 12026 |
|
11891 | | -def test_grants_table_type_managed(): |
11892 | | - model = create_sql_model("test_managed", parse_one("SELECT 1 as id"), kind="MANAGED") |
11893 | | - assert model.grants_table_type == DataObjectType.MANAGED_TABLE |
| 12027 | +@pytest.mark.parametrize( |
| 12028 | + "kind, expected", |
| 12029 | + [ |
| 12030 | + ("VIEW", DataObjectType.VIEW), |
| 12031 | + ("FULL", DataObjectType.TABLE), |
| 12032 | + ("MANAGED", DataObjectType.MANAGED_TABLE), |
| 12033 | + (ViewKind(materialized=True), DataObjectType.MATERIALIZED_VIEW), |
| 12034 | + ], |
| 12035 | +) |
| 12036 | +def test_grants_table_type(kind: t.Union[str, _ModelKind], expected: DataObjectType): |
| 12037 | + model = create_sql_model("test_table", parse_one("SELECT 1 as id"), kind=kind) |
| 12038 | + assert model.grants_table_type == expected |
0 commit comments