@@ -4680,3 +4680,79 @@ def test_wap_publish_failure(adapter_mock: Mock, make_snapshot: t.Callable[...,
46804680 # Execute audit with WAP ID and expect it to raise the exception
46814681 with pytest .raises (Exception , match = "WAP publish failed" ):
46824682 evaluator .audit (snapshot , snapshots = {}, wap_id = wap_id )
4683+
4684+
4685+ def test_properties_are_preserved_in_both_create_statements (
4686+ adapter_mock : Mock , make_snapshot : t .Callable [..., Snapshot ]
4687+ ) -> None :
4688+ # the below mocks are needed to create a situation
4689+ # where we trigger two create statements during evaluation
4690+ transaction_mock = Mock ()
4691+ transaction_mock .__enter__ = Mock ()
4692+ transaction_mock .__exit__ = Mock ()
4693+ session_mock = Mock ()
4694+ session_mock .__enter__ = Mock ()
4695+ session_mock .__exit__ = Mock ()
4696+ adapter_mock = Mock ()
4697+ adapter_mock .transaction .return_value = transaction_mock
4698+ adapter_mock .session .return_value = session_mock
4699+ adapter_mock .dialect = "trino"
4700+ adapter_mock .HAS_VIEW_BINDING = False
4701+ adapter_mock .wap_supported .return_value = False
4702+ adapter_mock .get_data_objects .return_value = []
4703+ adapter_mock .with_settings .return_value = adapter_mock
4704+ adapter_mock .table_exists .return_value = False
4705+
4706+ props = []
4707+
4708+ def mutate_view_properties (* args , ** kwargs ):
4709+ view_props = kwargs .get ("view_properties" )
4710+ if isinstance (view_props , dict ):
4711+ props .append (view_props ["creatable_type" ].sql ())
4712+ # simulate view pop
4713+ view_props .pop ("creatable_type" )
4714+ return None
4715+
4716+ adapter_mock .create_view .side_effect = mutate_view_properties
4717+
4718+ evaluator = SnapshotEvaluator (adapter_mock )
4719+
4720+ # create a view model with SECURITY INVOKER physical property
4721+ # AND self referenctial to trigger two create statements
4722+ model = load_sql_based_model (
4723+ parse ( # type: ignore
4724+ """
4725+ MODEL (
4726+ name test_schema.security_view,
4727+ kind VIEW,
4728+ physical_properties (
4729+ 'creatable_type' = 'SECURITY INVOKER'
4730+ )
4731+ );
4732+
4733+ SELECT 1 as col from test_schema.security_view;
4734+ """
4735+ ),
4736+ )
4737+
4738+ snapshot = make_snapshot (model )
4739+ snapshot .categorize_as (SnapshotChangeCategory .BREAKING )
4740+ evaluator .evaluate (
4741+ snapshot ,
4742+ start = "2024-01-01" ,
4743+ end = "2024-01-02" ,
4744+ execution_time = "2024-01-02" ,
4745+ snapshots = {},
4746+ )
4747+
4748+ # Verify create_view was called twice
4749+ assert adapter_mock .create_view .call_count == 2
4750+ first_call = adapter_mock .create_view .call_args_list [0 ]
4751+ second_call = adapter_mock .create_view .call_args_list [1 ]
4752+
4753+ # First call should be CREATE VIEW (replace=False) second CREATE OR REPLACE VIEW (replace=True)
4754+ assert first_call .kwargs .get ("replace" ) == False
4755+ assert second_call .kwargs .get ("replace" ) == True
4756+
4757+ # Both calls should have view_properties with security invoker
4758+ assert props == ["'SECURITY INVOKER'" , "'SECURITY INVOKER'" ]
0 commit comments