from __future__ import annotations import uuid from unittest.mock import patch from django.test import override_settings from farm_data.models import ParameterUpdateLog, SensorData, SensorParameter from integration_tests.base import IntegrationAPITestCase from plant.models import Plant @override_settings(ROOT_URLCONF="config.urls") class FarmManagementJourneyTests(IntegrationAPITestCase): def test_full_management_journey_persists_farm_related_records(self) -> None: primary_method = self.create_irrigation_method_via_api("Drip Prime") backup_method = self.create_irrigation_method_via_api( "Sprinkler Backup", category="pressure", water_efficiency_percent=78.0, ) irrigation_list_response = self.client.get("/api/irrigation/") self.assertEqual(irrigation_list_response.status_code, 200) self.assertGreaterEqual(len(irrigation_list_response.json()["data"]), 2) irrigation_detail_response = self.client.get(f"/api/irrigation/{primary_method['id']}/") self.assertEqual(irrigation_detail_response.status_code, 200) self.assertEqual(irrigation_detail_response.json()["data"]["name"], "Drip Prime") moisture_parameter = self.create_sensor_parameter_via_api() self.assertEqual(moisture_parameter["action"], ParameterUpdateLog.ACTION_ADDED) self.assertTrue( SensorParameter.objects.filter(sensor_key="sensor-7-1", code="soil_moisture").exists() ) moisture_parameter_update = self.create_sensor_parameter_via_api( metadata={"min": 5, "max": 85, "ui": "gauge"}, ) self.assertEqual(moisture_parameter_update["action"], ParameterUpdateLog.ACTION_MODIFIED) self.assertEqual( ParameterUpdateLog.objects.filter(parameter__code="soil_moisture").count(), 2, ) tomato = self.create_plant_via_api("Tomato") cucumber = self.create_plant_via_api("Cucumber", watering="daily") removable_plant = self.create_plant_via_api("Remove Plant") plants_list_response = self.client.get("/api/plants/") self.assertEqual(plants_list_response.status_code, 200) returned_names = {item["name"] for item in plants_list_response.json()["data"]} self.assertTrue({"Tomato", "Cucumber", "Remove Plant"}.issubset(returned_names)) plant_catalog = self.create_plant_via_api( "Pepper", growth_stage="", icon="sprout", ) Plant.objects.filter(pk=plant_catalog["id"]).update(growth_stage="", icon="") plant_names_response = self.client.get("/api/plants/names/") self.assertEqual(plant_names_response.status_code, 200) plant_names_payload = { item["name"]: item for item in plant_names_response.json()["data"] } self.assertEqual(plant_names_payload["Pepper"]["icon"], "leaf") self.assertEqual( plant_names_payload["Pepper"]["growth_stages"], ["initial", "vegetative", "flowering", "fruiting", "maturity"], ) pepper = Plant.objects.get(pk=plant_catalog["id"]) self.assertEqual( pepper.growth_stage, "initial, vegetative, flowering, fruiting, maturity", ) self.assertEqual(pepper.icon, "leaf") plant_patch_response = self.client.patch( f"/api/plants/{tomato['id']}/", data={"growth_stage": "flowering", "watering": "daily"}, format="json", ) self.assertEqual(plant_patch_response.status_code, 200) self.assertEqual(Plant.objects.get(pk=tomato["id"]).growth_stage, "flowering") plant_put_response = self.client.put( f"/api/plants/{cucumber['id']}/", data={ "name": "Cucumber", "light": "full sun", "watering": "every day", "soil": "sandy loam", "temperature": "18-30C", "growth_stage": "fruiting", "planting_season": "spring", "harvest_time": "70 days", "spacing": "40 cm", "fertilizer": "potassium rich", }, format="json", ) self.assertEqual(plant_put_response.status_code, 200) with patch( "plant.views.fetch_plant_info_from_api", return_value={ "name": "Tomato", "light": "full sun", "watering": "daily", "soil": "loamy", "temperature": "20-28C", "growth_stage": "flowering", "planting_season": "spring", "harvest_time": "90 days", "spacing": "50 cm", "fertilizer": "balanced NPK", }, ): plant_fetch_response = self.client.post( "/api/plants/fetch-info/", data={"name": "Tomato"}, format="json", ) self.assertEqual(plant_fetch_response.status_code, 200) self.assertEqual(plant_fetch_response.json()["data"]["name"], "Tomato") plant_delete_response = self.client.delete(f"/api/plants/{removable_plant['id']}/") self.assertEqual(plant_delete_response.status_code, 200) self.assertFalse(Plant.objects.filter(pk=removable_plant["id"]).exists()) farm_uuid = uuid.uuid4() created_farm = self.upsert_farm_via_api( farm_uuid=farm_uuid, plant_ids=[tomato["id"], cucumber["id"]], irrigation_method_id=primary_method["id"], sensor_payload={ "sensor-7-1": { "soil_moisture": 41.2, "soil_temperature": 23.4, "soil_ph": 6.8, "electrical_conductivity": 1.1, "nitrogen": 17.0, "phosphorus": 12.5, "potassium": 21.0, } }, ) self.assertEqual(created_farm["farm_uuid"], str(farm_uuid)) farm_record = SensorData.objects.get(farm_uuid=farm_uuid) self.assertCountEqual( list(farm_record.plants.values_list("id", flat=True)), [tomato["id"], cucumber["id"]], ) self.assertEqual(farm_record.irrigation_method_id, primary_method["id"]) self.assertEqual(farm_record.center_location_id, self.primary_location.id) updated_farm = self.upsert_farm_via_api( farm_uuid=farm_uuid, plant_ids=[tomato["id"]], irrigation_method_id=backup_method["id"], sensor_payload={ "sensor-7-1": { "nitrogen": 19.5, "soil_moisture": 44.0, }, "leaf-sensor": { "leaf_wetness": 11.0, "leaf_temperature": 21.3, }, }, ) self.assertEqual(updated_farm["irrigation_method_id"], backup_method["id"]) farm_record.refresh_from_db() self.assertEqual(farm_record.irrigation_method_id, backup_method["id"]) self.assertCountEqual(list(farm_record.plants.values_list("id", flat=True)), [tomato["id"]]) self.assertEqual(farm_record.sensor_payload["sensor-7-1"]["soil_temperature"], 23.4) self.assertEqual(farm_record.sensor_payload["sensor-7-1"]["soil_moisture"], 44.0) self.assertEqual(farm_record.sensor_payload["sensor-7-1"]["nitrogen"], 19.5) self.assertEqual(farm_record.sensor_payload["leaf-sensor"]["leaf_wetness"], 11.0) self.assertTrue( SensorParameter.objects.filter(sensor_key="leaf-sensor", code="leaf_wetness").exists() ) farm_detail_response = self.client.get(f"/api/farm-data/{farm_uuid}/detail/") self.assertEqual(farm_detail_response.status_code, 200) farm_detail = farm_detail_response.json()["data"] self.assertEqual(farm_detail["center_location"]["id"], self.primary_location.id) self.assertEqual(farm_detail["irrigation_method_id"], backup_method["id"]) self.assertEqual(farm_detail["plant_ids"], [tomato["id"]]) self.assertEqual(farm_detail["plants"][0]["name"], "Tomato") self.assertEqual( farm_detail["sensor_payload"]["leaf-sensor"]["leaf_temperature"], 21.3, ) self.assertCountEqual( [item["code"] for item in farm_detail["sensor_schema"]["leaf-sensor"]], ["leaf_temperature", "leaf_wetness"], )