feat: pass alarm style through crontab manager and GraphQL API
- crontab_manager.get_alarms now parses --style from the cron command (defaults to 'blink' for legacy entries without --style) - GraphQL Alarm type gains a 'style' field - setAlarm accepts a 'style' arg (default 'simple') and validates it against the styles registry; unknown styles raise a GraphQL error - _default_command embeds --style <name> into the cron command - startRinging accepts 'style' (default 'simple') and passes --style to the spawned wecker.py The crontab remains the single source of truth; the style simply rides in the cron command alongside --music-file.
This commit is contained in:
@@ -2,6 +2,7 @@ from unittest.mock import patch, MagicMock
|
||||
from fastapi.testclient import TestClient
|
||||
import tempfile
|
||||
import os
|
||||
import pytest
|
||||
import signal
|
||||
|
||||
# We need to set the environment variable before importing the app
|
||||
@@ -403,3 +404,107 @@ def test_pid_file_same_shared_constant_in_api():
|
||||
assert api_schema.PID_FILE is common.PID_FILE, (
|
||||
"api.schema.PID_FILE must reference common.PID_FILE, not redefine it"
|
||||
)
|
||||
|
||||
|
||||
def _cleanup_alarm(alarm_id):
|
||||
headers = {"X-API-Key": "test-secret"}
|
||||
client.post(
|
||||
"/graphql",
|
||||
json={"query": f'mutation {{ deleteAlarm(id: "{alarm_id}") }}'},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
|
||||
def test_set_alarm_accepts_and_returns_style():
|
||||
headers = {"X-API-Key": "test-secret"}
|
||||
mutation = '''
|
||||
mutation {
|
||||
setAlarm(cronExpression: "0 9 * * *", style: "blink") {
|
||||
id
|
||||
style
|
||||
}
|
||||
}
|
||||
'''
|
||||
res = client.post("/graphql", json={"query": mutation}, headers=headers)
|
||||
assert res.status_code == 200
|
||||
alarm = res.json()["data"]["setAlarm"]
|
||||
assert alarm["style"] == "blink"
|
||||
_cleanup_alarm(alarm["id"])
|
||||
|
||||
|
||||
def test_set_alarm_default_style_is_simple():
|
||||
headers = {"X-API-Key": "test-secret"}
|
||||
mutation = '''
|
||||
mutation {
|
||||
setAlarm(cronExpression: "0 9 * * *") { id style }
|
||||
}
|
||||
'''
|
||||
res = client.post("/graphql", json={"query": mutation}, headers=headers)
|
||||
assert res.status_code == 200
|
||||
alarm = res.json()["data"]["setAlarm"]
|
||||
assert alarm["style"] == "simple"
|
||||
_cleanup_alarm(alarm["id"])
|
||||
|
||||
|
||||
def test_set_alarm_rejects_unknown_style():
|
||||
headers = {"X-API-Key": "test-secret"}
|
||||
mutation = '''
|
||||
mutation {
|
||||
setAlarm(cronExpression: "0 9 * * *", style: "nope") { id }
|
||||
}
|
||||
'''
|
||||
res = client.post("/graphql", json={"query": mutation}, headers=headers)
|
||||
assert res.status_code == 200
|
||||
assert "errors" in res.json()
|
||||
assert "Unknown alarm style" in str(res.json()["errors"])
|
||||
|
||||
|
||||
def test_get_alarms_includes_style():
|
||||
headers = {"X-API-Key": "test-secret"}
|
||||
set_mut = '''
|
||||
mutation { setAlarm(cronExpression: "0 9 * * *", style: "blink") { id } }
|
||||
'''
|
||||
res = client.post("/graphql", json={"query": set_mut}, headers=headers)
|
||||
alarm_id = res.json()["data"]["setAlarm"]["id"]
|
||||
|
||||
res = client.post(
|
||||
"/graphql", json={"query": "{ getAlarms { id style } }"}, headers=headers
|
||||
)
|
||||
alarms = res.json()["data"]["getAlarms"]
|
||||
assert any(a["id"] == alarm_id and a["style"] == "blink" for a in alarms)
|
||||
_cleanup_alarm(alarm_id)
|
||||
|
||||
|
||||
def test_start_ringing_passes_style():
|
||||
from api.schema import Mutation
|
||||
|
||||
mutation = Mutation()
|
||||
with patch("api.schema.is_wecker_ringing", return_value=False), \
|
||||
patch("subprocess.Popen") as mock_popen:
|
||||
mock_popen.return_value.pid = 9999
|
||||
assert mutation.start_ringing(style="blink") is True
|
||||
argv = mock_popen.call_args[0][0]
|
||||
assert "--style" in argv and "blink" in argv
|
||||
|
||||
|
||||
def test_start_ringing_default_style_is_simple():
|
||||
from api.schema import Mutation
|
||||
|
||||
mutation = Mutation()
|
||||
with patch("api.schema.is_wecker_ringing", return_value=False), \
|
||||
patch("subprocess.Popen") as mock_popen:
|
||||
mock_popen.return_value.pid = 9999
|
||||
mutation.start_ringing()
|
||||
argv = mock_popen.call_args[0][0]
|
||||
assert "simple" in argv
|
||||
|
||||
|
||||
def test_start_ringing_rejects_unknown_style():
|
||||
from api.schema import Mutation
|
||||
|
||||
mutation = Mutation()
|
||||
with patch("api.schema.is_wecker_ringing", return_value=False), \
|
||||
patch("subprocess.Popen") as mock_popen:
|
||||
with pytest.raises(ValueError, match="Unknown alarm style"):
|
||||
mutation.start_ringing(style="nope")
|
||||
mock_popen.assert_not_called()
|
||||
|
||||
Reference in New Issue
Block a user