Refactored OwncastSentry internals and API validation.
CI / Formatting (push) Failing after 7s
CI / Linting (push) Successful in 12s
CI / Tests (push) Successful in 47s
CI / Type Checking (push) Successful in 11s
CI / Spelling (push) Successful in 7s

This commit is contained in:
2026-05-17 14:46:44 -04:00
parent 179d087e33
commit 0620c675d9
25 changed files with 2730 additions and 1569 deletions
+370
View File
@@ -0,0 +1,370 @@
# Copyright 2026 Logan Fick
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for database repository classes."""
from typing import TYPE_CHECKING
import pytest
from owncastsentry.types import (
UNKNOWN_STATUS_THRESHOLD,
AlreadySubscribedError,
NotSubscribedError,
StreamState,
)
if TYPE_CHECKING:
from owncastsentry.repository import StreamRepository, SubscriptionRepository
class TestStreamExists:
"""Stream existence checks."""
async def test_returns_true_for_existing_stream(
self, stream_repo: StreamRepository
) -> None:
"""Return True when the stream exists in the database."""
await stream_repo.create("example.com")
assert await stream_repo.exists("example.com") is True
async def test_returns_false_for_missing_stream(
self, stream_repo: StreamRepository
) -> None:
"""Return False when the stream does not exist in the database."""
assert await stream_repo.exists("missing.com") is False
class TestStreamCreate:
"""Stream creation behavior."""
async def test_returns_true_when_created(
self, stream_repo: StreamRepository
) -> None:
"""Return True when a stream row is inserted."""
assert await stream_repo.create("example.com") is True
async def test_returns_false_when_existing(
self, stream_repo: StreamRepository
) -> None:
"""Return False when a stream row already exists."""
await stream_repo.create("example.com")
assert await stream_repo.create("example.com") is False
class TestStreamDelete:
"""Stream record deletion."""
async def test_removes_stream_record(self, stream_repo: StreamRepository) -> None:
"""Remove the stream record so get_by_domain returns None."""
await stream_repo.create("example.com")
await stream_repo.delete("example.com")
assert await stream_repo.get_by_domain("example.com") is None
class TestGetSubscribedStreamsForRoom:
"""Subscribed stream lookup by room."""
async def test_returns_all_domains_for_room(
self,
stream_repo: StreamRepository,
subscription_repo: SubscriptionRepository,
) -> None:
"""Return all domains a room is subscribed to."""
await stream_repo.create("alpha.com")
await stream_repo.create("beta.com")
await subscription_repo.add("alpha.com", "!room1:example.com")
await subscription_repo.add("beta.com", "!room1:example.com")
result = await subscription_repo.get_subscribed_streams_for_room(
"!room1:example.com"
)
assert sorted(result) == ["alpha.com", "beta.com"]
async def test_returns_empty_list_for_unsubscribed_room(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Return an empty list when the room has no subscriptions."""
result = await subscription_repo.get_subscribed_streams_for_room(
"!nobody:example.com"
)
assert result == []
class TestHasRoomSubscriptions:
"""Room subscription existence checks."""
async def test_returns_true_for_subscribed_room(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Return True when the room has at least one subscription."""
await subscription_repo.add("alpha.com", "!room1:example.com")
assert await subscription_repo.has_room_subscriptions("!room1:example.com")
async def test_returns_false_for_unsubscribed_room(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Return False when the room has no subscriptions."""
assert not await subscription_repo.has_room_subscriptions(
"!nobody:example.com"
)
class TestGetRoomSubscriptions:
"""Resolved room subscription lookup."""
async def test_returns_sorted_stream_states_and_skips_missing_rows(
self,
stream_repo: StreamRepository,
subscription_repo: SubscriptionRepository,
) -> None:
"""Return sorted resolved subscriptions and skip missing stream rows."""
await stream_repo.create("beta.example")
await stream_repo.update(StreamState(domain="beta.example", name="Beta"))
await stream_repo.create("alpha.example")
await stream_repo.update(StreamState(domain="alpha.example", name="Alpha"))
await subscription_repo.add("beta.example", "!room:example.com")
await subscription_repo.add("missing.example", "!room:example.com")
await subscription_repo.add("alpha.example", "!room:example.com")
subscriptions = await subscription_repo.get_room_subscriptions(
"!room:example.com"
)
assert [subscription.domain for subscription in subscriptions] == [
"alpha.example",
"beta.example",
]
assert [subscription.stream_state.name for subscription in subscriptions] == [
"Alpha",
"Beta",
]
async def test_returns_empty_list_for_unsubscribed_room(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Return an empty list when the room has no resolved subscriptions."""
subscriptions = await subscription_repo.get_room_subscriptions(
"!nobody:example.com"
)
assert subscriptions == []
class TestGetLiveRoomSubscriptions:
"""Resolved live room subscription lookup."""
async def test_returns_online_streams_and_skips_inactive_states(
self,
stream_repo: StreamRepository,
subscription_repo: SubscriptionRepository,
) -> None:
"""Return only streams whose derived status is ONLINE."""
await stream_repo.create("offline.example")
await stream_repo.update(
StreamState(
domain="offline.example",
name="Offline",
last_disconnect_time="2026-01-01T00:00:00Z",
)
)
await stream_repo.create("online.example")
await stream_repo.update(
StreamState(
domain="online.example",
name="Online",
last_connect_time="2026-01-01T00:00:00Z",
)
)
await stream_repo.create("unknown.example")
await stream_repo.update(
StreamState(
domain="unknown.example",
name="Unknown",
last_connect_time="2026-01-01T00:00:00Z",
)
)
for _ in range(UNKNOWN_STATUS_THRESHOLD + 1):
await stream_repo.increment_failure_counter("unknown.example")
await subscription_repo.add("offline.example", "!room:example.com")
await subscription_repo.add("online.example", "!room:example.com")
await subscription_repo.add("unknown.example", "!room:example.com")
subscriptions = await subscription_repo.get_live_room_subscriptions(
"!room:example.com"
)
assert [subscription.domain for subscription in subscriptions] == [
"online.example"
]
async def test_returns_empty_list_for_room_with_no_live_streams(
self,
stream_repo: StreamRepository,
subscription_repo: SubscriptionRepository,
) -> None:
"""Return an empty list when no subscribed streams are live."""
await stream_repo.create("offline.example")
await subscription_repo.add("offline.example", "!room:example.com")
subscriptions = await subscription_repo.get_live_room_subscriptions(
"!room:example.com"
)
assert subscriptions == []
class TestAddSubscription:
"""Subscription creation behavior."""
async def test_adds_subscription(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Add a subscription row."""
await subscription_repo.add("alpha.com", "!room1:example.com")
assert await subscription_repo.get_subscribed_rooms("alpha.com") == [
"!room1:example.com"
]
async def test_raises_when_existing(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Raise AlreadySubscribedError when a subscription already exists."""
await subscription_repo.add("alpha.com", "!room1:example.com")
with pytest.raises(AlreadySubscribedError):
await subscription_repo.add("alpha.com", "!room1:example.com")
class TestRemoveSubscription:
"""Subscription removal behavior."""
async def test_removes_subscription(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Remove an existing subscription row."""
await subscription_repo.add("alpha.com", "!room1:example.com")
await subscription_repo.remove("alpha.com", "!room1:example.com")
assert await subscription_repo.get_subscribed_rooms("alpha.com") == []
async def test_raises_when_missing(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Raise NotSubscribedError when no subscription exists."""
with pytest.raises(NotSubscribedError):
await subscription_repo.remove("alpha.com", "!room1:example.com")
class TestGetAllSubscribedDomains:
"""Unique subscribed domain retrieval."""
async def test_returns_each_domain_once(
self,
stream_repo: StreamRepository,
subscription_repo: SubscriptionRepository,
) -> None:
"""Return each domain once even with multiple subscriptions."""
await stream_repo.create("alpha.com")
await subscription_repo.add("alpha.com", "!room1:example.com")
await subscription_repo.add("alpha.com", "!room2:example.com")
result = await subscription_repo.get_all_subscribed_domains()
assert result == ["alpha.com"]
async def test_returns_empty_list_with_no_subscriptions(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Return an empty list when there are no subscriptions."""
result = await subscription_repo.get_all_subscribed_domains()
assert result == []
class TestCountByDomain:
"""Subscription count by domain."""
async def test_returns_correct_count(
self,
stream_repo: StreamRepository,
subscription_repo: SubscriptionRepository,
) -> None:
"""Return the correct subscription count for a domain."""
await stream_repo.create("alpha.com")
await subscription_repo.add("alpha.com", "!room1:example.com")
await subscription_repo.add("alpha.com", "!room2:example.com")
assert await subscription_repo.count_by_domain("alpha.com") == 2
async def test_returns_zero_for_unknown_domain(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Return 0 for a domain with no subscriptions."""
assert await subscription_repo.count_by_domain("unknown.com") == 0
class TestCountByDomains:
"""Bulk subscription counts by domain."""
async def test_returns_counts_for_requested_domains(
self,
stream_repo: StreamRepository,
subscription_repo: SubscriptionRepository,
) -> None:
"""Return counts for requested domains and zero for missing domains."""
await stream_repo.create("alpha.com")
await stream_repo.create("beta.com")
await stream_repo.create("ignored.com")
await subscription_repo.add("alpha.com", "!room1:example.com")
await subscription_repo.add("alpha.com", "!room2:example.com")
await subscription_repo.add("beta.com", "!room3:example.com")
await subscription_repo.add("ignored.com", "!room4:example.com")
assert await subscription_repo.count_by_domains(
["beta.com", "missing.com", "alpha.com"]
) == {
"beta.com": 1,
"missing.com": 0,
"alpha.com": 2,
}
async def test_returns_empty_dict_for_empty_domain_list(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Return an empty mapping when no domains are requested."""
assert await subscription_repo.count_by_domains([]) == {}
class TestDeleteAllForDomain:
"""Bulk subscription deletion by domain."""
async def test_deletes_all_subscriptions_and_returns_count(
self,
stream_repo: StreamRepository,
subscription_repo: SubscriptionRepository,
) -> None:
"""Delete all subscriptions for the domain and return the count."""
await stream_repo.create("alpha.com")
await subscription_repo.add("alpha.com", "!room1:example.com")
await subscription_repo.add("alpha.com", "!room2:example.com")
deleted = await subscription_repo.delete_all_for_domain("alpha.com")
assert deleted == 2
rooms = await subscription_repo.get_subscribed_rooms("alpha.com")
assert rooms == []
async def test_returns_zero_for_unknown_domain(
self, subscription_repo: SubscriptionRepository
) -> None:
"""Return 0 when deleting subscriptions for an unknown domain."""
assert await subscription_repo.delete_all_for_domain("unknown.com") == 0