From 25f76242e6eaeea7284e9635ec0ea50d214a5601 Mon Sep 17 00:00:00 2001 From: Josue Kouka Date: Fri, 27 Jan 2017 06:33:26 +0100 Subject: [PATCH] kill phantomjs if stalled (#14606) --- mandayejs/mandaye/utils.py | 60 +++++++++++++++++++++++++++++----------------- tests/test_mandayejs.py | 17 +++++++++++++ 2 files changed, 55 insertions(+), 22 deletions(-) diff --git a/mandayejs/mandaye/utils.py b/mandayejs/mandaye/utils.py index 249948d..9bab803 100644 --- a/mandayejs/mandaye/utils.py +++ b/mandayejs/mandaye/utils.py @@ -17,6 +17,7 @@ import os import json import subprocess import logging +import multiprocessing from django.conf import settings @@ -28,29 +29,44 @@ logger = logging.getLogger(__name__) def exec_phantom(data, script='do_login.js'): - phantom = subprocess.Popen([ - settings.PHANTOM_JS_BINARY, - '--ignore-ssl-errors=yes', '--ssl-protocol=any', - os.path.join(settings.BASE_DIR, 'mandayejs', script)], - close_fds=True, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE - ) + result = None + waiting_time = getattr(settings, 'PHANTOM_JS_WAITING_TIME', 10) + + def run(send_end): + phantom = subprocess.Popen([ + settings.PHANTOM_JS_BINARY, + '--ignore-ssl-errors=yes', '--ssl-protocol=any', + os.path.join(settings.BASE_DIR, 'mandayejs', script)], + close_fds=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE + ) + stdout, stderr = phantom.communicate(json.dumps(data)) + + try: + result = json.loads(stdout) + except (ValueError,): + result = {"result": "failure, couldn't decode JSON"} + logger.error(stdout) + + if result.get('stderr', None): + logger.warning(result['stderr']) + + send_end.send(result) + + recv_end, send_end = multiprocessing.Pipe(False) + process = multiprocessing.Process(target=run, args=(send_end,)) + process.start() + process.join(waiting_time) + + if process.is_alive(): + process.terminate() + data.pop('locators') + logger.error("Phantomjs process stalled with conetext : %s" % data) + result = {'result': 'failure'} + else: + result = recv_end.recv() - stdout, stderr = phantom.communicate(json.dumps(data)) - - try: - result = json.loads(stdout) - except (ValueError,): - result = {"result": "failure, couldn't decode JSON"} - logger.error(stdout) - - # only kill process if it's still running - if phantom.poll() is None: - phantom.terminate() - - if result.get('stderr'): - logger.warning(result['stderr']) return result diff --git a/tests/test_mandayejs.py b/tests/test_mandayejs.py index 5cb83b7..dc8abb9 100644 --- a/tests/test_mandayejs.py +++ b/tests/test_mandayejs.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import json +import time import mock import pytest @@ -47,8 +48,12 @@ MOCKED_SITE_LOCATORS = [ class MockedPopen(mock.Mock): + stall_for = False def communicate(self, data): + if self.stall_for: + print(self.stall_for) + time.sleep(13) return self.expected_output @@ -272,6 +277,18 @@ def test_phantom_js_errors(mocked_popen, caplog): assert result['url'] == 'https://whatever.com/someurl' +@mock.patch('mandayejs.mandaye.utils.subprocess.Popen') +def test_phantom_js_stalled_process(mocked_popen, caplog): + mocked_popen.return_value = MockedPopen(expected_output=json.dumps({'whatever': 'whatever'}), stall_for=True) + result = exec_phantom(LOGIN_INFO) + + for record in caplog.records(): + assert record.levelname == 'ERROR' + assert record.message == "Phantomjs process stalled with conetext : {'cookies': [], 'form_submit_element': 'input[type=submit], button', 'auth_checker': 'tenants/static/js/auth.checker.js', 'address': 'https://whatever.com'}" + + assert result['result'] == 'failure' + + @mock.patch('mandayejs.applications.Test.SITE_LOCATORS', MOCKED_SITE_LOCATORS) def test_credentials_json_encoding(user_john): -- 2.11.0