fix: 포트 충돌 회피 — note_bridge 8098, intent_service 8099

Jellyfin(8096), OrbStack(8097) 포트 충돌으로 변경.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-19 13:53:55 +09:00
parent dc08d29509
commit c2257d3a86
2709 changed files with 619549 additions and 10 deletions

View File

@@ -0,0 +1,489 @@
import itertools
import re
from datetime import datetime, timedelta
import pytest
import icalendar
from icalendar import prop
from icalendar.cal import Calendar, Component, Event
from icalendar.prop import tzid_from_dt
def test_cal_Component(calendar_component):
"""A component is like a dictionary with extra methods and attributes."""
assert calendar_component
assert calendar_component.is_empty()
def test_nonempty_calendar_component(calendar_component):
"""Every key defines a property.A property can consist of either a
single item. This can be set with a single value...
"""
calendar_component["prodid"] = "-//max m//icalendar.mxm.dk/"
assert not calendar_component.is_empty()
assert calendar_component == Calendar({"PRODID": "-//max m//icalendar.mxm.dk/"})
# or with a list
calendar_component["ATTENDEE"] = ["Max M", "Rasmussen"]
assert calendar_component == Calendar(
{"ATTENDEE": ["Max M", "Rasmussen"], "PRODID": "-//max m//icalendar.mxm.dk/"}
)
def test_add_multiple_values(event_component):
"""add multiple values to a property.
If you use the add method you don't have to considder if a value is
a list or not.
"""
# add multiple values at once
event_component.add("attendee", ["test@test.com", "test2@test.com"])
# or add one per line
event_component.add("attendee", "maxm@mxm.dk")
event_component.add("attendee", "test@example.dk")
# add again multiple values at once to very concatenaton of lists
event_component.add("attendee", ["test3@test.com", "test4@test.com"])
assert event_component == Event(
{
"ATTENDEE": [
prop.vCalAddress("test@test.com"),
prop.vCalAddress("test2@test.com"),
prop.vCalAddress("maxm@mxm.dk"),
prop.vCalAddress("test@example.dk"),
prop.vCalAddress("test3@test.com"),
prop.vCalAddress("test4@test.com"),
]
}
)
def test_get_content_directly(c):
"""You can get the values back directly ..."""
c.add("prodid", "-//my product//")
assert c["prodid"] == prop.vText("-//my product//")
# ... or decoded to a python type
assert c.decoded("prodid") == b"-//my product//"
def test_get_default_value(c):
"""With default values for non existing properties"""
assert c.decoded("version", "No Version") == "No Version"
def test_default_list_example(c):
c.add("rdate", [datetime(2013, 3, 28), datetime(2013, 3, 27)])
assert isinstance(c.decoded("rdate"), prop.vDDDLists)
def test_render_component(calendar_component):
"""The component can render itself in the RFC 5545 format."""
calendar_component.add("attendee", "Max M")
assert (
calendar_component.to_ical()
== b"BEGIN:VCALENDAR\r\nATTENDEE:Max M\r\nEND:VCALENDAR\r\n"
)
def test_nested_component_event_ics(filled_event_component):
"""Check the ical string of the event component."""
assert filled_event_component.to_ical() == (
b"BEGIN:VEVENT\r\nDTEND:20000102T000000\r\n"
+ b"DTSTART:20000101T000000\r\nSUMMARY:A brief history of time\r"
+ b"\nEND:VEVENT\r\n"
)
def test_nested_components(calendar_component, filled_event_component):
"""Components can be nested, so You can add a subcomponent. Eg a calendar
holds events."""
self.assertEqual(
calendar_component.subcomponents,
[
Event(
{
"DTEND": "20000102T000000",
"DTSTART": "20000101T000000",
"SUMMARY": "A brief history of time",
}
)
],
)
def test_walk_filled_calendar_component(calendar_component, filled_event_component):
"""We can walk over nested componentes with the walk method."""
assert [i.name for i in calendar_component.walk()] == ["VCALENDAR", "VEVENT"]
def test_filter_walk(calendar_component, filled_event_component):
"""We can also just walk over specific component types, by filtering
them on their name."""
assert [i.name for i in calendar_component.walk("VEVENT")] == ["VEVENT"]
assert [i["dtstart"] for i in calendar_component.walk("VEVENT")] == [
"20000101T000000"
]
def test_recursive_property_items(calendar_component, filled_event_component):
"""We can enumerate property items recursively with the property_items
method."""
calendar_component.add("attendee", "Max M")
assert calendar_component.property_items() == [
("BEGIN", b"VCALENDAR"),
("ATTENDEE", prop.vCalAddress("Max M")),
("BEGIN", b"VEVENT"),
("DTEND", "20000102T000000"),
("DTSTART", "20000101T000000"),
("SUMMARY", "A brief history of time"),
("END", b"VEVENT"),
("END", b"VCALENDAR"),
]
def test_flat_property_items(calendar_component, filled_event_component):
"""We can also enumerate property items just under the component."""
assert calendar_component.property_items(recursive=False) == [
("BEGIN", b"VCALENDAR"),
("ATTENDEE", prop.vCalAddress("Max M")),
("END", b"VCALENDAR"),
]
def test_flat_property_items(filled_event_component):
"""Flat enumeration on the event."""
assert filled_event_component.property_items(recursive=False) == [
("BEGIN", b"VEVENT"),
("DTEND", "20000102T000000"),
("DTSTART", "20000101T000000"),
("SUMMARY", "A brief history of time"),
("END", b"VEVENT"),
]
def test_indent():
"""Text fields which span multiple mulitple lines require proper indenting"""
c = Calendar()
c["description"] = "Paragraph one\n\nParagraph two"
assert c.to_ical() == (
b"BEGIN:VCALENDAR\r\nDESCRIPTION:Paragraph one\\n\\nParagraph two"
+ b"\r\nEND:VCALENDAR\r\n"
)
def test_INLINE_properties(calendar_with_resources):
"""INLINE properties have their values on one property line. Note the
double quoting of the value with a colon in it.
"""
assert calendar_with_resources == Calendar(
{"RESOURCES": 'Chair, Table, "Room: 42"'}
)
assert calendar_with_resources.to_ical() == (
b'BEGIN:VCALENDAR\r\nRESOURCES:Chair\\, Table\\, "Room: 42"\r\n'
+ b"END:VCALENDAR\r\n"
)
def test_get_inline(calendar_with_resources):
"""The inline values must be handled by the get_inline() and
set_inline() methods.
"""
assert calendar_with_resources.get_inline("resources", decode=0) == [
"Chair",
"Table",
"Room: 42",
]
def test_get_inline_decoded(calendar_with_resources):
"""These can also be decoded"""
assert calendar_with_resources.get_inline("resources", decode=1) == [
b"Chair",
b"Table",
b"Room: 42",
]
def test_set_inline(calendar_with_resources):
"""You can set them directly ..."""
calendar_with_resources.set_inline(
"resources", ["A", "List", "of", "some, recources"], encode=1
)
assert calendar_with_resources["resources"] == 'A,List,of,"some, recources"'
assert calendar_with_resources.get_inline("resources", decode=0) == [
"A",
"List",
"of",
"some, recources",
]
def test_inline_free_busy_inline(c):
c["freebusy"] = (
"19970308T160000Z/PT3H,19970308T200000Z/PT1H,"
+ "19970308T230000Z/19970309T000000Z"
)
assert c.get_inline("freebusy", decode=0) == [
"19970308T160000Z/PT3H",
"19970308T200000Z/PT1H",
"19970308T230000Z/19970309T000000Z",
]
freebusy = c.get_inline("freebusy", decode=1)
assert isinstance(freebusy[0][0], datetime)
assert isinstance(freebusy[0][1], timedelta)
def test_cal_Component_add(comp, tzp):
"""Test the for timezone correctness: dtstart should preserve it's
timezone, created, dtstamp and last-modified must be in UTC.
"""
comp.add("dtstart", tzp.localize(datetime(2010, 10, 10, 10, 0, 0), "Europe/Vienna"))
comp.add("created", datetime(2010, 10, 10, 12, 0, 0))
comp.add("dtstamp", tzp.localize(datetime(2010, 10, 10, 14, 0, 0), "Europe/Vienna"))
comp.add("last-modified", tzp.localize_utc(datetime(2010, 10, 10, 16, 0, 0)))
lines = comp.to_ical().splitlines()
assert b"DTSTART;TZID=Europe/Vienna:20101010T100000" in lines
assert b"CREATED:20101010T120000Z" in lines
assert b"DTSTAMP:20101010T120000Z" in lines
assert b"LAST-MODIFIED:20101010T160000Z" in lines
def test_cal_Component_add_no_reencode(comp):
"""Already encoded values should not be re-encoded."""
comp.add("ATTACH", "me")
comp.add("ATTACH", "you", encode=False)
binary = prop.vBinary("us")
comp.add("ATTACH", binary)
assert comp["ATTACH"] == ["me", "you", binary]
def test_cal_Component_add_property_parameter(comp):
"""Test the for timezone correctness: dtstart should preserve it's
timezone, crated, dtstamp and last-modified must be in UTC.
"""
comp.add("X-TEST-PROP", "tryout.", parameters={"prop1": "val1", "prop2": "val2"})
lines = comp.to_ical().splitlines()
assert b"X-TEST-PROP;PROP1=val1;PROP2=val2:tryout." in lines
comp_prop = pytest.mark.parametrize(
"component_name, property_name",
[
("VEVENT", "DTSTART"),
("VEVENT", "DTEND"),
("VEVENT", "RECURRENCE-ID"),
("VTODO", "DUE"),
],
)
@comp_prop
def test_cal_Component_from_ical(component_name, property_name, tzp):
"""Check for proper handling of TZID parameter of datetime properties"""
component_str = "BEGIN:" + component_name + "\n"
component_str += property_name + ";TZID=America/Denver:"
component_str += "20120404T073000\nEND:" + component_name
component = Component.from_ical(component_str)
assert tzid_from_dt(component[property_name].dt) == "America/Denver"
@comp_prop
def test_cal_Component_from_ical_2(component_name, property_name, tzp):
"""Check for proper handling of TZID parameter of datetime properties"""
component_str = "BEGIN:" + component_name + "\n"
component_str += property_name + ":"
component_str += "20120404T073000\nEND:" + component_name
component = Component.from_ical(component_str)
assert component[property_name].dt.tzinfo == None
def test_cal_Component_to_ical_property_order():
component_str = [
b"BEGIN:VEVENT",
b"DTSTART:19970714T170000Z",
b"DTEND:19970715T035959Z",
b"SUMMARY:Bastille Day Party",
b"END:VEVENT",
]
component = Component.from_ical(b"\r\n".join(component_str))
sorted_str = component.to_ical().splitlines()
assert sorted_str != component_str
assert set(sorted_str) == set(component_str)
preserved_str = component.to_ical(sorted=False).splitlines()
assert preserved_str == component_str
def test_cal_Component_to_ical_parameter_order():
component_str = [
b"BEGIN:VEVENT",
b"X-FOOBAR;C=one;A=two;B=three:helloworld.",
b"END:VEVENT",
]
component = Component.from_ical(b"\r\n".join(component_str))
sorted_str = component.to_ical().splitlines()
assert sorted_str[0] == component_str[0]
assert sorted_str[1] == b"X-FOOBAR;A=two;B=three;C=one:helloworld."
assert sorted_str[2] == component_str[2]
preserved_str = component.to_ical(sorted=False).splitlines()
assert preserved_str == component_str
@pytest.fixture
def repr_example(c):
class ReprExample:
component = c
component["key1"] = "value1"
calendar = Calendar()
calendar["key1"] = "value1"
event = Event()
event["key1"] = "value1"
nested = Component(key1="VALUE1")
nested.add_component(component)
nested.add_component(calendar)
return ReprExample
def test_repr_component(repr_example):
"""Test correct class representation."""
assert re.match(r"Component\({u?'KEY1': u?'value1'}\)", str(repr_example.component))
def test_repr_calendar(repr_example):
assert re.match(r"VCALENDAR\({u?'KEY1': u?'value1'}\)", str(repr_example.calendar))
def test_repr_event(repr_example):
assert re.match(r"VEVENT\({u?'KEY1': u?'value1'}\)", str(repr_example.event))
def test_nested_components(repr_example):
"""Representation of nested Components"""
repr_example.calendar.add_component(repr_example.event)
print(repr_example.nested)
assert re.match(
r"Component\({u?'KEY1': u?'VALUE1'}, "
r"Component\({u?'KEY1': u?'value1'}\), "
r"VCALENDAR\({u?'KEY1': u?'value1'}, "
r"VEVENT\({u?'KEY1': u?'value1'}\)\)\)",
str(repr_example.nested),
)
def test_component_factory_VEVENT(factory):
"""Check the events in the component factory"""
component = factory["VEVENT"]
event = component(dtstart="19700101")
assert event.to_ical() == b"BEGIN:VEVENT\r\nDTSTART:19700101\r\nEND:VEVENT\r\n"
def test_component_factory_VCALENDAR(factory):
"""Check the VCALENDAR in the factory."""
assert factory.get("VCALENDAR") == icalendar.cal.Calendar
def test_minimal_calendar_component_with_one_event():
"""Setting up a minimal calendar component looks like this"""
cal = Calendar()
# Some properties are required to be compliant
cal["prodid"] = "-//My calendar product//mxm.dk//"
cal["version"] = "2.0"
# We also need at least one subcomponent for a calendar to be compliant
event = Event()
event["summary"] = "Python meeting about calendaring"
event["uid"] = "42"
event.add("dtstart", datetime(2005, 4, 4, 8, 0, 0))
cal.add_component(event)
assert (
cal.subcomponents[0].to_ical()
== b"BEGIN:VEVENT\r\nSUMMARY:Python meeting about calendaring\r\n"
+ b"DTSTART:20050404T080000\r\nUID:42\r\n"
+ b"END:VEVENT\r\n"
)
def test_calendar_with_parsing_errors_includes_all_events(calendars):
"""Parsing a complete calendar from a string will silently ignore wrong
events but adding the error information to the component's 'errors'
attribute. The error in the following is the third EXDATE: it has an
empty DATE.
"""
event_descriptions = [
e["DESCRIPTION"].to_ical() for e in calendars.parsing_error.walk("VEVENT")
]
assert event_descriptions == [b"Perfectly OK event", b"Wrong event"]
def test_calendar_with_parsing_errors_has_an_error_in_one_event(calendars):
"""Parsing a complete calendar from a string will silently ignore wrong
events but adding the error information to the component's 'errors'
attribute. The error in the following is the third EXDATE: it has an
empty DATE.
"""
errors = [e.errors for e in calendars.parsing_error.walk("VEVENT")]
assert errors == [[], [("EXDATE", "Expected datetime, date, or time, got: ''")]]
def test_cal_strict_parsing(calendars):
"""If components are damaged, we raise an exception."""
with pytest.raises(ValueError):
calendars.parsing_error_in_UTC_offset
def test_cal_ignore_errors_parsing(calendars, vUTCOffset_ignore_exceptions):
"""If we diable the errors, we should be able to put the calendar back together."""
assert (
calendars.parsing_error_in_UTC_offset.to_ical()
== calendars.parsing_error_in_UTC_offset.raw_ics
)
@pytest.mark.parametrize(
("calendar", "other_calendar"),
itertools.product(
[
"issue_156_RDATE_with_PERIOD_TZID_khal",
"issue_156_RDATE_with_PERIOD_TZID_khal_2",
"issue_178_custom_component_contains_other",
"issue_178_custom_component_inside_other",
"issue_526_calendar_with_events",
"issue_526_calendar_with_different_events",
"issue_526_calendar_with_event_subset",
],
repeat=2,
),
)
def test_comparing_calendars(calendars, calendar, other_calendar, tzp):
are_calendars_equal = calendars[calendar] == calendars[other_calendar]
are_calendars_actually_equal = calendar == other_calendar
assert are_calendars_equal == are_calendars_actually_equal
@pytest.mark.parametrize(
("calendar", "shuffeled_calendar"),
[
(
"issue_526_calendar_with_events",
"issue_526_calendar_with_shuffeled_events",
),
],
)
def test_calendars_with_same_subcomponents_in_different_order_are_equal(
calendars, calendar, shuffeled_calendar
):
assert (
calendars[calendar].subcomponents != calendars[shuffeled_calendar].subcomponents
)
assert calendars[calendar] == calendars[shuffeled_calendar]