work: добавил автоматический режим
This commit is contained in:
@@ -0,0 +1,432 @@
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
from unittest.mock import patch
|
||||
|
||||
from schedule import (
|
||||
ScheduleActionType,
|
||||
ScheduleService,
|
||||
load_schedule,
|
||||
)
|
||||
|
||||
|
||||
SCHEDULE_YAML = """
|
||||
version: 1
|
||||
|
||||
enabled: true
|
||||
timezone: local
|
||||
|
||||
templates:
|
||||
|
||||
test:
|
||||
|
||||
- time: "00:00"
|
||||
action:
|
||||
type: set
|
||||
power: off
|
||||
|
||||
- time: "09:00"
|
||||
action:
|
||||
type: set
|
||||
power: on
|
||||
speed: 1
|
||||
|
||||
- time: "10:00"
|
||||
action:
|
||||
type: auto
|
||||
speed: 3
|
||||
|
||||
- time: "12:00"
|
||||
action:
|
||||
type: set
|
||||
speed: 2
|
||||
|
||||
days:
|
||||
mon: test
|
||||
tue: test
|
||||
wed: test
|
||||
thu: test
|
||||
fri: test
|
||||
sat: test
|
||||
sun: test
|
||||
"""
|
||||
|
||||
|
||||
class FakeTionController:
|
||||
|
||||
def __init__(self):
|
||||
self.calls = []
|
||||
|
||||
async def power_on(self):
|
||||
self.calls.append(
|
||||
("power_on", None)
|
||||
)
|
||||
|
||||
async def power_off(self):
|
||||
self.calls.append(
|
||||
("power_off", None)
|
||||
)
|
||||
|
||||
async def set_speed(self, speed: int):
|
||||
self.calls.append(
|
||||
("set_speed", speed)
|
||||
)
|
||||
|
||||
|
||||
class FakeTionService:
|
||||
|
||||
def __init__(self):
|
||||
self.controller = FakeTionController()
|
||||
|
||||
async def execute(self, operation):
|
||||
return await operation(
|
||||
self.controller
|
||||
)
|
||||
|
||||
|
||||
def load_test_schedule():
|
||||
temp_dir = TemporaryDirectory()
|
||||
|
||||
path = (
|
||||
Path(temp_dir.name)
|
||||
/ "schedule.yaml"
|
||||
)
|
||||
|
||||
path.write_text(
|
||||
SCHEDULE_YAML,
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
config = load_schedule(path)
|
||||
|
||||
return temp_dir, config
|
||||
|
||||
|
||||
def print_resolution(
|
||||
title,
|
||||
resolution,
|
||||
):
|
||||
print()
|
||||
print("=" * 70)
|
||||
print(title)
|
||||
print("=" * 70)
|
||||
|
||||
print(
|
||||
"Current:",
|
||||
resolution.current.when
|
||||
if resolution.current
|
||||
else None,
|
||||
)
|
||||
|
||||
print(
|
||||
"Action:",
|
||||
resolution.current.point.action.type
|
||||
if resolution.current
|
||||
else None,
|
||||
)
|
||||
|
||||
print(
|
||||
"Scheduled speed:",
|
||||
resolution.scheduled_settings.speed,
|
||||
)
|
||||
|
||||
print(
|
||||
"AUTO:",
|
||||
resolution.auto_active,
|
||||
)
|
||||
|
||||
print(
|
||||
"Fallback:",
|
||||
resolution.auto_fallback_speed,
|
||||
)
|
||||
|
||||
|
||||
def test_resolve(service: ScheduleService):
|
||||
|
||||
# --------------------------------------------------
|
||||
# 09:30
|
||||
# Обычный SET speed=1
|
||||
# --------------------------------------------------
|
||||
|
||||
resolution = service.resolve(
|
||||
datetime(
|
||||
2026,
|
||||
9,
|
||||
14,
|
||||
9,
|
||||
30,
|
||||
)
|
||||
)
|
||||
|
||||
print_resolution(
|
||||
"TEST 1 — SET",
|
||||
resolution,
|
||||
)
|
||||
|
||||
assert resolution.auto_active is False
|
||||
|
||||
assert (
|
||||
resolution.auto_fallback_speed
|
||||
is None
|
||||
)
|
||||
|
||||
assert (
|
||||
resolution.scheduled_settings.speed
|
||||
== 1
|
||||
)
|
||||
|
||||
# --------------------------------------------------
|
||||
# 10:30
|
||||
# AUTO speed=3
|
||||
#
|
||||
# scheduled_settings.speed всё ещё 1,
|
||||
# потому что AUTO не участвует
|
||||
# в накоплении SET-настроек.
|
||||
#
|
||||
# Но fallback должен быть 3.
|
||||
# --------------------------------------------------
|
||||
|
||||
resolution = service.resolve(
|
||||
datetime(
|
||||
2026,
|
||||
9,
|
||||
14,
|
||||
10,
|
||||
30,
|
||||
)
|
||||
)
|
||||
|
||||
print_resolution(
|
||||
"TEST 2 — AUTO",
|
||||
resolution,
|
||||
)
|
||||
|
||||
assert (
|
||||
resolution.current.point.action.type
|
||||
== ScheduleActionType.AUTO
|
||||
)
|
||||
|
||||
assert resolution.auto_active is True
|
||||
|
||||
assert (
|
||||
resolution.auto_fallback_speed
|
||||
== 3
|
||||
)
|
||||
|
||||
assert (
|
||||
resolution.scheduled_settings.speed
|
||||
== 1
|
||||
)
|
||||
|
||||
# --------------------------------------------------
|
||||
# 12:30
|
||||
# AUTO закончился.
|
||||
# SET speed=2.
|
||||
# --------------------------------------------------
|
||||
|
||||
resolution = service.resolve(
|
||||
datetime(
|
||||
2026,
|
||||
9,
|
||||
14,
|
||||
12,
|
||||
30,
|
||||
)
|
||||
)
|
||||
|
||||
print_resolution(
|
||||
"TEST 3 — AFTER AUTO",
|
||||
resolution,
|
||||
)
|
||||
|
||||
assert resolution.auto_active is False
|
||||
|
||||
assert (
|
||||
resolution.auto_fallback_speed
|
||||
is None
|
||||
)
|
||||
|
||||
assert (
|
||||
resolution.scheduled_settings.speed
|
||||
== 2
|
||||
)
|
||||
|
||||
|
||||
async def test_process(
|
||||
service: ScheduleService,
|
||||
tion: FakeTionService,
|
||||
):
|
||||
|
||||
# --------------------------------------------------
|
||||
# 09:30
|
||||
#
|
||||
# Обычный SET.
|
||||
# ScheduleService должен применить speed=1.
|
||||
# --------------------------------------------------
|
||||
|
||||
fixed_now = datetime(
|
||||
2026,
|
||||
9,
|
||||
14,
|
||||
9,
|
||||
30,
|
||||
)
|
||||
|
||||
with patch(
|
||||
"schedule.service.datetime",
|
||||
wraps=datetime,
|
||||
) as mocked_datetime:
|
||||
|
||||
mocked_datetime.now.return_value = (
|
||||
fixed_now
|
||||
)
|
||||
|
||||
await service._process()
|
||||
|
||||
print()
|
||||
print(
|
||||
"09:30 calls:",
|
||||
tion.controller.calls,
|
||||
)
|
||||
|
||||
assert (
|
||||
"set_speed",
|
||||
1,
|
||||
) in tion.controller.calls
|
||||
|
||||
# Очищаем историю команд.
|
||||
tion.controller.calls.clear()
|
||||
|
||||
# --------------------------------------------------
|
||||
# 10:30
|
||||
#
|
||||
# AUTO.
|
||||
#
|
||||
# В расписании fallback speed=3,
|
||||
# но ScheduleService НЕ должен
|
||||
# отправить ни speed=1, ни speed=3.
|
||||
#
|
||||
# Скорость теперь принадлежит
|
||||
# будущему AutoController.
|
||||
# --------------------------------------------------
|
||||
|
||||
fixed_now = datetime(
|
||||
2026,
|
||||
9,
|
||||
14,
|
||||
10,
|
||||
30,
|
||||
)
|
||||
|
||||
with patch(
|
||||
"schedule.service.datetime",
|
||||
wraps=datetime,
|
||||
) as mocked_datetime:
|
||||
|
||||
mocked_datetime.now.return_value = (
|
||||
fixed_now
|
||||
)
|
||||
|
||||
await service._process()
|
||||
|
||||
print()
|
||||
print(
|
||||
"10:30 AUTO calls:",
|
||||
tion.controller.calls,
|
||||
)
|
||||
|
||||
speed_calls = [
|
||||
call
|
||||
for call in tion.controller.calls
|
||||
if call[0] == "set_speed"
|
||||
]
|
||||
|
||||
assert speed_calls == []
|
||||
|
||||
# Очищаем историю.
|
||||
tion.controller.calls.clear()
|
||||
|
||||
# --------------------------------------------------
|
||||
# 12:30
|
||||
#
|
||||
# AUTO закончился.
|
||||
# Расписание снова должно поставить speed=2.
|
||||
# --------------------------------------------------
|
||||
|
||||
fixed_now = datetime(
|
||||
2026,
|
||||
9,
|
||||
14,
|
||||
12,
|
||||
30,
|
||||
)
|
||||
|
||||
with patch(
|
||||
"schedule.service.datetime",
|
||||
wraps=datetime,
|
||||
) as mocked_datetime:
|
||||
|
||||
mocked_datetime.now.return_value = (
|
||||
fixed_now
|
||||
)
|
||||
|
||||
await service._process()
|
||||
|
||||
print()
|
||||
print(
|
||||
"12:30 calls:",
|
||||
tion.controller.calls,
|
||||
)
|
||||
|
||||
assert (
|
||||
"set_speed",
|
||||
2,
|
||||
) in tion.controller.calls
|
||||
|
||||
|
||||
async def main():
|
||||
|
||||
temp_dir, config = (
|
||||
load_test_schedule()
|
||||
)
|
||||
|
||||
try:
|
||||
# ----------------------------------------------
|
||||
# Проверка resolve()
|
||||
# ----------------------------------------------
|
||||
|
||||
service = ScheduleService(
|
||||
config
|
||||
)
|
||||
|
||||
test_resolve(service)
|
||||
|
||||
# ----------------------------------------------
|
||||
# Проверка реального _process(),
|
||||
# но через FakeTion.
|
||||
# ----------------------------------------------
|
||||
|
||||
tion = FakeTionService()
|
||||
|
||||
service = ScheduleService(
|
||||
config,
|
||||
tion=tion,
|
||||
)
|
||||
|
||||
await test_process(
|
||||
service,
|
||||
tion,
|
||||
)
|
||||
|
||||
finally:
|
||||
temp_dir.cleanup()
|
||||
|
||||
print()
|
||||
print("=" * 70)
|
||||
print("ALL AUTO SCHEDULE TESTS PASSED")
|
||||
print("=" * 70)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user