from django.contrib.auth import get_user_model from django.test import TestCase from rest_framework.test import APIRequestFactory, force_authenticate from farm_hub.models import FarmHub, FarmType from .models import DeviceCatalog, SensorExternalRequestLog from .views import DeviceCommandView, DeviceDetailView, DeviceLatestPayloadView, DeviceSummaryView class DeviceHubGenericViewsTests(TestCase): def setUp(self): self.factory = APIRequestFactory() self.user = get_user_model().objects.create_user( username="device-user", password="secret123", email="device@example.com", phone_number="09120001000", ) self.farm_type = FarmType.objects.create(name="گلخانه ای") self.farm = FarmHub.objects.create( owner=self.user, farm_type=self.farm_type, name="Device Farm", ) self.catalog = DeviceCatalog.objects.create( code="soil_sensor_v2", name="Soil Sensor V2", device_communication_type=DeviceCatalog.OUTPUT_ONLY, returned_data_fields=["soil_moisture", "soil_temperature"], payload_mapping={ "soil_moisture": ["moisture", "soil_moisture"], "soil_temperature": ["temperature", "soil_temperature"], }, display_schema={ "fields": [ {"id": "soil_moisture", "label": "رطوبت خاک", "unit": "%", "ideal_min": 40, "ideal_max": 70}, {"id": "soil_temperature", "label": "دمای خاک", "unit": "°C", "ideal_min": 18, "ideal_max": 30}, ] }, supported_widgets=["values_list", "comparison_chart", "radar_chart"], ) self.device = self.farm.sensors.create( name="Soil Device 1", sensor_catalog=self.catalog, sensor_type="soil", ) SensorExternalRequestLog.objects.create( farm_uuid=self.farm.farm_uuid, sensor_catalog_uuid=self.catalog.uuid, physical_device_uuid=self.device.physical_device_uuid, payload={"moisture": 52.4, "temperature": 23.1}, ) def test_device_detail_view_returns_generic_payload(self): request = self.factory.get( f"/api/device-hub/devices/{self.device.physical_device_uuid}/", {"device_code": self.catalog.code}, ) force_authenticate(request, user=self.user) response = DeviceDetailView.as_view()(request, physical_device_uuid=self.device.physical_device_uuid) self.assertEqual(response.status_code, 200) self.assertEqual(response.data["data"]["physical_device_uuid"], str(self.device.physical_device_uuid)) self.assertEqual(response.data["data"]["device_catalog"]["code"], self.catalog.code) def test_device_latest_payload_view_returns_normalized_readings(self): request = self.factory.get( f"/api/device-hub/devices/{self.device.physical_device_uuid}/latest/", {"device_code": self.catalog.code}, ) force_authenticate(request, user=self.user) response = DeviceLatestPayloadView.as_view()(request, physical_device_uuid=self.device.physical_device_uuid) self.assertEqual(response.status_code, 200) self.assertEqual(response.data["data"]["normalized_payload"]["soil_moisture"], 52.4) self.assertEqual(response.data["data"]["readings"]["soil_temperature"], 23.1) def test_device_summary_view_returns_supported_widgets(self): request = self.factory.get( f"/api/device-hub/devices/{self.device.physical_device_uuid}/summary/", {"device_code": self.catalog.code}, ) force_authenticate(request, user=self.user) response = DeviceSummaryView.as_view()(request, physical_device_uuid=self.device.physical_device_uuid) self.assertEqual(response.status_code, 200) self.assertIn("values_list", response.data["data"]["supportedWidgets"]) self.assertIn("sensorValuesList", response.data["data"]) def test_input_only_device_command_view_rejects_input_only_device_code(self): input_catalog = DeviceCatalog.objects.create( code="valve_v1", name="Valve V1", device_communication_type=DeviceCatalog.INPUT_ONLY, commands_schema=[ {"command": "open", "label": "Open", "payload_schema": {"duration_seconds": "integer"}}, ], ) input_device = self.farm.sensors.create( name="Valve 1", sensor_catalog=input_catalog, sensor_type="valve", ) request = self.factory.post( f"/api/device-hub/devices/{input_device.physical_device_uuid}/commands/", {"device_code": input_catalog.code, "command": "open", "payload": {"duration_seconds": 120}}, format="json", ) force_authenticate(request, user=self.user) response = DeviceCommandView.as_view()(request, physical_device_uuid=input_device.physical_device_uuid) self.assertEqual(response.status_code, 400) self.assertIn("device_code", response.data)