testgres 1.15.0__tar.gz → 1.15.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.
- {testgres-1.15.0/testgres.egg-info → testgres-1.15.2}/PKG-INFO +2 -2
- {testgres-1.15.0 → testgres-1.15.2}/pyproject.toml +1 -1
- {testgres-1.15.0 → testgres-1.15.2}/src/__init__.py +1 -1
- {testgres-1.15.0 → testgres-1.15.2}/src/impl/file_line_reader.py +9 -2
- testgres-1.15.2/src/impl/internal_utils.py +92 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/logger.py +1 -1
- {testgres-1.15.0 → testgres-1.15.2}/src/node.py +66 -18
- {testgres-1.15.0 → testgres-1.15.2/testgres.egg-info}/PKG-INFO +2 -2
- {testgres-1.15.0 → testgres-1.15.2}/testgres.egg-info/requires.txt +1 -1
- {testgres-1.15.0 → testgres-1.15.2}/tests/test_os_ops_common.py +16 -1
- {testgres-1.15.0 → testgres-1.15.2}/tests/test_testgres_common.py +91 -35
- {testgres-1.15.0 → testgres-1.15.2}/tests/test_testgres_remote.py +3 -0
- testgres-1.15.0/src/impl/internal_utils.py +0 -20
- {testgres-1.15.0 → testgres-1.15.2}/LICENSE +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/README.md +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/setup.cfg +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/api.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/backup.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/cache.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/config.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/connection.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/consts.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/decorators.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/defaults.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/enums.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/exceptions.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/impl/platforms/internal_platform_utils.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/impl/platforms/internal_platform_utils_factory.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/impl/platforms/linux/internal_platform_utils.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/impl/platforms/win32/internal_platform_utils.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/impl/port_manager__generic.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/impl/port_manager__generic2.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/impl/port_manager__this_host.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/node_app.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/port_manager.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/pubsub.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/raise_error.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/standby.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/src/utils.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/testgres.egg-info/SOURCES.txt +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/testgres.egg-info/dependency_links.txt +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/testgres.egg-info/top_level.txt +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/tests/test_api.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/tests/test_config.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/tests/test_os_ops_local.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/tests/test_os_ops_remote.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/tests/test_raise_error.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/tests/test_testgres_local.py +0 -0
- {testgres-1.15.0 → testgres-1.15.2}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testgres
|
|
3
|
-
Version: 1.15.
|
|
3
|
+
Version: 1.15.2
|
|
4
4
|
Summary: Testing utility for PostgreSQL and its extensions
|
|
5
5
|
Author-email: Postgres Professional <testgres@postgrespro.ru>
|
|
6
6
|
License: PostgreSQL
|
|
@@ -27,7 +27,7 @@ Requires-Dist: port-for>=0.4
|
|
|
27
27
|
Requires-Dist: six>=1.9.0
|
|
28
28
|
Requires-Dist: psutil
|
|
29
29
|
Requires-Dist: packaging
|
|
30
|
-
Requires-Dist: testgres.os_ops<4.0.0,>=3.
|
|
30
|
+
Requires-Dist: testgres.os_ops<4.0.0,>=3.2.0
|
|
31
31
|
Dynamic: license-file
|
|
32
32
|
|
|
33
33
|
[](https://github.com/postgrespro/testgres/actions/workflows/ci.yml)
|
|
@@ -57,7 +57,7 @@ from testgres.operations.os_ops import OsOperations, ConnectionParams
|
|
|
57
57
|
from testgres.operations.local_ops import LocalOperations
|
|
58
58
|
from testgres.operations.remote_ops import RemoteOperations
|
|
59
59
|
|
|
60
|
-
__version__ = "1.15.
|
|
60
|
+
__version__ = "1.15.2"
|
|
61
61
|
|
|
62
62
|
__all__ = [
|
|
63
63
|
"get_new_node",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
2
|
|
|
3
|
+
from . import internal_utils
|
|
4
|
+
|
|
3
5
|
import typing
|
|
4
6
|
|
|
5
7
|
from testgres.operations.os_ops import OsOperations
|
|
@@ -19,15 +21,20 @@ class FileLineReader:
|
|
|
19
21
|
os_ops: OsOperations,
|
|
20
22
|
file_name: str,
|
|
21
23
|
file_encoding: str = "utf-8",
|
|
24
|
+
file_pos: int = 0
|
|
22
25
|
):
|
|
23
26
|
assert isinstance(os_ops, OsOperations)
|
|
24
27
|
assert type(file_encoding) is str
|
|
25
28
|
self._os_ops = os_ops
|
|
26
29
|
self._file_name = file_name
|
|
27
30
|
self._file_encoding = file_encoding
|
|
28
|
-
self._file_pos =
|
|
31
|
+
self._file_pos = file_pos
|
|
29
32
|
self._buffer_pos = 0
|
|
30
|
-
self._buffer =
|
|
33
|
+
self._buffer = internal_utils.read_line_to_pos__bin(
|
|
34
|
+
os_ops,
|
|
35
|
+
file_name,
|
|
36
|
+
file_pos,
|
|
37
|
+
)
|
|
31
38
|
return
|
|
32
39
|
|
|
33
40
|
# interface ----------------------------------------------------------
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from testgres.operations.os_ops import OsOperations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import typing
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def send_log(level: int, msg: str) -> None:
|
|
8
|
+
assert type(level) is int
|
|
9
|
+
assert type(msg) is str
|
|
10
|
+
|
|
11
|
+
return logging.log(level, "[testgres] " + msg)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def send_log_info(msg: str) -> None:
|
|
15
|
+
assert type(msg) is str
|
|
16
|
+
|
|
17
|
+
return send_log(logging.INFO, msg)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def send_log_debug(msg: str) -> None:
|
|
21
|
+
assert type(msg) is str
|
|
22
|
+
|
|
23
|
+
return send_log(logging.DEBUG, msg)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def read_line_to_pos__bin(
|
|
27
|
+
os_ops: OsOperations,
|
|
28
|
+
filename: str,
|
|
29
|
+
position: int,
|
|
30
|
+
) -> bytes:
|
|
31
|
+
assert type(filename) is str
|
|
32
|
+
assert type(position) is int
|
|
33
|
+
assert len(filename) > 0
|
|
34
|
+
assert position >= 0
|
|
35
|
+
assert os_ops is not None
|
|
36
|
+
assert isinstance(os_ops, OsOperations)
|
|
37
|
+
|
|
38
|
+
if position == 0:
|
|
39
|
+
return b''
|
|
40
|
+
|
|
41
|
+
assert position > 0
|
|
42
|
+
|
|
43
|
+
read_position = position
|
|
44
|
+
result_blocks: typing.List[bytes] = []
|
|
45
|
+
|
|
46
|
+
C_BACK_READ_BLOCK_SIZE = 4096
|
|
47
|
+
|
|
48
|
+
while read_position > 0:
|
|
49
|
+
if read_position < C_BACK_READ_BLOCK_SIZE:
|
|
50
|
+
block_sz = read_position
|
|
51
|
+
else:
|
|
52
|
+
block_sz = C_BACK_READ_BLOCK_SIZE
|
|
53
|
+
|
|
54
|
+
assert block_sz > 0
|
|
55
|
+
assert block_sz <= C_BACK_READ_BLOCK_SIZE
|
|
56
|
+
|
|
57
|
+
read_position -= block_sz
|
|
58
|
+
|
|
59
|
+
assert read_position < position
|
|
60
|
+
assert read_position >= 0
|
|
61
|
+
|
|
62
|
+
block = os_ops.read_binary(filename, read_position, block_sz)
|
|
63
|
+
|
|
64
|
+
assert type(block) is bytes
|
|
65
|
+
|
|
66
|
+
if len(block) != block_sz:
|
|
67
|
+
err_msg = "[BUG CHECK] Readed block has bad size ({}). Expected size is ({}). File name {}.".format(
|
|
68
|
+
len(block),
|
|
69
|
+
block_sz,
|
|
70
|
+
filename,
|
|
71
|
+
)
|
|
72
|
+
raise RuntimeError(err_msg)
|
|
73
|
+
|
|
74
|
+
assert len(block) == block_sz
|
|
75
|
+
|
|
76
|
+
x = block.rfind(b"\n", 0, block_sz)
|
|
77
|
+
|
|
78
|
+
if x == -1:
|
|
79
|
+
result_blocks.append(block)
|
|
80
|
+
continue
|
|
81
|
+
|
|
82
|
+
if x == block_sz - 1:
|
|
83
|
+
break
|
|
84
|
+
|
|
85
|
+
block = block[x + 1:]
|
|
86
|
+
result_blocks.append(block)
|
|
87
|
+
break
|
|
88
|
+
|
|
89
|
+
result = b''.join(reversed(result_blocks))
|
|
90
|
+
assert type(result) is bytes
|
|
91
|
+
assert len(result) <= (position - read_position)
|
|
92
|
+
return result
|
|
@@ -31,7 +31,7 @@ class TestgresLogger(threading.Thread):
|
|
|
31
31
|
assert type(log_file_encoding) is str
|
|
32
32
|
assert os_ops is None or isinstance(os_ops, OsOperations)
|
|
33
33
|
|
|
34
|
-
threading.Thread.__init__(self)
|
|
34
|
+
threading.Thread.__init__(self, daemon=True)
|
|
35
35
|
|
|
36
36
|
if os_ops is None:
|
|
37
37
|
os_ops = tconf.os_ops
|
|
@@ -638,6 +638,12 @@ class PostgresNode(object):
|
|
|
638
638
|
assert type(with_force) is bool
|
|
639
639
|
assert max_attempts > 0
|
|
640
640
|
|
|
641
|
+
try:
|
|
642
|
+
self._try_shutdown_internal(max_attempts, with_force)
|
|
643
|
+
finally:
|
|
644
|
+
self._maybe_stop_logger()
|
|
645
|
+
|
|
646
|
+
def _try_shutdown_internal(self, max_attempts, with_force):
|
|
641
647
|
attempts = 0
|
|
642
648
|
|
|
643
649
|
# try stopping server N times
|
|
@@ -1278,7 +1284,7 @@ class PostgresNode(object):
|
|
|
1278
1284
|
if nAttempt == __class__._C_MAX_START_ATEMPTS:
|
|
1279
1285
|
self._raise_cannot_start_node(e, "Cannot start node after multiple attempts.")
|
|
1280
1286
|
|
|
1281
|
-
is_it_port_conflict = PostgresNodeUtils.
|
|
1287
|
+
is_it_port_conflict = PostgresNodeUtils.detect_port_conflict(log_reader)
|
|
1282
1288
|
|
|
1283
1289
|
if not is_it_port_conflict:
|
|
1284
1290
|
LOCAL__raise_cannot_start_node__std(e)
|
|
@@ -1331,11 +1337,13 @@ class PostgresNode(object):
|
|
|
1331
1337
|
"stop"
|
|
1332
1338
|
] + params # yapf: disable
|
|
1333
1339
|
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1340
|
+
try:
|
|
1341
|
+
execute_utility2(self._os_ops, _params, self.utils_log_file)
|
|
1342
|
+
self._manually_started_pm_pid = None
|
|
1343
|
+
finally:
|
|
1344
|
+
# always stop the reader thread, even if pg_ctl stop failed,
|
|
1345
|
+
# so it can't leak into interpreter shutdown.
|
|
1346
|
+
self._maybe_stop_logger()
|
|
1339
1347
|
return self
|
|
1340
1348
|
|
|
1341
1349
|
def kill(self, someone=None):
|
|
@@ -2430,9 +2438,14 @@ class PostgresNodeLogReader:
|
|
|
2430
2438
|
position: int
|
|
2431
2439
|
tail: bytes
|
|
2432
2440
|
|
|
2433
|
-
def __init__(self, position: int):
|
|
2441
|
+
def __init__(self, position: int, tail: bytes = b''):
|
|
2442
|
+
assert type(position) is int
|
|
2443
|
+
assert type(tail) is bytes
|
|
2444
|
+
assert position >= 0
|
|
2445
|
+
|
|
2434
2446
|
self.position = position
|
|
2435
|
-
self.tail =
|
|
2447
|
+
self.tail = tail
|
|
2448
|
+
return
|
|
2436
2449
|
|
|
2437
2450
|
# --------------------------------------------------------------------
|
|
2438
2451
|
class LogDataBlock:
|
|
@@ -2487,7 +2500,7 @@ class PostgresNodeLogReader:
|
|
|
2487
2500
|
if from_beginnig:
|
|
2488
2501
|
self._logs = dict()
|
|
2489
2502
|
else:
|
|
2490
|
-
self._logs = self._collect_logs()
|
|
2503
|
+
self._logs = self._collect_logs(find_line_start=True)
|
|
2491
2504
|
|
|
2492
2505
|
assert type(self._logs) is dict
|
|
2493
2506
|
return
|
|
@@ -2496,13 +2509,13 @@ class PostgresNodeLogReader:
|
|
|
2496
2509
|
assert self._node is not None
|
|
2497
2510
|
assert isinstance(self._node, PostgresNode)
|
|
2498
2511
|
|
|
2499
|
-
cur_logs
|
|
2512
|
+
cur_logs = self._collect_logs(find_line_start=False)
|
|
2500
2513
|
assert cur_logs is not None
|
|
2501
2514
|
assert type(cur_logs) is dict
|
|
2502
2515
|
|
|
2503
2516
|
assert type(self._logs) is dict
|
|
2504
2517
|
|
|
2505
|
-
result =
|
|
2518
|
+
result: typing.List[__class__.LogDataBlock] = []
|
|
2506
2519
|
|
|
2507
2520
|
for file_name, cur_log_info in cur_logs.items():
|
|
2508
2521
|
assert type(file_name) is str
|
|
@@ -2570,7 +2583,8 @@ class PostgresNodeLogReader:
|
|
|
2570
2583
|
|
|
2571
2584
|
return result
|
|
2572
2585
|
|
|
2573
|
-
def _collect_logs(self) -> typing.Dict[str, LogInfo]:
|
|
2586
|
+
def _collect_logs(self, find_line_start: bool) -> typing.Dict[str, LogInfo]:
|
|
2587
|
+
assert type(find_line_start) is bool
|
|
2574
2588
|
assert self._node is not None
|
|
2575
2589
|
assert isinstance(self._node, PostgresNode)
|
|
2576
2590
|
|
|
@@ -2587,18 +2601,52 @@ class PostgresNodeLogReader:
|
|
|
2587
2601
|
if not self._node.os_ops.path_exists(f):
|
|
2588
2602
|
continue
|
|
2589
2603
|
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2604
|
+
result[f] = self._create_log_info(
|
|
2605
|
+
self._node.os_ops,
|
|
2606
|
+
f,
|
|
2607
|
+
find_line_start,
|
|
2608
|
+
)
|
|
2609
|
+
continue
|
|
2595
2610
|
|
|
2596
2611
|
return result
|
|
2597
2612
|
|
|
2613
|
+
@staticmethod
|
|
2614
|
+
def _create_log_info(
|
|
2615
|
+
os_ops: OsOperations,
|
|
2616
|
+
filename: str,
|
|
2617
|
+
find_line_start: bool,
|
|
2618
|
+
) -> LogInfo:
|
|
2619
|
+
assert type(filename) is str
|
|
2620
|
+
assert type(find_line_start) is bool
|
|
2621
|
+
assert len(filename) > 0
|
|
2622
|
+
assert os_ops is not None
|
|
2623
|
+
assert isinstance(os_ops, OsOperations)
|
|
2624
|
+
|
|
2625
|
+
file_size = os_ops.get_file_size(filename)
|
|
2626
|
+
assert type(file_size) is int
|
|
2627
|
+
assert file_size >= 0
|
|
2628
|
+
|
|
2629
|
+
if not find_line_start:
|
|
2630
|
+
return __class__.LogInfo(
|
|
2631
|
+
position=file_size,
|
|
2632
|
+
tail=b'',
|
|
2633
|
+
)
|
|
2634
|
+
|
|
2635
|
+
tail = internal_utils.read_line_to_pos__bin(
|
|
2636
|
+
os_ops,
|
|
2637
|
+
filename,
|
|
2638
|
+
file_size,
|
|
2639
|
+
)
|
|
2640
|
+
|
|
2641
|
+
return __class__.LogInfo(
|
|
2642
|
+
position=file_size,
|
|
2643
|
+
tail=tail,
|
|
2644
|
+
)
|
|
2645
|
+
|
|
2598
2646
|
|
|
2599
2647
|
class PostgresNodeUtils:
|
|
2600
2648
|
@staticmethod
|
|
2601
|
-
def
|
|
2649
|
+
def detect_port_conflict(log_reader: PostgresNodeLogReader) -> bool:
|
|
2602
2650
|
assert type(log_reader) is PostgresNodeLogReader
|
|
2603
2651
|
|
|
2604
2652
|
blocks = log_reader.read()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: testgres
|
|
3
|
-
Version: 1.15.
|
|
3
|
+
Version: 1.15.2
|
|
4
4
|
Summary: Testing utility for PostgreSQL and its extensions
|
|
5
5
|
Author-email: Postgres Professional <testgres@postgrespro.ru>
|
|
6
6
|
License: PostgreSQL
|
|
@@ -27,7 +27,7 @@ Requires-Dist: port-for>=0.4
|
|
|
27
27
|
Requires-Dist: six>=1.9.0
|
|
28
28
|
Requires-Dist: psutil
|
|
29
29
|
Requires-Dist: packaging
|
|
30
|
-
Requires-Dist: testgres.os_ops<4.0.0,>=3.
|
|
30
|
+
Requires-Dist: testgres.os_ops<4.0.0,>=3.2.0
|
|
31
31
|
Dynamic: license-file
|
|
32
32
|
|
|
33
33
|
[](https://github.com/postgrespro/testgres/actions/workflows/ci.yml)
|
|
@@ -1352,8 +1352,15 @@ class TestOsOpsCommon:
|
|
|
1352
1352
|
|
|
1353
1353
|
tmpdir = os_ops.get_tempdir()
|
|
1354
1354
|
|
|
1355
|
-
|
|
1355
|
+
filedir = os_ops.build_path(
|
|
1356
1356
|
tmpdir,
|
|
1357
|
+
"test_isfile_false__not_exist-" + uuid.uuid4().bytes.hex(),
|
|
1358
|
+
)
|
|
1359
|
+
|
|
1360
|
+
os_ops.makedir(filedir)
|
|
1361
|
+
|
|
1362
|
+
filename = os_ops.build_path(
|
|
1363
|
+
filedir,
|
|
1357
1364
|
name_with_surprize.value,
|
|
1358
1365
|
)
|
|
1359
1366
|
|
|
@@ -1369,7 +1376,11 @@ class TestOsOpsCommon:
|
|
|
1369
1376
|
pass
|
|
1370
1377
|
else:
|
|
1371
1378
|
# We will check a real work with another host
|
|
1379
|
+
assert not os.path.exists(filedir)
|
|
1372
1380
|
assert not os.path.exists(filename)
|
|
1381
|
+
|
|
1382
|
+
os.mkdir(filedir)
|
|
1383
|
+
|
|
1373
1384
|
with open(filename, "a"):
|
|
1374
1385
|
os.utime(filename, None)
|
|
1375
1386
|
assert os.path.exists(filename)
|
|
@@ -1384,7 +1395,11 @@ class TestOsOpsCommon:
|
|
|
1384
1395
|
assert os.path.exists(filename)
|
|
1385
1396
|
os.remove(filename)
|
|
1386
1397
|
assert not os.path.exists(filename)
|
|
1398
|
+
os.rmdir(filedir)
|
|
1399
|
+
assert not os.path.exists(filedir)
|
|
1387
1400
|
logging.info("Local detecter is deleted [{}]".format(filename))
|
|
1401
|
+
|
|
1402
|
+
os_ops.rmdir(filedir)
|
|
1388
1403
|
return
|
|
1389
1404
|
|
|
1390
1405
|
def test_isfile_false__directory(
|
|
@@ -121,7 +121,7 @@ class TestTestgresCommon:
|
|
|
121
121
|
# Author: Mark G.
|
|
122
122
|
assert v.major == 1
|
|
123
123
|
assert v.minor == 15
|
|
124
|
-
assert v.micro ==
|
|
124
|
+
assert v.micro == 1
|
|
125
125
|
|
|
126
126
|
assert str(v) == testgres_version
|
|
127
127
|
return
|
|
@@ -190,15 +190,15 @@ class TestTestgresCommon:
|
|
|
190
190
|
return
|
|
191
191
|
|
|
192
192
|
def test_node_constructor__default(self):
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
193
|
+
with PostgresNode() as node:
|
|
194
|
+
assert node._os_ops is not None
|
|
195
|
+
assert isinstance(node._os_ops, OsOperations)
|
|
196
|
+
assert node._port_manager is not None
|
|
197
|
+
assert isinstance(node._port_manager, PortManager)
|
|
198
|
+
assert node._name is not None
|
|
199
|
+
assert type(node._name) is str
|
|
200
|
+
assert node._name != ""
|
|
201
|
+
assert node._base_dir is None
|
|
202
202
|
return
|
|
203
203
|
|
|
204
204
|
def test_node_constructor__host(self):
|
|
@@ -456,12 +456,70 @@ class TestTestgresCommon:
|
|
|
456
456
|
assert isinstance(node_svc, PostgresNodeService)
|
|
457
457
|
|
|
458
458
|
with __class__.helper__get_node(node_svc) as node:
|
|
459
|
-
node.init()
|
|
459
|
+
node.init()
|
|
460
|
+
|
|
461
|
+
nRestartAttempt = 0
|
|
462
|
+
|
|
463
|
+
while True:
|
|
464
|
+
nRestartAttempt += 1
|
|
465
|
+
|
|
466
|
+
logging.info("Attempt #{}".format(nRestartAttempt))
|
|
467
|
+
|
|
468
|
+
node.start()
|
|
469
|
+
|
|
470
|
+
# restart, ok
|
|
471
|
+
res = node.execute('select 1')
|
|
472
|
+
assert (res == [(1,)])
|
|
473
|
+
|
|
474
|
+
node_log_reader = PostgresNodeLogReader(
|
|
475
|
+
node,
|
|
476
|
+
from_beginnig=False,
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
try:
|
|
480
|
+
node.restart()
|
|
481
|
+
except StartNodeException as e:
|
|
482
|
+
logging.info("Exception ({}): {}".format(
|
|
483
|
+
type(e).__name__,
|
|
484
|
+
e,
|
|
485
|
+
))
|
|
486
|
+
|
|
487
|
+
if nRestartAttempt == 5:
|
|
488
|
+
raise
|
|
489
|
+
|
|
490
|
+
if not PostgresNodeUtils.detect_port_conflict(node_log_reader):
|
|
491
|
+
raise
|
|
492
|
+
|
|
493
|
+
logging.info("Node port {} conflicted with another PostgreSQL instance.".format(
|
|
494
|
+
node.port
|
|
495
|
+
))
|
|
496
|
+
|
|
497
|
+
logging.info("Wait for node stop")
|
|
498
|
+
|
|
499
|
+
nStopAttemtp = 0
|
|
500
|
+
|
|
501
|
+
while True:
|
|
502
|
+
if nStopAttemtp == 5:
|
|
503
|
+
raise RuntimeError("Node is not stopped!")
|
|
504
|
+
|
|
505
|
+
nStopAttemtp += 1
|
|
506
|
+
|
|
507
|
+
time.sleep(1)
|
|
508
|
+
|
|
509
|
+
node_status = node.status()
|
|
510
|
+
|
|
511
|
+
logging.info("Node status is {}".format(node_status))
|
|
512
|
+
|
|
513
|
+
if node_status == NodeStatus.Stopped:
|
|
514
|
+
break
|
|
515
|
+
continue
|
|
516
|
+
|
|
517
|
+
# node is stopped. try again
|
|
518
|
+
continue
|
|
519
|
+
|
|
520
|
+
assert node.status() == NodeStatus.Running
|
|
521
|
+
break
|
|
460
522
|
|
|
461
|
-
# restart, ok
|
|
462
|
-
res = node.execute('select 1')
|
|
463
|
-
assert (res == [(1,)])
|
|
464
|
-
node.restart()
|
|
465
523
|
res = node.execute('select 2')
|
|
466
524
|
assert (res == [(2,)])
|
|
467
525
|
|
|
@@ -771,6 +829,8 @@ class TestTestgresCommon:
|
|
|
771
829
|
finally:
|
|
772
830
|
if node.is_started:
|
|
773
831
|
node.stop()
|
|
832
|
+
|
|
833
|
+
node.cleanup(release_resources=True)
|
|
774
834
|
return
|
|
775
835
|
|
|
776
836
|
def test_kill_backgroud_writer__ok(
|
|
@@ -1630,7 +1690,7 @@ class TestTestgresCommon:
|
|
|
1630
1690
|
|
|
1631
1691
|
nAttempt = 0
|
|
1632
1692
|
while True:
|
|
1633
|
-
if PostgresNodeUtils.
|
|
1693
|
+
if PostgresNodeUtils.detect_port_conflict(node_log_reader):
|
|
1634
1694
|
logging.info("Node port {} conflicted with another PostgreSQL instance.".format(
|
|
1635
1695
|
node.port
|
|
1636
1696
|
))
|
|
@@ -1726,12 +1786,9 @@ class TestTestgresCommon:
|
|
|
1726
1786
|
__class__.helper__skip_test_if_pg_version_is_not_ge(current_version, "9.6")
|
|
1727
1787
|
|
|
1728
1788
|
with __class__.helper__get_node(node_svc) as master:
|
|
1729
|
-
old_version = not __class__.helper__pg_version_ge(current_version, '9.6')
|
|
1730
|
-
|
|
1731
1789
|
master.init(allow_streaming=True).start()
|
|
1732
1790
|
|
|
1733
|
-
|
|
1734
|
-
master.append_conf('synchronous_commit = remote_apply')
|
|
1791
|
+
master.append_conf('synchronous_commit = remote_apply')
|
|
1735
1792
|
|
|
1736
1793
|
# create standby
|
|
1737
1794
|
with master.replicate() as standby1, master.replicate() as standby2:
|
|
@@ -1748,21 +1805,20 @@ class TestTestgresCommon:
|
|
|
1748
1805
|
|
|
1749
1806
|
# set synchronous_standby_names
|
|
1750
1807
|
master.set_synchronous_standbys(First(2, [standby1, standby2]))
|
|
1751
|
-
master.
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
assert (__class__.helper__rm_carriage_returns(res) == b'1000000\n')
|
|
1808
|
+
master.reload()
|
|
1809
|
+
|
|
1810
|
+
master.safe_psql('create table abc(a int)')
|
|
1811
|
+
|
|
1812
|
+
# Create a large transaction that will take some time to apply
|
|
1813
|
+
# on standby to check that it applies synchronously
|
|
1814
|
+
# (If set synchronous_commit to 'on' or other lower level then
|
|
1815
|
+
# standby most likely won't catchup so fast and test will fail)
|
|
1816
|
+
master.safe_psql(
|
|
1817
|
+
'insert into abc select generate_series(1, 1000000)',
|
|
1818
|
+
)
|
|
1819
|
+
res = standby1.safe_psql('select count(*) from abc')
|
|
1820
|
+
assert (__class__.helper__rm_carriage_returns(res) == b'1000000\n')
|
|
1821
|
+
return
|
|
1766
1822
|
|
|
1767
1823
|
def test_logical_replication(self, node_svc: PostgresNodeService):
|
|
1768
1824
|
assert isinstance(node_svc, PostgresNodeService)
|
|
@@ -82,6 +82,7 @@ class TestTestgresRemote:
|
|
|
82
82
|
assert isinstance(node_version, Version)
|
|
83
83
|
|
|
84
84
|
if node.version < Version("11"):
|
|
85
|
+
node.cleanup(release_resources=True)
|
|
85
86
|
pytest.skip("This test does not work on old PG10-.")
|
|
86
87
|
|
|
87
88
|
try:
|
|
@@ -152,6 +153,8 @@ class TestTestgresRemote:
|
|
|
152
153
|
assert expectedMsg2 in exc.error
|
|
153
154
|
continue
|
|
154
155
|
|
|
156
|
+
node.cleanup(release_resources=True)
|
|
157
|
+
|
|
155
158
|
if not errorIsDetected:
|
|
156
159
|
pytest.xfail("All the bad data are processed without errors!")
|
|
157
160
|
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def send_log(level: int, msg: str) -> None:
|
|
5
|
-
assert type(level) is int
|
|
6
|
-
assert type(msg) is str
|
|
7
|
-
|
|
8
|
-
return logging.log(level, "[testgres] " + msg)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def send_log_info(msg: str) -> None:
|
|
12
|
-
assert type(msg) is str
|
|
13
|
-
|
|
14
|
-
return send_log(logging.INFO, msg)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def send_log_debug(msg: str) -> None:
|
|
18
|
-
assert type(msg) is str
|
|
19
|
-
|
|
20
|
-
return send_log(logging.DEBUG, msg)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|