|
52 | 52 | to_timestamp, |
53 | 53 | yesterday_ds, |
54 | 54 | ) |
55 | | -from sqlmesh.utils.errors import ConfigError, SQLMeshError, LinterError, PlanError |
| 55 | +from sqlmesh.utils.errors import ( |
| 56 | + ConfigError, |
| 57 | + SQLMeshError, |
| 58 | + LinterError, |
| 59 | + PlanError, |
| 60 | + NoChangesPlanError, |
| 61 | +) |
56 | 62 | from sqlmesh.utils.metaprogramming import Executable |
57 | 63 | from tests.utils.test_helpers import use_terminal_console |
58 | 64 | from tests.utils.test_filesystem import create_temp_file |
@@ -2218,3 +2224,83 @@ def test_plan_explain_skips_tests(sushi_context: Context, mocker: MockerFixture) |
2218 | 2224 | spy = mocker.spy(sushi_context, "_run_plan_tests") |
2219 | 2225 | sushi_context.plan(environment="dev", explain=True, no_prompts=True, include_unmodified=True) |
2220 | 2226 | spy.assert_called_once_with(skip_tests=True) |
| 2227 | + |
| 2228 | + |
| 2229 | +def test_dev_environment_virtual_update_with_environment_statements(tmp_path: Path) -> None: |
| 2230 | + models_dir = tmp_path / "models" |
| 2231 | + models_dir.mkdir() |
| 2232 | + model_sql = """ |
| 2233 | + MODEL ( |
| 2234 | + name db.test_model, |
| 2235 | + kind FULL |
| 2236 | + ); |
| 2237 | +
|
| 2238 | + SELECT 1 as id, 'test' as name |
| 2239 | + """ |
| 2240 | + |
| 2241 | + with open(models_dir / "test_model.sql", "w") as f: |
| 2242 | + f.write(model_sql) |
| 2243 | + |
| 2244 | + # Create initial context without environment statements |
| 2245 | + config = Config( |
| 2246 | + model_defaults=ModelDefaultsConfig(dialect="duckdb"), |
| 2247 | + gateways={"duckdb": GatewayConfig(connection=DuckDBConnectionConfig())}, |
| 2248 | + ) |
| 2249 | + |
| 2250 | + context = Context(paths=tmp_path, config=config) |
| 2251 | + |
| 2252 | + # First, apply to production |
| 2253 | + context.plan("prod", auto_apply=True, no_prompts=True) |
| 2254 | + |
| 2255 | + # Try to create dev environment without changes (should fail) |
| 2256 | + with pytest.raises(NoChangesPlanError, match="Creating a new environment requires a change"): |
| 2257 | + context.plan("dev", auto_apply=True, no_prompts=True) |
| 2258 | + |
| 2259 | + # Now create a new context with only new environment statements |
| 2260 | + config_with_statements = Config( |
| 2261 | + model_defaults=ModelDefaultsConfig(dialect="duckdb"), |
| 2262 | + gateways={"duckdb": GatewayConfig(connection=DuckDBConnectionConfig())}, |
| 2263 | + before_all=["CREATE TABLE IF NOT EXISTS audit_log (id INT, action VARCHAR(100))"], |
| 2264 | + after_all=["INSERT INTO audit_log VALUES (1, 'environment_created')"], |
| 2265 | + ) |
| 2266 | + |
| 2267 | + context_with_statements = Context(paths=tmp_path, config=config_with_statements) |
| 2268 | + |
| 2269 | + # This should succeed because environment statements are different |
| 2270 | + context_with_statements.plan("dev", auto_apply=True, no_prompts=True) |
| 2271 | + env = context_with_statements.state_reader.get_environment("dev") |
| 2272 | + assert env is not None |
| 2273 | + assert env.name == "dev" |
| 2274 | + |
| 2275 | + # Verify the environment statements were stored |
| 2276 | + stored_statements = context_with_statements.state_reader.get_environment_statements("dev") |
| 2277 | + assert len(stored_statements) == 1 |
| 2278 | + assert stored_statements[0].before_all == [ |
| 2279 | + "CREATE TABLE IF NOT EXISTS audit_log (id INT, action VARCHAR(100))" |
| 2280 | + ] |
| 2281 | + assert stored_statements[0].after_all == [ |
| 2282 | + "INSERT INTO audit_log VALUES (1, 'environment_created')" |
| 2283 | + ] |
| 2284 | + |
| 2285 | + # Update environment statements and plan again (should trigger another virtual update) |
| 2286 | + config_updated_statements = Config( |
| 2287 | + model_defaults=ModelDefaultsConfig(dialect="duckdb"), |
| 2288 | + gateways={"duckdb": GatewayConfig(connection=DuckDBConnectionConfig())}, |
| 2289 | + before_all=[ |
| 2290 | + "CREATE TABLE IF NOT EXISTS audit_log (id INT, action VARCHAR(100))", |
| 2291 | + "CREATE TABLE IF NOT EXISTS metrics (metric_name VARCHAR(50), value INT)", |
| 2292 | + ], |
| 2293 | + after_all=["INSERT INTO audit_log VALUES (1, 'environment_created')"], |
| 2294 | + ) |
| 2295 | + |
| 2296 | + context_updated = Context(paths=tmp_path, config=config_updated_statements) |
| 2297 | + context_updated.plan("dev", auto_apply=True, no_prompts=True) |
| 2298 | + |
| 2299 | + # Verify the updated statements were stored |
| 2300 | + updated_statements = context_updated.state_reader.get_environment_statements("dev") |
| 2301 | + assert len(updated_statements) == 1 |
| 2302 | + assert len(updated_statements[0].before_all) == 2 |
| 2303 | + assert ( |
| 2304 | + updated_statements[0].before_all[1] |
| 2305 | + == "CREATE TABLE IF NOT EXISTS metrics (metric_name VARCHAR(50), value INT)" |
| 2306 | + ) |
0 commit comments