-
Notifications
You must be signed in to change notification settings - Fork 53
Expand file tree
/
Copy pathtest_windows_compatibility.py
More file actions
186 lines (160 loc) · 6.96 KB
/
test_windows_compatibility.py
File metadata and controls
186 lines (160 loc) · 6.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
"""Test Windows compatibility fixes for pytest-postgresql."""
import subprocess
from unittest.mock import MagicMock, patch
from pytest_postgresql.executor import PostgreSQLExecutor
class TestWindowsCompatibility:
"""Test Windows-specific functionality."""
def test_base_command_unified(self) -> None:
"""Test that base command template is unified and cross-platform compatible."""
# The BASE_PROC_START_COMMAND should use the simplified format without single quotes
# around configuration values, which works on both Windows and Unix systems
command_template = PostgreSQLExecutor.BASE_PROC_START_COMMAND
# Should use simplified format without single quotes
assert "log_destination=stderr" in command_template
assert "log_destination='stderr'" not in command_template
assert "unix_socket_directories={unixsocketdir}" in command_template
assert "unix_socket_directories='{unixsocketdir}'" not in command_template
def test_windows_terminate_process(self) -> None:
"""Test Windows process termination."""
executor = PostgreSQLExecutor(
executable="/path/to/pg_ctl",
host="localhost",
port=5432,
datadir="/tmp/data",
unixsocketdir="/tmp/socket",
logfile="/tmp/log",
startparams="-w",
dbname="test",
)
# Mock process
mock_process = MagicMock()
executor.process = mock_process
# No need to mock platform.system() since the method doesn't check it anymore
executor._windows_terminate_process()
# Should call terminate first
mock_process.terminate.assert_called_once()
mock_process.wait.assert_called()
def test_windows_terminate_process_force_kill(self) -> None:
"""Test Windows process termination with force kill on timeout."""
executor = PostgreSQLExecutor(
executable="/path/to/pg_ctl",
host="localhost",
port=5432,
datadir="/tmp/data",
unixsocketdir="/tmp/socket",
logfile="/tmp/log",
startparams="-w",
dbname="test",
)
# Mock process that times out
mock_process = MagicMock()
mock_process.wait.side_effect = [subprocess.TimeoutExpired(cmd="test", timeout=5), None]
executor.process = mock_process
# No need to mock platform.system() since the method doesn't check it anymore
executor._windows_terminate_process()
# Should call terminate, wait (timeout), then kill, then wait again
mock_process.terminate.assert_called_once()
mock_process.kill.assert_called_once()
assert mock_process.wait.call_count == 2
def test_stop_method_windows(self) -> None:
"""Test stop method on Windows."""
executor = PostgreSQLExecutor(
executable="/path/to/pg_ctl",
host="localhost",
port=5432,
datadir="/tmp/data",
unixsocketdir="/tmp/socket",
logfile="/tmp/log",
startparams="-w",
dbname="test",
)
# Mock subprocess and process
with (
patch("subprocess.check_output") as mock_subprocess,
patch("platform.system", return_value="Windows"),
patch.object(executor, "_windows_terminate_process") as mock_terminate,
):
result = executor.stop()
# Should call pg_ctl stop and Windows terminate
mock_subprocess.assert_called_once()
mock_terminate.assert_called_once()
assert result is executor
def test_stop_method_unix(self) -> None:
"""Test stop method on Unix systems."""
executor = PostgreSQLExecutor(
executable="/path/to/pg_ctl",
host="localhost",
port=5432,
datadir="/tmp/data",
unixsocketdir="/tmp/socket",
logfile="/tmp/log",
startparams="-w",
dbname="test",
)
# Mock subprocess and super().stop
with (
patch("subprocess.check_output") as mock_subprocess,
patch("platform.system", return_value="Linux"),
patch("pytest_postgresql.executor.TCPExecutor.stop") as mock_super_stop,
):
mock_super_stop.return_value = executor
result = executor.stop()
# Should call pg_ctl stop and parent class stop
mock_subprocess.assert_called_once()
mock_super_stop.assert_called_once_with(None, None)
assert result is executor
def test_stop_method_fallback_on_killpg_error(self) -> None:
"""Test stop method falls back to Windows termination on killpg AttributeError."""
executor = PostgreSQLExecutor(
executable="/path/to/pg_ctl",
host="localhost",
port=5432,
datadir="/tmp/data",
unixsocketdir="/tmp/socket",
logfile="/tmp/log",
startparams="-w",
dbname="test",
)
# Mock subprocess and super().stop to raise AttributeError
with (
patch("subprocess.check_output") as mock_subprocess,
patch("platform.system", return_value="Linux"),
patch(
"pytest_postgresql.executor.TCPExecutor.stop",
side_effect=AttributeError("module 'os' has no attribute 'killpg'"),
),
patch.object(executor, "_windows_terminate_process") as mock_terminate,
):
result = executor.stop()
# Should call pg_ctl stop, fail on super().stop, then use Windows terminate
mock_subprocess.assert_called_once()
mock_terminate.assert_called_once()
assert result is executor
def test_command_formatting_windows(self) -> None:
"""Test that command is properly formatted for Windows paths."""
executor = PostgreSQLExecutor(
executable="C:/Program Files/PostgreSQL/bin/pg_ctl.exe",
host="localhost",
port=5555,
datadir="C:/temp/data",
unixsocketdir="C:/temp/socket",
logfile="C:/temp/log.txt",
startparams="-w -s",
dbname="testdb",
postgres_options="-c shared_preload_libraries=test",
)
# The command should be properly formatted without single quotes around values
expected_parts = [
"C:/Program Files/PostgreSQL/bin/pg_ctl.exe start",
'-D "C:/temp/data"',
'-o "-F -p 5555 -c log_destination=stderr',
"-c logging_collector=off",
"-c unix_socket_directories=C:/temp/socket",
'-c shared_preload_libraries=test"',
'-l "C:/temp/log.txt"',
"-w -s",
]
# Check if all expected parts are in the command
command = executor.command
for part in expected_parts:
assert part in command, f"Expected '{part}' in command: {command}"