@@ -565,7 +565,7 @@ def test_external_backward_compatibility_merge_2(self):
565565 """
566566 take backup with old binary without external dirs support
567567 take delta backup with new binary and 2 external directories
568- merge delta backup ajd restore it
568+ merge delta backup and restore it
569569 """
570570 fname = self .id ().split ('.' )[3 ]
571571 backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
@@ -654,7 +654,7 @@ def test_external_backward_compatibility_merge_2(self):
654654 pgdata = self .pgdata_content (
655655 node .base_dir , exclude_dirs = ['logs' ])
656656
657- # Merge chain chain with new binary
657+ # Merge chain using new binary
658658 self .merge_backup (backup_dir , 'node' , backup_id = backup_id )
659659
660660 # Restore merged backup
@@ -663,15 +663,19 @@ def test_external_backward_compatibility_merge_2(self):
663663
664664 node_restored .cleanup ()
665665
666- external_dir1_new = self .get_tblspace_path (node_restored , 'external_dir1' )
667- external_dir2_new = self .get_tblspace_path (node_restored , 'external_dir2' )
666+ external_dir1_new = self .get_tblspace_path (
667+ node_restored , 'external_dir1' )
668+ external_dir2_new = self .get_tblspace_path (
669+ node_restored , 'external_dir2' )
668670
669671 self .restore_node (
670672 backup_dir , 'node' , node_restored ,
671673 options = [
672674 "-j" , "4" ,
673- "--external-mapping={0}={1}" .format (external_dir1 , external_dir1_new ),
674- "--external-mapping={0}={1}" .format (external_dir2 , external_dir2_new )])
675+ "--external-mapping={0}={1}" .format (
676+ external_dir1 , external_dir1_new ),
677+ "--external-mapping={0}={1}" .format (
678+ external_dir2 , external_dir2_new )])
675679
676680 pgdata_restored = self .pgdata_content (
677681 node_restored .base_dir , exclude_dirs = ['logs' ])
@@ -699,7 +703,7 @@ def test_external_merge(self):
699703
700704 node .pgbench_init (scale = 3 )
701705
702- # FULL backup with old binary without external dirs support
706+ # take temp FULL backup
703707 tmp_id = self .backup_node (
704708 backup_dir , 'node' , node , options = ["-j" , "4" , "--stream" ])
705709
@@ -753,8 +757,10 @@ def test_external_merge(self):
753757 backup_dir , 'node' , node ,
754758 options = [
755759 "-j" , "4" ,
756- "--external-mapping={0}={1}" .format (external_dir1 , external_dir1_new ),
757- "--external-mapping={0}={1}" .format (external_dir2 , external_dir2_new )])
760+ "--external-mapping={0}={1}" .format (
761+ external_dir1 , external_dir1_new ),
762+ "--external-mapping={0}={1}" .format (
763+ external_dir2 , external_dir2_new )])
758764
759765 pgdata_restored = self .pgdata_content (
760766 node .base_dir , exclude_dirs = ['logs' ])
@@ -2459,3 +2465,75 @@ def test_smart_restore_externals(self):
24592465
24602466 # Clean after yourself
24612467 self .del_test_dir (module_name , fname )
2468+
2469+ # @unittest.skip("skip")
2470+ def test_external_validation (self ):
2471+ """
2472+ make node, create database,
2473+ take full backup with external directory,
2474+ corrupt external file in backup,
2475+ run validate which should fail
2476+ """
2477+ fname = self .id ().split ('.' )[3 ]
2478+ node = self .make_simple_node (
2479+ base_dir = os .path .join (module_name , fname , 'node' ),
2480+ set_replication = True ,
2481+ initdb_params = ['--data-checksums' ])
2482+
2483+ backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
2484+ self .init_pb (backup_dir )
2485+ self .add_instance (backup_dir , 'node' , node )
2486+ node .slow_start ()
2487+
2488+ # take temp FULL backup
2489+ tmp_id = self .backup_node (
2490+ backup_dir , 'node' , node , options = ['--stream' ])
2491+
2492+ external_dir = self .get_tblspace_path (node , 'external_dir' )
2493+
2494+ # fill external directories with data
2495+ self .restore_node (
2496+ backup_dir , 'node' , node , backup_id = tmp_id ,
2497+ data_dir = external_dir , options = ["-j" , "4" ])
2498+
2499+ self .delete_pb (backup_dir , 'node' , backup_id = tmp_id )
2500+
2501+ # take FULL backup
2502+ full_id = self .backup_node (
2503+ backup_dir , 'node' , node ,
2504+ options = [
2505+ '--stream' , '-E' , "{0}" .format (external_dir )])
2506+
2507+ # Corrupt file
2508+ file = os .path .join (
2509+ backup_dir , 'backups' , 'node' , full_id ,
2510+ 'external_directories' , 'externaldir1' , 'postgresql.auto.conf' )
2511+
2512+ with open (file , "r+b" , 0 ) as f :
2513+ f .seek (42 )
2514+ f .write (b"blah" )
2515+ f .flush ()
2516+ f .close
2517+
2518+ try :
2519+ self .validate_pb (backup_dir )
2520+ # we should die here because exception is what we expect to happen
2521+ self .assertEqual (
2522+ 1 , 0 ,
2523+ "Expecting Error because file in external dir is corrupted"
2524+ "\n Output: {0} \n CMD: {1}" .format (
2525+ repr (self .output ), self .cmd ))
2526+ except ProbackupException as e :
2527+ self .assertIn (
2528+ 'WARNING: Invalid CRC of backup file' ,
2529+ e .message ,
2530+ '\n Unexpected Error Message: {0}\n CMD: {1}' .format (
2531+ repr (e .message ), self .cmd ))
2532+
2533+ self .assertEqual (
2534+ 'CORRUPT' ,
2535+ self .show_pb (backup_dir , 'node' , full_id )['status' ],
2536+ 'Backup STATUS should be "CORRUPT"' )
2537+
2538+ # Clean after yourself
2539+ self .del_test_dir (module_name , fname )
0 commit comments