@@ -179,7 +179,7 @@ def test_no_missing_external_models_with_existing_file_not_ending_in_newline(
179179 assert edit .path == fix_path
180180
181181
182- def test_cron_validator (tmp_path , copy_to_temp_path ) -> None :
182+ def test_cron_interval_alignment (tmp_path , copy_to_temp_path ) -> None :
183183 sushi_paths = copy_to_temp_path ("examples/sushi" )
184184 sushi_path = sushi_paths [0 ]
185185
@@ -231,3 +231,57 @@ def test_cron_validator(tmp_path, copy_to_temp_path) -> None:
231231 lint .violation_msg
232232 == 'Upstream model "memory"."sushi"."step_1" has longer cron interval (@weekly) than this model (@daily)'
233233 )
234+
235+
236+ def test_cron_interval_alignment_valid_upstream (tmp_path , copy_to_temp_path ) -> None :
237+ sushi_paths = copy_to_temp_path ("examples/sushi" )
238+ sushi_path = sushi_paths [0 ]
239+
240+ # Override the config.py to turn on lint
241+ with open (sushi_path / "config.py" , "r" ) as f :
242+ read_file = f .read ()
243+
244+ before = """ linter=LinterConfig(
245+ enabled=False,
246+ rules=[
247+ "ambiguousorinvalidcolumn",
248+ "invalidselectstarexpansion",
249+ "noselectstar",
250+ "nomissingaudits",
251+ "nomissingowner",
252+ "nomissingexternalmodels",
253+ "cronintervalalignment",
254+ ],
255+ ),"""
256+ after = """linter=LinterConfig(enabled=True, rules=["cronintervalalignment"]),"""
257+ read_file = read_file .replace (before , after )
258+ assert after in read_file
259+ with open (sushi_path / "config.py" , "w" ) as f :
260+ f .writelines (read_file )
261+
262+ # Load the context with the temporary sushi path
263+ context = Context (paths = [sushi_path ])
264+
265+ context .load ()
266+
267+ # Create model with shorter cron interval that depends on model with longer interval
268+ upstream_model_a = load_sql_based_model (
269+ d .parse ("MODEL (name memory.sushi.step_a, cron '@weekly'); SELECT * FROM (SELECT 1)" )
270+ )
271+
272+ upstream_model_b = load_sql_based_model (
273+ d .parse ("MODEL (name memory.sushi.step_b, cron '@hourly'); SELECT * FROM (SELECT 1)" )
274+ )
275+
276+ downstream_model = load_sql_based_model (
277+ d .parse (
278+ "MODEL (name memory.sushi.step_c, cron '@daily', depends_on ['memory.sushi.step_1', 'memory.sushi.step_1_b']); SELECT * FROM (SELECT 1)"
279+ )
280+ )
281+
282+ context .upsert_model (upstream_model_a )
283+ context .upsert_model (upstream_model_b )
284+ context .upsert_model (downstream_model )
285+
286+ lints = context .lint_models (raise_on_error = False )
287+ assert len (lints ) == 0
0 commit comments