testgres 1.9.3__tar.gz → 1.10.1__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 (53) hide show
  1. {testgres-1.9.3/testgres.egg-info → testgres-1.10.1}/PKG-INFO +1 -1
  2. {testgres-1.9.3 → testgres-1.10.1}/setup.py +1 -1
  3. {testgres-1.9.3 → testgres-1.10.1}/testgres/backup.py +5 -1
  4. {testgres-1.9.3 → testgres-1.10.1}/testgres/cache.py +4 -3
  5. {testgres-1.9.3 → testgres-1.10.1}/testgres/connection.py +4 -5
  6. {testgres-1.9.3 → testgres-1.10.1}/testgres/node.py +120 -27
  7. {testgres-1.9.3 → testgres-1.10.1}/testgres/operations/local_ops.py +1 -1
  8. testgres-1.10.1/testgres/plugins/__init__.py +8 -0
  9. testgres-1.10.1/testgres/plugins/pg_probackup2/__init__.py +0 -0
  10. testgres-1.10.1/testgres/plugins/pg_probackup2/build/lib/pg_probackup2/__init__.py +0 -0
  11. testgres-1.10.1/testgres/plugins/pg_probackup2/build/lib/pg_probackup2/app.py +781 -0
  12. testgres-1.10.1/testgres/plugins/pg_probackup2/build/lib/pg_probackup2/gdb.py +346 -0
  13. testgres-1.10.1/testgres/plugins/pg_probackup2/build/lib/pg_probackup2/init_helpers.py +211 -0
  14. testgres-1.10.1/testgres/plugins/pg_probackup2/build/lib/pg_probackup2/storage/__init__.py +0 -0
  15. testgres-1.10.1/testgres/plugins/pg_probackup2/build/lib/pg_probackup2/storage/fs_backup.py +104 -0
  16. testgres-1.10.1/testgres/plugins/pg_probackup2/pg_probackup2/__init__.py +0 -0
  17. testgres-1.10.1/testgres/plugins/pg_probackup2/pg_probackup2/app.py +802 -0
  18. testgres-1.10.1/testgres/plugins/pg_probackup2/pg_probackup2/gdb.py +346 -0
  19. testgres-1.10.1/testgres/plugins/pg_probackup2/pg_probackup2/init_helpers.py +217 -0
  20. testgres-1.10.1/testgres/plugins/pg_probackup2/pg_probackup2/storage/__init__.py +0 -0
  21. testgres-1.10.1/testgres/plugins/pg_probackup2/pg_probackup2/storage/fs_backup.py +104 -0
  22. testgres-1.10.1/testgres/plugins/pg_probackup2/pg_probackup2/tests/basic_test.py +79 -0
  23. testgres-1.10.1/testgres/plugins/pg_probackup2/setup.py +18 -0
  24. {testgres-1.9.3 → testgres-1.10.1}/testgres/utils.py +12 -8
  25. {testgres-1.9.3 → testgres-1.10.1/testgres.egg-info}/PKG-INFO +1 -1
  26. testgres-1.10.1/testgres.egg-info/SOURCES.txt +51 -0
  27. {testgres-1.9.3 → testgres-1.10.1}/tests/test_simple.py +32 -1
  28. testgres-1.9.3/testgres.egg-info/SOURCES.txt +0 -35
  29. {testgres-1.9.3 → testgres-1.10.1}/LICENSE +0 -0
  30. {testgres-1.9.3 → testgres-1.10.1}/MANIFEST.in +0 -0
  31. {testgres-1.9.3 → testgres-1.10.1}/README.md +0 -0
  32. {testgres-1.9.3 → testgres-1.10.1}/setup.cfg +0 -0
  33. {testgres-1.9.3 → testgres-1.10.1}/testgres/__init__.py +0 -0
  34. {testgres-1.9.3 → testgres-1.10.1}/testgres/api.py +0 -0
  35. {testgres-1.9.3 → testgres-1.10.1}/testgres/config.py +0 -0
  36. {testgres-1.9.3 → testgres-1.10.1}/testgres/consts.py +0 -0
  37. {testgres-1.9.3 → testgres-1.10.1}/testgres/decorators.py +0 -0
  38. {testgres-1.9.3 → testgres-1.10.1}/testgres/defaults.py +0 -0
  39. {testgres-1.9.3 → testgres-1.10.1}/testgres/enums.py +0 -0
  40. {testgres-1.9.3 → testgres-1.10.1}/testgres/exceptions.py +0 -0
  41. {testgres-1.9.3 → testgres-1.10.1}/testgres/helpers/__init__.py +0 -0
  42. {testgres-1.9.3 → testgres-1.10.1}/testgres/helpers/port_manager.py +0 -0
  43. {testgres-1.9.3 → testgres-1.10.1}/testgres/logger.py +0 -0
  44. {testgres-1.9.3 → testgres-1.10.1}/testgres/operations/__init__.py +0 -0
  45. {testgres-1.9.3 → testgres-1.10.1}/testgres/operations/os_ops.py +0 -0
  46. {testgres-1.9.3 → testgres-1.10.1}/testgres/operations/remote_ops.py +0 -0
  47. {testgres-1.9.3 → testgres-1.10.1}/testgres/pubsub.py +0 -0
  48. {testgres-1.9.3 → testgres-1.10.1}/testgres/standby.py +0 -0
  49. {testgres-1.9.3 → testgres-1.10.1}/testgres.egg-info/dependency_links.txt +0 -0
  50. {testgres-1.9.3 → testgres-1.10.1}/testgres.egg-info/requires.txt +0 -0
  51. {testgres-1.9.3 → testgres-1.10.1}/testgres.egg-info/top_level.txt +0 -0
  52. {testgres-1.9.3 → testgres-1.10.1}/tests/test_remote.py +0 -0
  53. {testgres-1.9.3 → testgres-1.10.1}/tests/test_simple_remote.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: testgres
