@@ -748,6 +748,93 @@ def test_validate_instance_with_corrupted_page(self):
748748 # Clean after yourself
749749 self .del_test_dir (module_name , fname )
750750
751+ # @unittest.skip("skip")
752+ def test_validate_instance_with_corrupted_full_and_try_restore (self ):
753+ """make archive node, take FULL, PAGE1, PAGE2, FULL2, PAGE3 backups,
754+ corrupt file in FULL backup and run validate on instance,
755+ expect FULL to gain status CORRUPT, PAGE1 and PAGE2 to gain status ORPHAN,
756+ try to restore backup with --no-validation option"""
757+ fname = self .id ().split ('.' )[3 ]
758+ node = self .make_simple_node (base_dir = "{0}/{1}/node" .format (module_name , fname ),
759+ initdb_params = ['--data-checksums' ],
760+ pg_options = {'wal_level' : 'replica' }
761+ )
762+ backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
763+ self .init_pb (backup_dir )
764+ self .add_instance (backup_dir , 'node' , node )
765+ self .set_archiving (backup_dir , 'node' , node )
766+ node .start ()
767+
768+ node .safe_psql (
769+ "postgres" ,
770+ "create table t_heap as select i as id, md5(i::text) as text, md5(repeat(i::text,10))::tsvector as tsvector from generate_series(0,10000) i" )
771+ file_path_t_heap = node .safe_psql (
772+ "postgres" ,
773+ "select pg_relation_filepath('t_heap')" ).rstrip ()
774+ # FULL1
775+ backup_id_1 = self .backup_node (backup_dir , 'node' , node )
776+
777+ node .safe_psql (
778+ "postgres" ,
779+ "insert into t_heap select i as id, md5(i::text) as text, md5(repeat(i::text,10))::tsvector as tsvector from generate_series(0,10000) i" )
780+ # PAGE1
781+ backup_id_2 = self .backup_node (backup_dir , 'node' , node , backup_type = 'page' )
782+
783+ # PAGE2
784+ node .safe_psql (
785+ "postgres" ,
786+ "insert into t_heap select i as id, md5(i::text) as text, md5(repeat(i::text,10))::tsvector as tsvector from generate_series(20000,30000) i" )
787+ backup_id_3 = self .backup_node (backup_dir , 'node' , node , backup_type = 'page' )
788+
789+ # FULL1
790+ backup_id_4 = self .backup_node (backup_dir , 'node' , node )
791+
792+ # PAGE3
793+ node .safe_psql (
794+ "postgres" ,
795+ "insert into t_heap select i as id, md5(i::text) as text, md5(repeat(i::text,10))::tsvector as tsvector from generate_series(30000,40000) i" )
796+ backup_id_5 = self .backup_node (backup_dir , 'node' , node , backup_type = 'page' )
797+
798+ # Corrupt some file in FULL backup
799+ file_full = os .path .join (backup_dir , 'backups/node' , backup_id_1 , 'database' , file_path_t_heap )
800+ with open (file_full , "rb+" , 0 ) as f :
801+ f .seek (84 )
802+ f .write (b"blah" )
803+ f .flush ()
804+ f .close
805+
806+ # Validate Instance
807+ try :
808+ self .validate_pb (backup_dir , 'node' , options = ['--log-level-file=verbose' ])
809+ self .assertEqual (1 , 0 , "Expecting Error because of data files corruption.\n Output: {0} \n CMD: {1}" .format (
810+ repr (self .output ), self .cmd ))
811+ except ProbackupException as e :
812+ self .assertTrue (
813+ 'INFO: Validating backup {0}' .format (backup_id_1 ) in e .message
814+ and "INFO: Validate backups of the instance 'node'" in e .message
815+ and 'WARNING: Invalid CRC of backup file "{0}"' .format (file_full ) in e .message
816+ and 'WARNING: Backup {0} data files are corrupted' .format (backup_id_1 ) in e .message ,
817+ '\n Unexpected Error Message: {0}\n CMD: {1}' .format (repr (e .message ), self .cmd ))
818+
819+ self .assertEqual ('CORRUPT' , self .show_pb (backup_dir , 'node' , backup_id_1 )['status' ], 'Backup STATUS should be "CORRUPT"' )
820+ self .assertEqual ('ORPHAN' , self .show_pb (backup_dir , 'node' , backup_id_2 )['status' ], 'Backup STATUS should be "ORPHAN"' )
821+ self .assertEqual ('ORPHAN' , self .show_pb (backup_dir , 'node' , backup_id_3 )['status' ], 'Backup STATUS should be "ORPHAN"' )
822+ self .assertEqual ('OK' , self .show_pb (backup_dir , 'node' , backup_id_4 )['status' ], 'Backup STATUS should be "OK"' )
823+ self .assertEqual ('OK' , self .show_pb (backup_dir , 'node' , backup_id_5 )['status' ], 'Backup STATUS should be "OK"' )
824+
825+ node .cleanup ()
826+ restore_out = self .restore_node (
827+ backup_dir , 'node' , node ,
828+ options = ["--no-validate" ])
829+ self .assertIn (
830+ "INFO: Restore of backup {0} completed." .format (backup_id_5 ),
831+ restore_out ,
832+ '\n Unexpected Error Message: {0}\n CMD: {1}' .format (
833+ repr (self .output ), self .cmd ))
834+
835+ # Clean after yourself
836+ self .del_test_dir (module_name , fname )
837+
751838 # @unittest.skip("skip")
752839 def test_validate_instance_with_corrupted_full (self ):
753840 """make archive node, take FULL, PAGE1, PAGE2, FULL2, PAGE3 backups,
@@ -1582,3 +1669,62 @@ def test_validate_corrupted_full_1(self):
15821669
15831670 # Clean after yourself
15841671 self .del_test_dir (module_name , fname )
1672+
1673+ def test_file_size_corruption_no_validate (self ):
1674+
1675+ fname = self .id ().split ('.' )[3 ]
1676+ node = self .make_simple_node (
1677+ base_dir = "{0}/{1}/node" .format (module_name , fname ),
1678+ # initdb_params=['--data-checksums'],
1679+ pg_options = {'wal_level' : 'replica' }
1680+ )
1681+
1682+ backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
1683+
1684+ self .init_pb (backup_dir )
1685+ self .add_instance (backup_dir , 'node' , node )
1686+ self .set_archiving (backup_dir , 'node' , node )
1687+
1688+ node .start ()
1689+
1690+ node .safe_psql (
1691+ "postgres" ,
1692+ "create table t_heap as select 1 as id, md5(i::text) as text, "
1693+ "md5(repeat(i::text,10))::tsvector as tsvector "
1694+ "from generate_series(0,1000) i" )
1695+ node .safe_psql (
1696+ "postgres" ,
1697+ "CHECKPOINT;" )
1698+
1699+ heap_path = node .safe_psql (
1700+ "postgres" ,
1701+ "select pg_relation_filepath('t_heap')" ).rstrip ()
1702+ heap_size = node .safe_psql (
1703+ "postgres" ,
1704+ "select pg_relation_size('t_heap')" )
1705+
1706+ backup_id = self .backup_node (
1707+ backup_dir , 'node' , node , backup_type = "full" ,
1708+ options = ["-j" , "4" ], async = False , gdb = False )
1709+
1710+ node .stop ()
1711+ node .cleanup ()
1712+
1713+ # Let`s do file corruption
1714+ with open (os .path .join (backup_dir , "backups" , 'node' , backup_id , "database" , heap_path ), "rb+" , 0 ) as f :
1715+ f .truncate (int (heap_size ) - 4096 )
1716+ f .flush ()
1717+ f .close
1718+
1719+ node .cleanup ()
1720+
1721+ try :
1722+ self .restore_node (
1723+ backup_dir , 'node' , node ,
1724+ options = ["--no-validate" ])
1725+ except ProbackupException as e :
1726+ self .assertTrue ("ERROR: Data files restoring failed" in e .message , repr (e .message ))
1727+ print "\n Expected error: \n " + e .message
1728+
1729+ # Clean after yourself
1730+ self .del_test_dir (module_name , fname )
0 commit comments