@@ -4737,3 +4737,79 @@ def test_wap_publish_failure(adapter_mock: Mock, make_snapshot: t.Callable[...,
47374737 # Execute audit with WAP ID and expect it to raise the exception
47384738 with pytest .raises (Exception , match = "WAP publish failed" ):
47394739 evaluator .audit (snapshot , snapshots = {}, wap_id = wap_id )
4740+
4741+
4742+ def test_properties_are_preserved_in_both_create_statements (
4743+ adapter_mock : Mock , make_snapshot : t .Callable [..., Snapshot ]
4744+ ) -> None :
4745+ # the below mocks are needed to create a situation
4746+ # where we trigger two create statements during evaluation
4747+ transaction_mock = Mock ()
4748+ transaction_mock .__enter__ = Mock ()
4749+ transaction_mock .__exit__ = Mock ()
4750+ session_mock = Mock ()
4751+ session_mock .__enter__ = Mock ()
4752+ session_mock .__exit__ = Mock ()
4753+ adapter_mock = Mock ()
4754+ adapter_mock .transaction .return_value = transaction_mock
4755+ adapter_mock .session .return_value = session_mock
4756+ adapter_mock .dialect = "trino"
4757+ adapter_mock .HAS_VIEW_BINDING = False
4758+ adapter_mock .wap_supported .return_value = False
4759+ adapter_mock .get_data_objects .return_value = []
4760+ adapter_mock .with_settings .return_value = adapter_mock
4761+ adapter_mock .table_exists .return_value = False
4762+
4763+ props = []
4764+
4765+ def mutate_view_properties (* args , ** kwargs ):
4766+ view_props = kwargs .get ("view_properties" )
4767+ if isinstance (view_props , dict ):
4768+ props .append (view_props ["creatable_type" ].sql ())
4769+ # simulate view pop
4770+ view_props .pop ("creatable_type" )
4771+ return None
4772+
4773+ adapter_mock .create_view .side_effect = mutate_view_properties
4774+
4775+ evaluator = SnapshotEvaluator (adapter_mock )
4776+
4777+ # create a view model with SECURITY INVOKER physical property
4778+ # AND self referenctial to trigger two create statements
4779+ model = load_sql_based_model (
4780+ parse ( # type: ignore
4781+ """
4782+ MODEL (
4783+ name test_schema.security_view,
4784+ kind VIEW,
4785+ physical_properties (
4786+ 'creatable_type' = 'SECURITY INVOKER'
4787+ )
4788+ );
4789+
4790+ SELECT 1 as col from test_schema.security_view;
4791+ """
4792+ ),
4793+ )
4794+
4795+ snapshot = make_snapshot (model )
4796+ snapshot .categorize_as (SnapshotChangeCategory .BREAKING )
4797+ evaluator .evaluate (
4798+ snapshot ,
4799+ start = "2024-01-01" ,
4800+ end = "2024-01-02" ,
4801+ execution_time = "2024-01-02" ,
4802+ snapshots = {},
4803+ )
4804+
4805+ # Verify create_view was called twice
4806+ assert adapter_mock .create_view .call_count == 2
4807+ first_call = adapter_mock .create_view .call_args_list [0 ]
4808+ second_call = adapter_mock .create_view .call_args_list [1 ]
4809+
4810+ # First call should be CREATE VIEW (replace=False) second CREATE OR REPLACE VIEW (replace=True)
4811+ assert first_call .kwargs .get ("replace" ) == False
4812+ assert second_call .kwargs .get ("replace" ) == True
4813+
4814+ # Both calls should have view_properties with security invoker
4815+ assert props == ["'SECURITY INVOKER'" , "'SECURITY INVOKER'" ]
0 commit comments