UPDATE
This commit is contained in:
@@ -46,7 +46,7 @@ class RemoteSensingApiTests(TestCase):
|
||||
self.farm = SensorData.objects.create(
|
||||
farm_uuid="11111111-1111-1111-1111-111111111111",
|
||||
center_location=self.location,
|
||||
payload={},
|
||||
sensor_payload={},
|
||||
)
|
||||
self.temporal_end = timezone.localdate() - timedelta(days=1)
|
||||
self.temporal_start = self.temporal_end - timedelta(days=30)
|
||||
@@ -176,6 +176,241 @@ class RemoteSensingApiTests(TestCase):
|
||||
self.assertEqual(len(payload["cells"]), 1)
|
||||
self.assertEqual(payload["cells"][0]["cell_code"], "cell-1")
|
||||
|
||||
@patch("location_data.views.run_remote_sensing_analysis_task.delay")
|
||||
def test_post_remote_sensing_reuses_latest_completed_farm_cache_when_window_differs(self, mock_delay):
|
||||
fallback_start = self.temporal_start - timedelta(days=1)
|
||||
fallback_end = self.temporal_end - timedelta(days=1)
|
||||
run = RemoteSensingRun.objects.create(
|
||||
soil_location=self.location,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="",
|
||||
chunk_size_sqm=900,
|
||||
temporal_start=fallback_start,
|
||||
temporal_end=fallback_end,
|
||||
status=RemoteSensingRun.STATUS_SUCCESS,
|
||||
metadata={"farm_uuid": str(self.farm.farm_uuid), "stage": "completed"},
|
||||
)
|
||||
cell = AnalysisGridCell.objects.create(
|
||||
soil_location=self.location,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="",
|
||||
cell_code="cell-seeded-1",
|
||||
chunk_size_sqm=900,
|
||||
geometry=self.boundary,
|
||||
centroid_lat="35.689500",
|
||||
centroid_lon="51.389500",
|
||||
)
|
||||
AnalysisGridObservation.objects.create(
|
||||
cell=cell,
|
||||
run=run,
|
||||
temporal_start=fallback_start,
|
||||
temporal_end=fallback_end,
|
||||
ndvi=0.49,
|
||||
ndwi=0.17,
|
||||
soil_vv=0.10,
|
||||
soil_vv_db=-9.8,
|
||||
metadata={"backend_name": "openeo"},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
"/remote-sensing/",
|
||||
data={"farm_uuid": str(self.farm.farm_uuid), "force_refresh": False},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
payload = response.json()["data"]
|
||||
self.assertEqual(payload["status"], "success")
|
||||
self.assertEqual(payload["source"], "database")
|
||||
self.assertEqual(payload["temporal_extent"]["start_date"], fallback_start.isoformat())
|
||||
self.assertEqual(payload["temporal_extent"]["end_date"], fallback_end.isoformat())
|
||||
self.assertEqual(payload["metadata"]["cache_match"], "latest_completed_for_farm")
|
||||
self.assertEqual(payload["cells"][0]["cell_code"], "cell-seeded-1")
|
||||
self.assertEqual(payload["run"]["id"], run.id)
|
||||
self.assertNotIn("task_id", payload)
|
||||
mock_delay.assert_not_called()
|
||||
|
||||
@patch("location_data.views.run_remote_sensing_analysis_task.delay")
|
||||
def test_post_remote_sensing_returns_cached_results_without_enqueuing(self, mock_delay):
|
||||
run = RemoteSensingRun.objects.create(
|
||||
soil_location=self.location,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="",
|
||||
chunk_size_sqm=900,
|
||||
temporal_start=self.temporal_start,
|
||||
temporal_end=self.temporal_end,
|
||||
status=RemoteSensingRun.STATUS_SUCCESS,
|
||||
metadata={"farm_uuid": str(self.farm.farm_uuid), "stage": "completed"},
|
||||
)
|
||||
cell = AnalysisGridCell.objects.create(
|
||||
soil_location=self.location,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="",
|
||||
cell_code="cell-cache-1",
|
||||
chunk_size_sqm=900,
|
||||
geometry=self.boundary,
|
||||
centroid_lat="35.689500",
|
||||
centroid_lon="51.389500",
|
||||
)
|
||||
AnalysisGridObservation.objects.create(
|
||||
cell=cell,
|
||||
run=run,
|
||||
temporal_start=self.temporal_start,
|
||||
temporal_end=self.temporal_end,
|
||||
ndvi=0.52,
|
||||
ndwi=0.18,
|
||||
soil_vv=0.11,
|
||||
soil_vv_db=-9.2,
|
||||
metadata={"backend_name": "openeo"},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
"/remote-sensing/",
|
||||
data={"farm_uuid": str(self.farm.farm_uuid), "force_refresh": False},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
payload = response.json()["data"]
|
||||
self.assertEqual(payload["status"], "success")
|
||||
self.assertEqual(payload["source"], "database")
|
||||
self.assertTrue(payload["metadata"]["cache_hit"])
|
||||
self.assertEqual(payload["cells"][0]["cell_code"], "cell-cache-1")
|
||||
self.assertEqual(payload["run"]["id"], run.id)
|
||||
self.assertEqual(payload["run"]["status"], RemoteSensingRun.STATUS_SUCCESS)
|
||||
self.assertNotIn("task_id", payload)
|
||||
self.assertEqual(RemoteSensingRun.objects.count(), 1)
|
||||
mock_delay.assert_not_called()
|
||||
|
||||
@patch("location_data.views.run_remote_sensing_analysis_task.delay")
|
||||
def test_post_remote_sensing_cached_results_do_not_create_status_run(self, mock_delay):
|
||||
source_run = RemoteSensingRun.objects.create(
|
||||
soil_location=self.location,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="",
|
||||
chunk_size_sqm=900,
|
||||
temporal_start=self.temporal_start,
|
||||
temporal_end=self.temporal_end,
|
||||
status=RemoteSensingRun.STATUS_SUCCESS,
|
||||
metadata={"farm_uuid": str(self.farm.farm_uuid), "stage": "completed"},
|
||||
)
|
||||
cell = AnalysisGridCell.objects.create(
|
||||
soil_location=self.location,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="",
|
||||
cell_code="cell-status-cache-1",
|
||||
chunk_size_sqm=900,
|
||||
geometry=self.boundary,
|
||||
centroid_lat="35.689500",
|
||||
centroid_lon="51.389500",
|
||||
)
|
||||
AnalysisGridObservation.objects.create(
|
||||
cell=cell,
|
||||
run=source_run,
|
||||
temporal_start=self.temporal_start,
|
||||
temporal_end=self.temporal_end,
|
||||
ndvi=0.57,
|
||||
ndwi=0.19,
|
||||
soil_vv=0.12,
|
||||
soil_vv_db=-8.7,
|
||||
metadata={"backend_name": "openeo"},
|
||||
)
|
||||
|
||||
post_response = self.client.post(
|
||||
"/remote-sensing/",
|
||||
data={"farm_uuid": str(self.farm.farm_uuid), "force_refresh": False},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(post_response.status_code, 200)
|
||||
payload = post_response.json()["data"]
|
||||
self.assertEqual(payload["status"], "success")
|
||||
self.assertEqual(payload["run"]["id"], source_run.id)
|
||||
self.assertEqual(payload["summary"]["cell_count"], 1)
|
||||
self.assertEqual(payload["cells"][0]["cell_code"], "cell-status-cache-1")
|
||||
self.assertNotIn("task_id", payload)
|
||||
self.assertEqual(RemoteSensingRun.objects.count(), 1)
|
||||
mock_delay.assert_not_called()
|
||||
|
||||
@patch("location_data.views.run_remote_sensing_analysis_task.delay")
|
||||
def test_post_remote_sensing_returns_existing_processing_run_without_enqueuing(self, mock_delay):
|
||||
run = RemoteSensingRun.objects.create(
|
||||
soil_location=self.location,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="",
|
||||
chunk_size_sqm=900,
|
||||
temporal_start=self.temporal_start,
|
||||
temporal_end=self.temporal_end,
|
||||
status=RemoteSensingRun.STATUS_PENDING,
|
||||
metadata={
|
||||
"farm_uuid": str(self.farm.farm_uuid),
|
||||
"task_id": "e723ba3e-c53c-401b-b3a0-5f7013c7b401",
|
||||
"stage": "queued",
|
||||
},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
"/remote-sensing/",
|
||||
data={"farm_uuid": str(self.farm.farm_uuid), "force_refresh": False},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 202)
|
||||
payload = response.json()["data"]
|
||||
self.assertEqual(payload["status"], "processing")
|
||||
self.assertEqual(payload["source"], "processing")
|
||||
self.assertEqual(payload["run"]["id"], run.id)
|
||||
mock_delay.assert_not_called()
|
||||
|
||||
@patch("location_data.views.run_remote_sensing_analysis_task.delay")
|
||||
def test_post_remote_sensing_ignores_other_farm_cache_on_same_location(self, mock_delay):
|
||||
other_farm_uuid = "33333333-3333-3333-3333-333333333333"
|
||||
mock_delay.return_value = SimpleNamespace(id="f723ba3e-c53c-401b-b3a0-5f7013c7b402")
|
||||
other_run = RemoteSensingRun.objects.create(
|
||||
soil_location=self.location,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="",
|
||||
chunk_size_sqm=900,
|
||||
temporal_start=self.temporal_start,
|
||||
temporal_end=self.temporal_end,
|
||||
status=RemoteSensingRun.STATUS_SUCCESS,
|
||||
metadata={"farm_uuid": other_farm_uuid, "stage": "completed"},
|
||||
)
|
||||
other_cell = AnalysisGridCell.objects.create(
|
||||
soil_location=self.location,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="",
|
||||
cell_code="cell-other-farm",
|
||||
chunk_size_sqm=900,
|
||||
geometry=self.boundary,
|
||||
centroid_lat="35.689510",
|
||||
centroid_lon="51.389510",
|
||||
)
|
||||
AnalysisGridObservation.objects.create(
|
||||
cell=other_cell,
|
||||
run=other_run,
|
||||
temporal_start=self.temporal_start,
|
||||
temporal_end=self.temporal_end,
|
||||
ndvi=0.66,
|
||||
ndwi=0.31,
|
||||
soil_vv=0.15,
|
||||
soil_vv_db=-8.1,
|
||||
metadata={"backend_name": "openeo"},
|
||||
)
|
||||
|
||||
response = self.client.post(
|
||||
"/remote-sensing/",
|
||||
data={"farm_uuid": str(self.farm.farm_uuid), "force_refresh": False},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 202)
|
||||
payload = response.json()["data"]
|
||||
self.assertEqual(payload["status"], "processing")
|
||||
self.assertEqual(RemoteSensingRun.objects.count(), 2)
|
||||
self.assertNotEqual(payload["run"]["id"], other_run.id)
|
||||
mock_delay.assert_called_once()
|
||||
|
||||
def test_run_status_endpoint_returns_normalized_status(self):
|
||||
run = RemoteSensingRun.objects.create(
|
||||
soil_location=self.location,
|
||||
|
||||
Reference in New Issue
Block a user