@@ -43,12 +43,6 @@ def pytest_addoption(parser):
4343 default = str (default_config_path ),
4444 help = "Absolut path to test configuration" ,
4545 )
46- parser .addoption (
47- "--gd-test-token" ,
48- action = "store" ,
49- default = "" ,
50- help = "API token for staging tests" ,
51- )
5246
5347
5448@pytest .fixture (scope = "session" )
@@ -57,10 +51,11 @@ def test_config(request):
5751 with open (config_path ) as f :
5852 config = yaml .safe_load (f )
5953
60- # Override token from CLI argument (staging tests pass it via --gd-test-token)
61- cli_token = request .config .getoption ("--gd-test-token" )
62- if cli_token :
63- config ["token" ] = cli_token
54+ # Override token from TOKEN env var (set by make test-staging TOKEN=...)
55+ if config .get ("staging" , False ):
56+ env_token = os .environ .get ("TOKEN" )
57+ if env_token :
58+ config ["token" ] = env_token
6459
6560 return config
6661
@@ -179,20 +174,47 @@ def staging_preflight(test_config):
179174]
180175
181176
182- def _patch_file_for_staging (file_path : Path ) -> str | None :
183- """Replace local JDBC URL/username with staging values. Returns original content for restore."""
177+ _STAGING_BACKUP_SUFFIX = ".staging-backup"
178+
179+
180+ def _backup_path (file_path : Path ) -> Path :
181+ return file_path .with_suffix (file_path .suffix + _STAGING_BACKUP_SUFFIX )
182+
183+
184+ def _restore_from_backup (file_path : Path ) -> None :
185+ """Restore a file from its backup (left over from a previous interrupted run)."""
186+ backup = _backup_path (file_path )
187+ if backup .exists ():
188+ file_path .write_text (backup .read_text ())
189+ backup .unlink ()
190+ logger .info (f"Restored from stale backup: { file_path } " )
191+
192+
193+ def _patch_file_for_staging (file_path : Path ) -> bool :
194+ """Replace local JDBC URL/username with staging values. Writes backup to disk for crash safety."""
184195 if not file_path .exists ():
185- return None
196+ return False
186197 original = file_path .read_text ()
187198 patched = original .replace (_LOCAL_DS_URL , _STAGING_DS_URL ).replace (
188199 f"username: { _LOCAL_DS_USERNAME } " , f"username: { _STAGING_DS_USERNAME } "
189200 )
190201 # Also handle JSON format (username as a JSON field)
191202 patched = patched .replace (f'"username": "{ _LOCAL_DS_USERNAME } "' , f'"username": "{ _STAGING_DS_USERNAME } "' )
192203 if patched != original :
204+ _backup_path (file_path ).write_text (original )
193205 file_path .write_text (patched )
194206 logger .info (f"Patched for staging: { file_path } " )
195- return original
207+ return True
208+ return False
209+
210+
211+ def _restore_patched_file (file_path : Path ) -> None :
212+ """Restore a file from its backup and remove the backup."""
213+ backup = _backup_path (file_path )
214+ if backup .exists ():
215+ file_path .write_text (backup .read_text ())
216+ backup .unlink ()
217+ logger .info (f"Restored original: { file_path } " )
196218
197219
198220def _find_gooddata_layouts_dirs () -> list [Path ]:
@@ -236,21 +258,21 @@ def staging_patch_fixtures(test_config, staging_preflight):
236258 - Copies gooddata_layouts/default/ -> gooddata_layouts/<org_id>/ so the SDK
237259 can find layout files (it uses the org ID as the directory name)
238260
239- Restores everything on teardown (regardless of test outcome) .
261+ Uses on-disk backups so that interrupted runs self-heal on the next start .
240262 """
263+ # Always restore leftover backups from a previous interrupted run
264+ for fpath in _STAGING_PATCH_FILES :
265+ _restore_from_backup (fpath )
266+
241267 if not test_config .get ("staging" , False ):
242268 yield
243269 return
244270
245271 import shutil
246272
247273 # 1. Patch JDBC connection strings in fixture files
248- originals : dict [Path , str ] = {}
249- for fpath in _STAGING_PATCH_FILES :
250- original = _patch_file_for_staging (fpath )
251- if original is not None :
252- originals [fpath ] = original
253- logger .info (f"Patched { len (originals )} fixture files for staging" )
274+ patched_files = [fpath for fpath in _STAGING_PATCH_FILES if _patch_file_for_staging (fpath )]
275+ logger .info (f"Patched { len (patched_files )} fixture files for staging" )
254276
255277 # 2. Copy layout dirs (gooddata_layouts/default -> gooddata_layouts/<org_id>)
256278 from gooddata_sdk import GoodDataSdk
@@ -262,10 +284,9 @@ def staging_patch_fixtures(test_config, staging_preflight):
262284
263285 yield
264286
265- # Restore file contents
266- for fpath , content in originals .items ():
267- fpath .write_text (content )
268- logger .info (f"Restored original: { fpath } " )
287+ # Restore patched files from backups
288+ for fpath in patched_files :
289+ _restore_patched_file (fpath )
269290
270291 # Remove copied directories
271292 for d in copied_dirs :
0 commit comments