testgres-pg-probackup2 0.9.0__tar.gz → 0.9.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (17) hide show
  1. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/PKG-INFO +1 -1
  2. testgres_pg_probackup2-0.9.2/pg_probackup2/__init__.py +0 -0
  3. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/pg_probackup2/app.py +28 -26
  4. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/pg_probackup2/gdb.py +29 -3
  5. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/pg_probackup2/init_helpers.py +219 -26
  6. testgres_pg_probackup2-0.9.2/pg_probackup2/storage/__init__.py +0 -0
  7. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/setup.py +1 -1
  8. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/testgres_pg_probackup2.egg-info/PKG-INFO +1 -1
  9. testgres_pg_probackup2-0.9.0/pg_probackup2/__init__.py +0 -1
  10. testgres_pg_probackup2-0.9.0/pg_probackup2/storage/__init__.py +0 -1
  11. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/README.md +0 -0
  12. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/pg_probackup2/storage/fs_backup.py +0 -0
  13. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/setup.cfg +0 -0
  14. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/testgres_pg_probackup2.egg-info/SOURCES.txt +0 -0
  15. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/testgres_pg_probackup2.egg-info/dependency_links.txt +0 -0
  16. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/testgres_pg_probackup2.egg-info/requires.txt +0 -0
  17. {testgres_pg_probackup2-0.9.0 → testgres_pg_probackup2-0.9.2}/testgres_pg_probackup2.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testgres_pg_probackup2
3
- Version: 0.9.0
3
+ Version: 0.9.2
4
4
  Summary: Plugin for testgres that manages pg_probackup2
5
5
  Home-page: https://github.com/postgrespro/testgres
6
6
  Author: Postgres Professional
File without changes
@@ -126,7 +126,7 @@ class ProbackupApp:
126
126
  if self.verbose:
127
127
  print(self.test_class.cmd)
128
128
 
129
- cmdline = self._form_cmdline(binary_path, command)
129
+ cmdline = self._form_cmdline(binary_path, command, use_valgrind=gdb is False)
130
130
 
131
131
  if gdb is True:
132
132
  # general test flow for using GDBObj
@@ -168,35 +168,37 @@ class ProbackupApp:
168
168
 
169
169
  return command, strcommand
170
170
 
171
- def _form_cmdline(self, binary_path, command):
171
+ def _form_cmdline(self, binary_path, command, use_valgrind=True):
172
172
  cmdline = [binary_path, *command]
173
173
 
174
- if (self.valgrind == 'y' or self.valgrind_sup_path) and command[0] != "--version":
175
- os.makedirs(self.pb_log_path, exist_ok=True)
176
- valgrind_cmd = [
177
- "valgrind",
178
- "--gen-suppressions=all",
179
- "--leak-check=full",
180
- "--show-reachable=yes",
181
- "--error-limit=no",
182
- "--show-leak-kinds=all",
183
- "--errors-for-leak-kinds=all",
184
- "--error-exitcode=0",
185
- f"--log-file={os.path.join(self.pb_log_path, f'valgrind-{command[0]}-%p.log')}"
186
- ]
187
- if self.valgrind_sup_path:
188
- if os.path.isfile(self.valgrind_sup_path):
189
- valgrind_cmd += [f"--suppressions={self.valgrind_sup_path}"]
190
- else:
191
- raise FileNotFoundError(f"PG_PROBACKUP_VALGRIND_SUP must be the path to a valgrind suppression file, "
192
- f"but found: {self.valgrind_sup_path}")
174
+ if not use_valgrind or command[0] == "--version":
175
+ return cmdline
176
+ if self.valgrind != 'y' and not self.valgrind_sup_path:
177
+ return cmdline
178
+
179
+ os.makedirs(self.pb_log_path, exist_ok=True)
180
+ valgrind_cmd = [
181
+ "valgrind",
182
+ "--gen-suppressions=all",
183
+ "--leak-check=full",
184
+ "--show-reachable=yes",
185
+ "--error-limit=no",
186
+ "--show-leak-kinds=all",
187
+ "--errors-for-leak-kinds=all",
188
+ "--error-exitcode=0",
189
+ f"--log-file={os.path.join(self.pb_log_path, f'valgrind-{command[0]}-%p.log')}"
190
+ ]
191
+ if self.valgrind_sup_path:
192
+ if os.path.isfile(self.valgrind_sup_path):
193
+ valgrind_cmd += [f"--suppressions={self.valgrind_sup_path}"]
193
194
  else:
194
- # Assume the tests are started from the root of pg_probackup repository
195
- valgrind_cmd += [f"--suppressions=.valgrind.supp"]
196
-
197
- cmdline = valgrind_cmd + cmdline
195
+ raise FileNotFoundError(f"PG_PROBACKUP_VALGRIND_SUP must be the path to a valgrind suppression file, "
196
+ f"but found: {self.valgrind_sup_path}")
197
+ else:
198
+ # Assume the tests are started from the root of pg_probackup repository
199
+ valgrind_cmd += [f"--suppressions=.valgrind.supp"]
198
200
 
199
- return cmdline
201
+ return valgrind_cmd + cmdline
200
202
 
201
203
  def _execute_command(self, cmdline, env, command, gdb, expect_error, return_id, daemonize):
202
204
  try:
@@ -134,6 +134,8 @@ class GDBobj:
134
134
  )
135
135
 
136
136
  def remove_all_breakpoints(self):
137
+ if self._did_quit:
138
+ return
137
139
  if not self.has_breakpoint:
138
140
  return
139
141
 
@@ -149,6 +151,8 @@ class GDBobj:
149
151
  )
150
152
 
151
153
  def run_until_break(self):
154
+ if self._did_quit:
155
+ return
152
156
  result = self._execute('run', False)
153
157
  for line in result:
154
158
  if line.startswith('*stopped,reason="breakpoint-hit"'):
@@ -158,6 +162,8 @@ class GDBobj:
158
162
  )
159
163
 
160
164
  def continue_execution_until_running(self):
165
+ if self._did_quit:
166
+ return
161
167
  result = self._execute('continue')
162
168
 
163
169
  for line in result:
@@ -175,9 +181,23 @@ class GDBobj:
175
181
  def signal(self, sig):
176
182
  if 'KILL' in sig:
177
183
  self.remove_all_breakpoints()
184
+ # Avoid GDB 15.x SIGABRT: kill inferior directly, not via `signal`.
185
+ try:
186
+ pids = subprocess.check_output(
187
+ ['pgrep', '-P', str(self.gdb_pid)],
188
+ text=True
189
+ ).strip().split()
190
+ for pid in pids:
191
+ os.kill(int(pid), 9)
192
+ except (subprocess.CalledProcessError, ValueError, OSError):
193
+ pass
194
+ self.kill()
195
+ return
178
196
  self._execute(f'signal {sig}')
179
197
 
180
198
  def continue_execution_until_exit(self):
199
+ if self._did_quit:
200
+ return
181
201
  self.remove_all_breakpoints()
182
202
  result = self._execute('continue', False)
183
203
 
@@ -195,6 +215,8 @@ class GDBobj:
195
215
  )
196
216
 
197
217
  def continue_execution_until_error(self):
218
+ if self._did_quit:
219
+ return
198
220
  self.remove_all_breakpoints()
199
221
  result = self._execute('continue', False)
200
222
 
@@ -211,6 +233,8 @@ class GDBobj:
211
233
  'Failed to continue execution until error.\n')
212
234
 
213
235
  def continue_execution_until_break(self, ignore_count=0):
236
+ if self._did_quit:
237
+ return
214
238
  if ignore_count > 0:
