Tests: Python targets.

This commit is contained in:
Oisin Canty
2021-05-20 13:03:12 +00:00
parent f60389a782
commit e50bb120e2
7 changed files with 295 additions and 32 deletions

View File

@@ -1,19 +1,19 @@
import os import os
async def application(scope, receive, send): async def handler(prefix, scope, receive, send):
if scope['type'] == 'lifespan': if scope['type'] == 'lifespan':
with open('version', 'w+') as f: with open(prefix + 'version', 'w+') as f:
f.write( f.write(
scope['asgi']['version'] + ' ' + scope['asgi']['spec_version'] scope['asgi']['version'] + ' ' + scope['asgi']['spec_version']
) )
while True: while True:
message = await receive() message = await receive()
if message['type'] == 'lifespan.startup': if message['type'] == 'lifespan.startup':
os.remove('startup') os.remove(prefix + 'startup')
await send({'type': 'lifespan.startup.complete'}) await send({'type': 'lifespan.startup.complete'})
elif message['type'] == 'lifespan.shutdown': elif message['type'] == 'lifespan.shutdown':
os.remove('shutdown') os.remove(prefix + 'shutdown')
await send({'type': 'lifespan.shutdown.complete'}) await send({'type': 'lifespan.shutdown.complete'})
return return
@@ -25,3 +25,11 @@ async def application(scope, receive, send):
'headers': [(b'content-length', b'0'),], 'headers': [(b'content-length', b'0'),],
} }
) )
async def application(scope, receive, send):
return await handler('', scope, receive, send)
async def application2(scope, receive, send):
return await handler('app2_', scope, receive, send)

View File

@@ -0,0 +1,54 @@
async def application_201(scope, receive, send):
assert scope['type'] == 'http'
await send(
{
'type': 'http.response.start',
'status': 201,
'headers': [(b'content-length', b'0')],
}
)
async def application_200(scope, receive, send):
assert scope['type'] == 'http'
await send(
{
'type': 'http.response.start',
'status': 200,
'headers': [(b'content-length', b'0')],
}
)
def legacy_application_200(scope):
assert scope['type'] == 'http'
return legacy_app_http_200
async def legacy_app_http_200(receive, send):
await send(
{
'type': 'http.response.start',
'status': 200,
'headers': [(b'content-length', b'0')],
}
)
def legacy_application_201(scope, receive=None, send=None):
assert scope['type'] == 'http'
return legacy_app_http_201
async def legacy_app_http_201(receive, send):
await send(
{
'type': 'http.response.start',
'status': 201,
'headers': [(b'content-length', b'0')],
}
)

View File

@@ -0,0 +1,8 @@
def wsgi_target_a(env, start_response):
start_response('200', [('Content-Length', '1')])
return [b'1']
def wsgi_target_b(env, start_response):
start_response('200', [('Content-Length', '1')])
return [b'2']

View File

@@ -14,45 +14,88 @@ class TestASGILifespan(TestApplicationPython):
} }
load_module = 'asgi' load_module = 'asgi'
def setup_cookies(self, prefix):
base_dir = option.test_dir + '/python/lifespan/empty'
os.chmod(base_dir, 0o777)
for name in ['startup', 'shutdown', 'version']:
path = option.test_dir + '/python/lifespan/empty/' + prefix + name
open(path, 'a').close()
os.chmod(path, 0o777)
def assert_cookies(self, prefix):
for name in ['startup', 'shutdown']:
path = option.test_dir + '/python/lifespan/empty/' + prefix + name
exists = os.path.isfile(path)
if exists:
os.remove(path)
assert not exists, name
path = option.test_dir + '/python/lifespan/empty/' + prefix + 'version'
with open(path, 'r') as f:
version = f.read()
os.remove(path)
assert version == '3.0 2.0', 'version'
def test_asgi_lifespan(self): def test_asgi_lifespan(self):
self.load('lifespan/empty') self.load('lifespan/empty')
startup_path = option.test_dir + '/python/lifespan/empty/startup' self.setup_cookies('')
shutdown_path = option.test_dir + '/python/lifespan/empty/shutdown'
version_path = option.test_dir + '/python/lifespan/empty/version'
os.chmod(option.test_dir + '/python/lifespan/empty', 0o777)
open(startup_path, 'a').close()
os.chmod(startup_path, 0o777)
open(shutdown_path, 'a').close()
os.chmod(shutdown_path, 0o777)
open(version_path, 'a').close()
os.chmod(version_path, 0o777)
assert self.get()['status'] == 204 assert self.get()['status'] == 204
unit_stop() unit_stop()
is_startup = os.path.isfile(startup_path) self.assert_cookies('')
is_shutdown = os.path.isfile(shutdown_path)
if is_startup: def test_asgi_lifespan_targets(self):
os.remove(startup_path) assert 'success' in self.conf(
{
"listeners": {"*:7080": {"pass": "routes"}},
"routes": [
{
"match": {"uri": "/1"},
"action": {"pass": "applications/targets/1"},
},
{
"match": {"uri": "/2"},
"action": {"pass": "applications/targets/2"},
},
],
"applications": {
"targets": {
"type": "python",
"processes": {"spare": 0},
"working_directory": option.test_dir
+ "/python/lifespan/empty",
"path": option.test_dir + '/python/lifespan/empty',
"targets": {
"1": {"module": "asgi", "callable": "application"},
"2": {
"module": "asgi",
"callable": "application2",
},
},
}
},
}
)
if is_shutdown: self.setup_cookies('')
os.remove(shutdown_path) self.setup_cookies('app2_')
with open(version_path, 'r') as f: assert self.get(url="/1")['status'] == 204
version = f.read() assert self.get(url="/2")['status'] == 204
os.remove(version_path) unit_stop()
assert not is_startup, 'startup' self.assert_cookies('')
assert not is_shutdown, 'shutdown' self.assert_cookies('app2_')
assert version == '3.0 2.0', 'version'
def test_asgi_lifespan_failed(self): def test_asgi_lifespan_failed(self):
self.load('lifespan/failed') self.load('lifespan/failed')

