@@ -890,3 +890,106 @@ def test_validate_metadata_file_nonexistent(
890890
891891 assert cli_result .exit_code == 2 , "Expected exit code 2 for nonexistent file (Typer path validation)"
892892 assert "does not exist" in cli_result .output .lower (), "Expected error message about file not existing"
893+
894+
895+ @patch ("divbase_api.worker.tasks.create_s3_file_manager" )
896+ def test_update_dimensions_cleans_up_csi_index_files_from_worker (
897+ mock_create_s3_manager ,
898+ CONSTANTS ,
899+ project_map ,
900+ tmp_path ,
901+ monkeypatch ,
902+ ):
903+ """
904+ Test that CSI index files created during dimension calculation are deleted from the worker
905+ filesystem after update_vcf_dimensions_task completes.
906+ """
907+ mock_create_s3_manager .side_effect = lambda url = None : create_s3_file_manager (url = CONSTANTS ["MINIO_URL" ])
908+ monkeypatch .chdir (tmp_path )
909+
910+ project_name = CONSTANTS ["SPLIT_SCAFFOLD_PROJECT" ]
911+ bucket_name = CONSTANTS ["PROJECT_TO_BUCKET_MAP" ][project_name ]
912+ project_id = project_map [project_name ]
913+ user_id = 1
914+
915+ result = update_vcf_dimensions_task (
916+ bucket_name = bucket_name , project_id = project_id , project_name = project_name , user_id = user_id
917+ )
918+
919+ assert result ["status" ] == "completed"
920+
921+ vcf_files_remaining = list (tmp_path .glob ("*.vcf" )) + list (tmp_path .glob ("*.vcf.gz" ))
922+ assert vcf_files_remaining == [], (
923+ f"Expected all VCF files to be deleted from worker after task, but found: { vcf_files_remaining } "
924+ )
925+
926+ csi_files_remaining = list (tmp_path .glob ("*.csi" ))
927+ assert csi_files_remaining == [], (
928+ f"Expected all CSI index files to be deleted from worker after task, but found: { csi_files_remaining } "
929+ )
930+
931+
932+ @patch ("divbase_api.worker.tasks.create_s3_file_manager" )
933+ def test_update_dimensions_indexes_uncompressed_vcf (
934+ mock_create_s3_manager ,
935+ CONSTANTS ,
936+ db_session_sync ,
937+ project_map ,
938+ tmp_path ,
939+ ):
940+ """
941+ Test that update_vcf_dimensions_task correctly indexes a plain uncompressed .vcf file.
942+
943+ bcftools index --csi requires bgzipped input, so calculate_dimensions bgzips plain .vcf
944+ files to a temp .vcf.gz internally before indexing, then cleans up the temp files.
945+ This tests that the full indexing pipeline works end-to-end for uncompressed VCFs.
946+ """
947+ mock_create_s3_manager .side_effect = lambda url = None : create_s3_file_manager (url = CONSTANTS ["MINIO_URL" ])
948+
949+ project_name = CONSTANTS ["SPLIT_SCAFFOLD_PROJECT" ]
950+ bucket_name = CONSTANTS ["PROJECT_TO_BUCKET_MAP" ][project_name ]
951+ project_id = project_map [project_name ]
952+ user_id = 1
953+
954+ plain_vcf_name = "test_uncompressed_plain.vcf"
955+ vcf_path = tmp_path / plain_vcf_name
956+ vcf_content = (
957+ "##fileformat=VCFv4.2\n "
958+ "##contig=<ID=1,length=22053058>\n "
959+ "#CHROM\t POS\t ID\t REF\t ALT\t QUAL\t FILTER\t INFO\t FORMAT\t sample1\t sample2\n "
960+ "1\t 17504018\t .\t C\t A\t .\t PASS\t .\t GT\t 0/1\t 0/0\n "
961+ "1\t 22053057\t .\t G\t A\t .\t PASS\t .\t GT\t 1/1\t 0/1\n "
962+ )
963+ vcf_path .write_text (vcf_content )
964+
965+ s3_file_manager = create_s3_file_manager (url = CONSTANTS ["MINIO_URL" ])
966+ s3_file_manager .upload_files (
967+ to_upload = {plain_vcf_name : vcf_path },
968+ bucket_name = bucket_name ,
969+ )
970+
971+ try :
972+ result = update_vcf_dimensions_task (
973+ bucket_name = bucket_name , project_id = project_id , project_name = project_name , user_id = user_id
974+ )
975+
976+ assert result ["status" ] == "completed"
977+ indexed_files = result .get ("VCF_files_added" ) or []
978+ assert plain_vcf_name in indexed_files , f"Expected plain .vcf file to be indexed, got: { indexed_files } "
979+
980+ # Verify the dimensions were stored correctly in the DB
981+ db_session_sync .expire_all ()
982+ vcf_dimensions = get_vcf_metadata_by_project (project_id = project_id , db = db_session_sync )
983+ all_indexed_keys = [entry ["vcf_file_s3_key" ] for entry in vcf_dimensions .get ("vcf_files" , [])]
984+ assert plain_vcf_name in all_indexed_keys
985+
986+ entry = next (e for e in vcf_dimensions ["vcf_files" ] if e ["vcf_file_s3_key" ] == plain_vcf_name )
987+ assert entry ["sample_count" ] == 2
988+ assert entry ["variant_count" ] == 2
989+ assert "1" in entry ["scaffolds" ]
990+ assert "sample1" in entry ["samples" ]
991+ assert "sample2" in entry ["samples" ]
992+ finally :
993+ # Remove the uploaded file from the bucket to avoid polluting subsequent tests.
994+ # auto_clean_dimensions_entries_for_all_projects only cleans the DB, not the bucket.
995+ s3_file_manager .soft_delete_objects (objects = [plain_vcf_name ], bucket_name = bucket_name )
0 commit comments