UPDATE
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
from datetime import date
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.test import TestCase, override_settings
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from location_data.models import (
|
||||
AnalysisGridCell,
|
||||
BlockSubdivision,
|
||||
RemoteSensingSubdivisionOption,
|
||||
RemoteSensingSubdivisionOptionAssignment,
|
||||
RemoteSensingSubdivisionOptionBlock,
|
||||
RemoteSensingRun,
|
||||
RemoteSensingSubdivisionResult,
|
||||
SoilLocation,
|
||||
)
|
||||
|
||||
|
||||
@override_settings(ROOT_URLCONF="location_data.urls")
|
||||
class RemoteSensingSubdivisionOptionApiTests(TestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.boundary = {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[51.3890, 35.6890],
|
||||
[51.3900, 35.6890],
|
||||
[51.3900, 35.6900],
|
||||
[51.3890, 35.6900],
|
||||
[51.3890, 35.6890],
|
||||
]
|
||||
],
|
||||
}
|
||||
self.location = SoilLocation.objects.create(
|
||||
latitude="35.689200",
|
||||
longitude="51.389000",
|
||||
farm_boundary=self.boundary,
|
||||
)
|
||||
self.subdivision = BlockSubdivision.objects.create(
|
||||
soil_location=self.location,
|
||||
block_code="block-1",
|
||||
source_boundary=self.boundary,
|
||||
chunk_size_sqm=900,
|
||||
status="subdivided",
|
||||
)
|
||||
self.run = RemoteSensingRun.objects.create(
|
||||
soil_location=self.location,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="block-1",
|
||||
chunk_size_sqm=900,
|
||||
temporal_start=date(2025, 1, 1),
|
||||
temporal_end=date(2025, 1, 31),
|
||||
status=RemoteSensingRun.STATUS_SUCCESS,
|
||||
metadata={"stage": "completed"},
|
||||
)
|
||||
self.result = RemoteSensingSubdivisionResult.objects.create(
|
||||
soil_location=self.location,
|
||||
run=self.run,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="block-1",
|
||||
chunk_size_sqm=900,
|
||||
temporal_start=date(2025, 1, 1),
|
||||
temporal_end=date(2025, 1, 31),
|
||||
cluster_count=1,
|
||||
selected_features=["ndvi", "ndwi", "soil_vv_db"],
|
||||
metadata={"recommended_requested_k": 2, "active_requested_k": 1},
|
||||
)
|
||||
self.cells = [
|
||||
AnalysisGridCell.objects.create(
|
||||
soil_location=self.location,
|
||||
block_subdivision=self.subdivision,
|
||||
block_code="block-1",
|
||||
cell_code=f"cell-{index}",
|
||||
chunk_size_sqm=900,
|
||||
geometry={
|
||||
"type": "Polygon",
|
||||
"coordinates": [[
|
||||
[51.3890 + (index * 0.0001), 35.6890],
|
||||
[51.3891 + (index * 0.0001), 35.6890],
|
||||
[51.3891 + (index * 0.0001), 35.6891],
|
||||
[51.3890 + (index * 0.0001), 35.6891],
|
||||
[51.3890 + (index * 0.0001), 35.6890],
|
||||
]],
|
||||
},
|
||||
centroid_lat=f"{35.68905 + (index * 0.0001):.6f}",
|
||||
centroid_lon=f"{51.38905 + (index * 0.0001):.6f}",
|
||||
)
|
||||
for index in range(2)
|
||||
]
|
||||
self.option_k1 = RemoteSensingSubdivisionOption.objects.create(
|
||||
result=self.result,
|
||||
requested_k=1,
|
||||
effective_cluster_count=1,
|
||||
is_active=True,
|
||||
is_recommended=False,
|
||||
selection_source="system",
|
||||
metadata={"cluster_summaries": []},
|
||||
)
|
||||
self.option_k2 = RemoteSensingSubdivisionOption.objects.create(
|
||||
result=self.result,
|
||||
requested_k=2,
|
||||
effective_cluster_count=2,
|
||||
is_active=False,
|
||||
is_recommended=True,
|
||||
selection_source="system",
|
||||
metadata={"cluster_summaries": []},
|
||||
)
|
||||
for cell in self.cells:
|
||||
RemoteSensingSubdivisionOptionAssignment.objects.create(
|
||||
option=self.option_k1,
|
||||
cell=cell,
|
||||
cluster_label=0,
|
||||
raw_feature_values={"ndvi": 0.4},
|
||||
scaled_feature_values={"ndvi": 0.0},
|
||||
)
|
||||
RemoteSensingSubdivisionOptionBlock.objects.create(
|
||||
option=self.option_k1,
|
||||
cluster_label=0,
|
||||
sub_block_code="cluster-0",
|
||||
chunk_size_sqm=900,
|
||||
centroid_lat="35.689100",
|
||||
centroid_lon="51.389100",
|
||||
center_cell_code="cell-0",
|
||||
center_cell_lat="35.689050",
|
||||
center_cell_lon="51.389050",
|
||||
cell_count=2,
|
||||
cell_codes=[cell.cell_code for cell in self.cells],
|
||||
geometry=self.boundary,
|
||||
metadata={
|
||||
"source": "analysis_grid_cells",
|
||||
"center_selection": {"strategy": "coordinate_1_center", "center_cell_code": "cell-0"},
|
||||
},
|
||||
)
|
||||
for index, cell in enumerate(self.cells):
|
||||
RemoteSensingSubdivisionOptionAssignment.objects.create(
|
||||
option=self.option_k2,
|
||||
cell=cell,
|
||||
cluster_label=index,
|
||||
raw_feature_values={"ndvi": 0.4 + index},
|
||||
scaled_feature_values={"ndvi": float(index)},
|
||||
)
|
||||
RemoteSensingSubdivisionOptionBlock.objects.create(
|
||||
option=self.option_k2,
|
||||
cluster_label=index,
|
||||
sub_block_code=f"cluster-{index}",
|
||||
chunk_size_sqm=900,
|
||||
centroid_lat=f"{35.68905 + (index * 0.0001):.6f}",
|
||||
centroid_lon=f"{51.38905 + (index * 0.0001):.6f}",
|
||||
center_cell_code=cell.cell_code,
|
||||
center_cell_lat=f"{35.68905 + (index * 0.0001):.6f}",
|
||||
center_cell_lon=f"{51.38905 + (index * 0.0001):.6f}",
|
||||
cell_count=1,
|
||||
cell_codes=[cell.cell_code],
|
||||
geometry=cell.geometry,
|
||||
metadata={
|
||||
"source": "analysis_grid_cells",
|
||||
"center_selection": {"strategy": "coordinate_1_center", "center_cell_code": cell.cell_code},
|
||||
},
|
||||
)
|
||||
|
||||
def test_get_k_options_returns_all_persisted_options(self):
|
||||
response = self.client.get(
|
||||
f"/remote-sensing/results/{self.result.id}/k-options/"
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
payload = response.json()["data"]
|
||||
self.assertEqual(payload["result_id"], self.result.id)
|
||||
self.assertEqual(payload["active_requested_k"], 1)
|
||||
self.assertEqual(payload["recommended_requested_k"], 2)
|
||||
self.assertEqual([item["requested_k"] for item in payload["options"]], [1, 2])
|
||||
self.assertEqual(payload["options"][0]["cluster_blocks"][0]["center_cell_code"], "cell-0")
|
||||
|
||||
@patch("location_data.data_driven_subdivision.render_elbow_plot", return_value=None)
|
||||
def test_post_activate_k_marks_selected_option_active_and_syncs_result(self, _mock_plot):
|
||||
response = self.client.post(
|
||||
f"/remote-sensing/results/{self.result.id}/k-options/activate/",
|
||||
data={"requested_k": 2},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
payload = response.json()["data"]
|
||||
self.assertEqual(payload["activated_requested_k"], 2)
|
||||
self.assertEqual(payload["subdivision_result"]["cluster_count"], 2)
|
||||
self.assertEqual(
|
||||
payload["subdivision_result"]["metadata"]["active_requested_k"],
|
||||
2,
|
||||
)
|
||||
self.assertEqual(len(payload["subdivision_result"]["cluster_blocks"]), 2)
|
||||
self.assertEqual(
|
||||
payload["subdivision_result"]["cluster_blocks"][0]["center_cell_code"],
|
||||
"cell-0",
|
||||
)
|
||||
|
||||
self.option_k1.refresh_from_db()
|
||||
self.option_k2.refresh_from_db()
|
||||
self.assertFalse(self.option_k1.is_active)
|
||||
self.assertTrue(self.option_k2.is_active)
|
||||
self.assertEqual(self.option_k2.selection_source, "user")
|
||||
|
||||
self.result.refresh_from_db()
|
||||
self.assertEqual(self.result.cluster_count, 2)
|
||||
self.assertEqual(self.result.assignments.count(), 2)
|
||||
self.assertEqual(self.result.cluster_blocks.count(), 2)
|
||||
self.assertEqual(self.result.cluster_blocks.order_by("cluster_label").first().center_cell_code, "cell-0")
|
||||
Reference in New Issue
Block a user