Tests: added tests for basic statistics.
This commit is contained in:
@@ -24,6 +24,7 @@ from unit.check.unix_abstract import check_unix_abstract
|
|||||||
from unit.http import TestHTTP
|
from unit.http import TestHTTP
|
||||||
from unit.log import Log
|
from unit.log import Log
|
||||||
from unit.option import option
|
from unit.option import option
|
||||||
|
from unit.status import Status
|
||||||
from unit.utils import public_dir
|
from unit.utils import public_dir
|
||||||
from unit.utils import waitforfiles
|
from unit.utils import waitforfiles
|
||||||
|
|
||||||
@@ -429,6 +430,8 @@ def unit_run(state_dir=None):
|
|||||||
controller['pid'] = pid_by_name(controller['name'])
|
controller['pid'] = pid_by_name(controller['name'])
|
||||||
controller['fds'] = _count_fds(controller['pid'])
|
controller['fds'] = _count_fds(controller['pid'])
|
||||||
|
|
||||||
|
Status._check_zeros()
|
||||||
|
|
||||||
return unit_instance
|
return unit_instance
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
223
test/test_status.py
Normal file
223
test/test_status.py
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from unit.applications.lang.python import TestApplicationPython
|
||||||
|
from unit.option import option
|
||||||
|
from unit.status import Status
|
||||||
|
|
||||||
|
|
||||||
|
class TestStatus(TestApplicationPython):
|
||||||
|
prerequisites = {'modules': {'python': 'any'}}
|
||||||
|
|
||||||
|
def test_status(self):
|
||||||
|
assert 'error' in self.conf_delete('/status'), 'DELETE method'
|
||||||
|
|
||||||
|
def test_status_requests(self, skip_alert):
|
||||||
|
skip_alert(r'Python failed to import module "blah"')
|
||||||
|
|
||||||
|
assert 'success' in self.conf(
|
||||||
|
{
|
||||||
|
"listeners": {
|
||||||
|
"*:7080": {"pass": "routes"},
|
||||||
|
"*:7081": {"pass": "applications/empty"},
|
||||||
|
"*:7082": {"pass": "applications/blah"},
|
||||||
|
},
|
||||||
|
"routes": [{"action": {"return": 200}}],
|
||||||
|
"applications": {
|
||||||
|
"empty": {
|
||||||
|
"type": self.get_application_type(),
|
||||||
|
"processes": {"spare": 0},
|
||||||
|
"path": option.test_dir + '/python/empty',
|
||||||
|
"working_directory": option.test_dir + '/python/empty',
|
||||||
|
"module": "wsgi",
|
||||||
|
},
|
||||||
|
"blah": {
|
||||||
|
"type": self.get_application_type(),
|
||||||
|
"processes": {"spare": 0},
|
||||||
|
"module": "blah",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
Status.init()
|
||||||
|
|
||||||
|
assert self.get()['status'] == 200
|
||||||
|
assert Status.get('/requests/total') == 1, '2xx'
|
||||||
|
|
||||||
|
assert self.get(port=7081)['status'] == 200
|
||||||
|
assert Status.get('/requests/total') == 2, '2xx app'
|
||||||
|
|
||||||
|
assert (
|
||||||
|
self.get(headers={'Host': '/', 'Connection': 'close'})['status']
|
||||||
|
== 400
|
||||||
|
)
|
||||||
|
assert Status.get('/requests/total') == 3, '4xx'
|
||||||
|
|
||||||
|
assert self.get(port=7082)['status'] == 503
|
||||||
|
assert Status.get('/requests/total') == 4, '5xx'
|
||||||
|
|
||||||
|
self.http(
|
||||||
|
b"""GET / HTTP/1.1
|
||||||
|
Host: localhost
|
||||||
|
|
||||||
|
GET / HTTP/1.1
|
||||||
|
Host: localhost
|
||||||
|
Connection: close
|
||||||
|
|
||||||
|
""",
|
||||||
|
raw=True,
|
||||||
|
)
|
||||||
|
assert Status.get('/requests/total') == 6, 'pipeline'
|
||||||
|
|
||||||
|
(_, sock) = self.get(port=7081, no_recv=True, start=True)
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
assert Status.get('/requests/total') == 7, 'no receive'
|
||||||
|
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
def test_status_connections(self):
|
||||||
|
def check_connections(accepted, active, idle, closed):
|
||||||
|
Status.get('/connections') == {
|
||||||
|
'accepted': accepted,
|
||||||
|
'active': active,
|
||||||
|
'idle': idle,
|
||||||
|
'closed': closed,
|
||||||
|
}
|
||||||
|
|
||||||
|
assert 'success' in self.conf(
|
||||||
|
{
|
||||||
|
"listeners": {
|
||||||
|
"*:7080": {"pass": "routes"},
|
||||||
|
"*:7081": {"pass": "applications/delayed"},
|
||||||
|
},
|
||||||
|
"routes": [{"action": {"return": 200}}],
|
||||||
|
"applications": {
|
||||||
|
"delayed": {
|
||||||
|
"type": self.get_application_type(),
|
||||||
|
"processes": {"spare": 0},
|
||||||
|
"path": option.test_dir + "/python/delayed",
|
||||||
|
"working_directory": option.test_dir
|
||||||
|
+ "/python/delayed",
|
||||||
|
"module": "wsgi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
Status.init()
|
||||||
|
|
||||||
|
# accepted, closed
|
||||||
|
|
||||||
|
assert self.get()['status'] == 200
|
||||||
|
check_connections(1, 0, 0, 1)
|
||||||
|
|
||||||
|
# idle
|
||||||
|
|
||||||
|
_, sock = self.http(b'', start=True, raw=True, no_recv=True)
|
||||||
|
check_connections(2, 0, 1, 1)
|
||||||
|
|
||||||
|
self.get(sock=sock)
|
||||||
|
check_connections(2, 0, 0, 2)
|
||||||
|
|
||||||
|
# active
|
||||||
|
|
||||||
|
(_, sock) = self.get(
|
||||||
|
headers={
|
||||||
|
'Host': 'localhost',
|
||||||
|
'X-Delay': '2',
|
||||||
|
'Connection': 'close',
|
||||||
|
},
|
||||||
|
port=7081,
|
||||||
|
start=True,
|
||||||
|
read_timeout=1,
|
||||||
|
)
|
||||||
|
check_connections(3, 1, 0, 2)
|
||||||
|
|
||||||
|
self.get(sock=sock)
|
||||||
|
check_connections(3, 0, 0, 3)
|
||||||
|
|
||||||
|
def test_status_applications(self):
|
||||||
|
def check_applications(expert):
|
||||||
|
apps = list(self.conf_get('/status/applications').keys()).sort()
|
||||||
|
assert apps == expert.sort()
|
||||||
|
|
||||||
|
def check_application(name, running, starting, idle, active):
|
||||||
|
Status.get('/applications/' + name) == {
|
||||||
|
'processes': {
|
||||||
|
'running': running,
|
||||||
|
'starting': starting,
|
||||||
|
'idle': idle,
|
||||||
|
},
|
||||||
|
'requests': {'active': active},
|
||||||
|
}
|
||||||
|
|
||||||
|
self.load('delayed')
|
||||||
|
Status.init()
|
||||||
|
|
||||||
|
check_applications(['delayed'])
|
||||||
|
check_application('delayed', 0, 0, 0, 0)
|
||||||
|
|
||||||
|
# idle
|
||||||
|
|
||||||
|
assert self.get()['status'] == 200
|
||||||
|
check_application('delayed', 1, 0, 1, 0)
|
||||||
|
|
||||||
|
assert 'success' in self.conf('4', 'applications/delayed/processes')
|
||||||
|
check_application('delayed', 4, 0, 4, 0)
|
||||||
|
|
||||||
|
# active
|
||||||
|
|
||||||
|
(_, sock) = self.get(
|
||||||
|
headers={
|
||||||
|
'Host': 'localhost',
|
||||||
|
'X-Delay': '2',
|
||||||
|
'Connection': 'close',
|
||||||
|
},
|
||||||
|
start=True,
|
||||||
|
read_timeout=1,
|
||||||
|
)
|
||||||
|
check_application('delayed', 4, 0, 3, 1)
|
||||||
|
sock.close()
|
||||||
|
|
||||||
|
# starting
|
||||||
|
|
||||||
|
assert 'success' in self.conf(
|
||||||
|
{
|
||||||
|
"listeners": {
|
||||||
|
"*:7080": {"pass": "applications/restart"},
|
||||||
|
"*:7081": {"pass": "applications/delayed"},
|
||||||
|
},
|
||||||
|
"routes": [],
|
||||||
|
"applications": {
|
||||||
|
"restart": {
|
||||||
|
"type": self.get_application_type(),
|
||||||
|
"processes": {"spare": 0},
|
||||||
|
"path": option.test_dir + "/python/restart",
|
||||||
|
"working_directory": option.test_dir
|
||||||
|
+ "/python/restart",
|
||||||
|
"module": "longstart",
|
||||||
|
},
|
||||||
|
"delayed": {
|
||||||
|
"type": self.get_application_type(),
|
||||||
|
"processes": {"spare": 0},
|
||||||
|
"path": option.test_dir + "/python/delayed",
|
||||||
|
"working_directory": option.test_dir
|
||||||
|
+ "/python/delayed",
|
||||||
|
"module": "wsgi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
Status.init()
|
||||||
|
|
||||||
|
check_applications(['delayed', 'restart'])
|
||||||
|
check_application('restart', 0, 0, 0, 0)
|
||||||
|
check_application('delayed', 0, 0, 0, 0)
|
||||||
|
|
||||||
|
self.get(read_timeout=1)
|
||||||
|
|
||||||
|
check_application('restart', 0, 1, 0, 1)
|
||||||
|
check_application('delayed', 0, 0, 0, 0)
|
||||||
30
test/test_status_tls.py
Normal file
30
test/test_status_tls.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
from unit.applications.tls import TestApplicationTLS
|
||||||
|
from unit.status import Status
|
||||||
|
|
||||||
|
|
||||||
|
class TestStatusTLS(TestApplicationTLS):
|
||||||
|
prerequisites = {'modules': {'openssl': 'any'}}
|
||||||
|
|
||||||
|
def test_status_tls_requests(self):
|
||||||
|
self.certificate()
|
||||||
|
|
||||||
|
assert 'success' in self.conf(
|
||||||
|
{
|
||||||
|
"listeners": {
|
||||||
|
"*:7080": {"pass": "routes"},
|
||||||
|
"*:7081": {
|
||||||
|
"pass": "routes",
|
||||||
|
"tls": {"certificate": "default"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"routes": [{"action": {"return": 200}}],
|
||||||
|
"applications": {},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Status.init()
|
||||||
|
|
||||||
|
assert self.get()['status'] == 200
|
||||||
|
assert self.get_ssl(port=7081)['status'] == 200
|
||||||
|
|
||||||
|
assert Status.get('/requests/total') == 2
|
||||||
45
test/unit/status.py
Normal file
45
test/unit/status.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
from unit.control import TestControl
|
||||||
|
|
||||||
|
|
||||||
|
class Status:
|
||||||
|
_status = None
|
||||||
|
control = TestControl()
|
||||||
|
|
||||||
|
def _check_zeros():
|
||||||
|
assert Status.control.conf_get('/status') == {
|
||||||
|
'connections': {
|
||||||
|
'accepted': 0,
|
||||||
|
'active': 0,
|
||||||
|
'idle': 0,
|
||||||
|
'closed': 0,
|
||||||
|
},
|
||||||
|
'requests': {'total': 0},
|
||||||
|
'applications': {},
|
||||||
|
}
|
||||||
|
|
||||||
|
def init(status=None):
|
||||||
|
Status._status = (
|
||||||
|
status if status is not None else Status.control.conf_get('/status')
|
||||||
|
)
|
||||||
|
|
||||||
|
def diff():
|
||||||
|
def find_diffs(d1, d2):
|
||||||
|
if isinstance(d1, dict) and isinstance(d2, dict):
|
||||||
|
return {
|
||||||
|
k: find_diffs(d1.get(k, 0), d2.get(k, 0))
|
||||||
|
for k in d1
|
||||||
|
if k in d2
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
return d1 - d2
|
||||||
|
|
||||||
|
return find_diffs(Status.control.conf_get('/status'), Status._status)
|
||||||
|
|
||||||
|
def get(path='/'):
|
||||||
|
path = path.split('/')[1:]
|
||||||
|
diff = Status.diff()
|
||||||
|
|
||||||
|
for p in path:
|
||||||
|
diff = diff[p]
|
||||||
|
|
||||||
|
return diff
|
||||||
Reference in New Issue
Block a user