Skip to content

Commit d4e3fbe

Browse files
committed
Add new test for ready intervals
1 parent 311d3a1 commit d4e3fbe

File tree

1 file changed

+89
-9
lines changed

1 file changed

+89
-9
lines changed

tests/core/engine_adapter/integration/test_freshness.py

Lines changed: 89 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ def assert_model_evaluation(
8585
return timestamp, plan_or_run_result
8686

8787

88-
def create_freshness_model(name: str, schema: str, query: str, path: pathlib.Path):
88+
def create_model(
89+
name: str, schema: str, query: str, path: pathlib.Path, signals: str = "freshness()"
90+
):
8991
"""
9092
Create a freshness model with the given name, path, and query.
9193
"""
@@ -99,7 +101,7 @@ def create_freshness_model(name: str, schema: str, query: str, path: pathlib.Pat
99101
start '2024-01-01',
100102
kind FULL,
101103
signals (
102-
freshness(),
104+
{signals},
103105
)
104106
);
105107
@@ -167,7 +169,7 @@ def test_external_model_freshness(ctx: TestContext, tmp_path: pathlib.Path, mock
167169
)
168170

169171
# Create model that depends on external models
170-
model_name, model_path = create_freshness_model(
172+
model_name, model_path = create_model(
171173
"new_model",
172174
schema,
173175
f"SELECT col1 * col2 AS col FROM {external_table1}, {external_table2}",
@@ -237,31 +239,31 @@ def test_mixed_model_freshness(ctx: TestContext, tmp_path: pathlib.Path):
237239
context, schema, (external_table,) = initialize_context(ctx, tmp_path, num_external_models=1)
238240

239241
# Create parent model that depends on the external model
240-
parent_model_name, _ = create_freshness_model(
242+
parent_model_name, _ = create_model(
241243
"parent_model",
242244
schema,
243245
f"SELECT col1 AS new_col FROM {external_table}",
244246
tmp_path,
245247
)
246248

247249
# First child model depends only on the parent model
248-
create_freshness_model(
250+
create_model(
249251
"child_model1",
250252
schema,
251253
f"SELECT new_col FROM {parent_model_name}",
252254
tmp_path,
253255
)
254256

255257
# Second child model depends on the parent model and the external table
256-
create_freshness_model(
258+
create_model(
257259
"child_model2",
258260
schema,
259261
f"SELECT col1 + new_col FROM {parent_model_name}, {external_table}",
260262
tmp_path,
261263
)
262264

263265
# Third model does not depend on any models, so it should only be evaluated once
264-
create_freshness_model(
266+
create_model(
265267
"child_model3",
266268
schema,
267269
f"SELECT 1 AS col",
@@ -287,7 +289,7 @@ def test_mixed_model_freshness(ctx: TestContext, tmp_path: pathlib.Path):
287289
)
288290

289291
# Case 3: Mixed models are still evaluated if breaking changes are introduced
290-
create_freshness_model(
292+
create_model(
291293
"child_model2",
292294
schema,
293295
f"SELECT col1 * new_col FROM {parent_model_name}, {external_table}",
@@ -317,7 +319,7 @@ def test_missing_external_model_freshness(ctx: TestContext, tmp_path: pathlib.Pa
317319
context, schema, (external_table,) = initialize_context(ctx, tmp_path)
318320

319321
# Create model that depends on the external model
320-
create_freshness_model(
322+
create_model(
321323
"new_model",
322324
schema,
323325
f"SELECT * FROM {external_table}",
@@ -334,3 +336,81 @@ def test_missing_external_model_freshness(ctx: TestContext, tmp_path: pathlib.Pa
334336
with time_machine.travel(now() + timedelta(days=1)):
335337
with pytest.raises(SignalEvalError):
336338
context.run()
339+
340+
341+
@use_terminal_console
342+
def test_check_ready_intervals(ctx: TestContext, tmp_path: pathlib.Path):
343+
"""
344+
Scenario: Ensure that freshness evaluates the "ready" intervals of the parent snapshots i.e their
345+
missing intervals plus their signals applied.
346+
347+
"""
348+
349+
def _write_user_signal(signal: str, tmp_path: pathlib.Path):
350+
signal_code = f"""
351+
import typing as t
352+
from sqlmesh import signal
353+
354+
@signal()
355+
{signal}
356+
"""
357+
358+
test_signals = tmp_path / "signals/test_signals.py"
359+
test_signals.parent.mkdir(parents=True, exist_ok=True)
360+
test_signals.write_text(signal_code)
361+
362+
context, schema, _ = initialize_context(ctx, tmp_path, num_external_models=0)
363+
364+
_write_user_signal(
365+
"""
366+
def my_signal(batch):
367+
return True
368+
""",
369+
tmp_path,
370+
)
371+
372+
# Parent model depends on a custom signal
373+
parent_model, _ = create_model(
374+
"parent_model",
375+
schema,
376+
f"SELECT 1 AS col",
377+
tmp_path,
378+
signals="my_signal()",
379+
)
380+
381+
# Create a new model that depends on the parent model
382+
create_model(
383+
"child_model",
384+
schema,
385+
f"SELECT * FROM {parent_model}",
386+
tmp_path,
387+
)
388+
389+
# Case 1: Both models are evaluated when introduced in a plan and subsequent runs,
390+
# given that `my_signal()` always returns True.
391+
context.load()
392+
context.plan(auto_apply=True, no_prompts=True)
393+
394+
assert_model_evaluation(
395+
lambda: context.run(),
396+
day_delta=2,
397+
model_evaluations=2,
398+
)
399+
400+
# Case 2: By changing the signal to return False, both models should not be evaluated.
401+
_write_user_signal(
402+
"""
403+
def my_signal(batch):
404+
return False
405+
""",
406+
tmp_path,
407+
)
408+
409+
context.load()
410+
context.plan(auto_apply=True, no_prompts=True)
411+
412+
assert_model_evaluation(
413+
lambda: context.run(),
414+
day_delta=3,
415+
was_evaluated=False,
416+
)

0 commit comments

Comments
 (0)