@@ -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,94 @@ 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
- command += ['--log-directory=' + self .pb_log_path ]
125
- strcommand += ' ' + command [- 1 ]
146
+ log_arg = f'--log-directory={ self .pb_log_path } '
147
+ command = command + [log_arg ]
148
+ strcommand += f'{ log_arg } '
126
149
127
150
if 'pglz' in strcommand and \
128
- ' -j' not in strcommand and '--thread' not in strcommand :
151
+ ' -j' not in strcommand and \
152
+ '--thread' not in strcommand :
129
153
command += ['-j' ,'1' ]
130
154
strcommand += ' -j 1'
131
155
132
- self .test_class .cmd = binary_path + ' ' + strcommand
133
- if self .verbose :
134
- print (self .test_class .cmd )
156
+ return command ,strcommand
135
157
158
+ def _form_cmdline (self ,binary_path ,command ):
136
159
cmdline = [binary_path ,* command ]
137
- if gdb is True :
138
- # general test flow for using GDBObj
139
- return GDBobj (cmdline ,self .test_class )
140
160
161
+ if self .valgrind_sup_path and command [0 ]!= "--version" :
162
+ os .makedirs (self .pb_log_path ,exist_ok = True )
163
+ if self .valgrind_sup_path and not os .path .isfile (self .valgrind_sup_path ):
164
+ raise FileNotFoundError (f"PG_PROBACKUP_VALGRIND_SUP should contain path to valgrind suppression file, "
165
+ f"but found:{ self .valgrind_sup_path } " )
166
+ valgrind_cmd = [
167
+ "valgrind" ,
168
+ "--gen-suppressions=all" ,
169
+ "--leak-check=full" ,
170
+ "--show-reachable=yes" ,
171
+ "--error-limit=no" ,
172
+ "--show-leak-kinds=all" ,
173
+ "--errors-for-leak-kinds=all" ,
174
+ "--error-exitcode=0" ,
175
+ f"--log-file={ os .path .join (self .pb_log_path ,f'valgrind-{ command [0 ]} -%p.log' )} " ,
176
+ f"--suppressions={ self .valgrind_sup_path } " ,
177
+ "--"
178
+ ]
179
+ cmdline = valgrind_cmd + cmdline
180
+
181
+ return cmdline
182
+
183
+ def _execute_command (self ,cmdline ,env ,command ,gdb ,expect_error ,return_id ,daemonize ):
141
184
try :
142
- if type (gdb )is tuple and gdb [0 ]== 'suspend' :
143
- # special test flow for manually debug probackup
185
+ if isinstance (gdb ,tuple )and gdb [0 ]== 'suspend' :
144
186
gdb_port = gdb [1 ]
145
187
cmdline = ['gdbserver' ]+ ['localhost:' + str (gdb_port )]+ cmdline
146
188
logging .warning ("pg_probackup gdb suspended, waiting gdb connection on localhost:{0}" .format (gdb_port ))
147
189
190
+ # Execute command
148
191
start_time = time .time ()
149
192
if daemonize :
150
193
return self .form_daemon_process (cmdline ,env )
@@ -174,6 +217,7 @@ def run(self, command, gdb=False, old_binary=False, return_id=True, env=None,
174
217
return self .test_class .output
175
218
else :
176
219
raise ProbackupException (self .test_class .output ,self .test_class .cmd )
220
+ # ---- End run function ---- #
177
221
178
222
def get_backup_id (self ):
179
223
if init_params .major_version > 2 :