3
- Version: 1.9.3
3
+ Version: 1.10.1
4
4
  Summary: Testing utility for PostgreSQL and its extensions
5
5
  Home-page: https://github.com/postgrespro/testgres
6
6
  Author: Postgres Professional
@@ -27,7 +27,7 @@ with open('README.md', 'r') as f:
27
27
  readme = f.read()
28
28
 
29
29
  setup(
30
- version='1.9.3',
30
+ version='1.10.1',
31
31
  name='testgres',
32
32
  packages=['testgres', 'testgres.operations', 'testgres.helpers'],
33
33
  description='Testing utility for PostgreSQL and its extensions',
@@ -33,7 +33,8 @@ class NodeBackup(object):
33
33
  node,
34
34
  base_dir=None,
35
35
  username=None,
36
- xlog_method=XLogMethod.fetch):
36
+ xlog_method=XLogMethod.fetch,
37
+ options=None):
37
38
  """
38
39
  Create a new backup.
39
40
 
@@ -43,6 +44,8 @@ class NodeBackup(object):
43
44
  username: database user name.
44
45
  xlog_method: none | fetch | stream (see docs)
45
46
  """
47
+ if not options:
48
+ options = []
46
49
  self.os_ops = node.os_ops
47
50
  if not node.status():
48
51
  raise BackupException('Node must be running')
@@ -77,6 +80,7 @@ class NodeBackup(object):
77
80
  "-D", data_dir,
78
81
  "-X", xlog_method.value
79
82
  ] # yapf: disable
83
+ _params += options
80
84
  execute_utility(_params, self.log_file)
81
85
 
82
86
  def __enter__(self):
@@ -22,19 +22,20 @@ from .operations.local_ops import LocalOperations
22
22
  from .operations.os_ops import OsOperations
23
23
 
24
24
 
25
- def cached_initdb(data_dir, logfile=None, params=None, os_ops: OsOperations = LocalOperations()):
25
+ def cached_initdb(data_dir, logfile=None, params=None, os_ops: OsOperations = LocalOperations(), bin_path=None, cached=True):
26
26
  """
27
27
  Perform initdb or use cached node files.
28
28
  """
29
29
 
30
30
  def call_initdb(initdb_dir, log=logfile):
31
31
  try:
32
- _params = [get_bin_path("initdb"), "-D", initdb_dir, "-N"]
32
+ initdb_path = os.path.join(bin_path, 'initdb') if bin_path else get_bin_path("initdb")
33
+ _params = [initdb_path, "-D", initdb_dir, "-N"]
33
34
  execute_utility(_params + (params or []), log)
34
35
  except ExecUtilException as e:
35
36
  raise_from(InitNodeException("Failed to run initdb"), e)
36
37
 
37
- if params or not testgres_config.cache_initdb:
38
+ if params or not testgres_config.cache_initdb or not cached:
38
39
  call_initdb(data_dir, logfile)
39
40
  else:
40
41
  # Fetch cached initdb dir
@@ -104,14 +104,13 @@ class NodeConnection(object):
104
104
  def execute(self, query, *args):
105
105
  self.cursor.execute(query, args)
106
106
  try:
107
- res = self.cursor.fetchall()
108
107
  # pg8000 might return tuples
109
- if isinstance(res, tuple):
110
- res = [tuple(t) for t in res]
111
-
108
+ res = [tuple(t) for t in self.cursor.fetchall()]
112
109
  return res
