|
17 | 17 | from datajunction_server.models.query import ColumnMetadata, V3ColumnMetadata |
18 | 18 | from datajunction_server.service_clients import QueryServiceClient |
19 | 19 | from datajunction_server.sql.parsing.backends.antlr4 import parse |
20 | | -from datajunction_server.utils import get_query_service_client |
| 20 | +from datajunction_server.utils import get_query_service_client, get_session |
21 | 21 | from tests.sql.utils import compare_query_strings |
22 | 22 | from tests.construction.build_v3 import assert_sql_equal |
23 | 23 |
|
@@ -4283,3 +4283,93 @@ async def test_backfill_cube_query_service_failure( |
4283 | 4283 | ) |
4284 | 4284 | assert response.status_code == 500 |
4285 | 4285 | assert "failed to run cube backfill" in response.json()["message"].lower() |
| 4286 | + |
| 4287 | + |
| 4288 | +class TestCubeRefreshMaterialization: |
| 4289 | + """Tests for refreshing cube materializations without version bump.""" |
| 4290 | + |
| 4291 | + @pytest.mark.asyncio |
| 4292 | + async def test_refresh_materialization_no_version_bump( |
| 4293 | + self, |
| 4294 | + client_with_repairs_cube: AsyncClient, |
| 4295 | + mocker, |
| 4296 | + ): |
| 4297 | + """ |
| 4298 | + Test that PATCH with refresh_materialization=true and no other changes |
| 4299 | + calls refresh_cube_materialization without bumping the version. |
| 4300 | + """ |
| 4301 | + cube_name = "default.test_refresh_cube" |
| 4302 | + await make_a_test_cube( |
| 4303 | + client_with_repairs_cube, |
| 4304 | + cube_name, |
| 4305 | + with_materialization=True, |
| 4306 | + ) |
| 4307 | + |
| 4308 | + # Get the initial version |
| 4309 | + response = await client_with_repairs_cube.get(f"/nodes/{cube_name}/") |
| 4310 | + assert response.status_code == 200 |
| 4311 | + initial_version = response.json()["version"] |
| 4312 | + |
| 4313 | + # Add a deactivated materialization to the node revision so the |
| 4314 | + # re-activation logic gets exercised |
| 4315 | + from datetime import datetime, timezone |
| 4316 | + |
| 4317 | + from sqlalchemy import select |
| 4318 | + |
| 4319 | + from datajunction_server.database.materialization import Materialization |
| 4320 | + from datajunction_server.database.node import NodeRevision |
| 4321 | + |
| 4322 | + session_factory = client_with_repairs_cube.app.dependency_overrides[get_session] |
| 4323 | + session = session_factory() |
| 4324 | + result = await session.execute( |
| 4325 | + select(NodeRevision).where(NodeRevision.name == cube_name), |
| 4326 | + ) |
| 4327 | + node_rev = result.scalars().first() |
| 4328 | + deactivated_mat = Materialization( |
| 4329 | + node_revision_id=node_rev.id, |
| 4330 | + name="deactivated_mat", |
| 4331 | + strategy=None, |
| 4332 | + schedule="", |
| 4333 | + config={"cube": {"version": initial_version}}, |
| 4334 | + job="DruidCubeMaterializationJob", |
| 4335 | + deactivated_at=datetime.now(timezone.utc), |
| 4336 | + ) |
| 4337 | + session.add(deactivated_mat) |
| 4338 | + await session.commit() |
| 4339 | + |
| 4340 | + # Mock the refresh method on the query service client |
| 4341 | + qs_client = client_with_repairs_cube.app.dependency_overrides[ |
| 4342 | + get_query_service_client |
| 4343 | + ]() |
| 4344 | + mock_refresh = mocker.patch.object( |
| 4345 | + qs_client, |
| 4346 | + "refresh_cube_materialization", |
| 4347 | + return_value=mocker.MagicMock(urls=["http://workflow/refreshed"]), |
| 4348 | + ) |
| 4349 | + |
| 4350 | + # PATCH with refresh_materialization=true but no actual changes |
| 4351 | + response = await client_with_repairs_cube.patch( |
| 4352 | + f"/nodes/{cube_name}/?refresh_materialization=true", |
| 4353 | + json={}, |
| 4354 | + ) |
| 4355 | + # Should return 200 with no version change (returns None -> no content) |
| 4356 | + assert response.status_code == 200 |
| 4357 | + |
| 4358 | + # Verify refresh was called with correct args |
| 4359 | + mock_refresh.assert_called_once() |
| 4360 | + call_kwargs = mock_refresh.call_args[1] |
| 4361 | + assert call_kwargs["cube_name"] == cube_name |
| 4362 | + assert call_kwargs["cube_version"] == initial_version |
| 4363 | + assert isinstance(call_kwargs["materializations"], list) |
| 4364 | + assert len(call_kwargs["materializations"]) > 0 |
| 4365 | + # Deactivated materialization should be re-activated and included |
| 4366 | + mat_names = [m["name"] for m in call_kwargs["materializations"]] |
| 4367 | + assert "deactivated_mat" in mat_names |
| 4368 | + |
| 4369 | + # Verify the materialization was re-activated in the DB |
| 4370 | + await session.refresh(deactivated_mat) |
| 4371 | + assert deactivated_mat.deactivated_at is None |
| 4372 | + |
| 4373 | + # Verify version didn't change |
| 4374 | + response = await client_with_repairs_cube.get(f"/nodes/{cube_name}/") |
| 4375 | + assert response.json()["version"] == initial_version |
0 commit comments