@@ -174,51 +174,36 @@ def test_backup_via_unprivileged_user(self):
174174class AuthTest (unittest .TestCase ):
175175pb = None
176176node = None
177+ test_path = None
177178
178- # TODO move to object scope, replace module_name
179- @classmethod
180- def setUpClass (cls ):
179+ @unittest .skipIf (skip_test ,"Module pexpect isn't installed. You need to install it." )
180+ def setUp (self ):
181181
182- super (AuthTest , cls ). setUpClass ()
182+ super (). setUp ()
183183
184- cls .pb = ProbackupTest ()
185- cls .backup_dir = os .path .join (cls .pb .tmp_path ,module_name ,'backup' )
184+ self .pb = ProbackupTest ()
185+ self .test_path = os .path .join (self .pb .tmp_path ,module_name ,self ._testMethodName )
186+ self .backup_dir = os .path .join (self .test_path ,'backup' )
186187
187- cls .node = cls .pb .make_simple_node (
188- base_dir = "{}/node" . format ( module_name ),
188+ self .node = self .pb .make_simple_node (
189+ base_dir = os . path . join ( self . test_path , 'node' ),
189190set_replication = True ,
190191initdb_params = ['--data-checksums' ,'--auth-host=md5' ]
191192 )
192193
193- cls . username = cls .pb .get_username ()
194+ self . modify_pg_hba ( self . node , self .pb .get_username () )
194195
195- cls .modify_pg_hba (cls .node )
196-
197- cls .pb .init_pb (cls .backup_dir )
198- cls .pb .add_instance (cls .backup_dir ,cls .node .name ,cls .node )
199- cls .pb .set_archiving (cls .backup_dir ,cls .node .name ,cls .node )
196+ self .pb .init_pb (self .backup_dir )
197+ self .pb .add_instance (self .backup_dir ,self .node .name ,self .node )
198+ self .pb .set_archiving (self .backup_dir ,self .node .name ,self .node )
200199try :
201- cls .node .slow_start ()
200+ self .node .slow_start ()
202201except StartNodeException :
203202raise unittest .skip ("Node hasn't started" )
204203
205- if cls .pb .get_version (cls .node )< 100000 :
206- cls .node .safe_psql (
207- "postgres" ,
208- "CREATE ROLE backup WITH LOGIN PASSWORD 'password'; "
209- "GRANT USAGE ON SCHEMA pg_catalog TO backup; "
210- "GRANT EXECUTE ON FUNCTION current_setting(text) TO backup; "
211- "GRANT EXECUTE ON FUNCTION pg_is_in_recovery() TO backup; "
212- "GRANT EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) TO backup; "
213- "GRANT EXECUTE ON FUNCTION pg_stop_backup() TO backup; "
214- "GRANT EXECUTE ON FUNCTION pg_stop_backup(boolean) TO backup; "
215- "GRANT EXECUTE ON FUNCTION pg_create_restore_point(text) TO backup; "
216- "GRANT EXECUTE ON FUNCTION pg_switch_xlog() TO backup; "
217- "GRANT EXECUTE ON FUNCTION txid_current() TO backup; "
218- "GRANT EXECUTE ON FUNCTION txid_current_snapshot() TO backup; "
219- "GRANT EXECUTE ON FUNCTION txid_snapshot_xmax(txid_snapshot) TO backup;" )
220- elif cls .pb .get_version (cls .node )< 150000 :
221- cls .node .safe_psql (
204+ version = self .pb .get_version (self .node )
205+ if version < 150000 :
206+ self .node .safe_psql (
222207"postgres" ,
223208"CREATE ROLE backup WITH LOGIN PASSWORD 'password'; "
224209"GRANT USAGE ON SCHEMA pg_catalog TO backup; "
@@ -233,7 +218,7 @@ def setUpClass(cls):
233218"GRANT EXECUTE ON FUNCTION txid_current_snapshot() TO backup; "
234219"GRANT EXECUTE ON FUNCTION txid_snapshot_xmax(txid_snapshot) TO backup;" )
235220else :
236- cls .node .safe_psql (
221+ self .node .safe_psql (
237222"postgres" ,
238223"CREATE ROLE backup WITH LOGIN PASSWORD 'password'; "
239224"GRANT USAGE ON SCHEMA pg_catalog TO backup; "
@@ -247,16 +232,29 @@ def setUpClass(cls):
247232"GRANT EXECUTE ON FUNCTION txid_current_snapshot() TO backup; "
248233"GRANT EXECUTE ON FUNCTION txid_snapshot_xmax(txid_snapshot) TO backup;" )
249234
250- cls .pgpass_file = os .path .join (os .path .expanduser ('~' ),'.pgpass' )
251-
252- # TODO move to object scope, replace module_name
253- @classmethod
254- def tearDownClass (cls ):
255- cls .node .cleanup ()
256- cls .pb .del_test_dir (module_name ,'' )
235+ if version >= 150000 :
236+ home_dir = os .path .join (self .test_path ,"home" )
237+ os .makedirs (home_dir ,exist_ok = True )
238+ self .pb .test_env ['HOME' ]= home_dir
239+ self .pgpass_file = os .path .join (home_dir ,'.pgpass' )
240+ self .pgpass_file_lock = None
241+ else :
242+ # before PGv15 only true home dir were inspected.
243+ # Since we can't have separate file per test, we have to serialize
244+ # tests.
245+ self .pgpass_file = os .path .join (os .path .expanduser ('~' ),'.pgpass' )
246+ self .pgpass_file_lock = self .pgpass_file + '~probackup_test_lock'
247+ # have to lock pgpass by creating file in exclusive mode
248+ for i in range (120 ):
249+ try :
250+ open (self .pgpass_file_lock ,"x" ).close ()
251+ except FileExistsError :
252+ time .sleep (1 )
253+ else :
254+ break
255+ else :
256+ raise TimeoutError ("can't create ~/.pgpass~probackup_test_lock for 120 seconds" )
257257
258- @unittest .skipIf (skip_test ,"Module pexpect isn't installed. You need to install it." )
259- def setUp (self ):
260258self .pb_cmd = ['backup' ,
261259'-B' ,self .backup_dir ,
262260'--instance' ,self .node .name ,
@@ -268,6 +266,19 @@ def setUp(self):
268266 ]
269267
270268def tearDown (self ):
269+ if (self .pgpass_file_lock
270+ and hasattr (self ,"pgpass_line" )
271+ and os .path .exists (self .pgpass_file )):
272+ with open (self .pgpass_file ,'r' ,encoding = "utf-8" )as fl :
273+ lines = fl .readlines ()
274+ if self .pgpass_line in lines :
275+ lines .remove (self .pgpass_line )
276+ if len (lines )== 0 :
277+ os .remove (self .pgpass_file )
278+ else :
279+ with open (self .pgpass_file ,'w' ,encoding = "utf-8" )as fl :
280+ fl .writelines (lines )
281+
271282if "PGPASSWORD" in self .pb .test_env .keys ():
272283del self .pb .test_env ["PGPASSWORD" ]
273284
@@ -279,6 +290,10 @@ def tearDown(self):
279290except OSError :
280291pass
281292
293+ test_path = os .path .join (self .pb .tmp_path ,module_name )
294+ self .node .cleanup ()
295+ self .pb .del_test_dir (test_path ,self ._testMethodName )
296+
282297def test_empty_password (self ):
283298""" Test case: PGPB_AUTH03 - zero password length """
284299try :
@@ -313,7 +328,7 @@ def test_ctrl_c_event(self):
313328
314329def test_pgpassfile_env (self ):
315330""" Test case: PGPB_AUTH06 - set environment var PGPASSFILE """
316- path = os .path .join (self .pb . tmp_path , module_name ,'pgpass.conf' )
331+ path = os .path .join (self .test_path ,'pgpass.conf' )
317332line = ":" .join (['127.0.0.1' ,str (self .node .port ),'postgres' ,'backup' ,'password' ])
318333self .create_pgpass (path ,line )
319334self .pb .test_env ["PGPASSFILE" ]= path
@@ -367,7 +382,7 @@ def run_pb_with_auth(self, password=None, add_args = [], kill=False):
367382
368383
369384@classmethod
370- def modify_pg_hba (cls ,node ):
385+ def modify_pg_hba (self ,node , username ):
371386"""
372387 Description:
373388 Add trust authentication for user postgres. Need for add new role and set grant.
@@ -378,11 +393,12 @@ def modify_pg_hba(cls, node):
378393with open (hba_conf ,'r+' )as fio :
379394data = fio .read ()
380395fio .seek (0 )
381- fio .write ('host\t all\t %s\t 127.0.0.1/0\t trust\n %s' % (cls . username ,data ))
396+ fio .write ('host\t all\t %s\t 127.0.0.1/0\t trust\n %s' % (username ,data ))
382397
383398
384399def create_pgpass (self ,path ,line ):
400+ self .pgpass_line = line + "\n "
385401with open (path ,'w' )as passfile :
386402# host:port:db:username:password
387- passfile .write (line )
403+ passfile .write (self . pgpass_line )
388404os .chmod (path ,0o600 )