110
+ except ProgrammingError:
111
+ return None
113
112
  except Exception as e:
114
- print("Error executing query: {}".format(e))
113
+ print("Error executing query: {}\n {}".format(repr(e), query))
115
114
  return None
116
115
 
117
116
  def close(self):
@@ -127,7 +127,7 @@ class ProcessProxy(object):
127
127
 
128
128
 
129
129
  class PostgresNode(object):
130
- def __init__(self, name=None, port=None, base_dir=None, conn_params: ConnectionParams = ConnectionParams()):
130
+ def __init__(self, name=None, port=None, base_dir=None, conn_params: ConnectionParams = ConnectionParams(), bin_dir=None, prefix=None):
131
131
  """
132
132
  PostgresNode constructor.
133
133
 
@@ -135,12 +135,15 @@ class PostgresNode(object):
135
135
  name: node's application name.
136
136
  port: port to accept connections.
137
137
  base_dir: path to node's data directory.
138
+ bin_dir: path to node's binary directory.
138
139
  """
139
140
 
140
141
  # private
141
- self._pg_version = PgVer(get_pg_version())
142
+ self._pg_version = PgVer(get_pg_version(bin_dir))
142
143
  self._should_free_port = port is None
143
144
  self._base_dir = base_dir
145
+ self._bin_dir = bin_dir
146
+ self._prefix = prefix
144
147
  self._logger = None
145
148
  self._master = None
146
149
 
@@ -281,7 +284,7 @@ class PostgresNode(object):
281
284
  @property
282
285
  def base_dir(self):
283
286
  if not self._base_dir:
284
- self._base_dir = self.os_ops.mkdtemp(prefix=TMP_NODE)
287
+ self._base_dir = self.os_ops.mkdtemp(prefix=self._prefix or TMP_NODE)
285
288
 
286
289
  # NOTE: it's safe to create a new dir
287
290
  if not self.os_ops.path_exists(self._base_dir):
@@ -289,6 +292,12 @@ class PostgresNode(object):
289
292
 
290
293
  return self._base_dir
291
294
 
295
+ @property
296
+ def bin_dir(self):
297
+ if not self._bin_dir:
298
+ self._bin_dir = os.path.dirname(get_bin_path("pg_config"))
299
+ return self._bin_dir
300
+
292
301
  @property
293
302
  def logs_dir(self):
294
303
  path = os.path.join(self.base_dir, LOGS_DIR)
@@ -441,7 +450,7 @@ class PostgresNode(object):
441
450
 
442
451
  return result
443
452
 
444
- def init(self, initdb_params=None, **kwargs):
453
+ def init(self, initdb_params=None, cached=True, **kwargs):
445
454
  """
446
455
  Perform initdb for this node.
447
456
 
@@ -460,7 +469,9 @@ class PostgresNode(object):
460
469
  data_dir=self.data_dir,
461
470
  logfile=self.utils_log_file,
462
471
  os_ops=self.os_ops,
463
- params=initdb_params)
472
+ params=initdb_params,
473
+ bin_path=self.bin_dir,
474
+ cached=False)
464
475
 
465
476
  # initialize default config files
466
477
  self.default_conf(**kwargs)
@@ -619,7 +630,7 @@ class PostgresNode(object):
619
630
 
620
631
  try:
621
632
  _params = [
622
- get_bin_path("pg_ctl"),
633
+ self._get_bin_path('pg_ctl'),
623
634
  "-D", self.data_dir,
624
635
  "status"
625
636
  ] # yapf: disable
@@ -645,7 +656,7 @@ class PostgresNode(object):
645
656
  """
646
657
 
647
658
  # this one is tricky (blame PG 9.4)
648
- _params = [get_bin_path("pg_controldata")]
659
+ _params = [self._get_bin_path("pg_controldata")]
649
660
  _params += ["-D"] if self._pg_version >= PgVer('9.5') else []
650
661
  _params += [self.data_dir]
651
662
 
@@ -708,21 +719,37 @@ class PostgresNode(object):
708
719
  return self
709
720
 
710
721
  _params = [
711
- get_bin_path("pg_ctl"),
722
+ self._get_bin_path("pg_ctl"),
712
723
  "-D", self.data_dir,
713
724
  "-l", self.pg_log_file,
714
725
  "-w" if wait else '-W', # --wait or --no-wait
715
726
  "start"
716
727
  ] + params # yapf: disable
717
728
 