92
test/test_asgi_targets.py Normal file
View File

@@ -0,0 +1,92 @@
from distutils.version import LooseVersion
import pytest
from unit.applications.lang.python import TestApplicationPython
from unit.option import option
class TestASGITargets(TestApplicationPython):
prerequisites = {
'modules': {'python': lambda v: LooseVersion(v) >= LooseVersion('3.5')}
}
load_module = 'asgi'
@pytest.fixture(autouse=True)
def setup_method_fixture(self):
assert 'success' in self.conf(
{
"listeners": {"*:7080": {"pass": "routes"}},
"routes": [
{
"match": {"uri": "/1"},
"action": {"pass": "applications/targets/1"},
},
{
"match": {"uri": "/2"},
"action": {"pass": "applications/targets/2"},
},
],
"applications": {
"targets": {
"type": "python",
"processes": {"spare": 0},
"working_directory": option.test_dir
+ "/python/targets/",
"path": option.test_dir + '/python/targets/',
"protocol": "asgi",
"targets": {
"1": {
"module": "asgi",
"callable": "application_200",
},
"2": {
"module": "asgi",
"callable": "application_201",
},
},
}
},
}
)
def conf_targets(self, targets):
assert 'success' in self.conf(targets, 'applications/targets/targets')
def test_asgi_targets(self):
assert self.get(url='/1')['status'] == 200
assert self.get(url='/2')['status'] == 201
def test_asgi_targets_legacy(self):
self.conf_targets(
{
"1": {"module": "asgi", "callable": "legacy_application_200"},
"2": {"module": "asgi", "callable": "legacy_application_201"},
}
)
assert self.get(url='/1')['status'] == 200
assert self.get(url='/2')['status'] == 201
def test_asgi_targets_mix(self):
self.conf_targets(
{
"1": {"module": "asgi", "callable": "application_200"},
"2": {"module": "asgi", "callable": "legacy_application_201"},
}
)
assert self.get(url='/1')['status'] == 200
assert self.get(url='/2')['status'] == 201
def test_asgi_targets_broken(self, skip_alert):
skip_alert(r'Python failed to get "blah" from module')
self.conf_targets(
{
"1": {"module": "asgi", "callable": "application_200"},
"2": {"module": "asgi", "callable": "blah"},
}
)
assert self.get(url='/1')['status'] != 200

View File

@@ -0,0 +1,51 @@
import pytest
from unit.applications.lang.python import TestApplicationPython
from unit.option import option
class TestPythonTargets(TestApplicationPython):
prerequisites = {'modules': {'python': 'all'}}
def test_python_targets(self):
assert 'success' in self.conf(
{
"listeners": {"*:7080": {"pass": "routes"}},
"routes": [
{
"match": {"uri": "/1"},
"action": {"pass": "applications/targets/1"},
},
{
"match": {"uri": "/2"},
"action": {"pass": "applications/targets/2"},
},
],
"applications": {
"targets": {
"type": "python",
"working_directory": option.test_dir
+ "/python/targets/",
"path": option.test_dir + '/python/targets/',
"targets": {
"1": {
"module": "wsgi",
"callable": "wsgi_target_a",
},
"2": {
"module": "wsgi",
"callable": "wsgi_target_b",
},
},
}
},
}
)
resp = self.get(url='/1')
assert resp['status'] == 200
assert resp['body'] == '1'
resp = self.get(url='/2')
assert resp['status'] == 200
assert resp['body'] == '2'

View File

@@ -42,8 +42,15 @@ class TestApplicationPython(TestApplicationProto):
"module": module, "module": module,
} }
for attr in ('callable', 'home', 'limits', 'path', 'protocol', for attr in (
'threads'): 'callable',
'home',
'limits',
'path',
'protocol',
'targets',
'threads',
):
if attr in kwargs: if attr in kwargs:
app[attr] = kwargs.pop(attr) app[attr] = kwargs.pop(attr)