ttvdrops/config/tests/test_site_endpoint_smoke.py

349 lines
13 KiB
Python

from __future__ import annotations
from datetime import timedelta
from pathlib import Path
from typing import TYPE_CHECKING
from django.conf import settings
from django.test import TestCase
from django.urls import reverse
from django.utils import timezone
from chzzk.models import ChzzkCampaign
from kick.models import KickCategory
from kick.models import KickChannel
from kick.models import KickDropCampaign
from kick.models import KickOrganization
from kick.models import KickReward
from kick.models import KickUser
from twitch.models import Channel
from twitch.models import ChatBadge
from twitch.models import ChatBadgeSet
from twitch.models import DropBenefit
from twitch.models import DropCampaign
from twitch.models import Game
from twitch.models import Organization
from twitch.models import RewardCampaign
from twitch.models import TimeBasedDrop
if TYPE_CHECKING:
from datetime import datetime
from pathlib import Path
from django.test.client import _MonkeyPatchedWSGIResponse
class SiteEndpointSmokeTest(TestCase):
"""Smoke-test all named site endpoints with realistic fixture data."""
def setUp(self) -> None:
"""Set up representative Twitch, Kick, and CHZZK data for endpoint smoke tests."""
now: datetime = timezone.now()
# Twitch fixtures
self.twitch_org: Organization = Organization.objects.create(
twitch_id="smoke-org-1",
name="Smoke Organization",
)
self.twitch_game: Game = Game.objects.create(
twitch_id="smoke-game-1",
slug="smoke-game",
name="Smoke Game",
display_name="Smoke Game",
box_art="https://example.com/smoke-game.png",
)
self.twitch_game.owners.add(self.twitch_org)
self.twitch_channel: Channel = Channel.objects.create(
twitch_id="smoke-channel-1",
name="smokechannel",
display_name="SmokeChannel",
)
self.twitch_campaign: DropCampaign = DropCampaign.objects.create(
twitch_id="smoke-campaign-1",
name="Smoke Campaign",
description="Smoke campaign description",
game=self.twitch_game,
image_url="https://example.com/smoke-campaign.png",
start_at=now - timedelta(days=1),
end_at=now + timedelta(days=1),
operation_names=["DropCampaignDetails"],
is_fully_imported=True,
)
self.twitch_campaign.allow_channels.add(self.twitch_channel)
self.twitch_drop: TimeBasedDrop = TimeBasedDrop.objects.create(
twitch_id="smoke-drop-1",
name="Smoke Drop",
campaign=self.twitch_campaign,
required_minutes_watched=15,
start_at=now - timedelta(days=1),
end_at=now + timedelta(days=1),
)
self.twitch_benefit: DropBenefit = DropBenefit.objects.create(
twitch_id="smoke-benefit-1",
name="Smoke Benefit",
image_asset_url="https://example.com/smoke-benefit.png",
)
self.twitch_drop.benefits.add(self.twitch_benefit)
self.twitch_reward_campaign: RewardCampaign = RewardCampaign.objects.create(
twitch_id="smoke-reward-campaign-1",
name="Smoke Reward Campaign",
brand="Smoke Brand",
starts_at=now - timedelta(days=1),
ends_at=now + timedelta(days=2),
status="ACTIVE",
summary="Smoke reward summary",
external_url="https://example.com/smoke-reward",
is_sitewide=False,
game=self.twitch_game,
)
self.badge_set: ChatBadgeSet = ChatBadgeSet.objects.create(
set_id="smoke-badge-set",
)
ChatBadge.objects.create(
badge_set=self.badge_set,
badge_id="1",
image_url_1x="https://example.com/badge-1x.png",
image_url_2x="https://example.com/badge-2x.png",
image_url_4x="https://example.com/badge-4x.png",
title="Smoke Badge",
description="Smoke badge description",
)
# Kick fixtures
self.kick_org: KickOrganization = KickOrganization.objects.create(
kick_id="smoke-kick-org-1",
name="Smoke Kick Organization",
)
self.kick_category: KickCategory = KickCategory.objects.create(
kick_id=9101,
name="Smoke Kick Category",
slug="smoke-kick-category",
image_url="https://example.com/smoke-kick-category.png",
)
self.kick_campaign: KickDropCampaign = KickDropCampaign.objects.create(
kick_id="smoke-kick-campaign-1",
name="Smoke Kick Campaign",
status="active",
starts_at=now - timedelta(days=1),
ends_at=now + timedelta(days=1),
organization=self.kick_org,
category=self.kick_category,
rule_id=1,
rule_name="Watch to redeem",
is_fully_imported=True,
)
kick_user: KickUser = KickUser.objects.create(
kick_id=990001,
username="smokekickuser",
)
kick_channel: KickChannel = KickChannel.objects.create(
kick_id=990002,
slug="smokekickchannel",
user=kick_user,
)
self.kick_campaign.channels.add(kick_channel)
KickReward.objects.create(
kick_id="smoke-kick-reward-1",
name="Smoke Kick Reward",
image_url="drops/reward-image/smoke-kick-reward.png",
required_units=20,
campaign=self.kick_campaign,
category=self.kick_category,
organization=self.kick_org,
)
# CHZZK fixtures
self.chzzk_campaign: ChzzkCampaign = ChzzkCampaign.objects.create(
campaign_no=9901,
title="Smoke CHZZK Campaign",
description="Smoke CHZZK description",
category_type="game",
category_id="1",
category_value="SmokeGame",
service_id="chzzk",
state="ACTIVE",
start_date=now - timedelta(days=1),
end_date=now + timedelta(days=1),
has_ios_based_reward=False,
drops_campaign_not_started=False,
source_api="unit-test",
raw_json_v1={"ok": True},
)
self.chzzk_campaign.rewards.create( # pyright: ignore[reportAttributeAccessIssue]
reward_no=991,
title="Smoke CHZZK Reward",
reward_type="ITEM",
campaign_reward_type="Standard",
condition_type="watch",
condition_for_minutes=10,
ios_based_reward=False,
code_remaining_count=100,
)
# Core dataset download fixture
self.dataset_dir: Path = settings.DATA_DIR / "datasets"
self.dataset_dir.mkdir(parents=True, exist_ok=True)
self.dataset_name = "smoke-dataset.zst"
(self.dataset_dir / self.dataset_name).write_bytes(b"smoke")
def tearDown(self) -> None:
"""Clean up any files created for testing."""
dataset_path: Path = self.dataset_dir / self.dataset_name
if dataset_path.exists():
dataset_path.unlink()
def test_all_site_endpoints_return_success(self) -> None:
"""Test that all named site endpoints return a successful response with representative data."""
endpoints: list[tuple[str, dict[str, str | int], int]] = [
# Top-level config endpoints
("sitemap", {}, 200),
("sitemap-static", {}, 200),
("sitemap-twitch-channels", {}, 200),
("sitemap-twitch-drops", {}, 200),
("sitemap-twitch-others", {}, 200),
("sitemap-kick", {}, 200),
("sitemap-youtube", {}, 200),
# Core endpoints
("core:dashboard", {}, 200),
("core:search", {}, 200),
("core:debug", {}, 200),
("core:dataset_backups", {}, 200),
("core:dataset_backup_download", {"relative_path": self.dataset_name}, 200),
("core:docs_rss", {}, 200),
("core:campaign_feed", {}, 200),
("core:game_feed", {}, 200),
("core:game_campaign_feed", {"twitch_id": self.twitch_game.twitch_id}, 200),
("core:organization_feed", {}, 200),
("core:reward_campaign_feed", {}, 200),
("core:campaign_feed_atom", {}, 200),
("core:game_feed_atom", {}, 200),
(
"core:game_campaign_feed_atom",
{"twitch_id": self.twitch_game.twitch_id},
200,
),
("core:organization_feed_atom", {}, 200),
("core:reward_campaign_feed_atom", {}, 200),
("core:campaign_feed_discord", {}, 200),
("core:game_feed_discord", {}, 200),
(
"core:game_campaign_feed_discord",
{"twitch_id": self.twitch_game.twitch_id},
200,
),
("core:organization_feed_discord", {}, 200),
("core:reward_campaign_feed_discord", {}, 200),
# Twitch endpoints
("twitch:dashboard", {}, 200),
("twitch:badge_list", {}, 200),
("twitch:badge_set_detail", {"set_id": self.badge_set.set_id}, 200),
("twitch:campaign_list", {}, 200),
(
"twitch:campaign_detail",
{"twitch_id": self.twitch_campaign.twitch_id},
200,
),
("twitch:channel_list", {}, 200),
(
"twitch:channel_detail",
{"twitch_id": self.twitch_channel.twitch_id},
200,
),
("twitch:emote_gallery", {}, 200),
("twitch:games_grid", {}, 200),
("twitch:games_list", {}, 200),
("twitch:game_detail", {"twitch_id": self.twitch_game.twitch_id}, 200),
("twitch:org_list", {}, 200),
(
"twitch:organization_detail",
{"twitch_id": self.twitch_org.twitch_id},
200,
),
("twitch:reward_campaign_list", {}, 200),
(
"twitch:reward_campaign_detail",
{"twitch_id": self.twitch_reward_campaign.twitch_id},
200,
),
("twitch:export_campaigns_csv", {}, 200),
("twitch:export_campaigns_json", {}, 200),
("twitch:export_games_csv", {}, 200),
("twitch:export_games_json", {}, 200),
("twitch:export_organizations_csv", {}, 200),
("twitch:export_organizations_json", {}, 200),
# Kick endpoints
("kick:dashboard", {}, 200),
("kick:campaign_list", {}, 200),
("kick:campaign_detail", {"kick_id": self.kick_campaign.kick_id}, 200),
("kick:game_list", {}, 200),
("kick:game_detail", {"kick_id": self.kick_category.kick_id}, 200),
("kick:category_list", {}, 200),
("kick:category_detail", {"kick_id": self.kick_category.kick_id}, 200),
("kick:organization_list", {}, 200),
("kick:organization_detail", {"kick_id": self.kick_org.kick_id}, 200),
("kick:campaign_feed", {}, 200),
("kick:game_feed", {}, 200),
("kick:game_campaign_feed", {"kick_id": self.kick_category.kick_id}, 200),
("kick:category_feed", {}, 200),
(
"kick:category_campaign_feed",
{"kick_id": self.kick_category.kick_id},
200,
),
("kick:organization_feed", {}, 200),
("kick:campaign_feed_atom", {}, 200),
("kick:game_feed_atom", {}, 200),
(
"kick:game_campaign_feed_atom",
{"kick_id": self.kick_category.kick_id},
200,
),
("kick:category_feed_atom", {}, 200),
(
"kick:category_campaign_feed_atom",
{"kick_id": self.kick_category.kick_id},
200,
),
("kick:organization_feed_atom", {}, 200),
("kick:campaign_feed_discord", {}, 200),
("kick:game_feed_discord", {}, 200),
(
"kick:game_campaign_feed_discord",
{"kick_id": self.kick_category.kick_id},
200,
),
("kick:category_feed_discord", {}, 200),
(
"kick:category_campaign_feed_discord",
{"kick_id": self.kick_category.kick_id},
200,
),
("kick:organization_feed_discord", {}, 200),
# CHZZK endpoints
("chzzk:dashboard", {}, 200),
("chzzk:campaign_list", {}, 200),
(
"chzzk:campaign_detail",
{"campaign_no": self.chzzk_campaign.campaign_no},
200,
),
("chzzk:campaign_feed", {}, 200),
("chzzk:campaign_feed_atom", {}, 200),
("chzzk:campaign_feed_discord", {}, 200),
# YouTube endpoint
("youtube:index", {}, 200),
]
for route_name, kwargs, expected_status in endpoints:
response: _MonkeyPatchedWSGIResponse = self.client.get(
reverse(route_name, kwargs=kwargs),
)
assert response.status_code == expected_status, (
f"{route_name} returned {response.status_code}, expected {expected_status}"
)
response.close()