Skip to content

Commit 44d61c2

Browse files
authored
Add ability to run pg_probackup using valgrind (#263)
1 parent 0b9cc3f commit 44d61c2

File tree

2 files changed

+67
-22
lines changed

2 files changed

+67
-22
lines changed

testgres/plugins/pg_probackup2/pg_probackup2/app.py

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def __init__(self, test_class: unittest.TestCase,
6060
self.archive_compress = init_params.archive_compress
6161
self.test_class.output = None
6262
self.execution_time = None
63+
self.valgrind_sup_path = init_params.valgrind_sup_path
6364

6465
def form_daemon_process(self, cmdline, env):
6566
def stream_output(stream: subprocess.PIPE) -> None:
@@ -88,6 +89,7 @@ def stream_output(stream: subprocess.PIPE) -> None:
8889

8990
return self.process.pid
9091

92+
# ---- Start run function ---- #
9193
def run(self, command, gdb=False, old_binary=False, return_id=True, env=None,
9294
skip_log_directory=False, expect_error=False, use_backup_dir=True, daemonize=False):
9395
"""
@@ -98,53 +100,93 @@ def run(self, command, gdb=False, old_binary=False, return_id=True, env=None,
98100
gdb: when True it returns GDBObj(), when tuple('suspend', port) it runs probackup
99101
in suspended gdb mode with attachable gdb port, for local debugging
100102
"""
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):
101125
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:]]
103127
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:]]
105129
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:]]
111131

132+
def _get_binary_path(self, old_binary):
112133
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
119139

140+
def _add_options(self, command: list, skip_log_directory: bool):
120141
strcommand = ' '.join(str(p) for p in command)
142+
121143
if '--log-level-file' in strcommand and \
122144
'--log-directory' not in strcommand and \
123145
not skip_log_directory:
124146
command += ['--log-directory=' + self.pb_log_path]
125147
strcommand += ' ' + command[-1]
126148

127149
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:
129152
command += ['-j', '1']
130153
strcommand += ' -j 1'
131154

132-
self.test_class.cmd = binary_path + ' ' + strcommand
133-
if self.verbose:
134-
print(self.test_class.cmd)
155+
return command, strcommand
135156

157+
def _form_cmdline(self, binary_path, command):
136158
cmdline = [binary_path, *command]
137-
if gdb is True:
138-
# general test flow for using GDBObj
139-
return GDBobj(cmdline, self.test_class)
140159

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):
141183
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':
144185
gdb_port = gdb[1]
145186
cmdline = ['gdbserver'] + ['localhost:' + str(gdb_port)] + cmdline
146187
logging.warning("pg_probackup gdb suspended, waiting gdb connection on localhost:{0}".format(gdb_port))
147188

189+
# Execute command
148190
start_time = time.time()
149191
if daemonize:
150192
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,
174216
return self.test_class.output
175217
else:
176218
raise ProbackupException(self.test_class.output, self.test_class.cmd)
219+
# ---- End run function ---- #
177220

178221
def get_backup_id(self):
179222
if init_params.major_version > 2:

testgres/plugins/pg_probackup2/pg_probackup2/init_helpers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ def __init__(self):
214214
else:
215215
raise Exception('Can\'t process pg_probackup version \"{}\": the major version is expected to be a number'.format(self.probackup_version))
216216

217+
self.valgrind_sup_path = test_env.get('PG_PROBACKUP_VALGRIND_SUP', None)
218+
217219
def test_env(self):
218220
return self._test_env.copy()
219221

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy