Skip to content

Commit 67f23a7

Browse files
Merge branch 'master' into skip-ssl-check
2 parents fb6205d + 1c73113 commit 67f23a7

File tree

9 files changed

+141
-60
lines changed

9 files changed

+141
-60
lines changed

testgres/operations/local_ops.py

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -58,47 +58,55 @@ def _process_output(encoding, temp_file_path):
5858
output = output.decode(encoding)
5959
return output, None # In Windows stderr writing in stdout
6060

61-
def _run_command(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding):
62-
"""Execute a command and return the process and its output."""
63-
if os.name == 'nt' and stdout is None: # Windows
64-
with tempfile.NamedTemporaryFile(mode='w+b', delete=False) as temp_file:
65-
stdout = temp_file
66-
stderr = subprocess.STDOUT
67-
process = subprocess.Popen(
68-
cmd,
69-
shell=shell,
70-
stdin=stdin or subprocess.PIPE if input is not None else None,
71-
stdout=stdout,
72-
stderr=stderr,
73-
)
74-
if get_process:
75-
return process, None, None
76-
temp_file_path = temp_file.name
77-
78-
# Wait process finished
79-
process.wait()
80-
81-
output, error = self._process_output(encoding, temp_file_path)
82-
return process, output, error
83-
else: # Other OS
61+
def _run_command__nt(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding):
62+
with tempfile.NamedTemporaryFile(mode='w+b', delete=False) as temp_file:
63+
stdout = temp_file
64+
stderr = subprocess.STDOUT
8465
process = subprocess.Popen(
8566
cmd,
8667
shell=shell,
8768
stdin=stdin or subprocess.PIPE if input is not None else None,
88-
stdout=stdout or subprocess.PIPE,
89-
stderr=stderr or subprocess.PIPE,
69+
stdout=stdout,
70+
stderr=stderr,
9071
)
9172
if get_process:
9273
return process, None, None
93-
try:
94-
output, error = process.communicate(input=input.encode(encoding) if input else None, timeout=timeout)
95-
if encoding:
96-
output = output.decode(encoding)
97-
error = error.decode(encoding)
98-
return process, output, error
99-
except subprocess.TimeoutExpired:
100-
process.kill()
101-
raise ExecUtilException("Command timed out after {} seconds.".format(timeout))
74+
temp_file_path = temp_file.name
75+
76+
# Wait process finished
77+
process.wait()
78+
79+
output, error = self._process_output(encoding, temp_file_path)
80+
return process, output, error
81+
82+
def _run_command__generic(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding):
83+
process = subprocess.Popen(
84+
cmd,
85+
shell=shell,
86+
stdin=stdin or subprocess.PIPE if input is not None else None,
87+
stdout=stdout or subprocess.PIPE,
88+
stderr=stderr or subprocess.PIPE,
89+
)
90+
if get_process:
91+
return process, None, None
92+
try:
93+
output, error = process.communicate(input=input.encode(encoding) if input else None, timeout=timeout)
94+
if encoding:
95+
output = output.decode(encoding)
96+
error = error.decode(encoding)
97+
return process, output, error
98+
except subprocess.TimeoutExpired:
99+
process.kill()
100+
raise ExecUtilException("Command timed out after {} seconds.".format(timeout))
101+
102+
def _run_command(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding):
103+
"""Execute a command and return the process and its output."""
104+
if os.name == 'nt' and stdout is None: # Windows
105+
method = __class__._run_command__nt
106+
else: # Other OS
107+
method = __class__._run_command__generic
108+
109+
return method(self, cmd, shell, input, stdin, stdout, stderr, get_process, timeout, encoding)
102110

103111
def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False, encoding=None, shell=False,
104112
text=False, input=None, stdin=None, stdout=None, stderr=None, get_process=False, timeout=None,

testgres/operations/remote_ops.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,26 +68,26 @@ def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False,
6868

6969
exit_status = process.returncode
7070

71-
if encoding:
72-
result = result.decode(encoding)
73-
error = error.decode(encoding)
74-
75-
if expect_error:
76-
raise Exception(result, error)
71+
assert type(result) == bytes # noqa: E721
72+
assert type(error) == bytes # noqa: E721
7773

7874
if not error:
79-
error_found = 0
75+
error_found = False
8076
else:
81-
error = normalize_error(error)
8277
error_found = exit_status != 0 or any(
83-
marker in error for marker in ['error', 'Permission denied', 'fatal', 'No such file or directory']
78+
marker in error for marker in [b'error', b'Permission denied', b'fatal', b'No such file or directory']
8479
)
8580

86-
if not ignore_errors and error_found:
87-
if isinstance(error, bytes):
88-
message = b"Utility exited with non-zero code. Error: " + error
89-
else:
90-
message = f"Utility exited with non-zero code. Error: {error}"
81+
assert type(error_found) == bool # noqa: E721
82+
83+
if encoding:
84+
result = result.decode(encoding)
85+
error = error.decode(encoding)
86+
87+
if not ignore_errors and error_found and not expect_error:
88+
error = normalize_error(error)
89+
assert type(error) == str # noqa: E721
90+
message = "Utility exited with non-zero code. Error: " + error
9191
raise ExecUtilException(message=message, command=cmd, exit_code=exit_status, out=result)
9292

9393
if verbose:

tests/__init__.py

Whitespace-only changes.

tests/helpers/__init__.py

Whitespace-only changes.

tests/helpers/run_conditions.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import pytest
2+
import platform
3+
4+
5+
class RunConditions:
6+
# It is not a test kit!
7+
__test__ = False
8+
9+
def skip_if_windows():
10+
if platform.system().lower() == "windows":
11+
pytest.skip("This test does not support Windows.")

