11"""Discovery-stage tests for licensed resource filtering."""
22
33import asyncio
4+ import time
45from types import SimpleNamespace
56from unittest .mock import AsyncMock , MagicMock , patch
67
78import httpx
89import pytest
910
1011from redfetch import sync_discovery as discovery
12+ from redfetch import sync_planner as planner
13+ from redfetch .sync_types import (
14+ DesiredInstallTarget ,
15+ DesiredSet ,
16+ LocalSnapshot ,
17+ RemoteArtifact ,
18+ RemoteResourceState ,
19+ RemoteSnapshot ,
20+ )
21+
22+ FAR_FUTURE = int (time .time ()) + 86400 * 365 * 10
23+ PAST = int (time .time ()) - 86400 * 30
1124
1225
1326def make_license (
@@ -17,11 +30,12 @@ def make_license(
1730 * ,
1831 version_id : int = 101 ,
1932 file_id : int = 1001 ,
33+ end_date : int = FAR_FUTURE ,
2034) -> dict :
2135 return {
2236 "active" : True ,
23- "start_date" : "2024-01-01" ,
24- "end_date" : "2025-01-01" ,
37+ "start_date" : 1711170000 ,
38+ "end_date" : end_date ,
2539 "license_id" : 12345 ,
2640 "resource" : {
2741 "resource_id" : resource_id ,
@@ -109,3 +123,116 @@ def test_cross_compatible_licensed_resources_remain_in_scope(env, category_id, r
109123 target_key = f"/{ resource_id } /"
110124 assert target_key in desired_set .install_targets
111125 assert desired_set .install_targets [target_key ].sources == {"licensed" }
126+
127+
128+ # --- expired license discovery tests ---
129+
130+
131+ def test_expired_license_gets_discovery_block ():
132+ desired_set = asyncio .run (
133+ _discover_from_licenses ([make_license (9998 , 8 , end_date = PAST )], "LIVE" )
134+ )
135+ target = desired_set .install_targets ["/9998/" ]
136+ assert target .sources == {"licensed" }
137+ assert target .discovery_block == "license_expired"
138+
139+
140+ def test_valid_license_has_no_discovery_block ():
141+ desired_set = asyncio .run (
142+ _discover_from_licenses ([make_license (9998 , 8 , end_date = FAR_FUTURE )], "LIVE" )
143+ )
144+ target = desired_set .install_targets ["/9998/" ]
145+ assert target .sources == {"licensed" }
146+ assert target .discovery_block is None
147+
148+
149+ def test_unlimited_license_has_no_discovery_block ():
150+ desired_set = asyncio .run (
151+ _discover_from_licenses ([make_license (9998 , 8 , end_date = 0 )], "LIVE" )
152+ )
153+ target = desired_set .install_targets ["/9998/" ]
154+ assert target .sources == {"licensed" }
155+ assert target .discovery_block is None
156+
157+
158+ # --- expired license planner tests ---
159+
160+
161+ def _downloadable_state (resource_id : str , * , category_id : int = 8 ) -> RemoteResourceState :
162+ return RemoteResourceState (
163+ resource_id = resource_id ,
164+ title = f"Resource { resource_id } " ,
165+ category_id = category_id ,
166+ version_id = 1234 ,
167+ status = "downloadable" ,
168+ artifact = RemoteArtifact (
169+ file_id = 9876 ,
170+ filename = f"{ resource_id } .zip" ,
171+ download_url = f"https://example.com/{ resource_id } .zip" ,
172+ file_hash = "d41d8cd98f00b204e9800998ecf8427e" ,
173+ ),
174+ source_note = "manifest_plus_access_check" ,
175+ )
176+
177+
178+ def _build_plan_for_target (target , remote_state ):
179+ mock_settings = MagicMock ()
180+ mock_settings .ENV = "LIVE"
181+ mock_settings .from_env .return_value = SimpleNamespace (
182+ DOWNLOAD_FOLDER = "C:/downloads" ,
183+ SPECIAL_RESOURCES = {},
184+ PROTECTED_FILES_BY_RESOURCE = {},
185+ )
186+ desired_set = DesiredSet (
187+ mode = "full" ,
188+ resource_ids = {target .resource_id },
189+ install_targets = {target .target_key : target },
190+ )
191+ with patch ("redfetch.sync_planner.config.settings" , mock_settings ), \
192+ patch ("redfetch.sync_planner.config.CATEGORY_MAP" , {8 : "macros" , 11 : "plugins" , 25 : "lua" }):
193+ return planner .build_execution_plan (
194+ desired_set = desired_set ,
195+ remote_snapshot = RemoteSnapshot (resources = {target .resource_id : remote_state }),
196+ local_snapshot = LocalSnapshot (),
197+ settings_env = "LIVE" ,
198+ )
199+
200+
201+ def test_planner_blocks_on_discovery_block ():
202+ target = DesiredInstallTarget (
203+ target_key = "/9998/" ,
204+ resource_id = "9998" ,
205+ parent_id = None ,
206+ parent_target_key = None ,
207+ root_resource_id = "9998" ,
208+ target_kind = "root" ,
209+ sources = {"licensed" },
210+ title = "Expired Resource" ,
211+ category_id = 8 ,
212+ resolved_path = "C:/downloads/9998" ,
213+ discovery_block = "license_expired" ,
214+ )
215+ plan = _build_plan_for_target (target , _downloadable_state ("9998" ))
216+ action = plan .actions ["/9998/" ]
217+ assert action .action == "block"
218+ assert action .reason == "license_expired"
219+
220+
221+ def test_planner_blocks_discovery_block_even_when_watching ():
222+ target = DesiredInstallTarget (
223+ target_key = "/9998/" ,
224+ resource_id = "9998" ,
225+ parent_id = None ,
226+ parent_target_key = None ,
227+ root_resource_id = "9998" ,
228+ target_kind = "root" ,
229+ sources = {"watching" , "licensed" },
230+ title = "Watched + Expired Resource" ,
231+ category_id = 8 ,
232+ resolved_path = "C:/downloads/9998" ,
233+ discovery_block = "license_expired" ,
234+ )
235+ plan = _build_plan_for_target (target , _downloadable_state ("9998" ))
236+ action = plan .actions ["/9998/" ]
237+ assert action .action == "block"
238+ assert action .reason == "license_expired"
0 commit comments