Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions Dockerfile--std-all.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ENV PYTHON_VERSION=3
FROM base2_with_python-${PYTHON_VERSION} as final

#RUN apk add --no-cache mc
RUN apk add --no-cache git

# Full version of "ps" command
RUN apk add --no-cache procps
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile--std.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ ENV PYTHON_VERSION=3
# --------------------------------------------- final
FROM base2_with_python-${PYTHON_VERSION} as final

RUN apk add --no-cache git

ENV LANG=C.UTF-8

ADD . /pg/testgres
Expand Down
2 changes: 2 additions & 0 deletions Dockerfile--ubuntu_24_04.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ ENV PYTHON_VERSION=3
# --------------------------------------------- final
FROM base2_with_python-${PYTHON_VERSION} as final

RUN apt install -y git

ADD . /pg/testgres
WORKDIR /pg/testgres
RUN chown -R postgres /pg
Expand Down
2 changes: 1 addition & 1 deletion tests/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ pytest
pytest-xdist
psycopg2
six
testgres.os_ops>=0.0.2,<1.0.0
git+https://github.com/postgrespro/testgres.os_ops.git
199 changes: 199 additions & 0 deletions tests/test_os_ops_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .helpers.run_conditions import RunConditions

import os
import sys

import pytest
import re
Expand All @@ -14,6 +15,10 @@
import threading
import typing
import uuid
import subprocess
import psutil
import time
import signal as os_signal

from src import InvalidOperationException
from src import ExecUtilException
Expand Down Expand Up @@ -1137,3 +1142,197 @@ class tadWorkerData:

logging.info("Test is finished! Total error count is {}.".format(nErrors))
return

T_KILL_SIGNAL_DESCR = typing.Tuple[
str,
typing.Union[int, os_signal.Signals],
str
]

sm_kill_signal_ids: typing.List[T_KILL_SIGNAL_DESCR] = [
("SIGINT", os_signal.SIGINT, "2"),
# ("SIGQUIT", os_signal.SIGQUIT, "3"), # it creates coredump
("SIGKILL", os_signal.SIGKILL, "9"),
("SIGTERM", os_signal.SIGTERM, "15"),
("2", 2, "2"),
# ("3", 3, "3"), # it creates coredump
("9", 9, "9"),
("15", 15, "15"),
]

@pytest.fixture(
params=sm_kill_signal_ids,
ids=["signal: {}".format(x[0]) for x in sm_kill_signal_ids],
)
def kill_signal_id(self, request: pytest.FixtureRequest) -> T_KILL_SIGNAL_DESCR:
assert isinstance(request, pytest.FixtureRequest)
assert type(request.param) == tuple # noqa: E721
return request.param

def test_kill_signal(
self,
kill_signal_id: T_KILL_SIGNAL_DESCR,
):
assert type(kill_signal_id) == tuple # noqa: E721
assert "{}".format(kill_signal_id[1]) == kill_signal_id[2]
assert "{}".format(int(kill_signal_id[1])) == kill_signal_id[2]

def test_kill(
self,
os_ops: OsOperations,
kill_signal_id: T_KILL_SIGNAL_DESCR,
):
"""
Test listdir for listing directory contents.
"""
assert isinstance(os_ops, OsOperations)
assert type(kill_signal_id) == tuple # noqa: E721

cmd = [
sys.executable,
"-c",
"import time; print('ENTER');time.sleep(300);print('EXIT')"
]

logging.info("Local test process is creating ...")
proc = subprocess.Popen(
cmd,
text=True,
)

assert proc is not None
assert type(proc) == subprocess.Popen # noqa: E721
proc_pid = proc.pid
assert type(proc_pid) == int # noqa: E721
logging.info("Test process pid is {}".format(proc_pid))

logging.info("Get this test process ...")
p1 = psutil.Process(proc_pid)
assert p1 is not None
del p1

logging.info("Kill this test process ...")
os_ops.kill(proc_pid, kill_signal_id[1])

logging.info("Wait for finish ...")
proc.wait()

logging.info("Try to get this test process ...")

attempt = 0
while True:
if attempt == 20:
raise RuntimeError("Process did not die.")

attempt += 1

if attempt > 1:
logging.info("Sleep 1 seconds...")
time.sleep(1)

try:
psutil.Process(proc_pid)
except psutil.ZombieProcess as e:
logging.info("Exception {}: {}".format(
type(e).__name__,
str(e),
))
except psutil.NoSuchProcess:
logging.info("OK. Process died.")
break

logging.info("Process is alive!")
continue

return

def test_kill__unk_pid(
self,
os_ops: OsOperations,
kill_signal_id: T_KILL_SIGNAL_DESCR,
):
"""
Test listdir for listing directory contents.
"""
assert isinstance(os_ops, OsOperations)
assert type(kill_signal_id) == tuple # noqa: E721

cmd = [
sys.executable,
"-c",
"import sys; print(\"a\", file=sys.stdout); print(\"b\", file=sys.stderr)"
]

logging.info("Local test process is creating ...")
proc = subprocess.Popen(
cmd,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)

assert proc is not None
assert type(proc) == subprocess.Popen # noqa: E721
proc_pid = proc.pid
assert type(proc_pid) == int # noqa: E721
logging.info("Test process pid is {}".format(proc_pid))

logging.info("Wait for finish ...")
pout, perr = proc.communicate()
logging.info("STDOUT: {}".format(pout))
logging.info("STDERR: {}".format(pout))
assert type(pout) == str # noqa: E721
assert type(perr) == str # noqa: E721
assert pout == "a\n"
assert perr == "b\n"
assert type(proc.returncode) == int # noqa: E721
assert proc.returncode == 0

logging.info("Try to get this test process ...")

attempt = 0
while True:
if attempt == 20:
raise RuntimeError("Process did not die.")

attempt += 1

if attempt > 1:
logging.info("Sleep 1 seconds...")
time.sleep(1)

try:
psutil.Process(proc_pid)
except psutil.ZombieProcess as e:
logging.info("Exception {}: {}".format(
type(e).__name__,
str(e),
))
except psutil.NoSuchProcess:
logging.info("OK. Process died.")
break

logging.info("Process is alive!")
continue

# --------------------
with pytest.raises(expected_exception=Exception) as x:
os_ops.kill(proc_pid, kill_signal_id[1])

assert x is not None
assert isinstance(x.value, Exception)
assert not isinstance(x.value, AssertionError)

logging.info("Our error is [{}]".format(str(x.value)))
logging.info("Our exception has type [{}]".format(type(x.value).__name__))

if type(os_ops).__name__ == "LocalOsOperations":
assert type(x.value) == ProcessLookupError # noqa: E721
assert "No such process" in str(x.value)
elif type(os_ops).__name__ == "RemoteOsOperations":
assert type(x.value) == ExecUtilException # noqa: E721
assert "No such process" in str(x.value)
else:
RuntimeError("Unknown os_ops type: {}".format(type(os_ops).__name__))

return