diff --git a/frappe/commands/test_commands.py b/frappe/commands/test_commands.py index e331543c59..63393eb0a1 100644 --- a/frappe/commands/test_commands.py +++ b/frappe/commands/test_commands.py @@ -8,8 +8,10 @@ import json import os import secrets import shlex +import signal import string import subprocess +import time import types import unittest from contextlib import contextmanager @@ -21,6 +23,7 @@ from unittest.mock import patch # imports - third party imports import click +import requests from click import Command from click.testing import CliRunner, Result from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed @@ -1012,3 +1015,39 @@ class TestCLIImplementation(BaseTestCommands): self.execute("bench --site {site} migrat") self.assertNotEqual(self.returncode, 0) self.assertRegex(self.stderr, r"No such.*migrat.*migrate") + + +class TestGunicornWorker(IntegrationTestCase): + port = 8005 + + def spawn_gunicorn(self, args): + self.handle = subprocess.Popen( + [ + "gunicorn", + "-b", + f"127.0.0.1:{self.port}", + "-w1", + "frappe.app:application", + "--preload", + *args, + ], + ) + time.sleep(1) # let worker startup finish + self.addCleanup(self.kill_gunicorn) + + def kill_gunicorn(self): + self.handle.send_signal(signal.SIGINT) + try: + self.handle.communicate(timeout=1) + except subprocess.TimeoutExpired: + self.handle.kill() + + def test_gunicorn_ping_sync(self): + self.spawn_gunicorn([]) + path = f"http://{self.TEST_SITE}:{self.port}/api/method/ping" + self.assertEqual(requests.get(path).status_code, 200) + + def test_gunicorn_ping_gthread(self): + self.spawn_gunicorn(["--threads=2"]) + path = f"http://{self.TEST_SITE}:{self.port}/api/method/ping" + self.assertEqual(requests.get(path).status_code, 200)