@@ -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 backupajd restore it
568
+ merge delta backupand 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 chainchain with new binary
657
+ # Merge chainusing 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 )