@@ -19,6 +19,7 @@ const COMMON_INST_ARGS: &[&str] = &["--label=bootc.test=1"];
1919
2020// Metadata field names
2121const FIELD_TRY_BIND_STORAGE : & str = "try_bind_storage" ;
22+ const FIELD_EXPORT_IMAGE : & str = "export_image" ;
2223const FIELD_SUMMARY : & str = "summary" ;
2324const FIELD_ADJUST : & str = "adjust" ;
2425const FIELD_ENABLED : & str = "enabled" ;
@@ -38,6 +39,7 @@ const RUST_TESTS_COMMAND: &str = "bootc-integration-tests booted";
3839const BCVK_OPT_BIND_STORAGE_RO : & str = "--bind-storage-ro" ;
3940const ENV_BOOTC_UPGRADE_IMAGE : & str = "BOOTC_upgrade_image" ;
4041const ENV_BOOTC_BRIDGE_IMAGE : & str = "BOOTC_bridge_image" ;
42+ const ENV_BOOTC_SOURCE_IMAGE_ARCHIVE : & str = "BOOTC_source_image_archive" ;
4143
4244// Distro identifiers
4345const DISTRO_CENTOS_9 : & str = "centos-9" ;
@@ -272,12 +274,13 @@ fn verify_ssh_connectivity(sh: &Shell, port: u16, key_path: &Utf8Path) -> Result
272274#[ derive( Debug , Default ) ]
273275struct PlanMetadata {
274276 try_bind_storage : bool ,
277+ export_image : bool ,
275278 skip_if_composefs : bool ,
276279 skip_if_ostree : bool ,
277280 skip_if_uki : bool ,
278281}
279282
280- /// Parse integration.fmf to extract extra-try_bind_storage for all plans
283+ /// Parse integration.fmf to extract harness metadata for all plans.
281284#[ context( "Parsing integration.fmf" ) ]
282285fn parse_plan_metadata (
283286 plans_file : & Utf8Path ,
@@ -305,6 +308,18 @@ fn parse_plan_metadata(
305308 continue ;
306309 } ;
307310
311+ if let Some ( export_image) = plan_data
312+ . get ( serde_yaml:: Value :: String ( format ! (
313+ "extra-{FIELD_EXPORT_IMAGE}"
314+ ) ) )
315+ . and_then ( |v| v. as_bool ( ) )
316+ {
317+ plan_metadata
318+ . entry ( plan_name. to_string ( ) )
319+ . or_default ( )
320+ . export_image = export_image;
321+ }
322+
308323 if let Some ( try_bind) = plan_data. get ( & serde_yaml:: Value :: String ( format ! (
309324 "extra-{}" ,
310325 FIELD_TRY_BIND_STORAGE
@@ -550,6 +565,34 @@ pub(crate) fn run_tmt(sh: &Shell, args: &RunTmtArgs) -> Result<()> {
550565 // Reset plan-specific environment variables
551566 tmt_env_vars. clear ( ) ;
552567
568+ let _source_archive = if plan_metadata
569+ . iter ( )
570+ . find ( |( key, _) | plan. ends_with ( key. as_str ( ) ) )
571+ . is_some_and ( |( _, metadata) | metadata. export_image )
572+ {
573+ let fixture = tempfile:: Builder :: new ( )
574+ . prefix ( "bootc-source-" )
575+ . tempdir_in ( sh. current_dir ( ) . join ( "tmt/tests" ) ) ?;
576+ let fixture_path = Utf8Path :: from_path ( fixture. path ( ) )
577+ . context ( "Converting image fixture path to UTF-8" ) ?;
578+ let archive = fixture_path. join ( "image.oci.tar" ) ;
579+ cmd ! (
580+ sh,
581+ "podman save -q --format oci-archive -o {archive} {image}"
582+ )
583+ . run ( )
584+ . context ( "Exporting test source image" ) ?;
585+ let fixture_name = fixture_path
586+ . file_name ( )
587+ . context ( "Image fixture directory name" ) ?;
588+ tmt_env_vars. push ( format ! (
589+ "{ENV_BOOTC_SOURCE_IMAGE_ARCHIVE}={fixture_name}/image.oci.tar"
590+ ) ) ;
591+ Some ( fixture)
592+ } else {
593+ None
594+ } ;
595+
553596 // Get bcvk-opts based on plan metadata and distro support
554597 let plan_bcvk_opts = {
555598 let supports_bind_storage_ro = distro_supports_bind_storage_ro ( & distro) ;
@@ -1050,6 +1093,7 @@ struct TestDef {
10501093 test_command : String ,
10511094 /// Whether this test wants to try bind storage (if distro supports it)
10521095 try_bind_storage : bool ,
1096+ export_image : bool ,
10531097 /// Whether to skip this test for composefs backend
10541098 skip_if_composefs : bool ,
10551099 /// Whether to skip this test for ostree backend
@@ -1238,6 +1282,12 @@ fn generate_integration() -> Result<(String, String)> {
12381282 . and_then ( |v| v. as_bool ( ) )
12391283 . unwrap_or ( false ) ;
12401284
1285+ let export_image = metadata
1286+ . extra
1287+ . get ( FIELD_EXPORT_IMAGE )
1288+ . and_then ( |v| v. as_bool ( ) )
1289+ . unwrap_or ( false ) ;
1290+
12411291 let skip_if_ostree = metadata
12421292 . extra
12431293 . as_mapping ( )
@@ -1261,6 +1311,7 @@ fn generate_integration() -> Result<(String, String)> {
12611311 name : display_name,
12621312 test_command,
12631313 try_bind_storage,
1314+ export_image,
12641315 skip_if_composefs,
12651316 skip_if_ostree,
12661317 skip_if_uki,
@@ -1385,6 +1436,22 @@ fn generate_integration() -> Result<(String, String)> {
13851436 ) ;
13861437 }
13871438
1439+ if test. export_image {
1440+ plan_value. insert (
1441+ serde_yaml:: Value :: String ( format ! ( "extra-{FIELD_EXPORT_IMAGE}" ) ) ,
1442+ serde_yaml:: Value :: Bool ( true ) ,
1443+ ) ;
1444+ let mut environment = serde_yaml:: Mapping :: new ( ) ;
1445+ environment. insert (
1446+ serde_yaml:: Value :: String ( ENV_BOOTC_SOURCE_IMAGE_ARCHIVE . to_string ( ) ) ,
1447+ serde_yaml:: Value :: String ( "/sysroot/bootc-source.oci.tar" . to_string ( ) ) ,
1448+ ) ;
1449+ plan_value. insert (
1450+ serde_yaml:: Value :: String ( "environment" . to_string ( ) ) ,
1451+ serde_yaml:: Value :: Mapping ( environment) ,
1452+ ) ;
1453+ }
1454+
13881455 if test. skip_if_composefs {
13891456 plan_value. insert (
13901457 serde_yaml:: Value :: String ( format ! ( "extra-{}" , FIELD_FIXME_SKIP_IF_COMPOSEFS ) ) ,
@@ -1614,4 +1681,23 @@ use anyhow::Result;
16141681
16151682 assert ! ( parse_tmt_metadata( content, "#" ) . unwrap( ) . is_none( ) ) ;
16161683 }
1684+
1685+ #[ test]
1686+ fn test_parse_plan_image_export ( ) -> Result < ( ) > {
1687+ let file = tempfile:: NamedTempFile :: new ( ) ?;
1688+ let path = Utf8Path :: from_path ( file. path ( ) ) . unwrap ( ) ;
1689+ for ( value, expected) in [ ( "true" , true ) , ( "false" , false ) , ( "invalid" , false ) ] {
1690+ std:: fs:: write (
1691+ path,
1692+ format ! (
1693+ "/plan-51-switch-from-delta:\n extra-export_image: {value}\n extra-try_bind_storage: true\n "
1694+ ) ,
1695+ ) ?;
1696+ let plans = parse_plan_metadata ( path) ?;
1697+ let plan = & plans[ "/plan-51-switch-from-delta" ] ;
1698+ assert_eq ! ( plan. export_image, expected) ;
1699+ assert ! ( plan. try_bind_storage) ;
1700+ }
1701+ Ok ( ( ) )
1702+ }
16171703}
0 commit comments