718
- try:
719
- exit_status, out, error = execute_utility(_params, self.utils_log_file, verbose=True)
720
- if error and 'does not exist' in error:
721
- raise Exception
722
- except Exception as e:
723
- msg = 'Cannot start node'
724
- files = self._collect_special_files()
725
- raise_from(StartNodeException(msg, files), e)
729
+ startup_retries = 5
730
+ while True:
731
+ try:
732
+ exit_status, out, error = execute_utility(_params, self.utils_log_file, verbose=True)
733
+ if error and 'does not exist' in error:
734
+ raise Exception
735
+ except Exception as e:
736
+ files = self._collect_special_files()
737
+ if any(len(file) > 1 and 'Is another postmaster already '
738
+ 'running on port' in file[1].decode() for
739
+ file in files):
740
+ print("Detected an issue with connecting to port {0}. "
741
+ "Trying another port after a 5-second sleep...".format(self.port))
742
+ self.port = reserve_port()
743
+ options = {}
744
+ options['port'] = str(self.port)
745
+ self.set_auto_conf(options)
746
+ startup_retries -= 1
747
+ time.sleep(5)
748
+ continue
749
+
750
+ msg = 'Cannot start node'
751
+ raise_from(StartNodeException(msg, files), e)
752
+ break
726
753
  self._maybe_start_logger()
727
754
  self.is_started = True
728
755
  return self
@@ -742,7 +769,7 @@ class PostgresNode(object):
742
769
  return self
743
770
 
