Switch control and schedules to JSON payloads

This commit is contained in:
Artem Kokos
2026-05-16 10:29:54 +07:00
parent 13fba2fa44
commit 15529961d6
8 changed files with 1171 additions and 748 deletions

View File

@@ -77,25 +77,25 @@ class ScheduleApiTests(unittest.IsolatedAsyncioTestCase):
first = await self.client.post(
"/schedules/cron",
headers=self._headers(),
params={
json={
"target_id": "grp-1",
"hour": "22",
"minute": "00",
"day_of_week": "1",
"is_group": "true",
"state": "true",
"is_group": True,
"state": True,
},
)
second = await self.client.post(
"/schedules/cron",
headers=self._headers(),
params={
json={
"target_id": "grp-1",
"hour": "22",
"minute": "00",
"day_of_week": "5",
"is_group": "true",
"state": "false",
"is_group": True,
"state": False,
},
)
@@ -126,11 +126,11 @@ class ScheduleApiTests(unittest.IsolatedAsyncioTestCase):
response = await self.client.post(
"/schedules/once",
headers=self._headers(),
params={
json={
"target_id": "grp-1",
"run_at": run_at.isoformat(),
"is_group": "true",
"temp": "3200",
"is_group": True,
"temp": 3200,
},
)
@@ -162,12 +162,12 @@ class ScheduleApiTests(unittest.IsolatedAsyncioTestCase):
create_response = await self.client.post(
"/schedules/cron",
headers=self._headers(),
params={
json={
"target_id": "grp-1",
"hour": "21",
"minute": "15",
"is_group": "true",
"state": "true",
"is_group": True,
"state": True,
},
)
job_id = create_response.json()["job_id"]
@@ -220,12 +220,12 @@ class ScheduleApiTests(unittest.IsolatedAsyncioTestCase):
response = await self.client.post(
"/schedules/cron",
headers=self._headers(),
params={
json={
"target_id": "grp-1",
"hour": "99",
"minute": "99",
"is_group": "true",
"temp": "3200",
"is_group": True,
"temp": 3200,
},
)
@@ -237,3 +237,38 @@ class ScheduleApiTests(unittest.IsolatedAsyncioTestCase):
rows = result.scalars().all()
self.assertEqual(rows, [])
async def test_once_schedule_requires_exactly_one_time_selector(self):
run_at = datetime.now(app_tz) + timedelta(hours=2)
response = await self.client.post(
"/schedules/once",
headers=self._headers(),
json={
"target_id": "grp-1",
"run_at": run_at.isoformat(),
"hours_from_now": 2,
"is_group": True,
"state": False,
},
)
self.assertEqual(response.status_code, 422)
self.assertIn(
"Передайте ровно одно из полей run_at или hours_from_now",
str(response.json()),
)
async def test_schedule_rejects_legacy_query_only_contract(self):
response = await self.client.post(
"/schedules/cron",
headers=self._headers(),
params={
"target_id": "grp-1",
"hour": "7",
"minute": "30",
"is_group": "true",
"state": "true",
},
)
self.assertEqual(response.status_code, 422)

View File

@@ -229,7 +229,7 @@ class SecurityAndControlApiTests(unittest.IsolatedAsyncioTestCase):
response = await self.client.post(
"/control/device/dev-1",
headers=self._master_headers(),
params={"state": "true"},
json={"state": True},
)
self.assertEqual(response.status_code, 504)
@@ -263,7 +263,7 @@ class SecurityAndControlApiTests(unittest.IsolatedAsyncioTestCase):
response = await self.client.post(
"/control/group/grp-1",
headers=self._master_headers(),
params={"state": "true"},
json={"state": True},
)
self.assertEqual(response.status_code, 200)
@@ -299,7 +299,7 @@ class SecurityAndControlApiTests(unittest.IsolatedAsyncioTestCase):
response = await self.client.post(
"/control/group/grp-1",
headers=self._master_headers(),
params={"state": "true"},
json={"state": True},
)
self.assertEqual(response.status_code, 504)
@@ -368,13 +368,51 @@ class SecurityAndControlApiTests(unittest.IsolatedAsyncioTestCase):
response = await self.client.post(
"/control/device/dev-1",
headers=self._master_headers(),
params={"scene": "not_a_scene"},
json={"scene": "not_a_scene"},
)
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json()["detail"], "Неизвестная сцена")
self.assertEqual(await self._event_actions(), [])
async def test_device_control_rejects_conflicting_scene_and_temp_in_body(self):
self._set_single_device_state()
response = await self.client.post(
"/control/device/dev-1",
headers=self._master_headers(),
json={"scene": "party", "temp": 3200},
)
self.assertEqual(response.status_code, 422)
self.assertIn(
"Можно передать только один режим из scene, temp или rgb",
str(response.json()),
)
async def test_device_control_rejects_partial_rgb_triplet(self):
self._set_single_device_state()
response = await self.client.post(
"/control/device/dev-1",
headers=self._master_headers(),
json={"r": 255, "g": 128},
)
self.assertEqual(response.status_code, 422)
self.assertIn("Поля r, g и b нужно передавать вместе", str(response.json()))
async def test_device_control_rejects_legacy_query_only_contract(self):
self._set_single_device_state()
response = await self.client.post(
"/control/device/dev-1",
headers=self._master_headers(),
params={"state": "true"},
)
self.assertEqual(response.status_code, 422)
async def test_stats_summary_counts_real_commands_without_requested_duplicates(self):
self._set_single_device_state()
@@ -393,7 +431,7 @@ class SecurityAndControlApiTests(unittest.IsolatedAsyncioTestCase):
response = await self.client.post(
"/control/device/dev-1",
headers=self._master_headers(),
params={"temp": "4200"},
json={"temp": 4200},
)
self.assertEqual(response.status_code, 200)