tests/test_local.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import pytest
2+
3+
from testgres import ExecUtilException
4+
from testgres import LocalOperations
5+
6+
from .helpers.run_conditions import RunConditions
7+
8+
9+
class TestLocalOperations:
10+
11+
@pytest.fixture(scope="function", autouse=True)
12+
def setup(self):
13+
self.operations = LocalOperations()
14+
15+
def test_exec_command_success(self):
16+
"""
17+
Test exec_command for successful command execution.
18+
"""
19+
RunConditions.skip_if_windows()
20+
21+
cmd = "python3 --version"
22+
response = self.operations.exec_command(cmd, wait_exit=True, shell=True)
23+
24+
assert b'Python 3.' in response
25+
26+
def test_exec_command_failure(self):
27+
"""
28+
Test exec_command for command execution failure.
29+
"""
30+
RunConditions.skip_if_windows()
31+
32+
cmd = "nonexistent_command"
33+
while True:
34+
try:
35+
self.operations.exec_command(cmd, wait_exit=True, shell=True)
36+
except ExecUtilException as e:
37+
error = e.message
38+
break
39+
raise Exception("We wait an exception!")
40+
assert error == "Utility exited with non-zero code. Error `b'/bin/sh: 1: nonexistent_command: not found\\n'`"
41+
42+
def test_exec_command_failure__expect_error(self):
43+
"""
44+
Test exec_command for command execution failure.
45+
"""
46+
RunConditions.skip_if_windows()
47+
48+
cmd = "nonexistent_command"
49+
50+
exit_status, result, error = self.operations.exec_command(cmd, verbose=True, wait_exit=True, shell=True, expect_error=True)
51+
52+
assert error == b'/bin/sh: 1: nonexistent_command: not found\n'
53+
assert exit_status == 127
54+
assert result == b''

tests/test_remote.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,27 @@ def test_exec_command_failure(self):
3030
Test exec_command for command execution failure.
3131
"""
3232
cmd = "nonexistent_command"
33-
try:
34-
exit_status, result, error = self.operations.exec_command(cmd, verbose=True, wait_exit=True)
35-
except ExecUtilException as e:
36-
error = e.message
33+
while True:
34+
try:
35+
self.operations.exec_command(cmd, verbose=True, wait_exit=True)
36+
except ExecUtilException as e:
37+
error = e.message
38+
break
39+
raise Exception("We wait an exception!")
3740
assert error == 'Utility exited with non-zero code. Error: bash: line 1: nonexistent_command: command not found\n'
3841

42+
def test_exec_command_failure__expect_error(self):
43+
"""
44+
Test exec_command for command execution failure.
45+
"""
46+
cmd = "nonexistent_command"
47+
48+
exit_status, result, error = self.operations.exec_command(cmd, verbose=True, wait_exit=True, shell=True, expect_error=True)
49+
50+
assert error == b'bash: line 1: nonexistent_command: command not found\n'
51+
assert exit_status == 127
52+
assert result == b''
53+
3954
def test_is_executable_true(self):
4055
"""
4156
Test is_executable for an existing executable.

tests/test_simple.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@ def test_init_unique_system_id(self):
153153

154154
with scoped_config(cache_initdb=True,
155155
cached_initdb_unique=True) as config:
156-
157156
self.assertTrue(config.cache_initdb)
158157
self.assertTrue(config.cached_initdb_unique)
159158

@@ -376,21 +375,18 @@ def test_backup_multiple(self):
376375

377376
with node.backup(xlog_method='fetch') as backup1, \
378377
node.backup(xlog_method='fetch') as backup2:
379-
380378
self.assertNotEqual(backup1.base_dir, backup2.base_dir)
381379

382380
with node.backup(xlog_method='fetch') as backup:
383381
with backup.spawn_primary('node1', destroy=False) as node1, \
384382
backup.spawn_primary('node2', destroy=False) as node2:
385-
386383
self.assertNotEqual(node1.base_dir, node2.base_dir)
387384

388385
def test_backup_exhaust(self):
389386
with get_new_node() as node:
390387
node.init(allow_streaming=True).start()
391388

392389
with node.backup(xlog_method='fetch') as backup:
393-
394390
# exhaust backup by creating new node
395391
with backup.spawn_primary():
396392
pass
@@ -778,7 +774,6 @@ def test_pg_config(self):
778774

779775
# modify setting for this scope
780776
with scoped_config(cache_pg_config=False) as config:
781-
782777
# sanity check for value
783778
self.assertFalse(config.cache_pg_config)
784779

@@ -810,7 +805,6 @@ def test_config_stack(self):
810805
self.assertEqual(c1.cached_initdb_dir, d1)
811806

812807
with scoped_config(cached_initdb_dir=d2) as c2:
813-
814808
stack_size = len(testgres.config.config_stack)
815809

816810
# try to break a stack
@@ -840,7 +834,6 @@ def test_unix_sockets(self):
840834
def test_auto_name(self):
841835
with get_new_node().init(allow_streaming=True).start() as m:
842836
with m.replicate().start() as r:
843-
844837
# check that nodes are running
845838
self.assertTrue(m.status())
846839
self.assertTrue(r.status())

tests/test_simple_remote.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ def removing(f):
9494

9595

9696
class TestgresRemoteTests(unittest.TestCase):
97-
9897
def test_node_repr(self):
9998
with get_remote_node() as node:
10099
pattern = r"PostgresNode\(name='.+', port=.+, base_dir='.+'\)"
@@ -748,6 +747,7 @@ def test_pg_config(self):
748747

749748
# save right before config change
750749
c1 = get_pg_config()
750+
751751
# modify setting for this scope
752752
with scoped_config(cache_pg_config=False) as config:
753753
# sanity check for value

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