mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-09-14 18:56:52 +00:00
refine post-install and hardware GPU docs, Monitor UX and CLI styling
- rewrite the 15 post-install pages and the 3 hardware GPU pages so they reflect the current scripts (reversibility, tracked-tool counts, kernel parameters, per-tool commands, Alpine LXC propagation flow) - migrate the legacy step-badge helper on post-install/optional and create-vm/synology to the canonical pill component, with the stepLabel key added in each locale - fix rich-text i18n calls missing helpers across network, automated, optional, security, customization and the post-install landing pages, and escape the `<iface>` placeholder in automated so intl no longer parses it as a tag - remove the mouse-follow blue overlay from the docs landing layout - reposition the App-tab Edit button and stack the Search and Register controls vertically on mobile - move the Bulk update Configure/Edit control into the section header so it behaves the same on desktop and mobile - show a spinner during the final autoremove/autoclean pass of update-pve-safe so the cleanup step reads as active instead of silent - restyle the shell spinner and msg_info in a distinctive purple and drop the unused msg_lang duplicate - add a web-docs i18n build script and its CI workflow, plus tests for the pushover notification channel
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
import sys
|
||||
import unittest
|
||||
import urllib.parse
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
SCRIPTS_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(SCRIPTS_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(SCRIPTS_DIR))
|
||||
|
||||
from notification_channels import PushoverChannel, create_channel
|
||||
|
||||
|
||||
class PushoverChannelTests(unittest.TestCase):
|
||||
USER_KEY = "u" * 30
|
||||
API_TOKEN = "a" * 30
|
||||
|
||||
def make_channel(self, **kwargs):
|
||||
channel = PushoverChannel(
|
||||
user_key=kwargs.pop("user_key", self.USER_KEY),
|
||||
api_token=kwargs.pop("api_token", self.API_TOKEN),
|
||||
**kwargs,
|
||||
)
|
||||
channel.MAX_RETRIES = 1
|
||||
return channel
|
||||
|
||||
def test_requires_valid_user_key_and_api_token(self):
|
||||
channel = self.make_channel(user_key="")
|
||||
self.assertEqual(channel.validate_config(), (
|
||||
False, "Pushover user or group key is required"
|
||||
))
|
||||
|
||||
channel = self.make_channel(api_token="short")
|
||||
self.assertEqual(channel.validate_config(), (
|
||||
False, "Invalid Pushover application API token format"
|
||||
))
|
||||
|
||||
def test_optional_device_sound_and_factory(self):
|
||||
channel = create_channel("pushover", {
|
||||
"user_key": self.USER_KEY,
|
||||
"api_token": self.API_TOKEN,
|
||||
"device": "iphone_15",
|
||||
"sound": "magic",
|
||||
"critical_priority": "false",
|
||||
})
|
||||
|
||||
self.assertIsInstance(channel, PushoverChannel)
|
||||
self.assertEqual(channel.validate_config(), (True, ""))
|
||||
self.assertFalse(channel.critical_priority)
|
||||
|
||||
def test_critical_alert_uses_high_priority_and_api_limits(self):
|
||||
channel = self.make_channel(
|
||||
device="iphone_15",
|
||||
sound="magic",
|
||||
critical_priority="true",
|
||||
)
|
||||
request = {}
|
||||
|
||||
def fake_http(url, data, headers):
|
||||
request["url"] = url
|
||||
request["payload"] = urllib.parse.parse_qs(data.decode("utf-8"))
|
||||
request["headers"] = headers
|
||||
return 200, '{"status":1,"request":"test"}'
|
||||
|
||||
channel._http_request = fake_http
|
||||
result = channel.send("T" * 300, "M" * 1200, "critical")
|
||||
|
||||
self.assertTrue(result["success"])
|
||||
self.assertEqual(request["url"], PushoverChannel.API_URL)
|
||||
self.assertEqual(request["payload"]["priority"], ["1"])
|
||||
self.assertEqual(request["payload"]["device"], ["iphone_15"])
|
||||
self.assertEqual(request["payload"]["sound"], ["magic"])
|
||||
self.assertEqual(len(request["payload"]["title"][0]), 250)
|
||||
self.assertEqual(len(request["payload"]["message"][0]), 1024)
|
||||
self.assertTrue(request["payload"]["message"][0].endswith("…"))
|
||||
|
||||
def test_noncritical_alert_uses_normal_priority(self):
|
||||
channel = self.make_channel(critical_priority="true")
|
||||
request = {}
|
||||
|
||||
def fake_http(url, data, headers):
|
||||
request["payload"] = urllib.parse.parse_qs(data.decode("utf-8"))
|
||||
return 200, '{"status":1}'
|
||||
|
||||
channel._http_request = fake_http
|
||||
result = channel.send("Warning", "Message", "WARNING")
|
||||
|
||||
self.assertTrue(result["success"])
|
||||
self.assertEqual(request["payload"]["priority"], ["0"])
|
||||
|
||||
def test_api_error_does_not_expose_credentials(self):
|
||||
channel = self.make_channel()
|
||||
channel._http_request = lambda *args: (
|
||||
400, '{"status":0,"errors":["user identifier is invalid"]}'
|
||||
)
|
||||
|
||||
result = channel.send("Title", "Message")
|
||||
|
||||
self.assertFalse(result["success"])
|
||||
self.assertIn("user identifier is invalid", result["error"])
|
||||
self.assertNotIn(self.USER_KEY, result["error"])
|
||||
self.assertNotIn(self.API_TOKEN, result["error"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user