1616
1717use camino:: Utf8PathBuf ;
1818use color_eyre:: Result ;
19- use integration_tests:: integration_test;
19+ use integration_tests:: { integration_test, parameterized_integration_test } ;
2020
2121use std:: process:: Command ;
2222use tempfile:: TempDir ;
2323
24- use crate :: { get_test_image, run_bcvk, INTEGRATION_TEST_LABEL } ;
24+ use crate :: { get_test_image, run_bcvk, CapturedOutput , INTEGRATION_TEST_LABEL } ;
25+
26+ /// Validate that a disk image was created successfully with proper bootc installation
27+ ///
28+ /// This helper function verifies:
29+ /// - The disk image file exists and has non-zero size
30+ /// - The disk has valid partition table (using sfdisk, only for raw images)
31+ /// - The installation completed successfully (from output messages)
32+ ///
33+ /// Note: sfdisk can only read partition tables from raw disk images, not qcow2.
34+ /// For qcow2 images, partition validation is skipped.
35+ fn validate_disk_image (
36+ disk_path : & Utf8PathBuf ,
37+ output : & CapturedOutput ,
38+ context : & str ,
39+ ) -> Result < ( ) > {
40+ let metadata = std:: fs:: metadata ( disk_path) . expect ( "Failed to get disk metadata" ) ;
41+ assert ! ( metadata. len( ) > 0 , "{}: Disk image is empty" , context) ;
42+
43+ // Only verify partitions for raw images - sfdisk can't read qcow2 format
44+ let is_qcow2 = disk_path. as_str ( ) . ends_with ( ".qcow2" ) ;
45+ if !is_qcow2 {
46+ // Verify the disk has partitions using sfdisk -l
47+ let sfdisk_output = Command :: new ( "sfdisk" )
48+ . arg ( "-l" )
49+ . arg ( disk_path. as_str ( ) )
50+ . output ( )
51+ . expect ( "Failed to run sfdisk" ) ;
52+
53+ let sfdisk_stdout = String :: from_utf8_lossy ( & sfdisk_output. stdout ) ;
54+
55+ assert ! (
56+ sfdisk_output. status. success( ) ,
57+ "{}: sfdisk failed with exit code: {:?}" ,
58+ context,
59+ sfdisk_output. status. code( )
60+ ) ;
61+
62+ assert ! (
63+ sfdisk_stdout. contains( "Disk " )
64+ && ( sfdisk_stdout. contains( "sectors" ) || sfdisk_stdout. contains( "bytes" ) ) ,
65+ "{}: sfdisk output doesn't show expected disk information" ,
66+ context
67+ ) ;
68+
69+ let has_partitions = sfdisk_stdout. lines ( ) . any ( |line| {
70+ line. contains ( disk_path. as_str ( ) ) && ( line. contains ( "Linux" ) || line. contains ( "EFI" ) )
71+ } ) ;
72+
73+ assert ! (
74+ has_partitions,
75+ "{}: No bootc partitions found in sfdisk output. Output was:\n {}" ,
76+ context, sfdisk_stdout
77+ ) ;
78+ }
79+
80+ assert ! (
81+ output. stdout. contains( "Installation complete" ) || output. stderr. contains( "Installation complete" ) ,
82+ "{}: No 'Installation complete' message found in output. This indicates bootc install did not complete successfully. stdout: {}, stderr: {}" ,
83+ context,
84+ output. stdout, output. stderr
85+ ) ;
86+
87+ Ok ( ( ) )
88+ }
2589
2690/// Test actual bootc installation to a disk image
2791fn test_to_disk ( ) -> Result < ( ) > {
@@ -45,45 +109,7 @@ fn test_to_disk() -> Result<()> {
45109 output. stderr
46110 ) ;
47111
48- let metadata = std:: fs:: metadata ( & disk_path) . expect ( "Failed to get disk metadata" ) ;
49- assert ! ( metadata. len( ) > 0 ) ;
50-
51- // Verify the disk has partitions using sfdisk -l
52- let sfdisk_output = Command :: new ( "sfdisk" )
53- . arg ( "-l" )
54- . arg ( disk_path. as_str ( ) )
55- . output ( )
56- . expect ( "Failed to run sfdisk" ) ;
57-
58- let sfdisk_stdout = String :: from_utf8_lossy ( & sfdisk_output. stdout ) ;
59-
60- assert ! (
61- sfdisk_output. status. success( ) ,
62- "sfdisk failed with exit code: {:?}" ,
63- sfdisk_output. status. code( )
64- ) ;
65-
66- assert ! (
67- sfdisk_stdout. contains( "Disk " )
68- && ( sfdisk_stdout. contains( "sectors" ) || sfdisk_stdout. contains( "bytes" ) ) ,
69- "sfdisk output doesn't show expected disk information"
70- ) ;
71-
72- let has_partitions = sfdisk_stdout. lines ( ) . any ( |line| {
73- line. contains ( disk_path. as_str ( ) ) && ( line. contains ( "Linux" ) || line. contains ( "EFI" ) )
74- } ) ;
75-
76- assert ! (
77- has_partitions,
78- "No bootc partitions found in sfdisk output. Output was:\n {}" ,
79- sfdisk_stdout
80- ) ;
81-
82- assert ! (
83- output. stdout. contains( "Installation complete" ) || output. stderr. contains( "Installation complete" ) ,
84- "No 'Installation complete' message found in output. This indicates bootc install did not complete successfully. stdout: {}, stderr: {}" ,
85- output. stdout, output. stderr
86- ) ;
112+ validate_disk_image ( & disk_path, & output, "test_to_disk" ) ?;
87113 Ok ( ( ) )
88114}
89115integration_test ! ( test_to_disk) ;
@@ -111,9 +137,6 @@ fn test_to_disk_qcow2() -> Result<()> {
111137 output. stderr
112138 ) ;
113139
114- let metadata = std:: fs:: metadata ( & disk_path) . expect ( "Failed to get disk metadata" ) ;
115- assert ! ( metadata. len( ) > 0 ) ;
116-
117140 // Verify the file is actually qcow2 format using qemu-img info
118141 let qemu_img_output = Command :: new ( "qemu-img" )
119142 . args ( [ "info" , disk_path. as_str ( ) ] )
@@ -134,11 +157,7 @@ fn test_to_disk_qcow2() -> Result<()> {
134157 qemu_img_stdout
135158 ) ;
136159
137- assert ! (
138- output. stdout. contains( "Installation complete" ) || output. stderr. contains( "Installation complete" ) ,
139- "No 'Installation complete' message found in output. This indicates bootc install did not complete successfully. stdout: {}, stderr: {}" ,
140- output. stdout, output. stderr
141- ) ;
160+ validate_disk_image ( & disk_path, & output, "test_to_disk_qcow2" ) ?;
142161 Ok ( ( ) )
143162}
144163integration_test ! ( test_to_disk_qcow2) ;
@@ -300,3 +319,40 @@ fn test_to_disk_different_imgref_same_digest() -> Result<()> {
300319 Ok ( ( ) )
301320}
302321integration_test ! ( test_to_disk_different_imgref_same_digest) ;
322+
323+ /// Test to-disk with various bootc images to ensure compatibility
324+ ///
325+ /// This parameterized test runs to-disk with multiple container images,
326+ /// particularly testing AlmaLinux which had cross-device link issues (issue #125)
327+ fn test_to_disk_for_image ( image : & str ) -> Result < ( ) > {
328+ let temp_dir = TempDir :: new ( ) . expect ( "Failed to create temp directory" ) ;
329+ let disk_path = Utf8PathBuf :: try_from ( temp_dir. path ( ) . join ( "test-disk.img" ) )
330+ . expect ( "temp path is not UTF-8" ) ;
331+
332+ let output = run_bcvk ( & [
333+ "to-disk" ,
334+ "--label" ,
335+ INTEGRATION_TEST_LABEL ,
336+ // Not all iamges have one
337+ "--filesystem=ext4" ,
338+ image,
339+ disk_path. as_str ( ) ,
340+ ] ) ?;
341+
342+ assert ! (
343+ output. success( ) ,
344+ "to-disk with image {} failed with exit code: {:?}. stdout: {}, stderr: {}" ,
345+ image,
346+ output. exit_code( ) ,
347+ output. stdout,
348+ output. stderr
349+ ) ;
350+
351+ validate_disk_image (
352+ & disk_path,
353+ & output,
354+ & format ! ( "test_to_disk_multi_image({})" , image) ,
355+ ) ?;
356+ Ok ( ( ) )
357+ }
358+ parameterized_integration_test ! ( test_to_disk_for_image) ;
0 commit comments