215
239
  result = self._execute(
216
240
  'continue ' + str(ignore_count),
@@ -253,6 +277,8 @@ class GDBobj:
253
277
 
254
278
  # use for breakpoint, run, continue
255
279
  def _execute(self, cmd, running=True):
280
+ if self._did_quit:
281
+ return []
256
282
  output = []
257
283
  self.proc.stdin.flush()
258
284
  self.proc.stdin.write(cmd + '\n')
@@ -320,9 +346,9 @@ def needs_gdb(func):
320
346
  check = _check_gdb_flag_or_skip_test()
321
347
  if not check:
322
348
  @functools.wraps(func)
323
- def ok_wrapped(self):
349
+ def ok_wrapped(self, *args, **kwargs):
324
350
  self._gdb_decorated = True
325
- func(self)
351
+ return func(self, *args, **kwargs)
326
352
 
327
353
  return ok_wrapped
328
354
  reason = check[1]
@@ -330,7 +356,7 @@ def needs_gdb(func):
330
356
  return unittest.skip(reason)(func)
331
357
  elif check[0] == "fail":
332
358
  @functools.wraps(func)
333
- def fail_wrapper(self):
359
+ def fail_wrapper(self, *args, **kwargs):
334
360
  self.fail(reason)
335
361
 
336
362
  return fail_wrapper
@@ -9,7 +9,7 @@ import subprocess
9
9
  import sys
10
10
  import traceback
11
11
  import testgres
12
- from testgres.operations.exceptions import InvalidOperationException
12
+ import typing
13
13
 
14
14
  try:
15
15
  import lz4.frame # noqa: F401
@@ -38,7 +38,46 @@ except Exception as e:
38
38
  logging.warning("Can't configure testgres: {0}".format(e))
39
39
 
40
40
 
41
+ class InitData_ServerProps:
42
+ pgpro_edition: typing.Optional[str]
43
+ num_version: int
44
+
45
+ def __init__(
46
+ self,
47
+ pgpro_edition: typing.Optional[str],
48
+ num_version: int,
49
+ ):
50
+ assert pgpro_edition is None or type(pgpro_edition) is str
51
+ assert type(num_version) is int
52
+ self.pgpro_edition = pgpro_edition
53
+ self.num_version = num_version
54
+ return
55
+
56
+
57
+ class InitData_BinaryName:
58
+ pg_config: str
59
+ postgres: str
60
+ initdb: str
61
+
62
+ def __init__(
63
+ self,
64
+ pg_config: str,
65
+ initdb: str,
66
+ postgres: str,
67
+ ):
68
+ assert type(pg_config) is str
69
+ assert type(postgres) is str
70
+ assert type(initdb) is str
71
+
72
+ self.pg_config = pg_config
73
+ self.postgres = postgres
74
+ self.initdb = initdb
75
+ return
76
+
77
+
41
78
  class Init(object):
79
+ _server_props: InitData_ServerProps
80
+
42
81
  def __init__(self):
43
82
  if '-v' in sys.argv or '--verbose' in sys.argv:
44
83
  self.verbose = True
@@ -50,21 +89,38 @@ class Init(object):
50
89
 
51
90
  pg_bin = testgres.get_bin_dir(os_ops)
52
91
  if pg_bin is None:
53
- raise InvalidOperationException(
54
- "Failed to determine the Postgres binary directory. Specify the path to the directory in PG_BIN or put it into the system PATH.")
55
- postgres = os_ops.build_path(pg_bin, 'postgres.exe' if os_name == 'nt' else 'postgres')
92
+ raise testgres.InvalidOperationException(
93
+ "Failed to determine the Postgres binary directory. Specify the path to the directory in PG_BIN or put it into the system PATH.",
94
+ )
95
+
96
+ if not os_ops.path_exists(pg_bin):
97
+ raise testgres.InvalidOperationException(
98
+ "Path [{}] is not found.".format(pg_bin),
99
+ )
100
+
101
+ pg_config_path = os_ops.build_path(
102
+ pg_bin,
103
+ __class__._get_binary_names(os_ops).pg_config,
104
+ )
56
105
 
57
- pgpro_edition = os_ops.exec_command(
58
- [postgres, "-C", "pgpro_edition"],
59
- encoding='utf-8',
60
- ignore_errors=True).rstrip()
61
- self.is_enterprise = pgpro_edition == 'enterprise'
62
- self.is_shardman = pgpro_edition == 'shardman'
63
- self.is_pgpro = pgpro_edition != ''
106
+ assert type(pg_config_path) is str
107
+
108
+ if os_ops.path_exists(pg_config_path):
109
+ self._server_props = __class__._init__get_server_props__via_pg_config(
110
+ os_ops,
111
+ pg_config_path,
112
+ )
113
+ else:
114
+ self._server_props = __class__._init__get_server_props__via_server(
115
+ os_ops,
116
+ pg_bin,
117
+ )
64
118
 
65
119
  # TODO: Always test with NLS support and remove this flag
66
120
  self.is_nls_enabled = True
67
121
 
122
+ postgres = os_ops.build_path(pg_bin, 'postgres.exe' if os_name == 'nt' else 'postgres')
123
+
68
124
  if os_name == 'posix':
69
125
  ldd = os_ops.exec_command(
70
126
  ['ldd', postgres],
@@ -81,19 +137,11 @@ class Init(object):
81
137
  break
82
138
  else:
83
139
  # Fall back to trying to determine lz4 support via pg_config
84
- pg_config = testgres.get_pg_config(os_ops=os_ops)
85
- self.is_lz4_enabled = '-llz4' in pg_config['LIBS']
86
-
87
- server_version_out = os_ops.exec_command(
88
- [postgres, "-C", "server_version"],
89
- encoding='utf-8')
90
- server_version = testgres.parse_pg_version(server_version_out)
91
- parts = [*server_version.split('.'), '0', '0'][:3]
92
- parts[0] = re.match(r'\d+', parts[0]).group()
93
- # Server_version consists of two fields (x.y) so num_version always ends with 00
94
- num_version = reduce(lambda v, x: v * 100 + int(x), parts, 0)
95
- # For backward compatibility
96
- self.pg_config_version = num_version
140
+ pg_config_data = testgres.utils.get_pg_config2(
141
+ pg_config_path=pg_config_path,
142
+ os_ops=os_ops,
143
+ )
144
+ self.is_lz4_enabled = '-llz4' in pg_config_data['LIBS']
97
145
 
98
146
  os.environ['LANGUAGE'] = 'en' # set default locale language to en. All messages will use this locale
99
147
  test_env = os.environ.copy()
@@ -163,7 +211,7 @@ class Init(object):
163
211
  self.probackup_path = probackup_path_tmp
164
212
 
165
213
  if not self.probackup_path:
166
- raise Exception('pg_probackup binary is not found')
214
+ raise Exception('pg_probackup binary is not found, add it to PATH or point PGPROBACKUPBIN')
167
215
 
168
216
  if os_name == 'posix':
169
217
  self.EXTERNAL_DIRECTORY_DELIMITER = ':'
@@ -210,7 +258,7 @@ class Init(object):
210
258
  self.old_probackup_version = match.group(0) if match else None
211
259
 
212
260
  self.remote = test_env.get('PGPROBACKUP_SSH_REMOTE', None) == 'ON'
213
- self.ptrack = test_env.get('PG_PROBACKUP_PTRACK', None) == 'ON' and num_version >= 110000
261
+ self.ptrack = test_env.get('PG_PROBACKUP_PTRACK', None) == 'ON' and self._server_props.num_version >= 110000
214
262
  self.wal_tree_enabled = test_env.get('PG_PROBACKUP_WAL_TREE_ENABLED', None) == 'ON'
215
263
 
216
264
  self.bckp_source = test_env.get('PG_PROBACKUP_SOURCE', 'pro').lower()
@@ -262,6 +310,151 @@ class Init(object):
262
310
  def test_env(self):
263
311
  return self._test_env.copy()
264
312
 
313
+ @property
314
+ def is_enterprise(self) -> bool:
315
+ assert type(self._server_props) is InitData_ServerProps
316
+ return self._server_props.pgpro_edition == 'enterprise'
317
+
318
+ @property
319
+ def is_shardman(self) -> bool:
320
+ assert type(self._server_props) is InitData_ServerProps
321
+ return self._server_props.pgpro_edition == 'shardman'
322
+
323
+ @property
324
+ def is_pgpro(self) -> bool:
325
+ assert type(self._server_props) is InitData_ServerProps
326
+ return self._server_props.pgpro_edition is not None
327
+
328
+ @property
329
+ def pg_config_version(self) -> int:
330
+ assert type(self._server_props) is InitData_ServerProps
331
+ return self._server_props.num_version
332
+
333
+ @staticmethod
334
+ def _init__get_server_props__via_pg_config(
335
+ os_ops: testgres.OsOperations,
336
+ pg_config_path: str,
337
+ ) -> InitData_ServerProps:
338
+ assert isinstance(os_ops, testgres.OsOperations)
339
+ assert type(pg_config_path) is str
340
+
341
+ pg_config = testgres.utils.get_pg_config2(
342
+ pg_config_path=pg_config_path,
343
+ os_ops=os_ops,
344
+ )
345
+ assert type(pg_config) is dict
346
+
347
+ pgpro_edition = pg_config.get('PGPRO_EDITION')
348
+ assert pgpro_edition is None or type(pgpro_edition) is str
349
+
350
+ version_str = pg_config.get('VERSION', '')
351
+ assert type(version_str) is str
352
+
353
+ if not version_str:
354
+ raise RuntimeError("Field 'VERSION' not found in pg_config output")
355
+
356
+ version_num = testgres.parse_pg_version(version_str)
357
+ parts = [*version_num.split('.'), '0', '0'][:3]
358
+ parts[0] = re.match(r'\d+', parts[0]).group()
359
+
360
+ num_version = reduce(lambda v, x: v * 100 + int(x), parts, 0)
361
+ assert type(num_version) is int
362
+
363
+ return InitData_ServerProps(
364
+ pgpro_edition=pgpro_edition,
365
+ num_version=num_version,
366
+ )
367
+
368
+ @staticmethod
369
+ def _init__get_server_props__via_server(
370
+ os_ops: testgres.OsOperations,
371
+ pg_bin_dir: str,
372
+ ) -> InitData_ServerProps:
373
+ assert isinstance(os_ops, testgres.OsOperations)
374
+ assert type(pg_bin_dir) is str
375
+
376
+ tmpdir = os_ops.mkdtemp()
377
+ assert type(tmpdir) is str
378
+ assert os_ops.path_exists(tmpdir)
379
+ assert os_ops.is_abs_path(tmpdir)
380
+
381
+ try:
382
+ initdb = os_ops.build_path(
383
+ pg_bin_dir,
384
+ __class__._get_binary_names(os_ops).initdb,
385
+ )
386
+
387
+ os_ops.exec_command(
388
+ [initdb, "-D", tmpdir],
389
+ encoding='utf-8',
390
+ )
391
+
392
+ postgres = os_ops.build_path(
393
+ pg_bin_dir,
394
+ __class__._get_binary_names(os_ops).postgres,
395
+ )
396
+
397
+ pgpro_edition_out: typing.Optional[str] = None
398
+ try:
399
+ exec_r = os_ops.exec_command(
400
+ [postgres, "-C", "pgpro_edition", "-D", tmpdir],
401
+ encoding='utf-8',
402
+ )
403
+ assert type(exec_r) is str
404
+ pgpro_edition_out = exec_r.strip()
405
+ except testgres.ExecUtilException as e:
406
+ assert e.exit_code != 0
407
+
408
+ logging.debug("Exception ({}): {}".format(
409
+ type(e).__name__,
410
+ e,
411
+ ))
412
+
413
+ assert pgpro_edition_out is None or type(pgpro_edition_out) is str
414
+ pgpro_edition = pgpro_edition_out
415
+
416
+ server_version_out = os_ops.exec_command(
417
+ [postgres, "-C", "server_version", "-D", tmpdir],
418
+ encoding='utf-8'
419
+ )
420
+ assert type(server_version_out) is str
421
+ server_version = testgres.parse_pg_version(server_version_out)
422
+ parts = [*server_version.split('.'), '0', '0'][:3]
423
+ parts[0] = re.match(r'\d+', parts[0]).group()
424
+ # Server_version consists of two fields (x.y) so num_version always ends with 00
425
+ pg_config_version = reduce(lambda v, x: v * 100 + int(x), parts, 0)
426
+ finally:
427
+ os_ops.rmdirs(tmpdir)
428
+
429
+ return InitData_ServerProps(
430
+ pgpro_edition=pgpro_edition,
431
+ num_version=pg_config_version,
432
+ )
433
+
434
+ sm_binary_names__win32 = InitData_BinaryName(
435
+ pg_config="pg_config.exe",
436
+ initdb="initdb.exe",
437
+ postgres="postgres.exe",
438
+ )
439
+
440
+ sm_binary_names__linux = InitData_BinaryName(
441
+ pg_config="pg_config",
442
+ initdb="initdb",
443
+ postgres="postgres",
444
+ )
445
+
446
+ @staticmethod
447
+ def _get_binary_names(
448
+ os_ops: testgres.OsOperations,
449
+ ) -> InitData_BinaryName:
450
+ assert isinstance(os_ops, testgres.OsOperations)
451
+
452
+ platform_name = os_ops.get_platform()
453
+ if platform_name == "win32":
454
+ return __class__.sm_binary_names__win32
455
+
456
+ return __class__.sm_binary_names__linux
457
+
265
458
 
266
459
  try:
267
460
  init_params = Init()
@@ -4,7 +4,7 @@ except ImportError:
4
4
  from distutils.core import setup
5
5
 
6
6
  setup(
7
- version='0.9.0',
7
+ version='0.9.2',
8
8
  name='testgres_pg_probackup2',
9
9
  packages=['pg_probackup2', 'pg_probackup2.storage'],
10
10
  description='Plugin for testgres that manages pg_probackup2',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testgres_pg_probackup2
3
- Version: 0.9.0
3
+ Version: 0.9.2
4
4
  Summary: Plugin for testgres that manages pg_probackup2
5
5
  Home-page: https://github.com/postgrespro/testgres
6
6
  Author: Postgres Professional