Projet

Général

Profil

« Précédent | Suivant » 

Révision ecb03255

Ajouté par Josué Kouka il y a environ 7 ans

kill phantomjs process if timeout (#14606)

Voir les différences:

mandayejs/mandaye/utils.py
17 17
import json
18 18
import subprocess
19 19
import logging
20
import multiprocessing
20 21

  
21 22
from django.conf import settings
22 23

  
......
28 29

  
29 30

  
30 31
def exec_phantom(data, script='do_login.js'):
31
    phantom = subprocess.Popen([
32
        settings.PHANTOM_JS_BINARY,
33
        '--ignore-ssl-errors=yes', '--ssl-protocol=any',
34
        os.path.join(settings.BASE_DIR, 'mandayejs', script)],
35
        close_fds=True,
36
        stdin=subprocess.PIPE,
37
        stdout=subprocess.PIPE
38
    )
39 32

  
40
    stdout, stderr = phantom.communicate(json.dumps(data))
33
    def run(send_end):
34
        phantom = subprocess.Popen([
35
            settings.PHANTOM_JS_BINARY,
36
            '--ignore-ssl-errors=yes', '--ssl-protocol=any',
37
            os.path.join(settings.BASE_DIR, 'mandayejs', script)],
38
            close_fds=True,
39
            stdin=subprocess.PIPE,
40
            stdout=subprocess.PIPE
41
        )
42
        stdout, stderr = phantom.communicate(json.dumps(data))
43

  
44
        try:
45
            result = json.loads(stdout)
46
        except (ValueError,):
47
            result = {"result": "failure, couldn't decode JSON"}
48
            logger.error(stdout)
49

  
50
        if result.get('stderr'):
51
            logger.warning(result['stderr'])
52

  
53
        send_end.send(result)
54

  
55
    recv_end, send_end = multiprocessing.Pipe(False)
56
    process = multiprocessing.Process(target=run, args=(send_end,))
57
    process.start()
58
    process.join(settings.PHANTOM_JS_TIMEOUT)
59

  
60
    if process.is_alive():
61
        process.terminate()
62
        # Don't log locators, they may contain credentials (passwords)
63
        context = {k: v for k, v in data.items() if k != 'locators'}
64
        logger.error("PhantomJS process timeout, context: %s" % context)
65
        result = {'result': 'timeout'}
66
    else:
67
        result = recv_end.recv()
41 68

  
42
    try:
43
        result = json.loads(stdout)
44
    except (ValueError,):
45
        result = {"result": "failure, couldn't decode JSON"}
46
        logger.error(stdout)
47

  
48
        # only kill process if it's still running
49
        if phantom.poll() is None:
50
            phantom.terminate()
51

  
52
    if result.get('stderr'):
53
        logger.warning(result['stderr'])
54 69
    return result
55 70

  
56 71

  
mandayejs/mandaye/views.py
155 155
        credentials.delete()
156 156
        messages.error(request, _('wrong user credentials'))
157 157
        url = resolve_url('associate')
158
    elif result.get('result') == 'timeout':
159
        messages.error(request, _('server took too long to respond'))
160
        url = resolve_url('associate')
158 161
    elif result.get('result') == 'redirect':
159 162
        url = result.get('url', '/')
160 163
    else:
mandayejs/settings.py
164 164

  
165 165
PHANTOM_JS_BINARY = '/usr/bin/phantomjs'
166 166

  
167
# Default timeout before killing Phantomjs process
168
PHANTOM_JS_TIMEOUT = 10
167 169

  
168 170
JSONFIELD_ENCODER_CLASS = 'django.core.serializers.json.DjangoJSONEncoder'
169 171

  
tests/settings.py
47 47
api_settings.user_settings.update({
48 48
    'DEFAULT_AUTHENTICATION_CLASSES' : AUTHENTICATION_CLASSES,
49 49
})
50

  
51

  
52
PHANTOM_JS_TIMEOUT = 0.25
tests/test_mandayejs.py
1 1
# -*- coding: utf-8 -*-
2 2

  
3 3
import json
4
import time
4 5
import mock
5 6
import pytest
6 7

  
......
47 48

  
48 49

  
49 50
class MockedPopen(mock.Mock):
51
    stall_for = False
50 52

  
51 53
    def communicate(self, data):
54
        if self.stall_for:
55
            time.sleep(13)
52 56
        return self.expected_output
53 57

  
54 58

  
......
272 276
    assert result['url'] == 'https://whatever.com/someurl'
273 277

  
274 278

  
279
@mock.patch('mandayejs.mandaye.utils.subprocess.Popen')
280
def test_phantom_js_timeout(mocked_popen, caplog):
281
    mocked_popen.return_value = MockedPopen(expected_output=json.dumps({'whatever': 'whatever'}), stall_for=True)
282
    result = exec_phantom(LOGIN_INFO)
283

  
284
    for record in caplog.records():
285
        assert record.levelname == 'ERROR'
286
        assert 'https://whatever.com' in record.message
287
        assert 'tenants/static/js/auth.checker.js' in record.message
288
        assert 'input[type=submit], button' in record.message
289

  
290
    assert result['result'] == 'timeout'
291

  
292

  
275 293
@mock.patch('mandayejs.applications.Test.SITE_LOCATORS', MOCKED_SITE_LOCATORS)
276 294
def test_credentials_json_encoding(user_john):
277 295

  

Formats disponibles : Unified diff