744
771
  _params = [
745
- get_bin_path("pg_ctl"),
772
+ self._get_bin_path("pg_ctl"),
746
773
  "-D", self.data_dir,
747
774
  "-w" if wait else '-W', # --wait or --no-wait
748
775
  "stop"
@@ -782,7 +809,7 @@ class PostgresNode(object):
782
809
  """
783
810
 
784
811
  _params = [
785
- get_bin_path("pg_ctl"),
812
+ self._get_bin_path("pg_ctl"),
786
813
  "-D", self.data_dir,
787
814
  "-l", self.pg_log_file,
788
815
  "-w", # wait
@@ -814,7 +841,7 @@ class PostgresNode(object):
814
841
  """
815
842
 
816
843
  _params = [
817
- get_bin_path("pg_ctl"),
844
+ self._get_bin_path("pg_ctl"),
818
845
  "-D", self.data_dir,
819
846
  "reload"
820
847
  ] + params # yapf: disable
@@ -835,7 +862,7 @@ class PostgresNode(object):
835
862
  """
836
863
 
837
864
  _params = [
838
- get_bin_path("pg_ctl"),
865
+ self._get_bin_path("pg_ctl"),
839
866
  "-D", self.data_dir,
840
867
  "-w", # wait
841
868
  "promote"
@@ -871,7 +898,7 @@ class PostgresNode(object):
871
898
  """
872
899
 
873
900
  _params = [
874
- get_bin_path("pg_ctl"),
901
+ self._get_bin_path("pg_ctl"),
875
902
  "-D", self.data_dir,
876
903
  "-w" # wait
877
904
  ] + params # yapf: disable
@@ -945,7 +972,7 @@ class PostgresNode(object):
945
972
  username = username or default_username()
946
973
 
947
974
  psql_params = [
948
- get_bin_path("psql"),
975
+ self._get_bin_path("psql"),
949
976
  "-p", str(self.port),
950
977
  "-h", self.host,
951
978
  "-U", username,
@@ -1066,7 +1093,7 @@ class PostgresNode(object):
1066
1093
  filename = filename or tmpfile()
1067
1094
 
1068
1095
  _params = [
1069
- get_bin_path("pg_dump"),
1096
+ self._get_bin_path("pg_dump"),
1070
1097
  "-p", str(self.port),
1071
1098
  "-h", self.host,
1072
1099
  "-f", filename,
@@ -1094,7 +1121,7 @@ class PostgresNode(object):
1094
1121
  username = username or default_username()
1095
1122
 
1096
1123
  _params = [
1097
- get_bin_path("pg_restore"),
1124
+ self._get_bin_path("pg_restore"),
1098
1125
  "-p", str(self.port),
1099
1126
  "-h", self.host,
1100
1127
  "-U", username,
@@ -1344,7 +1371,7 @@ class PostgresNode(object):
1344
1371
  username=None,
1345
1372
  stdout=None,
1346
1373
  stderr=None,
1347
- options=[]):
1374
+ options=None):
1348
1375
  """
1349
1376
  Spawn a pgbench process.
1350
1377
 
@@ -1358,13 +1385,15 @@ class PostgresNode(object):
1358
1385
  Returns:
1359
1386
  Process created by subprocess.Popen.
1360
1387
  """
1388
+ if options is None:
1389
+ options = []
1361
1390
 
1362
1391
  # Set default arguments
1363
1392
  dbname = dbname or default_dbname()
1364
1393
  username = username or default_username()
1365
1394
 
1366
1395
  _params = [
1367
- get_bin_path("pgbench"),
1396
+ self._get_bin_path("pgbench"),
1368
1397
  "-p", str(self.port),
1369
1398
  "-h", self.host,
1370
1399
  "-U", username,
@@ -1377,6 +1406,29 @@ class PostgresNode(object):
1377
1406
 
1378
1407
  return proc
1379
1408
 
1409
+ def pgbench_with_wait(self,
1410
+ dbname=None,
1411
+ username=None,
1412
+ stdout=None,
1413
+ stderr=None,
1414
+ options=None):
1415
+ """
1416
+ Do pgbench command and wait.
1417
+
1418
+ Args:
1419
+ dbname: database name to connect to.
1420
+ username: database user name.
1421
+ stdout: stdout file to be used by Popen.
1422
+ stderr: stderr file to be used by Popen.
1423
+ options: additional options for pgbench (list).
1424
+ """
1425
+ if options is None:
1426
+ options = []
1427
+
1428
+ with self.pgbench(dbname, username, stdout, stderr, options) as pgbench:
1429
+ pgbench.wait()
1430
+ return
1431
+
1380
1432
  def pgbench_init(self, **kwargs):
1381
1433
  """
1382
1434
  Small wrapper for pgbench_run().
@@ -1416,7 +1468,7 @@ class PostgresNode(object):
1416
1468
  username = username or default_username()
1417
1469
 
1418
1470
  _params = [
1419
- get_bin_path("pgbench"),
1471
+ self._get_bin_path("pgbench"),
1420
1472
  "-p", str(self.port),
1421
1473
  "-h", self.host,
1422
1474
  "-U", username,
@@ -1587,6 +1639,47 @@ class PostgresNode(object):
1587
1639
 
1588
1640
  self.os_ops.write(path, auto_conf, truncate=True)
1589
1641
 
1642
+ def upgrade_from(self, old_node, options=None):
1643
+ """
1644
+ Upgrade this node from an old node using pg_upgrade.
1645
+
1646
+ Args:
1647
+ old_node: An instance of PostgresNode representing the old node.
1648
+ """
1649
+ if not os.path.exists(old_node.data_dir):
1650
+ raise Exception("Old node must be initialized")
1651
+
1652
+ if not os.path.exists(self.data_dir):
1653
+ self.init()
1654
+
1655
+ if not options:
1656
+ options = []
1657
+
1658
+ pg_upgrade_binary = self._get_bin_path("pg_upgrade")
1659
+
1660
+ if not os.path.exists(pg_upgrade_binary):
1661
+ raise Exception("pg_upgrade does not exist in the new node's binary path")
1662
+
1663
+ upgrade_command = [
1664
+ pg_upgrade_binary,
1665
+ "--old-bindir", old_node.bin_dir,
1666
+ "--new-bindir", self.bin_dir,
1667
+ "--old-datadir", old_node.data_dir,
1668
+ "--new-datadir", self.data_dir,
1669
+ "--old-port", str(old_node.port),
1670
+ "--new-port", str(self.port),
1671
+ ]
1672
+ upgrade_command += options
1673
+
1674
+ return self.os_ops.exec_command(upgrade_command)
1675
+
1676
+ def _get_bin_path(self, filename):
1677
+ if self.bin_dir:
1678
+ bin_path = os.path.join(self.bin_dir, filename)
1679
+ else:
1680
+ bin_path = get_bin_path(filename)
1681
+ return bin_path
1682
+
1590
1683
 
1591
1684
  class NodeApp:
1592
1685
 
@@ -44,7 +44,7 @@ class LocalOperations(OsOperations):
44
44
  def _raise_exec_exception(message, command, exit_code, output):
45
45
  """Raise an ExecUtilException."""
46
46
  raise ExecUtilException(message=message.format(output),
47
- command=command,
47
+ command=' '.join(command) if isinstance(command, list) else command,
48
48
  exit_code=exit_code,
49
49
  out=output)
50
50
 
@@ -0,0 +1,8 @@
1
+ from pg_probackup2.gdb import GDBobj
2
+ from pg_probackup2.app import ProbackupApp, ProbackupException
3
+ from pg_probackup2.init_helpers import init_params
4
+ from pg_probackup2.storage.fs_backup import FSTestBackupDir
5
+
6
+ __all__ = [
7
+ "ProbackupApp", "ProbackupException", "init_params", "FSTestBackupDir", "GDBobj"
8
+ ]