mirror of
https://github.com/agessaman/meshcore-bot.git
synced 2026-10-31 18:12:45 +00:00
A codex review of the branch found seven places where earlier refactor commits changed behavior. Each is restored here with a test: - base_service imported flood_scope relatively; the local-service loader also runs that file as local_services.base_service, where the import cannot resolve. Now absolute. - Radio-health fields were initialized after commands and services were built, so a plugin constructor reading is_radio_offline raised. They are now set before any plugin. - Removing the per-command can_execute overrides made 31 commands honor skip_channel_check, which their overrides had dropped. BaseCommand.honors_skip_channel_check (False on exactly those commands) keeps them enforcing their channel list. - CommandManager.get_plugin_metadata, WxCommand.get_weather_for_zipcode and PluginLoader.validate_plugin were public compatibility entry points; they are back. - feed_manager stopped exporting DEFAULT_MAX_FEED_RESPONSE_BYTES and DEFAULT_MAX_PARSED_FEED_ITEMS despite the commit saying it re-exported them; it does now. - wx and gwx logged companion-location lookup failures at WARNING; the shared helper logged at debug. It now takes the level. - The INFO 'MESSAGE ROUTING' / 'DIRECT MESSAGE' lines for pubkey-correlated DMs were removed with the dead path_info computation; they are logged again by a log-only helper.
83 lines
3.3 KiB
Python
83 lines
3.3 KiB
Python
"""modules.feed_parse: the parsing and config pieces FeedManager and the viewer share."""
|
|
|
|
import configparser
|
|
from datetime import datetime, timezone
|
|
from types import SimpleNamespace
|
|
|
|
import pytest
|
|
|
|
from modules import feed_parse as fp
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("value", "expected"),
|
|
[
|
|
(0, None),
|
|
("", None),
|
|
(1700000000, datetime(2023, 11, 14, 22, 13, 20, tzinfo=timezone.utc)),
|
|
("2024-05-06T07:08:09Z", datetime(2024, 5, 6, 7, 8, 9, tzinfo=timezone.utc)),
|
|
# fromisoformat (3.11+) accepts these before the UTC-tagging fallback is
|
|
# reached, so they come back naive. Pinned as current behavior.
|
|
("2024-05-06 07:08:09", datetime(2024, 5, 6, 7, 8, 9)),
|
|
("2024-05-06", datetime(2024, 5, 6)),
|
|
("not a date", None),
|
|
(["list"], None),
|
|
],
|
|
)
|
|
def test_parse_item_timestamp(value, expected):
|
|
assert fp.parse_item_timestamp(value) == expected
|
|
|
|
|
|
def test_parse_item_timestamp_microsoft_format():
|
|
assert fp.parse_item_timestamp("/Date(1700000000000)/") == datetime(2023, 11, 14, 22, 13, 20, tzinfo=timezone.utc)
|
|
|
|
|
|
def test_rss_entry_published():
|
|
assert fp.rss_entry_published(SimpleNamespace(published_parsed=(2024, 1, 2, 3, 4, 5, 0, 0, 0))) == datetime(
|
|
2024, 1, 2, 3, 4, 5, tzinfo=timezone.utc
|
|
)
|
|
assert fp.rss_entry_published(SimpleNamespace()) is None
|
|
assert fp.rss_entry_published(SimpleNamespace(published_parsed=None)) is None
|
|
|
|
|
|
def test_api_item_fields_reads_nested_and_custom_fields():
|
|
item = {"t": {"name": "Hello"}, "body": 5, "link": "http://x", "when": "2024-05-06"}
|
|
got = fp.api_item_fields(item, {"title_field": "t.name", "description_field": "body", "timestamp_field": "when"})
|
|
assert got == {
|
|
"title": "Hello", "emoji": "", "link": "http://x", "description": "5",
|
|
"published": datetime(2024, 5, 6), "raw": item,
|
|
}
|
|
assert fp.api_item_fields({}, {})["title"] == "Untitled"
|
|
|
|
|
|
def _config(**sections):
|
|
cfg = configparser.ConfigParser()
|
|
for name, values in sections.items():
|
|
cfg[name] = values
|
|
return cfg
|
|
|
|
|
|
def test_config_helpers_defaults_and_clamps():
|
|
empty = _config()
|
|
assert fp.feed_allow_private_urls(empty) is False
|
|
assert fp.feed_max_response_bytes(empty) == fp.DEFAULT_MAX_FEED_RESPONSE_BYTES
|
|
assert fp.feed_max_parsed_items(empty) == fp.DEFAULT_MAX_PARSED_FEED_ITEMS
|
|
cfg = _config(Feed_Manager={"max_response_bytes": "10", "max_parsed_items": "0"})
|
|
assert fp.feed_max_response_bytes(cfg) == 1024
|
|
assert fp.feed_max_parsed_items(cfg) == 1
|
|
|
|
|
|
def test_allow_private_falls_back_to_feed_command():
|
|
assert fp.feed_allow_private_urls(_config(Feed_Command={"allow_private_urls": "true"})) is True
|
|
assert fp.feed_allow_private_urls(_config(Feed_Command={"allow_private_urls": "maybe"})) is False
|
|
cfg = _config(Feed_Command={"allow_private_urls": "true"}, Feed_Manager={"allow_private_urls": "false"})
|
|
assert fp.feed_allow_private_urls(cfg) is False
|
|
assert fp.feed_allow_private_urls(_config(Feed_Command={"allow_private_urls": "true"}, Feed_Manager={})) is True
|
|
|
|
|
|
def test_feed_manager_still_exports_the_size_defaults():
|
|
from modules import feed_manager
|
|
|
|
assert feed_manager.DEFAULT_MAX_FEED_RESPONSE_BYTES == fp.DEFAULT_MAX_FEED_RESPONSE_BYTES
|
|
assert feed_manager.DEFAULT_MAX_PARSED_FEED_ITEMS == fp.DEFAULT_MAX_PARSED_FEED_ITEMS
|