@@ -565,7 +565,7 @@ def test_external_backward_compatibility_merge_2(self):
565
565
"""
566
566
take backup with old binary without external dirs support
567
567
take delta backup with new binary and 2 external directories
568
- merge delta backup ajd restore it
568
+ merge delta backup and restore it
569
569
"""
570
570
fname = self .id ().split ('.' )[3 ]
571
571
backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
@@ -654,7 +654,7 @@ def test_external_backward_compatibility_merge_2(self):
654
654
pgdata = self .pgdata_content (
655
655
node .base_dir , exclude_dirs = ['logs' ])
656
656
657
- # Merge chain chain with new binary
657
+ # Merge chain using new binary
658
658
self .merge_backup (backup_dir , 'node' , backup_id = backup_id )
659
659
660
660
# Restore merged backup
@@ -663,15 +663,19 @@ def test_external_backward_compatibility_merge_2(self):
663
663
664
664
node_restored .cleanup ()
665
665
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' )
668
670
669
671
self .restore_node (
670
672
backup_dir , 'node' , node_restored ,
671
673
options = [
672
674
"-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 )])
675
679
676
680
pgdata_restored = self .pgdata_content (
677
681
node_restored .base_dir , exclude_dirs = ['logs' ])
@@ -699,7 +703,7 @@ def test_external_merge(self):
699
703
700
704
node .pgbench_init (scale = 3 )
701
705
702
- # FULL backup with old binary without external dirs support
706
+ # take temp FULL backup
703
707
tmp_id = self .backup_node (
704
708
backup_dir , 'node' , node , options = ["-j" , "4" , "--stream" ])
705
709
@@ -753,8 +757,10 @@ def test_external_merge(self):
753
757
backup_dir , 'node' , node ,
754
758
options = [
755
759
"-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 )])
758
764
759
765
pgdata_restored = self .pgdata_content (
760
766
node .base_dir , exclude_dirs = ['logs' ])
@@ -2459,3 +2465,75 @@ def test_smart_restore_externals(self):
2459
2465
2460
2466
# Clean after yourself
2461
2467
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