@@ -60,6 +60,7 @@ def __init__(self, test_class: unittest.TestCase,
60
60
self .archive_compress = init_params .archive_compress
61
61
self .test_class .output = None
62
62
self .execution_time = None
63
+ self .valgrind_sup_path = init_params .valgrind_sup_path
63
64
64
65
def form_daemon_process (self ,cmdline ,env ):
65
66
def stream_output (stream :subprocess .PIPE )-> None :
@@ -88,6 +89,7 @@ def stream_output(stream: subprocess.PIPE) -> None:
88
89
89
90
return self .process .pid
90
91
92
+ # ---- Start run function ---- #
91
93
def run (self ,command ,gdb = False ,old_binary = False ,return_id = True ,env = None ,
92
94
skip_log_directory = False ,expect_error = False ,use_backup_dir = True ,daemonize = False ):
93
95
"""
@@ -98,53 +100,93 @@ def run(self, command, gdb=False, old_binary=False, return_id=True, env=None,
98
100
gdb: when True it returns GDBObj(), when tuple('suspend', port) it runs probackup
99
101
in suspended gdb mode with attachable gdb port, for local debugging
100
102
"""
103
+ command = self ._add_backup_dir_to_cmd (command ,use_backup_dir )
104
+ # Old bin or regular one
105
+ binary_path = self ._get_binary_path (old_binary )
106
+
107
+ if not env :
108
+ env = self .test_env
109
+ # Add additional options if needed
110
+ command ,strcommand = self ._add_options (command ,skip_log_directory )
111
+
112
+ self .test_class .cmd = f"{ binary_path } { strcommand } "
113
+ if self .verbose :
114
+ print (self .test_class .cmd )
115
+
116
+ cmdline = self ._form_cmdline (binary_path ,command )
117
+
118
+ if gdb is True :
119
+ # general test flow for using GDBObj
120
+ return GDBobj (cmdline ,self .test_class )
121
+
122
+ return self ._execute_command (cmdline ,env ,command ,gdb ,expect_error ,return_id ,daemonize )
123
+
124
+ def _add_backup_dir_to_cmd (self ,command :list ,use_backup_dir :TestBackupDir ):
101
125
if isinstance (use_backup_dir ,TestBackupDir ):
102
- command = [command [0 ],* use_backup_dir .pb_args ,* command [1 :]]
126
+ return [command [0 ],* use_backup_dir .pb_args ,* command [1 :]]
103
127
elif use_backup_dir :
104
- command = [command [0 ],* self .backup_dir .pb_args ,* command [1 :]]
128
+ return [command [0 ],* self .backup_dir .pb_args ,* command [1 :]]
105
129
else :
106
- command = [command [0 ],* self .backup_dir .pb_args [2 :],* command [1 :]]
107
-
108
- if not self .probackup_old_path and old_binary :
109
- logging .error ('PGPROBACKUPBIN_OLD is not set' )
110
- exit (1 )
130
+ return [command [0 ],* self .backup_dir .pb_args [2 :],* command [1 :]]
111
131
132
+ def _get_binary_path (self ,old_binary ):
112
133
if old_binary :
113
- binary_path = self .probackup_old_path
114
- else :
115
- binary_path = self .probackup_path
116
-
117
- if not env :
118
- env = self .test_env
134
+ if not self .probackup_old_path :
135
+ logging .error ('PGPROBACKUPBIN_OLD is not set' )
136
+ exit (1 )
137
+ return self .probackup_old_path
138
+ return self .probackup_path
119
139
140
+ def _add_options (self ,command :list ,skip_log_directory :bool ):
120
141
strcommand = ' ' .join (str (p )for p in command )
142
+
121
143
if '--log-level-file' in strcommand and \
122
144
'--log-directory' not in strcommand and \
123
145
not skip_log_directory :
124
146
command += ['--log-directory=' + self .pb_log_path ]
125
147
strcommand += ' ' + command [- 1 ]
126
148
127
149
if 'pglz' in strcommand and \
128
- ' -j' not in strcommand and '--thread' not in strcommand :
150
+ ' -j' not in strcommand and \
151
+ '--thread' not in strcommand :
129
152
command += ['-j' ,'1' ]
130
153
strcommand += ' -j 1'
131
154
132
- self .test_class .cmd = binary_path + ' ' + strcommand
133
- if self .verbose :
134
- print (self .test_class .cmd )
155
+ return command ,strcommand
135
156
157
+ def _form_cmdline (self ,binary_path ,command ):
136
158
cmdline = [binary_path ,* command ]
137
- if gdb is True :
138
- # general test flow for using GDBObj
139
- return GDBobj (cmdline ,self .test_class )
140
159
160
+ if self .valgrind_sup_path and command [0 ]!= "--version" :
161
+ os .makedirs (self .pb_log_path ,exist_ok = True )
162
+ if self .valgrind_sup_path and not os .path .isfile (self .valgrind_sup_path ):
163
+ raise FileNotFoundError (f"PG_PROBACKUP_VALGRIND_SUP should contain path to valgrind suppression file, "
164
+ f"but found:{ self .valgrind_sup_path } " )
165
+ valgrind_cmd = [
166
+ "valgrind" ,
167
+ "--gen-suppressions=all" ,
168
+ "--leak-check=full" ,
169
+ "--show-reachable=yes" ,
170
+ "--error-limit=no" ,
171
+ "--show-leak-kinds=all" ,
172
+ "--errors-for-leak-kinds=all" ,
173
+ "--error-exitcode=0" ,
174
+ f"--log-file={ os .path .join (self .pb_log_path ,f'valgrind-{ command [0 ]} -%p.log' )} " ,
175
+ f"--suppressions={ self .valgrind_sup_path } " ,
176
+ "--"
177
+ ]
178
+ cmdline = valgrind_cmd + cmdline
179
+
180
+ return cmdline
181
+
182
+ def _execute_command (self ,cmdline ,env ,command ,gdb ,expect_error ,return_id ,daemonize ):
141
183
try :
142
- if type (gdb )is tuple and gdb [0 ]== 'suspend' :
143
- # special test flow for manually debug probackup
184
+ if isinstance (gdb ,tuple )and gdb [0 ]== 'suspend' :
144
185
gdb_port = gdb [1 ]
145
186
cmdline = ['gdbserver' ]+ ['localhost:' + str (gdb_port )]+ cmdline
146
187
logging .warning ("pg_probackup gdb suspended, waiting gdb connection on localhost:{0}" .format (gdb_port ))
147
188
189
+ # Execute command
148
190
start_time = time .time ()
149
191
if daemonize :
150
192
return self .form_daemon_process (cmdline ,env )
@@ -174,6 +216,7 @@ def run(self, command, gdb=False, old_binary=False, return_id=True, env=None,
174
216
return self .test_class .output
175
217
else :
176
218
raise ProbackupException (self .test_class .output ,self .test_class .cmd )
219
+ # ---- End run function ---- #
177
220
178
221
def get_backup_id (self ):
179
222
if init_params .major_version > 2 :