diff --git a/modules/nf-neuro/betcrop/antsbet/main.nf b/modules/nf-neuro/betcrop/antsbet/main.nf index 04e51c10..8fbdf282 100644 --- a/modules/nf-neuro/betcrop/antsbet/main.nf +++ b/modules/nf-neuro/betcrop/antsbet/main.nf @@ -45,14 +45,9 @@ process BETCROP_ANTSBET { """ stub: - def args = task.ext.args ?: '' def prefix = task.ext.prefix ?: "${meta.id}" - """ - antsBrainExtraction.sh -h - scil_volume_math.py -h - mrcalc -h - + """ touch ${prefix}__t1_bet.nii.gz touch ${prefix}__t1_bet_mask.nii.gz @@ -62,5 +57,16 @@ process BETCROP_ANTSBET { mrtrix: \$(mrcalc -version 2>&1 | sed -n 's/== mrcalc \\([0-9.]\\+\\).*/\\1/p') ants: \$(antsRegistration --version | grep "Version" | sed -E 's/.*v([0-9]+\\+\\).*/\\1/') END_VERSIONS + + function handle_code () { + local code=\$? + ignore=( 1 ) + exit \$([[ " \${ignore[@]} " =~ " \$code " ]] && echo 0 || echo \$code) + } + trap 'handle_code' ERR + + antsBrainExtraction.sh + scil_volume_math.py -h + mrcalc -h """ } diff --git a/modules/nf-neuro/betcrop/antsbet/tests/main.nf.test b/modules/nf-neuro/betcrop/antsbet/tests/main.nf.test index 5ca26428..bd15b356 100644 --- a/modules/nf-neuro/betcrop/antsbet/tests/main.nf.test +++ b/modules/nf-neuro/betcrop/antsbet/tests/main.nf.test @@ -14,7 +14,6 @@ nextflow_process { tag "subworkflows/load_test_data" test("betcrop - antsbet") { - setup { run("LOAD_TEST_DATA", alias: "LOAD_DATA") { script "../../../../../subworkflows/nf-neuro/load_test_data/main.nf" @@ -26,7 +25,6 @@ nextflow_process { } } } - when { process { """ @@ -68,14 +66,76 @@ nextflow_process { """ } } - then { assertAll( { assert process.success }, - { assert snapshot(process.out).match() } + { assert snapshot( + niftiMD5SUM(process.out.t1.get(0).get(1)), + niftiMD5SUM(process.out.mask.get(0).get(1)), + process.out.versions + ).match() } + ) + } + } + test("betcrop - antsbet - stub-run") { + options "-stub-run" + setup { + run("LOAD_TEST_DATA", alias: "LOAD_DATA") { + script "../../../../../subworkflows/nf-neuro/load_test_data/main.nf" + process { + """ + input[0] = Channel.from( [ "T1w.zip", "transform.zip", "antsbet.zip" ] ) + input[1] = "test.load-test-data" + """ + } + } + } + when { + process { + """ + ch_split_test_data = LOAD_DATA.out.test_data_directory + .branch{ + t1: it.simpleName == "T1w" + transform: it.simpleName == "transform" + template: it.simpleName == "antsbet" + } + ch_t1 = ch_split_test_data.t1.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/T1w.nii.gz") + ] + } + ch_template = ch_split_test_data.template.map{ + test_data_directory -> [ + [ id: 'test' ], + file("\${test_data_directory}/t1_template.nii.gz"), + file("\${test_data_directory}/t1_brain_probability_map.nii.gz") + ] + } + ch_mask = ch_split_test_data.transform.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/t1_to_bet_template_mask.nii.gz") + ] + } + ch_transform = ch_split_test_data.transform.map{ + test_data_directory -> [ + [ id:'test' ], + file("\${test_data_directory}/t1_to_bet_template.mat") + ] + } + input[0] = ch_t1 + .join(ch_template) + .join(ch_mask) + .join(ch_transform) + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.versions).match() } ) } - } - } diff --git a/modules/nf-neuro/betcrop/antsbet/tests/main.nf.test.snap b/modules/nf-neuro/betcrop/antsbet/tests/main.nf.test.snap index 13625be9..b76e32d5 100644 --- a/modules/nf-neuro/betcrop/antsbet/tests/main.nf.test.snap +++ b/modules/nf-neuro/betcrop/antsbet/tests/main.nf.test.snap @@ -1,51 +1,28 @@ { "betcrop - antsbet": { "content": [ - { - "0": [ - [ - { - "id": "test" - }, - "test__t1_bet.nii.gz:md5,bd666c4ce559eab93690131f8b2a9101" - ] - ], - "1": [ - [ - { - "id": "test" - }, - "test__t1_bet_mask.nii.gz:md5,48c91d01a6c59d48e4ce84431d5e4971" - ] - ], - "2": [ - "versions.yml:md5,9fde1445bc10857db69e440781e58cb7" - ], - "mask": [ - [ - { - "id": "test" - }, - "test__t1_bet_mask.nii.gz:md5,48c91d01a6c59d48e4ce84431d5e4971" - ] - ], - "t1": [ - [ - { - "id": "test" - }, - "test__t1_bet.nii.gz:md5,bd666c4ce559eab93690131f8b2a9101" - ] - ], - "versions": [ - "versions.yml:md5,9fde1445bc10857db69e440781e58cb7" - ] - } + "test__t1_bet.nii.gz:md5:header,72167012fa8893d3c3531d5d1245b84a,data,e31b24e1dadf5b067211544fca1f3f01", + "test__t1_bet_mask.nii.gz:md5:header,f7389fe98c9a7e3a87c90b7ca05ea14a,data,1572808125554e50ff73fbe0e28037a9", + [ + "versions.yml:md5,9fde1445bc10857db69e440781e58cb7" + ] ], "meta": { "nf-test": "0.9.0", - "nextflow": "24.04.4" + "nextflow": "24.10.1" }, - "timestamp": "2024-10-30T17:42:18.337235926" + "timestamp": "2024-12-17T20:31:09.4739" + }, + "betcrop - antsbet - stub-run": { + "content": [ + [ + "versions.yml:md5,9fde1445bc10857db69e440781e58cb7" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.10.1" + }, + "timestamp": "2024-12-12T10:20:29.72452" } } \ No newline at end of file diff --git a/modules/nf-neuro/betcrop/synthbet/main.nf b/modules/nf-neuro/betcrop/synthbet/main.nf index b122b226..cbbeddeb 100644 --- a/modules/nf-neuro/betcrop/synthbet/main.nf +++ b/modules/nf-neuro/betcrop/synthbet/main.nf @@ -40,8 +40,6 @@ process BETCROP_SYNTHBET { def prefix = task.ext.prefix ?: "${meta.id}" """ - mri_synthstrip -h - touch ${prefix}__bet_image.nii.gz touch ${prefix}__brain_mask.nii.gz @@ -49,5 +47,14 @@ process BETCROP_SYNTHBET { "${task.process}": Freesurfer: \$(mri_convert -version | grep "freesurfer" | sed -E 's/.* ([0-9]+\\.[0-9]+\\.[0-9]+).*/\\1/') END_VERSIONS + + function handle_code () { + local code=\$? + ignore=( 1 ) + exit \$([[ " \${ignore[@]} " =~ " \$code " ]] && echo 0 || echo \$code) + } + trap 'handle_code' ERR + + mri_synthstrip -h """ } diff --git a/modules/nf-neuro/betcrop/synthbet/tests/main.nf.test b/modules/nf-neuro/betcrop/synthbet/tests/main.nf.test index 6fae76ab..7e71d665 100644 --- a/modules/nf-neuro/betcrop/synthbet/tests/main.nf.test +++ b/modules/nf-neuro/betcrop/synthbet/tests/main.nf.test @@ -14,7 +14,6 @@ nextflow_process { tag "subworkflows/load_test_data" test("betcrop - synthbet") { - setup { run("LOAD_TEST_DATA", alias: "LOAD_DATA") { script "../../../../../subworkflows/nf-neuro/load_test_data/main.nf" @@ -26,7 +25,6 @@ nextflow_process { } } } - when { process { """ @@ -40,7 +38,6 @@ nextflow_process { """ } } - then { assertAll( { assert process.success }, @@ -48,4 +45,38 @@ nextflow_process { ) } } + + test("betcrop - synthbet - stub-run") { + options "-stub-run" + setup { + run("LOAD_TEST_DATA", alias: "LOAD_DATA") { + script "../../../../../subworkflows/nf-neuro/load_test_data/main.nf" + process { + """ + input[0] = Channel.from( [ "freesurfer.zip" ] ) + input[1] = "test.load-test-data" + """ + } + } + } + when { + process { + """ + input[0] = LOAD_DATA.out.test_data_directory.map{ + test_data_directory -> [ + [ id:'test', single_end:false ], // meta map + file("\${test_data_directory}/anat_image.nii.gz"), + [] + ] + } + """ + } + } + then { + assertAll( + { assert process.success }, + { assert snapshot(process.out.versions).match() } + ) + } + } } diff --git a/modules/nf-neuro/betcrop/synthbet/tests/main.nf.test.snap b/modules/nf-neuro/betcrop/synthbet/tests/main.nf.test.snap index 8be3fb46..94588233 100644 --- a/modules/nf-neuro/betcrop/synthbet/tests/main.nf.test.snap +++ b/modules/nf-neuro/betcrop/synthbet/tests/main.nf.test.snap @@ -1,4 +1,16 @@ { + "betcrop - synthbet - stub-run": { + "content": [ + [ + "versions.yml:md5,c639461870ca534b5105f61d672f740f" + ] + ], + "meta": { + "nf-test": "0.9.0", + "nextflow": "24.10.1" + }, + "timestamp": "2024-12-12T10:54:37.644838" + }, "betcrop - synthbet": { "content": [ { @@ -52,4 +64,4 @@ }, "timestamp": "2024-11-25T18:19:01.459548926" } -} +} \ No newline at end of file diff --git a/subworkflows/nf-neuro/load_test_data/main.nf b/subworkflows/nf-neuro/load_test_data/main.nf index 5a1dbcc3..ed9f1535 100644 --- a/subworkflows/nf-neuro/load_test_data/main.nf +++ b/subworkflows/nf-neuro/load_test_data/main.nf @@ -21,7 +21,7 @@ def locate_local_cache () { cache_location.mkdirs() } catch (Exception _e) { - error "Failed to create cache location: $cache_location" + error "Failed to create cache location: $cache_location | $_e" } } @@ -73,7 +73,7 @@ def add_cache_entry ( name, manager ) { } catch (Exception _e) { manager.delete_entry(name) - error "Failed to fetch test data archive: $name | $_e" + error "Failed to download test archive: $name | $_e" } return cache_entry @@ -102,7 +102,7 @@ def delete_cache_entry ( name, manager ) { cache_entry.delete() } catch (Exception _e) { - error "Failed to delete test data archive: $name" + error "Failed to delete cache entry for test archive: $name | $_e" } } } @@ -136,12 +136,13 @@ def setup_cache () { return cache_manager } +def unzip_test_archive ( archive, destination ) { + // Unzip the test data archive to the destination directory. + // Exception are not handled here, and are propagated to the caller. -def fetch_archive ( name, destination, manager ) { - // Unzip all archive content to destination def content = null try { - content = new java.util.zip.ZipFile("${manager.get_entry(name)}") + content = new java.util.zip.ZipFile("$archive") content.entries().each{ entry -> def local_target = file("$destination/${entry.getName()}") if (entry.isDirectory()) { @@ -154,13 +155,30 @@ def fetch_archive ( name, destination, manager ) { } } content.close() - - return destination.resolve("${name.take(name.lastIndexOf('.'))}") } catch (Exception _e) { if (content) content.close() - manager.delete_entry(name) - error "Failed to extract test data archive: $name | $_e" + throw _e + } +} + +def fetch_archive ( name, destination, manager ) { + // Unzip all archive content to destination + try { + unzip_test_archive(manager.get_entry(name), destination) + + return destination.resolve("${name.take(name.lastIndexOf('.'))}") + } + catch (java.util.zip.ZipException _e) { + try { + manager.delete_entry(name) + unzip_test_archive(manager.get_entry(name), destination) + + return destination.resolve("${name.take(name.lastIndexOf('.'))}") + } + catch (Exception _ee) { + error "Failed to fetch test archive: $name | $_ee" + } } }