mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-16 02:02:58 -07:00
Update cherrypy-18.6.1
This commit is contained in:
parent
b3ae6bd695
commit
ebffd124f6
57 changed files with 1269 additions and 1509 deletions
|
@ -1,25 +1,24 @@
|
|||
import os
|
||||
import platform
|
||||
import threading
|
||||
import time
|
||||
import socket
|
||||
import importlib
|
||||
|
||||
from six.moves.http_client import HTTPConnection
|
||||
from http.client import HTTPConnection
|
||||
|
||||
from distutils.spawn import find_executable
|
||||
import pytest
|
||||
from path import Path
|
||||
from more_itertools import consume
|
||||
import portend
|
||||
|
||||
import cherrypy
|
||||
from cherrypy._cpcompat import (
|
||||
json_decode,
|
||||
HTTPSConnection,
|
||||
)
|
||||
from cherrypy._cpcompat import HTTPSConnection
|
||||
from cherrypy.lib import sessions
|
||||
from cherrypy.lib import reprconf
|
||||
from cherrypy.lib.httputil import response_codes
|
||||
from cherrypy.test import helper
|
||||
from cherrypy import _json as json
|
||||
|
||||
localDir = os.path.dirname(__file__)
|
||||
localDir = Path(__file__).dirname()
|
||||
|
||||
|
||||
def http_methods_allowed(methods=['GET', 'HEAD']):
|
||||
|
@ -48,9 +47,10 @@ def setup_server():
|
|||
cherrypy.session.cache.clear()
|
||||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.json_out()
|
||||
def data(self):
|
||||
cherrypy.session['aha'] = 'foo'
|
||||
return repr(cherrypy.session._data)
|
||||
return cherrypy.session._data
|
||||
|
||||
@cherrypy.expose
|
||||
def testGen(self):
|
||||
|
@ -142,14 +142,18 @@ def setup_server():
|
|||
class SessionTest(helper.CPWebCase):
|
||||
setup_server = staticmethod(setup_server)
|
||||
|
||||
def tearDown(self):
|
||||
# Clean up sessions.
|
||||
for fname in os.listdir(localDir):
|
||||
if fname.startswith(sessions.FileSession.SESSION_PREFIX):
|
||||
path = Path(localDir) / fname
|
||||
path.remove_p()
|
||||
@classmethod
|
||||
def teardown_class(cls):
|
||||
"""Clean up sessions."""
|
||||
super(cls, cls).teardown_class()
|
||||
consume(
|
||||
file.remove_p()
|
||||
for file in localDir.listdir()
|
||||
if file.basename().startswith(
|
||||
sessions.FileSession.SESSION_PREFIX
|
||||
)
|
||||
)
|
||||
|
||||
@pytest.mark.xfail(reason='#1534')
|
||||
def test_0_Session(self):
|
||||
self.getPage('/set_session_cls/cherrypy.lib.sessions.RamSession')
|
||||
self.getPage('/clear')
|
||||
|
@ -157,82 +161,81 @@ class SessionTest(helper.CPWebCase):
|
|||
# Test that a normal request gets the same id in the cookies.
|
||||
# Note: this wouldn't work if /data didn't load the session.
|
||||
self.getPage('/data')
|
||||
self.assertBody("{'aha': 'foo'}")
|
||||
assert self.body == b'{"aha": "foo"}'
|
||||
c = self.cookies[0]
|
||||
self.getPage('/data', self.cookies)
|
||||
self.assertEqual(self.cookies[0], c)
|
||||
self.cookies[0] == c
|
||||
|
||||
self.getPage('/testStr')
|
||||
self.assertBody('1')
|
||||
assert self.body == b'1'
|
||||
cookie_parts = dict([p.strip().split('=')
|
||||
for p in self.cookies[0][1].split(';')])
|
||||
# Assert there is an 'expires' param
|
||||
self.assertEqual(set(cookie_parts.keys()),
|
||||
set(['session_id', 'expires', 'Path']))
|
||||
expected_cookie_keys = {'session_id', 'expires', 'Path', 'Max-Age'}
|
||||
assert set(cookie_parts.keys()) == expected_cookie_keys
|
||||
self.getPage('/testGen', self.cookies)
|
||||
self.assertBody('2')
|
||||
assert self.body == b'2'
|
||||
self.getPage('/testStr', self.cookies)
|
||||
self.assertBody('3')
|
||||
assert self.body == b'3'
|
||||
self.getPage('/data', self.cookies)
|
||||
self.assertDictEqual(json_decode(self.body),
|
||||
{'counter': 3, 'aha': 'foo'})
|
||||
expected_data = {'counter': 3, 'aha': 'foo'}
|
||||
assert json.decode(self.body.decode('utf-8')) == expected_data
|
||||
self.getPage('/length', self.cookies)
|
||||
self.assertBody('2')
|
||||
assert self.body == b'2'
|
||||
self.getPage('/delkey?key=counter', self.cookies)
|
||||
self.assertStatus(200)
|
||||
assert self.status_code == 200
|
||||
|
||||
self.getPage('/set_session_cls/cherrypy.lib.sessions.FileSession')
|
||||
self.getPage('/testStr')
|
||||
self.assertBody('1')
|
||||
assert self.body == b'1'
|
||||
self.getPage('/testGen', self.cookies)
|
||||
self.assertBody('2')
|
||||
assert self.body == b'2'
|
||||
self.getPage('/testStr', self.cookies)
|
||||
self.assertBody('3')
|
||||
assert self.body == b'3'
|
||||
self.getPage('/delkey?key=counter', self.cookies)
|
||||
self.assertStatus(200)
|
||||
assert self.status_code == 200
|
||||
|
||||
# Wait for the session.timeout (1 second)
|
||||
time.sleep(2)
|
||||
self.getPage('/')
|
||||
self.assertBody('1')
|
||||
assert self.body == b'1'
|
||||
self.getPage('/length', self.cookies)
|
||||
self.assertBody('1')
|
||||
assert self.body == b'1'
|
||||
|
||||
# Test session __contains__
|
||||
self.getPage('/keyin?key=counter', self.cookies)
|
||||
self.assertBody('True')
|
||||
assert self.body == b'True'
|
||||
cookieset1 = self.cookies
|
||||
|
||||
# Make a new session and test __len__ again
|
||||
self.getPage('/')
|
||||
self.getPage('/length', self.cookies)
|
||||
self.assertBody('2')
|
||||
assert self.body == b'2'
|
||||
|
||||
# Test session delete
|
||||
self.getPage('/delete', self.cookies)
|
||||
self.assertBody('done')
|
||||
assert self.body == b'done'
|
||||
self.getPage('/delete', cookieset1)
|
||||
self.assertBody('done')
|
||||
assert self.body == b'done'
|
||||
|
||||
def f():
|
||||
return [
|
||||
x
|
||||
for x in os.listdir(localDir)
|
||||
if x.startswith('session-')
|
||||
if x.startswith('session-') and not x.endswith('.lock')
|
||||
]
|
||||
self.assertEqual(f(), [])
|
||||
assert f() == []
|
||||
|
||||
# Wait for the cleanup thread to delete remaining session files
|
||||
self.getPage('/')
|
||||
self.assertNotEqual(f(), [])
|
||||
assert f() != []
|
||||
time.sleep(2)
|
||||
self.assertEqual(f(), [])
|
||||
assert f() == []
|
||||
|
||||
def test_1_Ram_Concurrency(self):
|
||||
self.getPage('/set_session_cls/cherrypy.lib.sessions.RamSession')
|
||||
self._test_Concurrency()
|
||||
|
||||
@pytest.mark.xfail(reason='#1306')
|
||||
def test_2_File_Concurrency(self):
|
||||
self.getPage('/set_session_cls/cherrypy.lib.sessions.FileSession')
|
||||
self._test_Concurrency()
|
||||
|
@ -243,7 +246,7 @@ class SessionTest(helper.CPWebCase):
|
|||
|
||||
# Get initial cookie
|
||||
self.getPage('/')
|
||||
self.assertBody('1')
|
||||
assert self.body == b'1'
|
||||
cookies = self.cookies
|
||||
|
||||
data_dict = {}
|
||||
|
@ -285,13 +288,14 @@ class SessionTest(helper.CPWebCase):
|
|||
|
||||
for e in errors:
|
||||
print(e)
|
||||
self.assertEqual(hitcount, expected)
|
||||
assert len(errors) == 0
|
||||
assert hitcount == expected
|
||||
|
||||
def test_3_Redirect(self):
|
||||
# Start a new session
|
||||
self.getPage('/testStr')
|
||||
self.getPage('/iredir', self.cookies)
|
||||
self.assertBody('FileSession')
|
||||
assert self.body == b'FileSession'
|
||||
|
||||
def test_4_File_deletion(self):
|
||||
# Start a new session
|
||||
|
@ -319,9 +323,9 @@ class SessionTest(helper.CPWebCase):
|
|||
# grab the cookie ID
|
||||
id1 = self.cookies[0][1].split(';', 1)[0].split('=', 1)[1]
|
||||
self.getPage('/regen')
|
||||
self.assertBody('logged in')
|
||||
assert self.body == b'logged in'
|
||||
id2 = self.cookies[0][1].split(';', 1)[0].split('=', 1)[1]
|
||||
self.assertNotEqual(id1, id2)
|
||||
assert id1 != id2
|
||||
|
||||
self.getPage('/testStr')
|
||||
# grab the cookie ID
|
||||
|
@ -332,8 +336,8 @@ class SessionTest(helper.CPWebCase):
|
|||
'session_id=maliciousid; '
|
||||
'expires=Sat, 27 Oct 2017 04:18:28 GMT; Path=/;')])
|
||||
id2 = self.cookies[0][1].split(';', 1)[0].split('=', 1)[1]
|
||||
self.assertNotEqual(id1, id2)
|
||||
self.assertNotEqual(id2, 'maliciousid')
|
||||
assert id1 != id2
|
||||
assert id2 != 'maliciousid'
|
||||
|
||||
def test_7_session_cookies(self):
|
||||
self.getPage('/set_session_cls/cherrypy.lib.sessions.RamSession')
|
||||
|
@ -343,18 +347,18 @@ class SessionTest(helper.CPWebCase):
|
|||
cookie_parts = dict([p.strip().split('=')
|
||||
for p in self.cookies[0][1].split(';')])
|
||||
# Assert there is no 'expires' param
|
||||
self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path']))
|
||||
assert set(cookie_parts.keys()) == {'temp', 'Path'}
|
||||
id1 = cookie_parts['temp']
|
||||
self.assertEqual(list(sessions.RamSession.cache), [id1])
|
||||
assert list(sessions.RamSession.cache) == [id1]
|
||||
|
||||
# Send another request in the same "browser session".
|
||||
self.getPage('/session_cookie', self.cookies)
|
||||
cookie_parts = dict([p.strip().split('=')
|
||||
for p in self.cookies[0][1].split(';')])
|
||||
# Assert there is no 'expires' param
|
||||
self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path']))
|
||||
self.assertBody(id1)
|
||||
self.assertEqual(list(sessions.RamSession.cache), [id1])
|
||||
assert set(cookie_parts.keys()) == {'temp', 'Path'}
|
||||
assert self.body.decode('utf-8') == id1
|
||||
assert list(sessions.RamSession.cache) == [id1]
|
||||
|
||||
# Simulate a browser close by just not sending the cookies
|
||||
self.getPage('/session_cookie')
|
||||
|
@ -362,12 +366,11 @@ class SessionTest(helper.CPWebCase):
|
|||
cookie_parts = dict([p.strip().split('=')
|
||||
for p in self.cookies[0][1].split(';')])
|
||||
# Assert there is no 'expires' param
|
||||
self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path']))
|
||||
assert set(cookie_parts.keys()) == {'temp', 'Path'}
|
||||
# Assert a new id has been generated...
|
||||
id2 = cookie_parts['temp']
|
||||
self.assertNotEqual(id1, id2)
|
||||
self.assertEqual(set(sessions.RamSession.cache.keys()),
|
||||
set([id1, id2]))
|
||||
assert id1 != id2
|
||||
assert set(sessions.RamSession.cache.keys()) == {id1, id2}
|
||||
|
||||
# Wait for the session.timeout on both sessions
|
||||
time.sleep(2.5)
|
||||
|
@ -398,115 +401,147 @@ class SessionTest(helper.CPWebCase):
|
|||
t.join()
|
||||
|
||||
|
||||
try:
|
||||
importlib.import_module('memcache')
|
||||
def is_memcached_present():
|
||||
executable = find_executable('memcached')
|
||||
return bool(executable)
|
||||
|
||||
host, port = '127.0.0.1', 11211
|
||||
for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
|
||||
socket.SOCK_STREAM):
|
||||
af, socktype, proto, canonname, sa = res
|
||||
s = None
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def memcached_server_present():
|
||||
is_memcached_present() or pytest.skip('memcached not available')
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def memcached_client_present():
|
||||
pytest.importorskip('memcache')
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def memcached_instance(request, watcher_getter, memcached_server_present):
|
||||
"""
|
||||
Start up an instance of memcached.
|
||||
"""
|
||||
|
||||
port = portend.find_available_local_port()
|
||||
|
||||
def is_occupied():
|
||||
try:
|
||||
s = socket.socket(af, socktype, proto)
|
||||
# See http://groups.google.com/group/cherrypy-users/
|
||||
# browse_frm/thread/bbfe5eb39c904fe0
|
||||
s.settimeout(1.0)
|
||||
s.connect((host, port))
|
||||
s.close()
|
||||
except socket.error:
|
||||
if s:
|
||||
s.close()
|
||||
raise
|
||||
break
|
||||
except (ImportError, socket.error):
|
||||
class MemcachedSessionTest(helper.CPWebCase):
|
||||
setup_server = staticmethod(setup_server)
|
||||
portend.Checker().assert_free('localhost', port)
|
||||
except Exception:
|
||||
return True
|
||||
return False
|
||||
|
||||
def test(self):
|
||||
return self.skip('memcached not reachable ')
|
||||
else:
|
||||
class MemcachedSessionTest(helper.CPWebCase):
|
||||
setup_server = staticmethod(setup_server)
|
||||
proc = watcher_getter(
|
||||
name='memcached',
|
||||
arguments=['-p', str(port)],
|
||||
checker=is_occupied,
|
||||
request=request,
|
||||
)
|
||||
return locals()
|
||||
|
||||
def test_0_Session(self):
|
||||
self.getPage('/set_session_cls/cherrypy.Sessions.MemcachedSession')
|
||||
|
||||
self.getPage('/testStr')
|
||||
self.assertBody('1')
|
||||
self.getPage('/testGen', self.cookies)
|
||||
self.assertBody('2')
|
||||
self.getPage('/testStr', self.cookies)
|
||||
self.assertBody('3')
|
||||
self.getPage('/length', self.cookies)
|
||||
self.assertErrorPage(500)
|
||||
self.assertInBody('NotImplementedError')
|
||||
self.getPage('/delkey?key=counter', self.cookies)
|
||||
self.assertStatus(200)
|
||||
@pytest.fixture
|
||||
def memcached_configured(
|
||||
memcached_instance, monkeypatch,
|
||||
memcached_client_present,
|
||||
):
|
||||
server = 'localhost:{port}'.format_map(memcached_instance)
|
||||
monkeypatch.setattr(
|
||||
sessions.MemcachedSession,
|
||||
'servers',
|
||||
[server],
|
||||
)
|
||||
|
||||
# Wait for the session.timeout (1 second)
|
||||
time.sleep(1.25)
|
||||
self.getPage('/')
|
||||
self.assertBody('1')
|
||||
|
||||
# Test session __contains__
|
||||
self.getPage('/keyin?key=counter', self.cookies)
|
||||
self.assertBody('True')
|
||||
@pytest.mark.skipif(
|
||||
platform.system() == 'Windows',
|
||||
reason='pytest-services helper does not work under Windows',
|
||||
)
|
||||
@pytest.mark.usefixtures('memcached_configured')
|
||||
class MemcachedSessionTest(helper.CPWebCase):
|
||||
setup_server = staticmethod(setup_server)
|
||||
|
||||
# Test session delete
|
||||
self.getPage('/delete', self.cookies)
|
||||
self.assertBody('done')
|
||||
def test_0_Session(self):
|
||||
self.getPage(
|
||||
'/set_session_cls/cherrypy.lib.sessions.MemcachedSession'
|
||||
)
|
||||
|
||||
def test_1_Concurrency(self):
|
||||
client_thread_count = 5
|
||||
request_count = 30
|
||||
self.getPage('/testStr')
|
||||
assert self.body == b'1'
|
||||
self.getPage('/testGen', self.cookies)
|
||||
assert self.body == b'2'
|
||||
self.getPage('/testStr', self.cookies)
|
||||
assert self.body == b'3'
|
||||
self.getPage('/length', self.cookies)
|
||||
self.assertErrorPage(500)
|
||||
assert b'NotImplementedError' in self.body
|
||||
self.getPage('/delkey?key=counter', self.cookies)
|
||||
assert self.status_code == 200
|
||||
|
||||
# Get initial cookie
|
||||
self.getPage('/')
|
||||
self.assertBody('1')
|
||||
cookies = self.cookies
|
||||
# Wait for the session.timeout (1 second)
|
||||
time.sleep(1.25)
|
||||
self.getPage('/')
|
||||
assert self.body == b'1'
|
||||
|
||||
data_dict = {}
|
||||
# Test session __contains__
|
||||
self.getPage('/keyin?key=counter', self.cookies)
|
||||
assert self.body == b'True'
|
||||
|
||||
def request(index):
|
||||
for i in range(request_count):
|
||||
self.getPage('/', cookies)
|
||||
# Uncomment the following line to prove threads overlap.
|
||||
# sys.stdout.write("%d " % index)
|
||||
if not self.body.isdigit():
|
||||
self.fail(self.body)
|
||||
data_dict[index] = int(self.body)
|
||||
# Test session delete
|
||||
self.getPage('/delete', self.cookies)
|
||||
assert self.body == b'done'
|
||||
|
||||
# Start <request_count> concurrent requests from
|
||||
# each of <client_thread_count> clients
|
||||
ts = []
|
||||
for c in range(client_thread_count):
|
||||
data_dict[c] = 0
|
||||
t = threading.Thread(target=request, args=(c,))
|
||||
ts.append(t)
|
||||
t.start()
|
||||
def test_1_Concurrency(self):
|
||||
client_thread_count = 5
|
||||
request_count = 30
|
||||
|
||||
for t in ts:
|
||||
t.join()
|
||||
# Get initial cookie
|
||||
self.getPage('/')
|
||||
assert self.body == b'1'
|
||||
cookies = self.cookies
|
||||
|
||||
hitcount = max(data_dict.values())
|
||||
expected = 1 + (client_thread_count * request_count)
|
||||
self.assertEqual(hitcount, expected)
|
||||
data_dict = {}
|
||||
|
||||
def test_3_Redirect(self):
|
||||
# Start a new session
|
||||
self.getPage('/testStr')
|
||||
self.getPage('/iredir', self.cookies)
|
||||
self.assertBody('memcached')
|
||||
def request(index):
|
||||
for i in range(request_count):
|
||||
self.getPage('/', cookies)
|
||||
# Uncomment the following line to prove threads overlap.
|
||||
# sys.stdout.write("%d " % index)
|
||||
if not self.body.isdigit():
|
||||
self.fail(self.body)
|
||||
data_dict[index] = int(self.body)
|
||||
|
||||
def test_5_Error_paths(self):
|
||||
self.getPage('/unknown/page')
|
||||
self.assertErrorPage(
|
||||
404, "The path '/unknown/page' was not found.")
|
||||
# Start <request_count> concurrent requests from
|
||||
# each of <client_thread_count> clients
|
||||
ts = []
|
||||
for c in range(client_thread_count):
|
||||
data_dict[c] = 0
|
||||
t = threading.Thread(target=request, args=(c,))
|
||||
ts.append(t)
|
||||
t.start()
|
||||
|
||||
# Note: this path is *not* the same as above. The above
|
||||
# takes a normal route through the session code; this one
|
||||
# skips the session code's before_handler and only calls
|
||||
# before_finalize (save) and on_end (close). So the session
|
||||
# code has to survive calling save/close without init.
|
||||
self.getPage('/restricted', self.cookies, method='POST')
|
||||
self.assertErrorPage(405, response_codes[405][1])
|
||||
for t in ts:
|
||||
t.join()
|
||||
|
||||
hitcount = max(data_dict.values())
|
||||
expected = 1 + (client_thread_count * request_count)
|
||||
assert hitcount == expected
|
||||
|
||||
def test_3_Redirect(self):
|
||||
# Start a new session
|
||||
self.getPage('/testStr')
|
||||
self.getPage('/iredir', self.cookies)
|
||||
assert self.body == b'MemcachedSession'
|
||||
|
||||
def test_5_Error_paths(self):
|
||||
self.getPage('/unknown/page')
|
||||
self.assertErrorPage(
|
||||
404, "The path '/unknown/page' was not found.")
|
||||
|
||||
# Note: this path is *not* the same as above. The above
|
||||
# takes a normal route through the session code; this one
|
||||
# skips the session code's before_handler and only calls
|
||||
# before_finalize (save) and on_end (close). So the session
|
||||
# code has to survive calling save/close without init.
|
||||
self.getPage('/restricted', self.cookies, method='POST')
|
||||
self.assertErrorPage(405, response_codes[405][1])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue