66import signal
77import subprocess
88import shutil
9+ from time import sleep
910import six
1011import testgres
1112import hashlib
1213import re
1314import getpass
1415import select
15- from time import sleep
16+ import time
1617import re
1718import json
1819import random
@@ -150,8 +151,9 @@ def __str__(self):
150151
151152class PostgresNodeExtended (testgres .PostgresNode ):
152153
153- def __init__ (self , base_dir = None , * args , ** kwargs ):
154- super (PostgresNodeExtended , self ).__init__ (name = 'test' , base_dir = base_dir , * args , ** kwargs )
154+ def __init__ (self , base_dir = None , port = None , bin_dir = None , * args , ** kwargs ):
155+ assert port is None or type (port ) == int
156+ super (PostgresNodeExtended , self ).__init__ (name = 'test' , base_dir = base_dir , port = port , bin_dir = bin_dir , * args , ** kwargs )
155157 self .is_started = False
156158
157159 def slow_start (self , replica = False ):
@@ -414,25 +416,28 @@ def is_test_result_ok(test_case):
414416 #
415417 # 2. python versions 3.11+ mixin, verified on 3.11, taken from: https://stackoverflow.com/a/39606065
416418
417- if not isinstance (test_case , unittest .TestCase ):
418- raise AssertionError ("test_case is not instance of unittest.TestCase" )
419-
420- if hasattr (test_case , '_outcome' ): # Python 3.4+
421- if hasattr (test_case ._outcome , 'errors' ):
422- # Python 3.4 - 3.10 (These two methods have no side effects)
423- result = test_case .defaultTestResult () # These two methods have no side effects
424- test_case ._feedErrorsToResult (result , test_case ._outcome .errors )
425- else :
426- # Python 3.11+ and pytest 5.3.5+
427- result = test_case ._outcome .result
428- if not hasattr (result , 'errors' ):
429- result .errors = []
430- if not hasattr (result , 'failures' ):
431- result .failures = []
432- else : # Python 2.7, 3.0-3.3
433- result = getattr (test_case , '_outcomeForDoCleanups' , test_case ._resultForDoCleanups )
419+ if hasattr (test_case ._outcome , 'errors' ):
420+ # Python 3.4 - 3.10 (These two methods have no side effects)
421+ result = test_case .defaultTestResult () # These two methods have no side effects
422+ test_case ._feedErrorsToResult (result , test_case ._outcome .errors )
423+ else :
424+ # Python 3.11+ and pytest 5.3.5+
425+ result = test_case ._outcome .result
426+ if not hasattr (result , 'errors' ):
427+ result .errors = []
428+ if not hasattr (result , 'failures' ):
429+ result .failures = []
434430
435431 ok = all (test != test_case for test , text in result .errors + result .failures )
432+ # check subtests as well
433+ ok = ok and all (getattr (test , 'test_case' , None ) != test_case
434+ for test , text in result .errors + result .failures )
435+
436+ # for pytest 8+
437+ if hasattr (result , '_excinfo' ):
438+ if result ._excinfo is not None and len (result ._excinfo ) > 0 :
439+ # if test was successful, _excinfo will be None, else it will be non-empty list
440+ ok = False
436441
437442 return ok
438443
@@ -475,12 +480,14 @@ def pg_config_version(self):
475480
476481 def make_empty_node (
477482 self ,
478- base_dir = None ):
483+ base_dir = None ,
484+ port = None ,
485+ bin_dir = None ):
479486 real_base_dir = os .path .join (self .tmp_path , base_dir )
480487 shutil .rmtree (real_base_dir , ignore_errors = True )
481488 os .makedirs (real_base_dir )
482489
483- node = PostgresNodeExtended (base_dir = real_base_dir )
490+ node = PostgresNodeExtended (base_dir = real_base_dir , port = port , bin_dir = bin_dir )
484491 node .should_rm_dirs = True
485492 self .nodes_to_cleanup .append (node )
486493
@@ -489,12 +496,14 @@ def make_empty_node(
489496 def make_simple_node (
490497 self ,
491498 base_dir = None ,
499+ port = None ,
500+ bin_dir = None ,
492501 set_replication = False ,
493502 ptrack_enable = False ,
494503 initdb_params = [],
495504 pg_options = {}):
496505
497- node = self .make_empty_node (base_dir )
506+ node = self .make_empty_node (base_dir , port = port , bin_dir = bin_dir )
498507 node .init (
499508 initdb_params = initdb_params , allow_streaming = set_replication )
500509
@@ -910,6 +919,24 @@ def get_backup_filelist_diff(self, filelist_A, filelist_B):
910919
911920 return filelist_diff
912921
922+ def wait_instance_wal_exists (self , backup_dir , instance , file , timeout = 300 ):
923+ """Wait for WAL segment appeared in the WAL archive"""
924+ start = time .time ()
925+ fl = f'wal/{ instance } /{ file } '
926+ while time .time () - start < timeout :
927+ if os .path .exists (fl ):
928+ break
929+ time .sleep (0.25 )
930+
931+ def wait_server_wal_exists (self , data_dir , wal_dir , file , timeout = 300 ):
932+ """Wait for WAL segment appeared in the server WAL dir"""
933+ start = time .time ()
934+ fl = f'{ data_dir } /{ wal_dir } /{ file } '
935+ while time .time () - start < timeout :
936+ if os .path .exists (fl ):
937+ return
938+ time .sleep (0.25 )
939+
913940 # used for partial restore
914941 def truncate_every_file_in_dir (self , path ):
915942 for file in os .listdir (path ):
0 commit comments