2018-12-19 15:44:03 +00:00
|
|
|
import signal
|
|
|
|
import time
|
|
|
|
|
2018-12-18 21:24:44 +00:00
|
|
|
import psutil
|
|
|
|
|
2018-12-18 21:04:29 +00:00
|
|
|
from catfish.project import Project
|
2018-12-19 15:44:03 +00:00
|
|
|
from catfish.utils.processes import (
|
2018-12-21 14:35:41 +00:00
|
|
|
get_running_process_for,
|
2018-12-19 15:44:03 +00:00
|
|
|
is_process_running,
|
|
|
|
terminate_processes,
|
|
|
|
wait_for_process_terminate,
|
|
|
|
)
|
2018-12-18 21:04:29 +00:00
|
|
|
from catfish.worker import BASE_SOCKET_DIR
|
|
|
|
from catfish.worker.server import PayloadType, read_logs_for_process, send_to_server
|
2018-12-13 11:36:22 +00:00
|
|
|
from tests import BaseWorkerTestCase
|
2018-12-13 11:25:09 +00:00
|
|
|
|
|
|
|
|
|
|
|
class WorkerServerTestCase(BaseWorkerTestCase):
|
2018-12-18 21:24:44 +00:00
|
|
|
def test_ping(self):
|
|
|
|
response = send_to_server(PayloadType.PING, {})
|
|
|
|
self.assertEqual(response, {"ping": "pong"})
|
|
|
|
|
|
|
|
|
|
|
|
class ProcessWorkerTestCase(BaseWorkerTestCase):
|
|
|
|
def setUp(self):
|
|
|
|
super().setUp()
|
|
|
|
self.project = Project(self.EXAMPLE_DIR)
|
|
|
|
self.process = self.project.get_process("bg")
|
|
|
|
|
2018-12-13 11:25:09 +00:00
|
|
|
def test_server_creates_process(self):
|
2018-12-18 21:04:29 +00:00
|
|
|
response = send_to_server(
|
|
|
|
PayloadType.PROCESS,
|
2018-12-18 21:24:44 +00:00
|
|
|
{"path": str(self.project.root), "process": str(self.process.name)},
|
2018-12-18 21:04:29 +00:00
|
|
|
)
|
2018-12-13 11:36:22 +00:00
|
|
|
self.assertTrue(is_process_running(response["pid"]))
|
2018-12-21 14:35:41 +00:00
|
|
|
self.assertEqual(get_running_process_for(self.process).pid, response["pid"])
|
|
|
|
self.assertTrue(self.process.is_running)
|
2018-12-13 11:36:22 +00:00
|
|
|
|
2018-12-18 21:24:44 +00:00
|
|
|
def test_additional_environment(self):
|
|
|
|
response = send_to_server(
|
|
|
|
PayloadType.PROCESS,
|
|
|
|
{"path": str(self.project.root), "process": str(self.process.name)},
|
|
|
|
)
|
|
|
|
env = psutil.Process(response["pid"]).environ()
|
|
|
|
self.assertEqual(env["PYTHONUNBUFFERED"], "1")
|
|
|
|
self.assertEqual(env["CATFISH_IDENT"], self.process.ident)
|
2018-12-18 21:42:23 +00:00
|
|
|
self.assertEqual(env["FOO"], "bar")
|
|
|
|
|
|
|
|
def test_additional_path(self):
|
|
|
|
response = send_to_server(
|
|
|
|
PayloadType.PROCESS,
|
|
|
|
{"path": str(self.project.root), "process": str(self.process.name)},
|
|
|
|
)
|
|
|
|
env = psutil.Process(response["pid"]).environ()
|
2018-12-18 21:24:44 +00:00
|
|
|
path_dirs = env["PATH"].split(":")
|
|
|
|
for path in self.project.get_extra_path():
|
|
|
|
self.assertIn(str(path), path_dirs)
|
2018-12-13 16:52:37 +00:00
|
|
|
|
2018-12-21 14:02:27 +00:00
|
|
|
def test_sets_working_dir(self):
|
|
|
|
response = send_to_server(
|
|
|
|
PayloadType.PROCESS,
|
|
|
|
{"path": str(self.project.root), "process": str(self.process.name)},
|
|
|
|
)
|
|
|
|
cwd = psutil.Process(response["pid"]).cwd()
|
|
|
|
self.assertEqual(cwd, str(self.project.root))
|
|
|
|
|
2018-12-19 15:44:03 +00:00
|
|
|
def test_process_restart(self):
|
|
|
|
response = send_to_server(
|
|
|
|
PayloadType.PROCESS,
|
|
|
|
{"path": str(self.project.root), "process": str(self.process.name)},
|
|
|
|
)
|
|
|
|
initial_pid = response["pid"]
|
|
|
|
psutil.Process(initial_pid).send_signal(signal.SIGHUP)
|
|
|
|
wait_for_process_terminate(initial_pid)
|
|
|
|
time.sleep(2)
|
2018-12-21 14:35:41 +00:00
|
|
|
new_process = get_running_process_for(self.process)
|
2018-12-19 15:44:03 +00:00
|
|
|
self.assertNotEqual(new_process.pid, initial_pid)
|
|
|
|
self.assertFalse(is_process_running(initial_pid))
|
|
|
|
self.assertTrue(is_process_running(new_process.pid))
|
|
|
|
|
2018-12-19 17:26:09 +00:00
|
|
|
def test_process_restart_on_1_exit(self):
|
|
|
|
response = send_to_server(
|
|
|
|
PayloadType.PROCESS, {"path": str(self.project.root), "process": "die"}
|
|
|
|
)
|
|
|
|
initial_pid = response["pid"]
|
|
|
|
wait_for_process_terminate(initial_pid)
|
|
|
|
time.sleep(2)
|
2018-12-21 14:35:41 +00:00
|
|
|
new_process = get_running_process_for(self.project.get_process("die"))
|
2018-12-19 17:26:09 +00:00
|
|
|
self.assertNotEqual(new_process.pid, initial_pid)
|
|
|
|
self.assertFalse(is_process_running(initial_pid))
|
|
|
|
self.assertTrue(is_process_running(new_process.pid))
|
|
|
|
|
2018-12-19 17:10:58 +00:00
|
|
|
def test_process_restart_on_0_exit(self):
|
|
|
|
response = send_to_server(
|
2018-12-19 17:26:09 +00:00
|
|
|
PayloadType.PROCESS, {"path": str(self.project.root), "process": "exit"}
|
2018-12-19 17:10:58 +00:00
|
|
|
)
|
|
|
|
initial_pid = response["pid"]
|
|
|
|
wait_for_process_terminate(initial_pid)
|
|
|
|
time.sleep(2)
|
2018-12-21 14:35:41 +00:00
|
|
|
new_process = get_running_process_for(self.project.get_process("exit"))
|
2018-12-19 17:10:58 +00:00
|
|
|
self.assertNotEqual(new_process.pid, initial_pid)
|
|
|
|
self.assertFalse(is_process_running(initial_pid))
|
|
|
|
self.assertTrue(is_process_running(new_process.pid))
|
|
|
|
|
2018-12-19 15:44:03 +00:00
|
|
|
def test_process_terminate(self):
|
|
|
|
response = send_to_server(
|
|
|
|
PayloadType.PROCESS,
|
|
|
|
{"path": str(self.project.root), "process": str(self.process.name)},
|
|
|
|
)
|
|
|
|
initial_pid = response["pid"]
|
|
|
|
terminate_processes([psutil.Process(initial_pid)])
|
|
|
|
wait_for_process_terminate(initial_pid)
|
|
|
|
time.sleep(2)
|
2018-12-21 14:35:41 +00:00
|
|
|
self.assertIsNone(get_running_process_for(self.process))
|
2018-12-19 15:44:03 +00:00
|
|
|
self.assertFalse(is_process_running(initial_pid))
|
|
|
|
|
2018-12-13 16:52:37 +00:00
|
|
|
|
|
|
|
class ProcessLogsTestCase(BaseWorkerTestCase):
|
2018-12-18 21:04:29 +00:00
|
|
|
def setUp(self):
|
|
|
|
super().setUp()
|
|
|
|
self.project = Project(self.EXAMPLE_DIR)
|
|
|
|
self.process = self.project.get_process("bg")
|
|
|
|
|
2018-12-13 16:52:37 +00:00
|
|
|
def test_creates_socket(self):
|
2018-12-18 21:04:29 +00:00
|
|
|
send_to_server(
|
|
|
|
PayloadType.PROCESS,
|
|
|
|
{"path": str(self.project.root), "process": str(self.process.name)},
|
|
|
|
)
|
|
|
|
stdout_socket = BASE_SOCKET_DIR.joinpath(self.process.logs_socket)
|
2018-12-18 15:49:20 +00:00
|
|
|
self.assertTrue(stdout_socket.exists())
|
2018-12-13 16:52:37 +00:00
|
|
|
|
|
|
|
def test_gets_logs(self):
|
2018-12-18 21:04:29 +00:00
|
|
|
send_to_server(
|
|
|
|
PayloadType.PROCESS,
|
|
|
|
{"path": str(self.project.root), "process": str(self.process.name)},
|
|
|
|
)
|
|
|
|
stdout_iter = read_logs_for_process(self.process)
|
2018-12-13 16:52:37 +00:00
|
|
|
for i in range(3):
|
|
|
|
self.assertEqual(next(stdout_iter), "Round {}".format(i))
|
2018-12-23 12:55:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ProcessPortTestCase(BaseWorkerTestCase):
|
|
|
|
def setUp(self):
|
|
|
|
super().setUp()
|
|
|
|
self.project = Project(self.EXAMPLE_DIR)
|
|
|
|
self.process = self.project.get_process("web")
|
|
|
|
|
|
|
|
def test_assigns_port(self):
|
|
|
|
response = send_to_server(
|
|
|
|
PayloadType.PROCESS,
|
|
|
|
{"path": str(self.project.root), "process": str(self.process.name)},
|
|
|
|
)
|
|
|
|
process = psutil.Process(response["pid"])
|
|
|
|
self.assertIn("PORT", process.environ())
|
|
|
|
self.assertEqual(self.process.port, process.environ()["PORT"])
|
|
|
|
|
|
|
|
def test_doesnt_assign_port(self):
|
|
|
|
response = send_to_server(
|
|
|
|
PayloadType.PROCESS, {"path": str(self.project.root), "process": "bg"}
|
|
|
|
)
|
|
|
|
process = psutil.Process(response["pid"])
|
|
|
|
self.assertNotIn("PORT", process.environ())
|
|
|
|
self.assertIsNone(self.process.port)
|
|
|
|
|
|
|
|
def test_keeps_port_on_restart(self):
|
|
|
|
response = send_to_server(
|
|
|
|
PayloadType.PROCESS,
|
|
|
|
{"path": str(self.project.root), "process": str(self.process.name)},
|
|
|
|
)
|
|
|
|
initial_pid = response["pid"]
|
|
|
|
initial_process = psutil.Process(initial_pid)
|
|
|
|
port = initial_process.environ()["PORT"]
|
|
|
|
psutil.Process(initial_pid).send_signal(signal.SIGHUP)
|
|
|
|
wait_for_process_terminate(initial_pid)
|
|
|
|
time.sleep(2)
|
|
|
|
new_process = get_running_process_for(self.process)
|
|
|
|
self.assertEqual(new_process.environ()["PORT"], port)
|