|
| 1 | +import json |
1 | 2 | import logging
|
| 3 | +import pytest |
2 | 4 | import string
|
| 5 | +import time_machine |
3 | 6 | from contextlib import contextmanager
|
4 | 7 | from os import getcwd, path, remove
|
5 | 8 | from pathlib import Path
|
6 | 9 | from shutil import rmtree
|
| 10 | +from unittest.mock import MagicMock |
| 11 | + |
7 | 12 | from click import ClickException
|
8 |
| -import pytest |
9 | 13 | from click.testing import CliRunner
|
10 |
| -import time_machine |
11 |
| -import json |
12 |
| -from unittest.mock import MagicMock |
13 | 14 | from sqlmesh import RuntimeEnv
|
14 | 15 | from sqlmesh.cli.project_init import ProjectTemplate, init_example_project
|
15 | 16 | from sqlmesh.cli.main import cli
|
@@ -42,13 +43,13 @@ def disable_logging():
|
42 | 43 | logging.disable(logging.NOTSET)
|
43 | 44 |
|
44 | 45 |
|
45 |
| -def create_example_project(temp_dir) -> None: |
| 46 | +def create_example_project(temp_dir, template=ProjectTemplate.DEFAULT) -> None: |
46 | 47 | """
|
47 | 48 | Sets up CLI tests requiring a real SQLMesh project by:
|
48 | 49 | - Creating the SQLMesh example project in the temp_dir directory
|
49 | 50 | - Overwriting the config.yaml file so the duckdb database file will be created in the temp_dir directory
|
50 | 51 | """
|
51 |
| - init_example_project(temp_dir, engine_type="duckdb") |
| 52 | + init_example_project(temp_dir, engine_type="duckdb", template=template) |
52 | 53 | with open(temp_dir / "config.yaml", "w", encoding="utf-8") as f:
|
53 | 54 | f.write(
|
54 | 55 | f"""gateways:
|
@@ -2044,3 +2045,133 @@ def test_render(runner: CliRunner, tmp_path: Path):
|
2044 | 2045 | """
|
2045 | 2046 |
|
2046 | 2047 | assert expected in cleaned_output
|
| 2048 | + |
| 2049 | + |
| 2050 | +@time_machine.travel(FREEZE_TIME) |
| 2051 | +def test_signals(runner: CliRunner, tmp_path: Path): |
| 2052 | + create_example_project(tmp_path, template=ProjectTemplate.EMPTY) |
| 2053 | + |
| 2054 | + # Create signals module |
| 2055 | + signals_dir = tmp_path / "signals" |
| 2056 | + signals_dir.mkdir(exist_ok=True) |
| 2057 | + |
| 2058 | + # Create signal definitions |
| 2059 | + (signals_dir / "signal.py").write_text( |
| 2060 | + """from sqlmesh import signal |
| 2061 | +@signal() |
| 2062 | +def only_first_two_ready(batch): |
| 2063 | + if len(batch) > 2: |
| 2064 | + return batch[:2] |
| 2065 | + return batch |
| 2066 | +
|
| 2067 | +@signal() |
| 2068 | +def none_ready(batch): |
| 2069 | + return False |
| 2070 | +""" |
| 2071 | + ) |
| 2072 | + |
| 2073 | + # Create model with signals |
| 2074 | + (tmp_path / "models" / "model_with_signals.sql").write_text( |
| 2075 | + """MODEL ( |
| 2076 | + name sqlmesh_example.model_with_signals, |
| 2077 | + kind INCREMENTAL_BY_TIME_RANGE ( |
| 2078 | + time_column ds |
| 2079 | + ), |
| 2080 | + start '2022-12-28', |
| 2081 | + cron '@daily', |
| 2082 | + signals [ |
| 2083 | + only_first_two_ready() |
| 2084 | + ] |
| 2085 | +); |
| 2086 | +
|
| 2087 | +SELECT |
| 2088 | + ds::DATE as ds, |
| 2089 | + 'test' as value |
| 2090 | +FROM VALUES |
| 2091 | + ('2022-12-28'), |
| 2092 | + ('2022-12-29'), |
| 2093 | + ('2022-12-30'), |
| 2094 | + ('2022-12-31'), |
| 2095 | + ('2023-01-01') |
| 2096 | +AS t(ds) |
| 2097 | +WHERE ds::DATE BETWEEN @start_ds AND @end_ds |
| 2098 | +""" |
| 2099 | + ) |
| 2100 | + |
| 2101 | + # Create model with no ready intervals |
| 2102 | + (tmp_path / "models" / "model_with_unready.sql").write_text( |
| 2103 | + """MODEL ( |
| 2104 | + name sqlmesh_example.model_with_unready, |
| 2105 | + kind INCREMENTAL_BY_TIME_RANGE ( |
| 2106 | + time_column ds |
| 2107 | + ), |
| 2108 | + start '2022-12-28', |
| 2109 | + cron '@daily', |
| 2110 | + signals [ |
| 2111 | + none_ready() |
| 2112 | + ] |
| 2113 | +); |
| 2114 | +
|
| 2115 | +SELECT |
| 2116 | + ds::DATE as ds, |
| 2117 | + 'unready' as value |
| 2118 | +FROM VALUES |
| 2119 | + ('2022-12-28'), |
| 2120 | + ('2022-12-29'), |
| 2121 | + ('2022-12-30'), |
| 2122 | + ('2022-12-31'), |
| 2123 | + ('2023-01-01') |
| 2124 | +AS t(ds) |
| 2125 | +WHERE ds::DATE BETWEEN @start_ds AND @end_ds |
| 2126 | +""" |
| 2127 | + ) |
| 2128 | + |
| 2129 | + # Test 1: Normal plan flow with --no-prompts --auto-apply |
| 2130 | + result = runner.invoke( |
| 2131 | + cli, |
| 2132 | + [ |
| 2133 | + "--paths", |
| 2134 | + str(tmp_path), |
| 2135 | + "plan", |
| 2136 | + "--no-prompts", |
| 2137 | + "--auto-apply", |
| 2138 | + ], |
| 2139 | + ) |
| 2140 | + assert result.exit_code == 0 |
| 2141 | + |
| 2142 | + assert "Checking signals for sqlmesh_example.model_with_signals" in result.output |
| 2143 | + assert "[1/1] only_first_two_ready" in result.output |
| 2144 | + assert "check: 2022-12-28 - 2022-12-31" in result.output |
| 2145 | + assert "ready: 2022-12-28 - 2022-12-29" in result.output |
| 2146 | + |
| 2147 | + assert "Checking signals for sqlmesh_example.model_with_unready" in result.output |
| 2148 | + assert "[1/1] none_ready" in result.output |
| 2149 | + assert "ready: no intervals" in result.output |
| 2150 | + |
| 2151 | + # Test 2: Run command with start and end dates |
| 2152 | + result = runner.invoke( |
| 2153 | + cli, |
| 2154 | + [ |
| 2155 | + "--paths", |
| 2156 | + str(tmp_path), |
| 2157 | + "run", |
| 2158 | + "--start", |
| 2159 | + "2022-12-29", |
| 2160 | + "--end", |
| 2161 | + "2022-12-31", |
| 2162 | + ], |
| 2163 | + ) |
| 2164 | + assert result.exit_code == 0 |
| 2165 | + |
| 2166 | + assert "Checking signals for sqlmesh_example.model_with_signals" in result.output |
| 2167 | + assert "[1/1] only_first_two_ready" in result.output |
| 2168 | + assert "check: 2022-12-30 - 2022-12-31" in result.output |
| 2169 | + assert "ready: 2022-12-30 - 2022-12-31" in result.output |
| 2170 | + |
| 2171 | + assert "Checking signals for sqlmesh_example.model_with_unready" in result.output |
| 2172 | + assert "[1/1] none_ready" in result.output |
| 2173 | + assert "check: 2022-12-29 - 2022-12-31" in result.output |
| 2174 | + assert "ready: no intervals" in result.output |
| 2175 | + |
| 2176 | + # Only one model was executed |
| 2177 | + assert "100.0% • 1/1 • 0:00:00" in result.output |
0 commit comments