Refactor DropCampaign ACL check and add regression tests for campaign details import
This commit is contained in:
parent
4f254f7cba
commit
9f34641e9b
3 changed files with 335 additions and 3 deletions
265
example.json
Normal file
265
example.json
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
[
|
||||
{
|
||||
"data": {
|
||||
"user": {
|
||||
"id": "17658559",
|
||||
"dropCampaign": {
|
||||
"id": "3b965979-ecd2-11f0-876e-0a58a9feac02",
|
||||
"self": {
|
||||
"isAccountConnected": true,
|
||||
"__typename": "DropCampaignSelfEdge"
|
||||
},
|
||||
"allow": {
|
||||
"channels": null,
|
||||
"isEnabled": false,
|
||||
"__typename": "DropCampaignACL"
|
||||
},
|
||||
"accountLinkURL": "https://link.smite2.com/",
|
||||
"description": "Viewers will receive 50 Wandering Market Coins for each two hours spent viewing participating streams. Watch to earn 7 drops for a total of 350 Wandering Market Coins for the week!",
|
||||
"detailsURL": "https://www.smite2.com/news/closed-alpha-twitch-drops/",
|
||||
"endAt": "2026-01-17T10:58:59.999Z",
|
||||
"eventBasedDrops": [],
|
||||
"game": {
|
||||
"id": "2094865572",
|
||||
"slug": "smite-2",
|
||||
"displayName": "SMITE 2",
|
||||
"__typename": "Game"
|
||||
},
|
||||
"imageURL": "https://static-cdn.jtvnw.net/twitch-quests-assets/CAMPAIGN/47db66e8-933c-484f-ab5a-30ba09093098.png",
|
||||
"name": "Jan Drops Week 2",
|
||||
"owner": {
|
||||
"id": "51a157a0-674a-4863-b120-7bb6ee2466a8",
|
||||
"name": "Hi-Rez Studios",
|
||||
"__typename": "Organization"
|
||||
},
|
||||
"startAt": "2026-01-10T11:00:00Z",
|
||||
"status": "ACTIVE",
|
||||
"timeBasedDrops": [
|
||||
{
|
||||
"id": "933c8f91-ecd2-11f0-b3fd-0a58a9feac02",
|
||||
"requiredSubs": 0,
|
||||
"benefitEdges": [
|
||||
{
|
||||
"benefit": {
|
||||
"id": "ccb3fb7f-e59b-11ef-aef0-0a58a9feac02",
|
||||
"createdAt": "2025-02-07T21:37:58.881Z",
|
||||
"entitlementLimit": 1,
|
||||
"game": {
|
||||
"id": "2094865572",
|
||||
"name": "SMITE 2",
|
||||
"__typename": "Game"
|
||||
},
|
||||
"imageAssetURL": "https://static-cdn.jtvnw.net/twitch-quests-assets/REWARD/903496ad-de97-41ff-ad97-12f099e20ea8.jpeg",
|
||||
"isIosAvailable": false,
|
||||
"name": "Market Coins Bundle 1",
|
||||
"ownerOrganization": {
|
||||
"id": "51a157a0-674a-4863-b120-7bb6ee2466a8",
|
||||
"name": "Hi-Rez Studios",
|
||||
"__typename": "Organization"
|
||||
},
|
||||
"distributionType": "DIRECT_ENTITLEMENT",
|
||||
"__typename": "DropBenefit"
|
||||
},
|
||||
"entitlementLimit": 1,
|
||||
"__typename": "DropBenefitEdge"
|
||||
}
|
||||
],
|
||||
"endAt": "2026-01-17T10:58:59.999Z",
|
||||
"name": "Market Coins Bundle 1",
|
||||
"preconditionDrops": null,
|
||||
"requiredMinutesWatched": 120,
|
||||
"startAt": "2026-01-10T11:00:00Z",
|
||||
"__typename": "TimeBasedDrop"
|
||||
},
|
||||
{
|
||||
"id": "9909373d-ecd2-11f0-92b1-0a58a9feac02",
|
||||
"requiredSubs": 0,
|
||||
"benefitEdges": [
|
||||
{
|
||||
"benefit": {
|
||||
"id": "ccb3fb7f-e59b-11ef-aef0-0a58a9feac02",
|
||||
"createdAt": "2025-02-07T21:37:58.881Z",
|
||||
"entitlementLimit": 1,
|
||||
"game": {
|
||||
"id": "2094865572",
|
||||
"name": "SMITE 2",
|
||||
"__typename": "Game"
|
||||
},
|
||||
"imageAssetURL": "https://static-cdn.jtvnw.net/twitch-quests-assets/REWARD/903496ad-de97-41ff-ad97-12f099e20ea8.jpeg",
|
||||
"isIosAvailable": false,
|
||||
"name": "Market Coins Bundle 1",
|
||||
"ownerOrganization": {
|
||||
"id": "51a157a0-674a-4863-b120-7bb6ee2466a8",
|
||||
"name": "Hi-Rez Studios",
|
||||
"__typename": "Organization"
|
||||
},
|
||||
"distributionType": "DIRECT_ENTITLEMENT",
|
||||
"__typename": "DropBenefit"
|
||||
},
|
||||
"entitlementLimit": 1,
|
||||
"__typename": "DropBenefitEdge"
|
||||
}
|
||||
],
|
||||
"endAt": "2026-01-17T10:58:59.999Z",
|
||||
"name": "Market Coins Bundle 2",
|
||||
"preconditionDrops": null,
|
||||
"requiredMinutesWatched": 240,
|
||||
"startAt": "2026-01-10T11:00:00Z",
|
||||
"__typename": "TimeBasedDrop"
|
||||
},
|
||||
{
|
||||
"id": "a5289489-ecd2-11f0-b098-0a58a9feac02",
|
||||
"requiredSubs": 0,
|
||||
"benefitEdges": [
|
||||
{
|
||||
"benefit": {
|
||||
"id": "ccb3fb7f-e59b-11ef-aef0-0a58a9feac02",
|
||||
"createdAt": "2025-02-07T21:37:58.881Z",
|
||||
"entitlementLimit": 1,
|
||||
"game": {
|
||||
"id": "2094865572",
|
||||
"name": "SMITE 2",
|
||||
"__typename": "Game"
|
||||
},
|
||||
"imageAssetURL": "https://static-cdn.jtvnw.net/twitch-quests-assets/REWARD/903496ad-de97-41ff-ad97-12f099e20ea8.jpeg",
|
||||
"isIosAvailable": false,
|
||||
"name": "Market Coins Bundle 1",
|
||||
"ownerOrganization": {
|
||||
"id": "51a157a0-674a-4863-b120-7bb6ee2466a8",
|
||||
"name": "Hi-Rez Studios",
|
||||
"__typename": "Organization"
|
||||
},
|
||||
"distributionType": "DIRECT_ENTITLEMENT",
|
||||
"__typename": "DropBenefit"
|
||||
},
|
||||
"entitlementLimit": 1,
|
||||
"__typename": "DropBenefitEdge"
|
||||
}
|
||||
],
|
||||
"endAt": "2026-01-17T10:58:59.999Z",
|
||||
"name": "Market Coins Bundle 3",
|
||||
"preconditionDrops": null,
|
||||
"requiredMinutesWatched": 360,
|
||||
"startAt": "2026-01-10T11:00:00Z",
|
||||
"__typename": "TimeBasedDrop"
|
||||
},
|
||||
{
|
||||
"id": "ab5ea171-ecd2-11f0-9e33-0a58a9feac02",
|
||||
"requiredSubs": 0,
|
||||
"benefitEdges": [
|
||||
{
|
||||
"benefit": {
|
||||
"id": "ccb3fb7f-e59b-11ef-aef0-0a58a9feac02",
|
||||
"createdAt": "2025-02-07T21:37:58.881Z",
|
||||
"entitlementLimit": 1,
|
||||
"game": {
|
||||
"id": "2094865572",
|
||||
"name": "SMITE 2",
|
||||
"__typename": "Game"
|
||||
},
|
||||
"imageAssetURL": "https://static-cdn.jtvnw.net/twitch-quests-assets/REWARD/903496ad-de97-41ff-ad97-12f099e20ea8.jpeg",
|
||||
"isIosAvailable": false,
|
||||
"name": "Market Coins Bundle 1",
|
||||
"ownerOrganization": {
|
||||
"id": "51a157a0-674a-4863-b120-7bb6ee2466a8",
|
||||
"name": "Hi-Rez Studios",
|
||||
"__typename": "Organization"
|
||||
},
|
||||
"distributionType": "DIRECT_ENTITLEMENT",
|
||||
"__typename": "DropBenefit"
|
||||
},
|
||||
"entitlementLimit": 1,
|
||||
"__typename": "DropBenefitEdge"
|
||||
}
|
||||
],
|
||||
"endAt": "2026-01-17T10:58:59.999Z",
|
||||
"name": "Market Coins Bundle 4",
|
||||
"preconditionDrops": null,
|
||||
"requiredMinutesWatched": 480,
|
||||
"startAt": "2026-01-10T11:00:00Z",
|
||||
"__typename": "TimeBasedDrop"
|
||||
},
|
||||
{
|
||||
"id": "b19b7afb-ecd2-11f0-bbd3-0a58a9feac02",
|
||||
"requiredSubs": 0,
|
||||
"benefitEdges": [
|
||||
{
|
||||
"benefit": {
|
||||
"id": "ccb3fb7f-e59b-11ef-aef0-0a58a9feac02",
|
||||
"createdAt": "2025-02-07T21:37:58.881Z",
|
||||
"entitlementLimit": 1,
|
||||
"game": {
|
||||
"id": "2094865572",
|
||||
"name": "SMITE 2",
|
||||
"__typename": "Game"
|
||||
},
|
||||
"imageAssetURL": "https://static-cdn.jtvnw.net/twitch-quests-assets/REWARD/903496ad-de97-41ff-ad97-12f099e20ea8.jpeg",
|
||||
"isIosAvailable": false,
|
||||
"name": "Market Coins Bundle 1",
|
||||
"ownerOrganization": {
|
||||
"id": "51a157a0-674a-4863-b120-7bb6ee2466a8",
|
||||
"name": "Hi-Rez Studios",
|
||||
"__typename": "Organization"
|
||||
},
|
||||
"distributionType": "DIRECT_ENTITLEMENT",
|
||||
"__typename": "DropBenefit"
|
||||
},
|
||||
"entitlementLimit": 1,
|
||||
"__typename": "DropBenefitEdge"
|
||||
}
|
||||
],
|
||||
"endAt": "2026-01-17T10:58:59.999Z",
|
||||
"name": "Market Coins Bundle 5",
|
||||
"preconditionDrops": null,
|
||||
"requiredMinutesWatched": 600,
|
||||
"startAt": "2026-01-10T11:00:00Z",
|
||||
"__typename": "TimeBasedDrop"
|
||||
},
|
||||
{
|
||||
"id": "b82db8e0-ecd2-11f0-8c96-0a58a9feac02",
|
||||
"requiredSubs": 0,
|
||||
"benefitEdges": [
|
||||
{
|
||||
"benefit": {
|
||||
"id": "ccb3fb7f-e59b-11ef-aef0-0a58a9feac02",
|
||||
"createdAt": "2025-02-07T21:37:58.881Z",
|
||||
"entitlementLimit": 1,
|
||||
"game": {
|
||||
"id": "2094865572",
|
||||
"name": "SMITE 2",
|
||||
"__typename": "Game"
|
||||
},
|
||||
"imageAssetURL": "https://static-cdn.jtvnw.net/twitch-quests-assets/REWARD/903496ad-de97-41ff-ad97-12f099e20ea8.jpeg",
|
||||
"isIosAvailable": false,
|
||||
"name": "Market Coins Bundle 1",
|
||||
"ownerOrganization": {
|
||||
"id": "51a157a0-674a-4863-b120-7bb6ee2466a8",
|
||||
"name": "Hi-Rez Studios",
|
||||
"__typename": "Organization"
|
||||
},
|
||||
"distributionType": "DIRECT_ENTITLEMENT",
|
||||
"__typename": "DropBenefit"
|
||||
},
|
||||
"entitlementLimit": 1,
|
||||
"__typename": "DropBenefitEdge"
|
||||
}
|
||||
],
|
||||
"endAt": "2026-01-17T10:58:59.999Z",
|
||||
"name": "Market Coins Bundle 6",
|
||||
"preconditionDrops": null,
|
||||
"requiredMinutesWatched": 720,
|
||||
"startAt": "2026-01-10T11:00:00Z",
|
||||
"__typename": "TimeBasedDrop"
|
||||
}
|
||||
],
|
||||
"__typename": "DropCampaign"
|
||||
},
|
||||
"__typename": "User"
|
||||
}
|
||||
},
|
||||
"extensions": {
|
||||
"durationMilliseconds": 48,
|
||||
"operationName": "DropCampaignDetails"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -694,7 +694,7 @@ class Command(BaseCommand):
|
|||
)
|
||||
|
||||
# Process allowed channels from the campaign's ACL
|
||||
if drop_campaign.allow and drop_campaign.allow.channels:
|
||||
if drop_campaign.allow:
|
||||
self._process_allowed_channels(
|
||||
campaign_obj=campaign_obj,
|
||||
allow_schema=drop_campaign.allow,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
|
|
@ -7,15 +8,16 @@ from django.test import TestCase
|
|||
|
||||
from twitch.management.commands.better_import_drops import Command
|
||||
from twitch.models import Channel
|
||||
from twitch.models import DropBenefit
|
||||
from twitch.models import DropCampaign
|
||||
from twitch.models import Game
|
||||
from twitch.models import Organization
|
||||
from twitch.models import TimeBasedDrop
|
||||
from twitch.schemas import DropBenefitSchema
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from debug_toolbar.panels.templates.panel import QuerySet
|
||||
|
||||
from twitch.models import DropBenefit
|
||||
|
||||
|
||||
class GetOrUpdateBenefitTests(TestCase):
|
||||
"""Tests for the _get_or_update_benefit method in better_import_drops.Command."""
|
||||
|
|
@ -540,3 +542,68 @@ class GameImportTests(TestCase):
|
|||
game = Game.objects.get(twitch_id="497057")
|
||||
assert game.slug == "destiny-2"
|
||||
assert game.display_name == "Destiny 2"
|
||||
|
||||
|
||||
class ExampleJsonImportTests(TestCase):
|
||||
"""Regression tests based on the real-world `example.json` payload."""
|
||||
|
||||
def test_imports_drop_campaign_details_and_persists_urls(self) -> None:
|
||||
"""Ensure `imageURL` and other URL-ish fields are persisted from DropCampaignDetails."""
|
||||
command = Command()
|
||||
command.pre_fill_cache()
|
||||
|
||||
repo_root: Path = Path(__file__).resolve().parents[2]
|
||||
example_path: Path = repo_root / "example.json"
|
||||
|
||||
responses = json.loads(example_path.read_text(encoding="utf-8"))
|
||||
|
||||
success, broken_dir = command.process_responses(
|
||||
responses=responses,
|
||||
file_path=example_path,
|
||||
options={},
|
||||
)
|
||||
|
||||
assert success is True
|
||||
assert broken_dir is None
|
||||
|
||||
campaign: DropCampaign = DropCampaign.objects.get(twitch_id="3b965979-ecd2-11f0-876e-0a58a9feac02")
|
||||
|
||||
# Core campaign fields
|
||||
assert campaign.name == "Jan Drops Week 2"
|
||||
assert "Viewers will receive 50 Wandering Market Coins" in campaign.description
|
||||
assert campaign.details_url == "https://www.smite2.com/news/closed-alpha-twitch-drops/"
|
||||
assert campaign.account_link_url == "https://link.smite2.com/"
|
||||
|
||||
# The regression: ensure imageURL makes it into DropCampaign.image_url
|
||||
assert (
|
||||
campaign.image_url
|
||||
== "https://static-cdn.jtvnw.net/twitch-quests-assets/CAMPAIGN/47db66e8-933c-484f-ab5a-30ba09093098.png"
|
||||
)
|
||||
|
||||
# Allow ACL normalization
|
||||
assert campaign.allow_is_enabled is False
|
||||
assert campaign.allow_channels.count() == 0
|
||||
|
||||
# Operation name provenance
|
||||
assert campaign.operation_name == "DropCampaignDetails"
|
||||
|
||||
# Related game/org normalization
|
||||
game: Game = Game.objects.get(twitch_id="2094865572")
|
||||
assert game.display_name == "SMITE 2"
|
||||
assert game.slug == "smite-2"
|
||||
|
||||
org: Organization = Organization.objects.get(twitch_id="51a157a0-674a-4863-b120-7bb6ee2466a8")
|
||||
assert org.name == "Hi-Rez Studios"
|
||||
assert game.owners.filter(pk=org.pk).exists()
|
||||
|
||||
# Drops + benefits
|
||||
assert TimeBasedDrop.objects.filter(campaign=campaign).count() == 6
|
||||
first_drop: TimeBasedDrop = TimeBasedDrop.objects.get(twitch_id="933c8f91-ecd2-11f0-b3fd-0a58a9feac02")
|
||||
assert first_drop.name == "Market Coins Bundle 1"
|
||||
assert first_drop.required_minutes_watched == 120
|
||||
assert DropBenefit.objects.count() == 1
|
||||
benefit: DropBenefit = DropBenefit.objects.get(twitch_id="ccb3fb7f-e59b-11ef-aef0-0a58a9feac02")
|
||||
assert (
|
||||
benefit.image_asset_url
|
||||
== "https://static-cdn.jtvnw.net/twitch-quests-assets/REWARD/903496ad-de97-41ff-ad97-12f099e20ea8.jpeg"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue