10000 Fix initdb error on Windows by demonolock · Pull Request #99 · postgrespro/testgres · GitHub
[go: up one dir, main page]

Skip to content

Fix initdb error on Windows #99

New issue
8000

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix initdb error on Windows - fix pgbench
  • Loading branch information
vshepard committed Dec 17, 2023
commit 036b924230f9e1100f8b234ada531c0031bf2c4d
17 changes: 7 additions & 10 deletions testgres/operations/local_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,7 @@ def _run_command(cmd, shell, input, timeout, encoding, temp_file=None):
stdout=stdout,
stderr=stderr,
)

try:
return process.communicate(input=input.encode(encoding) if input else None, timeout=timeout), process
except subprocess.TimeoutExpired:
process.kill()
raise ExecUtilException("Command timed out after {} seconds.".format(timeout))
return process

@staticmethod
def _raise_exec_exception(message, command, exit_code, output):
Expand Down Expand Up @@ -151,10 +146,12 @@ def _exec_command_windows(self, cmd, wait_exit=False, verbose=False,
input=None, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
get_process=None, timeout=None):
with tempfile.NamedTemporaryFile(mode='w+b') as temp_file:
_, process = self._run_command(cmd, shell, input, timeout, encoding, temp_file)
if get_process:
return process
output = self._process_output(process, encoding, temp_file)
process = self._run_command(cmd, shell, input, timeout, encoding, temp_file)
try:
output = process.communicate(input=input.encode(encoding) if input else None, timeout=timeout)
except subprocess.TimeoutExpired:
process.kill()
raise ExecUtilException("Command timed out after {} seconds.".format(timeout))

if process.returncode != 0 or has_errors(output):
if process.returncode == 0:
Expand Down
21 changes: 12 additions & 9 deletions testgres/operations/remote_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ def __init__(self, conn_params: ConnectionParams):
self.conn_params = conn_params
self.host = conn_params.host
self.ssh_key = conn_params.ssh_key
if self.ssh_key:
self.ssh_cmd = ["-i", self.ssh_key]
else:
self.ssh_cmd = []
self.remote = True
self.username = conn_params.username or self.get_user()
self.add_known_host(self.host)
Expand Down Expand Up @@ -91,9 +95,9 @@ def exec_command(self, cmd, wait_exit=False, verbose=False, expect_error=False,
"""
ssh_cmd = []
if isinstance(cmd, str):
ssh_cmd = ['ssh', f"{self.username}@{self.host}", '-i', self.ssh_key, cmd]
ssh_cmd = ['ssh', f"{self.username}@{self.host}"] + self.ssh_cmd + [cmd]
elif isinstance(cmd, list):
ssh_cmd = ['ssh', f"{self.username}@{self.host}", '-i', self.ssh_key] + cmd
ssh_cmd = ['ssh', f"{self.username}@{self.host}"] + self.ssh_cmd + cmd
process = subprocess.Popen(ssh_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if get_process:
return process
Expand Down Expand Up @@ -242,9 +246,9 @@ def mkdtemp(self, prefix=None):
- prefix (str): The prefix of the temporary directory name.
"""
if prefix:
command = ["ssh", "-i", self.ssh_key, f"{self.username}@{self.host}", f"mktemp -d {prefix}XXXXX"]
command = ["ssh"] + self.ssh_cmd + [f"{self.username}@{self.host}", f"mktemp -d {prefix}XXXXX"]
else:
command = ["ssh", "-i", self.ssh_key, f"{self.username}@{self.host}", "mktemp -d"]
command = ["ssh"] + self.ssh_cmd + [f"{self.username}@{self.host}", "mktemp -d"]

result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

Expand Down Expand Up @@ -288,7 +292,7 @@ def write(self, filename, data, truncate=False, binary=False, read_and_write=Fal

with tempfile.NamedTemporaryFile(mode=mode, delete=False) as tmp_file:
if not truncate:
scp_cmd = ['scp', '-i', self.ssh_key, f"{self.username}@{self.host}:{filename}", tmp_file.name]
scp_cmd = ['scp'] + self.ssh_cmd + [f"{self.username}@{self.host}:{filename}", tmp_file.name]
subprocess.run(scp_cmd, check=False) # The file might not exist yet
tmp_file.seek(0, os.SEEK_END)

Expand All @@ -304,12 +308,11 @@ def write(self, filename, data, truncate=False, binary=False, read_and_write=Fal
tmp_file.write(data)

tmp_file.flush()

scp_cmd = ['scp', '-i', self.ssh_key, tmp_file.name, f"{self.username}@{self.host}:{filename}"]
scp_cmd = ['scp'] + self.ssh_cmd + [tmp_file.name, f"{self.username}@{self.host}:{filename}"]
subprocess.run(scp_cmd, check=True)

remote_directory = os.path.dirname(filename)
mkdir_cmd = ['ssh', '-i', self.ssh_key, f"{self.username}@{self.host}", f"mkdir -p {remote_directory}"]
mkdir_cmd = ['ssh'] + self.ssh_cmd + [f"{self.username}@{self.host}", f"mkdir -p {remote_directory}"]
subprocess.run(mkdir_cmd, check=True)

os.remove(tmp_file.name)
Expand Down Expand Up @@ -374,7 +377,7 @@ def get_pid(self):
return int(self.exec_command("echo $$", encoding=get_default_encoding()))

def get_process_children(self, pid):
command = ["ssh", "-i", self.ssh_key, f"{self.username}@{self.host}", f"pgrep -P {pid}"]
command = ["ssh"] + self.ssh_cmd + [f"{self.username}@{self.host}", f"pgrep -P {pid}"]

result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

Expand Down
44 changes: 3 additions & 41 deletions testgres/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@
from __future__ import print_function

import os
import random
import socket

import sys

from contextlib import contextmanager
from packaging.version import Version, InvalidVersion
import re

from port_for import PortForException
from six import iteritems

from helpers.port_manager import PortManager
from .exceptions import ExecUtilException
from .config import testgres_config as tconf

Expand All @@ -40,49 +38,13 @@ def reserve_port():
"""
Generate a new port and add it to 'bound_ports'.
"""
port = select_random(exclude_ports=bound_ports)
port_mng = PortManager()
port = port_mng.find_free_port(exclude_ports=bound_ports)
bound_ports.add(port)

return port


def select_random(
ports=None,
exclude_ports=None,
) -> int:
"""
Return random unused port number.
Standard function from port_for does not work on Windows because of error
'port_for.exceptions.PortForException: Can't select a port'
We should update it.
"""
if ports is None:
ports = set(range(1024, 65535))

if exclude_ports is None:
exclude_ports = set()

ports.difference_update(set(exclude_ports))

sampled_ports = random.sample(tuple(ports), min(len(ports), 100))

for port in sampled_ports:
if is_port_free(port):
return port

raise PortForException("Can't select a port")


def is_port_free(port: int) -> bool:
"""Check if a port is free to use."""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
try:
s.bind(("", port))
return True
except OSError:
return False


def release_port(port):
"""
Free port provided by reserve_port().
Expand Down
9 changes: 4 additions & 5 deletions tests/test_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ class TestRemoteOperations:

@pytest.fixture(scope="function", autouse=True)
def setup(self):
conn_params = ConnectionParams(host=os.getenv('RDBMS_TESTPOOL1_HOST') or '172.18.0.3',
username='dev',
ssh_key=os.getenv(
'RDBMS_TESTPOOL_SSHKEY') or '../../container_files/postgres/ssh/id_ed25519')
conn_params = ConnectionParams(host=os.getenv('RDBMS_TESTPOOL1_HOST') or '127.0.0.1',
username=os.getenv('USER'),
ssh_key=os.getenv('RDBMS_TESTPOOL_SSHKEY'))
self.operations = RemoteOperations(conn_params)

def test_exec_command_success(self):
Expand All @@ -41,7 +40,7 @@ def test_is_executable_true(self):
"""
Test is_executable for an existing executable.
"""
cmd = "postgres"
cmd = os.getenv('PG_CONFIG')
response = self.operations.is_executable(cmd)

assert response is True
Expand Down
2 changes: 2 additions & 0 deletions 1E0A tests/test_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,8 @@ def test_pgbench(self):
out, _ = proc.communicate()
out = out.decode('utf-8')

proc.stdout.close()

self.assertTrue('tps' in out)

def test_pg_config(self):
Expand Down
7 changes: 3 additions & 4 deletions tests/test_simple_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@
from testgres.utils import PgVer
from testgres.node import ProcessProxy, ConnectionParams

conn_params = ConnectionParams(host=os.getenv('RDBMS_TESTPOOL1_HOST') or '172.18.0.3',
username='dev',
ssh_key=os.getenv(
'RDBMS_TESTPOOL_SSHKEY') or '../../container_files/postgres/ssh/id_ed25519')
conn_params = ConnectionParams(host=os.getenv('RDBMS_TESTPOOL1_HOST') or '127.0.0.1',
username=os.getenv('USER'),
ssh_key=os.getenv('RDBMS_TESTPOOL_SSHKEY'))
os_ops = RemoteOperations(conn_params)
testgres_config.set_os_ops(os_ops=os_ops)

Expand Down
0