@@ -26,6 +26,9 @@ def make_args(**overrides):
2626 "skip_preflight" : False ,
2727 "preflight_strict" : False ,
2828 "preflight_report" : "build/preflight-report.json" ,
29+ "enable_snapshots" : False ,
30+ "snapshot_dir" : None ,
31+ "rollback_to_snapshot" : None ,
2932 }
3033 base .update (overrides )
3134 return Namespace (** base )
@@ -174,3 +177,75 @@ def test_execute_porting_strict_preflight_treats_risks_as_failures():
174177
175178 assert execute_porting (args , logger ) == 2
176179 run_preflight_mock .return_value .has_failures .assert_called_once_with (strict = True )
180+
181+
182+ def test_execute_porting_restores_snapshot_and_exits ():
183+ logger = MagicMock ()
184+ args = make_args (rollback_to_snapshot = "phase3_modified" )
185+
186+ with (
187+ patch ("src.app.workflow.initialize_cache_manager" ) as bootstrap ,
188+ patch ("src.app.workflow.log_run_configuration" ),
189+ patch ("src.app.workflow.OtaToolsManager" ) as otatools_manager_cls ,
190+ patch ("src.app.workflow.resolve_remote_inputs" ),
191+ patch ("src.app.workflow.StageSnapshotManager" ) as snapshot_manager_cls ,
192+ patch ("src.app.workflow.resolve_work_paths" ) as resolve_work_paths ,
193+ ):
194+ bootstrap .return_value .exit_code = None
195+ bootstrap .return_value .cache_manager = None
196+ otatools_manager_cls .return_value .ensure_otatools .return_value = True
197+ resolve_work_paths .return_value = (
198+ MagicMock (),
199+ MagicMock (),
200+ MagicMock (),
201+ MagicMock (),
202+ )
203+
204+ assert execute_porting (args , logger ) == 0
205+
206+ snapshot_manager_cls .return_value .restore .assert_called_once ()
207+
208+
209+ def test_execute_porting_captures_snapshots_when_enabled ():
210+ logger = MagicMock ()
211+ args = make_args (enable_snapshots = True )
212+
213+ with (
214+ patch ("src.app.workflow.initialize_cache_manager" ) as bootstrap ,
215+ patch ("src.app.workflow.log_run_configuration" ),
216+ patch ("src.app.workflow.OtaToolsManager" ) as otatools_manager_cls ,
217+ patch ("src.app.workflow.resolve_remote_inputs" ),
218+ patch ("src.app.workflow.run_preflight" ) as run_preflight_mock ,
219+ patch ("src.app.workflow.save_preflight_report" ),
220+ patch ("src.app.workflow.StageSnapshotManager" ) as snapshot_manager_cls ,
221+ patch ("src.app.workflow.resolve_work_paths" ) as resolve_work_paths ,
222+ patch ("src.app.workflow.RomPackage" ) as rom_package_cls ,
223+ patch ("src.app.workflow.PortingContext" ) as porting_context_cls ,
224+ patch ("src.app.workflow.load_device_config" , return_value = {}),
225+ patch ("src.app.workflow.determine_pack_settings" , return_value = ("payload" , "erofs" )),
226+ patch ("src.app.workflow.run_modification_phases" ),
227+ patch ("src.app.workflow.run_repacking" ),
228+ ):
229+ bootstrap .return_value .exit_code = None
230+ bootstrap .return_value .cache_manager = None
231+ otatools_manager_cls .return_value .ensure_otatools .return_value = True
232+ run_preflight_mock .return_value .has_failures .return_value = False
233+ resolve_work_paths .return_value = (
234+ MagicMock (),
235+ MagicMock (),
236+ MagicMock (),
237+ MagicMock (),
238+ )
239+ stock = rom_package_cls .return_value
240+ porting_context = porting_context_cls .return_value
241+ porting_context .stock = stock
242+ porting_context .device_config = {}
243+
244+ assert execute_porting (args , logger ) == 0
245+
246+ capture_calls = snapshot_manager_cls .return_value .capture .call_args_list
247+ assert [call .args [0 ] for call in capture_calls ] == [
248+ "phase2_initialized" ,
249+ "phase3_modified" ,
250+ "phase4_repacked" ,
251+ ]
0 commit comments