| Server IP : 3.147.158.171 / Your IP : 216.73.216.88 Web Server : Apache/2.4.67 (Amazon Linux) OpenSSL/3.5.5 System : Linux ip-172-31-2-178.us-east-2.compute.internal 6.1.172-216.329.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Wed May 20 06:31:34 UTC 2026 x86_64 User : ec2-user ( 1000) PHP Version : 8.4.21 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /tsai/repo/api/tests/unit/ |
Upload File : |
"""Unit tests for concrete posting-history events on the schedule calendar.
Covers build_history_events (real posted/failed events with links + status) and
its integration into build_calendar alongside the recurring RRULE schedule.
"""
from datetime import datetime
from app.appTypes import Character, ContentSchedule, PostingRecord, SiteConfig
from app.services.schedule_calendar import build_calendar, build_history_events
def _site() -> SiteConfig:
return SiteConfig(
cb_host="chat.example.test",
api_host="https://api.example.test",
wp_host="https://example.test",
wp_dir="example",
drupal_host="https://drupal.example.test",
drupal_api="https://drupal.example.test/jsonapi",
slug="mysite",
)
def _success_record(**overrides) -> PostingRecord:
base = dict(
ts="2026-07-01T09:15:00",
date="2026-07-01",
site="mysite",
kind="article",
character="Jane",
status="success",
post_id=123,
url="https://example.test/?p=123",
title="Tariffs & You",
model="gpt-x",
)
base.update(overrides)
return PostingRecord(**base)
def _failed_record(**overrides) -> PostingRecord:
base = dict(
ts="2026-07-02T09:15:00",
date="2026-07-02",
site="mysite",
kind="article",
character="Jane",
status="failed",
error="boom",
)
base.update(overrides)
return PostingRecord(**base)
def _blocks_to_text(blocks):
return "\r\n".join("\r\n".join(b) for b in blocks)
def test_success_event_has_url_and_confirmed_status():
blocks = build_history_events([_success_record()], _site())
text = _blocks_to_text(blocks)
assert "URL:https://example.test/?p=123" in text
assert "STATUS:CONFIRMED" in text
assert "SUMMARY:✅ Posted: Tariffs & You" in text or "✅ Posted: Tariffs" in text
assert "CATEGORIES:ARTICLE,POSTED" in text
# UID is derived from post_id and distinct from recurring schedule UIDs.
assert "UID:tsai-post-mysite-article-123@tsai.local" in text
assert "tsai-schedule-" not in text
def test_failed_event_is_cancelled_and_has_no_url():
blocks = build_history_events([_failed_record()], _site())
text = _blocks_to_text(blocks)
assert "STATUS:CANCELLED" in text
assert "CATEGORIES:ARTICLE,FAILED" in text
assert "URL:" not in text
assert "⚠️ Failed: Jane (article)" in text
assert "Error: boom" in text
def test_failed_events_get_unique_uids():
recs = [_failed_record(), _failed_record()] # same day, no post_id
blocks = build_history_events(recs, _site())
uids = [ln for b in blocks for ln in b if ln.startswith("UID:")]
assert len(uids) == 2
assert uids[0] != uids[1]
def test_bad_timestamp_is_skipped():
blocks = build_history_events([_success_record(ts="not-a-date")], _site())
assert blocks == []
def test_build_calendar_merges_history_with_schedule():
site = _site()
char = Character(
name="Jane",
email="jane@example.test",
description="desc",
enabled=True,
date="2026-01-01",
articleSchedule=ContentSchedule(daysOfWeek=[1], preferredHours=[9]),
)
ics = build_calendar(
[(char, site)],
calendar_name="Test",
now=datetime(2026, 7, 3, 12, 0, 0),
history=[([_success_record(), _failed_record()], site)],
)
# Recurring schedule event still present...
assert "RRULE:FREQ=WEEKLY" in ics
# ...alongside concrete history events.
assert "URL:https://example.test/?p=123" in ics
assert "STATUS:CANCELLED" in ics
assert ics.startswith("BEGIN:VCALENDAR")
assert ics.rstrip().endswith("END:VCALENDAR")