mirror of
https://github.com/django/daphne.git
synced 2024-11-21 23:46:33 +03:00
Start on fixing tests
This commit is contained in:
parent
017797c05b
commit
22aa56e196
|
@ -20,6 +20,8 @@ class CommandLineInterface(object):
|
|||
|
||||
description = "Django HTTP/WebSocket server"
|
||||
|
||||
server_class = Server
|
||||
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser(
|
||||
description=self.description,
|
||||
|
@ -124,12 +126,6 @@ class CommandLineInterface(object):
|
|||
default=False,
|
||||
action='store_true',
|
||||
)
|
||||
self.parser.add_argument(
|
||||
'--threads',
|
||||
help='Number of threads to run the application in',
|
||||
type=int,
|
||||
default=2,
|
||||
)
|
||||
self.parser.add_argument(
|
||||
'application',
|
||||
help='The application to dispatch to as path.to.module:instance.path',
|
||||
|
@ -197,7 +193,7 @@ class CommandLineInterface(object):
|
|||
'Starting server at %s' %
|
||||
(', '.join(endpoints), )
|
||||
)
|
||||
self.server = Server(
|
||||
self.server = self.server_class(
|
||||
application=application,
|
||||
endpoints=endpoints,
|
||||
http_timeout=args.http_timeout,
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# coding=utf-8
|
||||
|
||||
channel_layer = {}
|
|
@ -1,200 +0,0 @@
|
|||
# coding: utf8
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
from unittest import TestCase
|
||||
|
||||
from six import string_types
|
||||
|
||||
from ..cli import CommandLineInterface
|
||||
from ..server import Server, build_endpoint_description_strings
|
||||
|
||||
# this is the callable that will be tested here
|
||||
build = build_endpoint_description_strings
|
||||
|
||||
|
||||
class TestEndpointDescriptions(TestCase):
|
||||
def testBasics(self):
|
||||
self.assertEqual(build(), [], msg="Empty list returned when no kwargs given")
|
||||
|
||||
def testTcpPortBindings(self):
|
||||
self.assertEqual(
|
||||
build(port=1234, host='example.com'),
|
||||
['tcp:port=1234:interface=example.com']
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
build(port=8000, host='127.0.0.1'),
|
||||
['tcp:port=8000:interface=127.0.0.1']
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
build(port=8000, host='[200a::1]'),
|
||||
['tcp:port=8000:interface=200a\:\:1']
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
build(port=8000, host='200a::1'),
|
||||
['tcp:port=8000:interface=200a\:\:1']
|
||||
)
|
||||
|
||||
# incomplete port/host kwargs raise errors
|
||||
self.assertRaises(
|
||||
ValueError,
|
||||
build, port=123
|
||||
)
|
||||
self.assertRaises(
|
||||
ValueError,
|
||||
build, host='example.com'
|
||||
)
|
||||
|
||||
def testUnixSocketBinding(self):
|
||||
self.assertEqual(
|
||||
build(unix_socket='/tmp/daphne.sock'),
|
||||
['unix:/tmp/daphne.sock']
|
||||
)
|
||||
|
||||
def testFileDescriptorBinding(self):
|
||||
self.assertEqual(
|
||||
build(file_descriptor=5),
|
||||
['fd:fileno=5']
|
||||
)
|
||||
|
||||
def testMultipleEnpoints(self):
|
||||
self.assertEqual(
|
||||
sorted(
|
||||
build(
|
||||
file_descriptor=123,
|
||||
unix_socket='/tmp/daphne.sock',
|
||||
port=8080,
|
||||
host='10.0.0.1'
|
||||
)
|
||||
),
|
||||
sorted([
|
||||
'tcp:port=8080:interface=10.0.0.1',
|
||||
'unix:/tmp/daphne.sock',
|
||||
'fd:fileno=123'
|
||||
])
|
||||
)
|
||||
|
||||
|
||||
class TestCLIInterface(TestCase):
|
||||
# construct a string that will be accepted as the channel_layer argument
|
||||
_import_channel_layer_string = 'daphne.tests.asgi:channel_layer'
|
||||
|
||||
def setUp(self):
|
||||
logging.disable(logging.CRITICAL)
|
||||
# patch out the servers run method
|
||||
self._default_server_run = Server.run
|
||||
Server.run = lambda x: x
|
||||
|
||||
def tearDown(self):
|
||||
logging.disable(logging.NOTSET)
|
||||
# restore the original server run method
|
||||
Server.run = self._default_server_run
|
||||
|
||||
def build_cli(self, cli_args=''):
|
||||
# split the string and append the channel_layer positional argument
|
||||
if isinstance(cli_args, string_types):
|
||||
cli_args = cli_args.split()
|
||||
|
||||
args = cli_args + [self._import_channel_layer_string]
|
||||
cli = CommandLineInterface()
|
||||
cli.run(args)
|
||||
return cli
|
||||
|
||||
def get_endpoints(self, cli_args=''):
|
||||
cli = self.build_cli(cli_args=cli_args)
|
||||
return cli.server.endpoints
|
||||
|
||||
def checkCLI(self, args='', endpoints=None, msg='Expected endpoints do not match.'):
|
||||
endpoints = endpoints or []
|
||||
cli = self.build_cli(cli_args=args)
|
||||
generated_endpoints = sorted(cli.server.endpoints)
|
||||
endpoints.sort()
|
||||
self.assertEqual(
|
||||
generated_endpoints,
|
||||
endpoints,
|
||||
msg=msg
|
||||
)
|
||||
|
||||
def testCLIBasics(self):
|
||||
self.checkCLI(
|
||||
'',
|
||||
['tcp:port=8000:interface=127.0.0.1']
|
||||
)
|
||||
|
||||
self.checkCLI(
|
||||
'-p 123',
|
||||
['tcp:port=123:interface=127.0.0.1']
|
||||
)
|
||||
|
||||
self.checkCLI(
|
||||
'-b 10.0.0.1',
|
||||
['tcp:port=8000:interface=10.0.0.1']
|
||||
)
|
||||
self.checkCLI(
|
||||
'-b 200a::1',
|
||||
['tcp:port=8000:interface=200a\:\:1']
|
||||
)
|
||||
self.checkCLI(
|
||||
'-b [200a::1]',
|
||||
['tcp:port=8000:interface=200a\:\:1']
|
||||
)
|
||||
self.checkCLI(
|
||||
'-p 8080 -b example.com',
|
||||
['tcp:port=8080:interface=example.com']
|
||||
)
|
||||
|
||||
def testCLIEndpointCreation(self):
|
||||
self.checkCLI(
|
||||
'-p 8080 -u /tmp/daphne.sock',
|
||||
[
|
||||
'tcp:port=8080:interface=127.0.0.1',
|
||||
'unix:/tmp/daphne.sock',
|
||||
],
|
||||
'Default binding host patched in when only port given'
|
||||
)
|
||||
|
||||
self.checkCLI(
|
||||
'-b example.com -u /tmp/daphne.sock',
|
||||
[
|
||||
'tcp:port=8000:interface=example.com',
|
||||
'unix:/tmp/daphne.sock',
|
||||
],
|
||||
'Default port patched in when missing.'
|
||||
)
|
||||
|
||||
self.checkCLI(
|
||||
'-u /tmp/daphne.sock --fd 5',
|
||||
[
|
||||
'fd:fileno=5',
|
||||
'unix:/tmp/daphne.sock'
|
||||
],
|
||||
'File descriptor and unix socket bound, TCP ignored.'
|
||||
)
|
||||
|
||||
def testMixedCLIEndpointCreation(self):
|
||||
self.checkCLI(
|
||||
'-p 8080 -e unix:/tmp/daphne.sock',
|
||||
[
|
||||
'tcp:port=8080:interface=127.0.0.1',
|
||||
'unix:/tmp/daphne.sock'
|
||||
],
|
||||
'Mix host/port args with endpoint args'
|
||||
)
|
||||
|
||||
self.checkCLI(
|
||||
'-p 8080 -e tcp:port=8080:interface=127.0.0.1',
|
||||
[
|
||||
'tcp:port=8080:interface=127.0.0.1',
|
||||
] * 2,
|
||||
'Do not try to de-duplicate endpoint description strings.'
|
||||
'This would fail when running the server.'
|
||||
)
|
||||
|
||||
def testCustomEndpoints(self):
|
||||
self.checkCLI(
|
||||
'-e imap:',
|
||||
['imap:']
|
||||
)
|
|
@ -4,8 +4,7 @@ Contains a test case class to allow verifying ASGI messages
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from collections import defaultdict
|
||||
import six
|
||||
from six.moves.urllib import parse
|
||||
from urllib import parse
|
||||
import socket
|
||||
import unittest
|
||||
|
||||
|
@ -33,19 +32,19 @@ class ASGITestCaseBase(unittest.TestCase):
|
|||
self.assertEqual(set(), present_keys - required_keys - optional_keys)
|
||||
|
||||
def assert_valid_reply_channel(self, reply_channel):
|
||||
self.assertIsInstance(reply_channel, six.text_type)
|
||||
self.assertIsInstance(reply_channel, str)
|
||||
# The reply channel is decided by the server.
|
||||
self.assertTrue(reply_channel.startswith('test!'))
|
||||
|
||||
def assert_valid_path(self, path, request_path):
|
||||
self.assertIsInstance(path, six.text_type)
|
||||
self.assertIsInstance(path, str)
|
||||
self.assertEqual(path, request_path)
|
||||
# Assert that it's already url decoded
|
||||
self.assertEqual(path, parse.unquote(path))
|
||||
|
||||
def assert_valid_address_and_port(self, host):
|
||||
address, port = host
|
||||
self.assertIsInstance(address, six.text_type)
|
||||
self.assertIsInstance(address, str)
|
||||
self.assert_is_ip_address(address)
|
||||
self.assertIsInstance(port, int)
|
||||
|
||||
|
@ -74,17 +73,17 @@ class ASGIHTTPTestCase(ASGITestCaseBase):
|
|||
self.assert_valid_path(channel_message['path'], request_path)
|
||||
|
||||
http_version = channel_message['http_version']
|
||||
self.assertIsInstance(http_version, six.text_type)
|
||||
self.assertIsInstance(http_version, str)
|
||||
self.assertIn(http_version, ['1.0', '1.1', '1.2'])
|
||||
|
||||
method = channel_message['method']
|
||||
self.assertIsInstance(method, six.text_type)
|
||||
self.assertIsInstance(method, str)
|
||||
self.assertTrue(method.isupper())
|
||||
self.assertEqual(channel_message['method'], request_method)
|
||||
|
||||
query_string = channel_message['query_string']
|
||||
# Assert that query_string is a byte string and still url encoded
|
||||
self.assertIsInstance(query_string, six.binary_type)
|
||||
self.assertIsInstance(query_string, bytes)
|
||||
self.assertEqual(query_string, parse.urlencode(request_params or []).encode('ascii'))
|
||||
|
||||
# Ordering of header names is not important, but the order of values for a header
|
||||
|
@ -107,22 +106,22 @@ class ASGIHTTPTestCase(ASGITestCaseBase):
|
|||
|
||||
scheme = channel_message.get('scheme')
|
||||
if scheme is not None:
|
||||
self.assertIsInstance(scheme, six.text_type)
|
||||
self.assertIsInstance(scheme, str)
|
||||
self.assertTrue(scheme) # May not be empty
|
||||
|
||||
root_path = channel_message.get('root_path')
|
||||
if root_path is not None:
|
||||
self.assertIsInstance(root_path, six.text_type)
|
||||
self.assertIsInstance(root_path, str)
|
||||
|
||||
body = channel_message.get('body')
|
||||
# Ensure we test for presence of 'body' if a request body was given
|
||||
if request_body is not None or body is not None:
|
||||
self.assertIsInstance(body, six.binary_type)
|
||||
self.assertIsInstance(body, str)
|
||||
self.assertEqual(body, (request_body or '').encode('ascii'))
|
||||
|
||||
body_channel = channel_message.get('body_channel')
|
||||
if body_channel is not None:
|
||||
self.assertIsInstance(body_channel, six.text_type)
|
||||
self.assertIsInstance(body_channel, str)
|
||||
self.assertIn('?', body_channel)
|
||||
|
||||
client = channel_message.get('client')
|
||||
|
@ -137,7 +136,7 @@ class ASGIHTTPTestCase(ASGITestCaseBase):
|
|||
self.assertTrue(message)
|
||||
self.assertTrue(response.startswith(b'HTTP'))
|
||||
|
||||
status_code_bytes = six.text_type(message['status']).encode('ascii')
|
||||
status_code_bytes = str(message['status']).encode('ascii')
|
||||
self.assertIn(status_code_bytes, response)
|
||||
|
||||
if 'content' in message:
|
||||
|
|
12
setup.cfg
12
setup.cfg
|
@ -1,2 +1,14 @@
|
|||
[bdist_wheel]
|
||||
universal=1
|
||||
|
||||
[tool:pytest]
|
||||
addopts = tests/
|
||||
|
||||
[yapf]
|
||||
based_on_style = pep8
|
||||
column_limit = 120
|
||||
join_multiple_lines = false
|
||||
split_arguments_when_comma_terminated = true
|
||||
split_before_expression_after_opening_paren = true
|
||||
split_before_first_argument = true
|
||||
split_penalty_after_opening_bracket = -10
|
||||
|
|
13
setup.py
13
setup.py
|
@ -23,13 +23,18 @@ setup(
|
|||
packages=find_packages() + ['twisted.plugins'],
|
||||
include_package_data=True,
|
||||
install_requires=[
|
||||
'asgiref~=1.1',
|
||||
'asgiref~=2.0',
|
||||
'twisted>=17.5',
|
||||
'autobahn>=0.18',
|
||||
],
|
||||
extras_require={
|
||||
'tests': ['hypothesis', 'tox']
|
||||
},
|
||||
setup_requires=[
|
||||
'pytest-runner',
|
||||
],
|
||||
tests_require=[
|
||||
'hypothesis',
|
||||
'tox',
|
||||
'pytest',
|
||||
],
|
||||
entry_points={'console_scripts': [
|
||||
'daphne = daphne.cli:CommandLineInterface.entrypoint',
|
||||
]},
|
||||
|
|
237
tests/test_cli.py
Normal file
237
tests/test_cli.py
Normal file
|
@ -0,0 +1,237 @@
|
|||
# coding: utf8
|
||||
|
||||
import logging
|
||||
from unittest import TestCase
|
||||
|
||||
from daphne.cli import CommandLineInterface
|
||||
from daphne.endpoints import build_endpoint_description_strings as build
|
||||
|
||||
|
||||
class TestEndpointDescriptions(TestCase):
|
||||
"""
|
||||
Tests that the endpoint parsing/generation works as intended.
|
||||
"""
|
||||
|
||||
def testBasics(self):
|
||||
self.assertEqual(build(), [], msg='Empty list returned when no kwargs given')
|
||||
|
||||
def testTcpPortBindings(self):
|
||||
self.assertEqual(
|
||||
build(port=1234, host='example.com'),
|
||||
['tcp:port=1234:interface=example.com']
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
build(port=8000, host='127.0.0.1'),
|
||||
['tcp:port=8000:interface=127.0.0.1']
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
build(port=8000, host='[200a::1]'),
|
||||
[r'tcp:port=8000:interface=200a\:\:1']
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
build(port=8000, host='200a::1'),
|
||||
[r'tcp:port=8000:interface=200a\:\:1']
|
||||
)
|
||||
|
||||
# incomplete port/host kwargs raise errors
|
||||
self.assertRaises(
|
||||
ValueError,
|
||||
build, port=123
|
||||
)
|
||||
self.assertRaises(
|
||||
ValueError,
|
||||
build, host='example.com'
|
||||
)
|
||||
|
||||
def testUnixSocketBinding(self):
|
||||
self.assertEqual(
|
||||
build(unix_socket='/tmp/daphne.sock'),
|
||||
['unix:/tmp/daphne.sock']
|
||||
)
|
||||
|
||||
def testFileDescriptorBinding(self):
|
||||
self.assertEqual(
|
||||
build(file_descriptor=5),
|
||||
['fd:fileno=5']
|
||||
)
|
||||
|
||||
def testMultipleEnpoints(self):
|
||||
self.assertEqual(
|
||||
sorted(
|
||||
build(
|
||||
file_descriptor=123,
|
||||
unix_socket='/tmp/daphne.sock',
|
||||
port=8080,
|
||||
host='10.0.0.1'
|
||||
)
|
||||
),
|
||||
sorted([
|
||||
'tcp:port=8080:interface=10.0.0.1',
|
||||
'unix:/tmp/daphne.sock',
|
||||
'fd:fileno=123'
|
||||
])
|
||||
)
|
||||
|
||||
|
||||
class TestCLIInterface(TestCase):
|
||||
"""
|
||||
Tests the overall CLI class.
|
||||
"""
|
||||
|
||||
class TestedCLI(CommandLineInterface):
|
||||
"""
|
||||
CommandLineInterface subclass that we used for testing (has a fake
|
||||
server subclass).
|
||||
"""
|
||||
|
||||
class TestedServer:
|
||||
"""
|
||||
Mock server object for testing.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.init_kwargs = kwargs
|
||||
|
||||
def run(self):
|
||||
pass
|
||||
|
||||
server_class = TestedServer
|
||||
|
||||
def setUp(self):
|
||||
logging.disable(logging.CRITICAL)
|
||||
|
||||
def tearDown(self):
|
||||
logging.disable(logging.NOTSET)
|
||||
|
||||
def assertCLI(self, args, server_kwargs):
|
||||
"""
|
||||
Asserts that the CLI class passes the right args to the server class.
|
||||
Passes in a fake application automatically.
|
||||
"""
|
||||
cli = self.TestedCLI()
|
||||
cli.run(args + ['daphne:__version__']) # We just pass something importable as app
|
||||
# Check the server got all arguments as intended
|
||||
for key, value in server_kwargs.items():
|
||||
# Get the value and sort it if it's a list (for endpoint checking)
|
||||
actual_value = cli.server.init_kwargs.get(key)
|
||||
if isinstance(actual_value, list):
|
||||
actual_value.sort()
|
||||
# Check values
|
||||
self.assertEqual(
|
||||
value,
|
||||
actual_value,
|
||||
'Wrong value for server kwarg %s: %r != %r' % (
|
||||
key,
|
||||
value,
|
||||
actual_value,
|
||||
),
|
||||
)
|
||||
|
||||
def testCLIBasics(self):
|
||||
"""
|
||||
Tests basic endpoint generation.
|
||||
"""
|
||||
self.assertCLI(
|
||||
[],
|
||||
{
|
||||
'endpoints': ['tcp:port=8000:interface=127.0.0.1'],
|
||||
},
|
||||
)
|
||||
self.assertCLI(
|
||||
['-p', '123'],
|
||||
{
|
||||
'endpoints': ['tcp:port=123:interface=127.0.0.1'],
|
||||
},
|
||||
)
|
||||
self.assertCLI(
|
||||
['-b', '10.0.0.1'],
|
||||
{
|
||||
'endpoints': ['tcp:port=8000:interface=10.0.0.1'],
|
||||
},
|
||||
)
|
||||
self.assertCLI(
|
||||
['-b', '200a::1'],
|
||||
{
|
||||
'endpoints': [r'tcp:port=8000:interface=200a\:\:1'],
|
||||
},
|
||||
)
|
||||
self.assertCLI(
|
||||
['-b', '[200a::1]'],
|
||||
{
|
||||
'endpoints': [r'tcp:port=8000:interface=200a\:\:1'],
|
||||
},
|
||||
)
|
||||
self.assertCLI(
|
||||
['-p', '8080', '-b', 'example.com'],
|
||||
{
|
||||
'endpoints': ['tcp:port=8080:interface=example.com'],
|
||||
},
|
||||
)
|
||||
|
||||
def testUnixSockets(self):
|
||||
self.assertCLI(
|
||||
['-p', '8080', '-u', '/tmp/daphne.sock'],
|
||||
{
|
||||
'endpoints': [
|
||||
'tcp:port=8080:interface=127.0.0.1',
|
||||
'unix:/tmp/daphne.sock',
|
||||
],
|
||||
},
|
||||
)
|
||||
self.assertCLI(
|
||||
['-b', 'example.com', '-u', '/tmp/daphne.sock'],
|
||||
{
|
||||
'endpoints': [
|
||||
'tcp:port=8000:interface=example.com',
|
||||
'unix:/tmp/daphne.sock',
|
||||
],
|
||||
},
|
||||
)
|
||||
self.assertCLI(
|
||||
['-u', '/tmp/daphne.sock', '--fd', '5'],
|
||||
{
|
||||
'endpoints': [
|
||||
'fd:fileno=5',
|
||||
'unix:/tmp/daphne.sock'
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
def testMixedCLIEndpointCreation(self):
|
||||
"""
|
||||
Tests mixing the shortcut options with the endpoint string options.
|
||||
"""
|
||||
self.assertCLI(
|
||||
['-p', '8080', '-e', 'unix:/tmp/daphne.sock'],
|
||||
{
|
||||
'endpoints': [
|
||||
'tcp:port=8080:interface=127.0.0.1',
|
||||
'unix:/tmp/daphne.sock'
|
||||
],
|
||||
},
|
||||
)
|
||||
self.assertCLI(
|
||||
['-p', '8080', '-e', 'tcp:port=8080:interface=127.0.0.1'],
|
||||
{
|
||||
'endpoints': [
|
||||
'tcp:port=8080:interface=127.0.0.1',
|
||||
'tcp:port=8080:interface=127.0.0.1',
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
def testCustomEndpoints(self):
|
||||
"""
|
||||
Tests entirely custom endpoints
|
||||
"""
|
||||
self.assertCLI(
|
||||
['-e', 'imap:'],
|
||||
{
|
||||
'endpoints': [
|
||||
'imap:',
|
||||
],
|
||||
},
|
||||
)
|
Loading…
Reference in New Issue
Block a user