[Python-modules-commits] [pytest-tornado] 01/02: Imported Upstream version 0.4.4

Daniel Stender danstender-guest at moszumanska.debian.org
Mon Jul 20 07:25:37 UTC 2015


This is an automated email from the git hooks/post-receive script.

danstender-guest pushed a commit to branch master
in repository pytest-tornado.

commit b37b6fb3c2b3f307bb080e51e81214d3ade565af
Author: Daniel Stender <debian at danielstender.com>
Date:   Mon Jul 20 09:23:17 2015 +0200

    Imported Upstream version 0.4.4
---
 .coveralls.yml                       |   2 +
 .gitignore                           |  55 ++++++++++
 .travis.yml                          |  17 +++
 LICENSE                              | 202 +++++++++++++++++++++++++++++++++++
 README.rst                           | 114 ++++++++++++++++++++
 pytest_tornado/__init__.py           |   0
 pytest_tornado/plugin.py             | 156 +++++++++++++++++++++++++++
 pytest_tornado/test/test_async.py    |  90 ++++++++++++++++
 pytest_tornado/test/test_fixtures.py |  27 +++++
 pytest_tornado/test/test_param.py    |  73 +++++++++++++
 pytest_tornado/test/test_server.py   |  70 ++++++++++++
 setup.cfg                            |   2 +
 setup.py                             |  41 +++++++
 13 files changed, 849 insertions(+)

diff --git a/.coveralls.yml b/.coveralls.yml
new file mode 100644
index 0000000..6b11c80
--- /dev/null
+++ b/.coveralls.yml
@@ -0,0 +1,2 @@
+service_name: travis-ci
+parallel: true # if the CI is running your build in parallel
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6f5820e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,55 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+#  Usually these files are written by a python script from a template
+#  before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.cache
+nosetests.xml
+coverage.xml
+.ropeproject/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..e3f0f6a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,17 @@
+language: python
+python:
+    - 2.7
+    - 3.4
+env:
+    - TORNADO_VERSION=4.1 PYTEST_VERSION=2.7.0
+    - TORNADO_VERSION=4.1 PYTEST_VERSION=2.6.4
+    - TORNADO_VERSION=3.2.2 PYTEST_VERSION=2.6.4
+    - TORNADO_VERSION=3.2.2 PYTEST_VERSION=2.5.2
+install:
+    - pip install -q tornado==$TORNADO_VERSION pytest==$PYTEST_VERSION
+    - python setup.py install
+    - pip install pytest-cov coveralls
+script:
+    - py.test --strict --cov=pytest_tornado/plugin.py --cov-report=term-missing
+after_success:
+  - coveralls
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..16b925b
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,114 @@
+pytest-tornado
+==============
+
+.. image:: https://travis-ci.org/eugeniy/pytest-tornado.svg?branch=master
+    :target: https://travis-ci.org/eugeniy/pytest-tornado
+
+.. image:: https://coveralls.io/repos/eugeniy/pytest-tornado/badge.svg
+    :target: https://coveralls.io/r/eugeniy/pytest-tornado
+
+A py.test_ plugin providing fixtures and markers to simplify testing
+of asynchronous tornado applications.
+
+Installation
+------------
+
+::
+
+    pip install pytest-tornado
+
+
+Example
+-------
+
+.. code-block:: python
+
+    import pytest
+    import tornado.web
+
+    class MainHandler(tornado.web.RequestHandler):
+        def get(self):
+            self.write("Hello, world")
+
+    application = tornado.web.Application([
+        (r"/", MainHandler),
+    ])
+
+    @pytest.fixture
+    def app():
+        return application
+
+    @pytest.mark.gen_test
+    def test_hello_world(http_client, base_url):
+        response = yield http_client.fetch(base_url)
+        assert response.code == 200
+
+
+Running tests
+-------------
+
+::
+
+    py.test
+
+
+Fixtures
+--------
+
+io_loop
+    creates an instance of the `tornado.ioloop.IOLoop`_ for each test case
+
+http_port
+    get a port used by the test server
+
+base_url
+    get an absolute base url for the test server,
+    for example, ``http://localhost:59828``
+
+http_server
+    start a tornado HTTP server, you must create an ``app`` fixture,
+    which returns the `tornado.web.Application`_ to be tested
+
+http_client
+    get an asynchronous HTTP client
+
+
+Show fixtures provided by the plugin::
+
+    py.test --fixtures
+
+
+Markers
+-------
+
+A ``gen_test`` marker lets you write a coroutine-style tests used with the
+`tornado.gen`_ module:
+
+.. code-block:: python
+
+    @pytest.mark.gen_test
+    def test_tornado(http_client):
+        response = yield http_client.fetch('http://www.tornadoweb.org/')
+        assert response.code == 200
+
+
+Marked tests will time out after 5 seconds. The timeout can be modified by
+setting an ``ASYNC_TEST_TIMEOUT`` environment variable,
+``--async-test-timeout`` command line argument or a marker argument.
+
+.. code-block:: python
+
+    @pytest.mark.gen_test(timeout=5)
+    def test_tornado(http_client):
+        yield http_client.fetch('http://www.tornadoweb.org/')
+
+
+Show markers provided by the plugin::
+
+    py.test --markers
+
+
+.. _py.test: http://pytest.org/
+.. _`tornado.ioloop.IOLoop`: http://tornado.readthedocs.org/en/latest/ioloop.html#ioloop-objects
+.. _`tornado.web.Application`: http://tornado.readthedocs.org/en/latest/web.html#application-configuration
+.. _`tornado.gen`: http://tornado.readthedocs.org/en/latest/gen.html
diff --git a/pytest_tornado/__init__.py b/pytest_tornado/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/pytest_tornado/plugin.py b/pytest_tornado/plugin.py
new file mode 100644
index 0000000..21a6f62
--- /dev/null
+++ b/pytest_tornado/plugin.py
@@ -0,0 +1,156 @@
+import os
+import types
+import inspect
+import functools
+import pytest
+import tornado
+import tornado.gen
+import tornado.testing
+import tornado.httpserver
+import tornado.httpclient
+
+
+def _get_async_test_timeout():
+    try:
+        return float(os.environ.get('ASYNC_TEST_TIMEOUT'))
+    except (ValueError, TypeError):
+        return 5
+
+
+def pytest_addoption(parser):
+    parser.addoption('--async-test-timeout', type=float,
+                     default=_get_async_test_timeout(),
+                     help='timeout in seconds before failing the test')
+    parser.addoption('--app-fixture', default='app',
+                     help='fixture name returning a tornado application')
+
+
+def pytest_configure(config):
+    config.addinivalue_line("markers",
+                            "gen_test(timeout=None): "
+                            "mark the test as asynchronous, it will be "
+                            "run using tornado's event loop")
+
+
+def _argnames(func):
+    spec = inspect.getargspec(func)
+    if spec.defaults:
+        return spec.args[:-len(spec.defaults)]
+    if isinstance(func, types.FunctionType):
+        return spec.args
+    # Func is a bound method, skip "self"
+    return spec.args[1:]
+
+
+def _timeout(item):
+    default_timeout = item.config.getoption('async_test_timeout')
+    gen_test = item.get_marker('gen_test')
+    if gen_test:
+        return gen_test.kwargs.get('timeout', default_timeout)
+    return default_timeout
+
+
+ at pytest.mark.tryfirst
+def pytest_pycollect_makeitem(collector, name, obj):
+    if collector.funcnamefilter(name) and inspect.isgeneratorfunction(obj):
+        item = pytest.Function(name, parent=collector)
+        if 'gen_test' in item.keywords:
+            return list(collector._genfunctions(name, obj))
+
+
+def pytest_runtest_setup(item):
+    if 'gen_test' in item.keywords and 'io_loop' not in item.fixturenames:
+        # inject an event loop fixture for all async tests
+        item.fixturenames.append('io_loop')
+
+
+ at pytest.mark.tryfirst
+def pytest_pyfunc_call(pyfuncitem):
+    if 'gen_test' in pyfuncitem.keywords:
+        io_loop = pyfuncitem.funcargs.get('io_loop')
+
+        funcargs = dict((arg, pyfuncitem.funcargs[arg])
+                        for arg in _argnames(pyfuncitem.obj))
+
+        coroutine = tornado.gen.coroutine(pyfuncitem.obj)
+        io_loop.run_sync(functools.partial(coroutine, **funcargs),
+                         timeout=_timeout(pyfuncitem))
+
+        # prevent other pyfunc calls from executing
+        return True
+
+
+ at pytest.fixture
+def io_loop(request):
+    """Create an instance of the `tornado.ioloop.IOLoop` for each test case.
+    """
+    io_loop = tornado.ioloop.IOLoop()
+    io_loop.make_current()
+
+    def _close():
+        io_loop.clear_current()
+        if (not tornado.ioloop.IOLoop.initialized() or
+                io_loop is not tornado.ioloop.IOLoop.instance()):
+            io_loop.close(all_fds=True)
+
+    request.addfinalizer(_close)
+    return io_loop
+
+
+ at pytest.fixture
+def _unused_port():
+    return tornado.testing.bind_unused_port()
+
+
+ at pytest.fixture
+def http_port(_unused_port):
+    """Get a port used by the test server.
+    """
+    return _unused_port[1]
+
+
+ at pytest.fixture
+def base_url(http_port):
+    """Create an absolute base url (scheme://host:port)
+    """
+    return 'http://localhost:%s' % http_port
+
+
+ at pytest.fixture
+def http_server(request, io_loop, _unused_port):
+    """Start a tornado HTTP server.
+
+    You must create an `app` fixture, which returns
+    the `tornado.web.Application` to be tested.
+
+    Raises:
+        FixtureLookupError: tornado application fixture not found
+    """
+    http_app = request.getfuncargvalue(request.config.option.app_fixture)
+    server = tornado.httpserver.HTTPServer(http_app, io_loop=io_loop)
+    server.add_socket(_unused_port[0])
+
+    def _stop():
+        server.stop()
+
+        if hasattr(server, 'close_all_connections'):
+            io_loop.run_sync(server.close_all_connections,
+                             timeout=request.config.option.async_test_timeout)
+
+    request.addfinalizer(_stop)
+    return server
+
+
+ at pytest.fixture
+def http_client(request, http_server):
+    """Get an asynchronous HTTP client.
+    """
+    client = tornado.httpclient.AsyncHTTPClient(io_loop=http_server.io_loop)
+
+    def _close():
+        if (not tornado.ioloop.IOLoop.initialized() or
+                client.io_loop is not tornado.ioloop.IOLoop.instance()):
+            client.close()
+
+    request.addfinalizer(_close)
+    return client
diff --git a/pytest_tornado/test/test_async.py b/pytest_tornado/test/test_async.py
new file mode 100644
index 0000000..cd70534
--- /dev/null
+++ b/pytest_tornado/test/test_async.py
@@ -0,0 +1,90 @@
+import functools
+import pytest
+from tornado import gen
+from tornado.ioloop import TimeoutError
+
+
+ at gen.coroutine
+def dummy_coroutine(io_loop):
+    yield gen.Task(io_loop.add_callback)
+    raise gen.Return(True)
+
+
+def test_explicit_start_and_stop(io_loop):
+    future = dummy_coroutine(io_loop)
+    future.add_done_callback(lambda *args: io_loop.stop())
+    io_loop.start()
+    assert future.result()
+
+
+def test_run_sync(io_loop):
+    dummy = functools.partial(dummy_coroutine, io_loop)
+    finished = io_loop.run_sync(dummy)
+    assert finished
+
+
+ at pytest.mark.gen_test
+def test_gen_test_sync(io_loop):
+    assert True
+
+
+ at pytest.mark.gen_test
+def test_gen_test(io_loop):
+    result = yield dummy_coroutine(io_loop)
+    assert result
+
+
+ at pytest.mark.gen_test
+def test_gen_test_swallows_exceptions(io_loop):
+    with pytest.raises(ZeroDivisionError):
+        1 / 0
+
+
+ at pytest.mark.gen_test
+def test_generator_raises(io_loop):
+    with pytest.raises(ZeroDivisionError):
+        yield gen.Task(io_loop.add_callback)
+        1 / 0
+
+
+ at pytest.mark.gen_test
+def test_explicit_gen_test_marker(request, io_loop):
+    yield gen.Task(io_loop.add_callback)
+    assert 'gen_test' in request.keywords
+
+
+ at pytest.mark.gen_test(timeout=2.1)
+def test_gen_test_marker_with_params(request, io_loop):
+    yield gen.Task(io_loop.add_callback)
+    assert request.keywords['gen_test'].kwargs['timeout'] == 2.1
+
+
+ at pytest.mark.xfail(raises=TimeoutError)
+ at pytest.mark.gen_test(timeout=0.1)
+def test_gen_test_with_timeout(io_loop):
+    yield gen.Task(io_loop.add_timeout, io_loop.time() + 1)
+
+
+def test_sync_tests_no_gen_test_marker(request):
+    assert 'gen_test' not in request.keywords
+
+
+def test_generators_with_disabled_gen_test_marker():
+    def _dummy(a, b):
+        assert a*3 == b
+
+    for i in range(3):
+        yield _dummy, i, i*3
+
+
+class TestClass:
+    @pytest.mark.gen_test
+    def test_gen_test(self, io_loop):
+        result = yield dummy_coroutine(io_loop)
+        assert result
+
+    @pytest.mark.gen_test
+    def test_generator_raises(self, io_loop):
+        with pytest.raises(ZeroDivisionError):
+            yield gen.Task(io_loop.add_callback)
+            1 / 0
diff --git a/pytest_tornado/test/test_fixtures.py b/pytest_tornado/test/test_fixtures.py
new file mode 100644
index 0000000..ca8fc9d
--- /dev/null
+++ b/pytest_tornado/test/test_fixtures.py
@@ -0,0 +1,27 @@
+import pytest
+from tornado import gen
+
+_used_fixture = False
+
+
+ at gen.coroutine
+def dummy(io_loop):
+    yield gen.Task(io_loop.add_callback)
+    raise gen.Return(True)
+
+
+ at pytest.fixture(scope='module')
+def preparations():
+    global _used_fixture
+    _used_fixture = True
+
+
+pytestmark = pytest.mark.usefixtures('preparations')
+
+
+ at pytest.mark.xfail(pytest.__version__ < '2.7.0',
+                   reason='py.test 2.7 adds hookwrapper, fixes collection')
+ at pytest.mark.gen_test
+def test_uses_pytestmark_fixtures(io_loop):
+    assert (yield dummy(io_loop))
+    assert _used_fixture
diff --git a/pytest_tornado/test/test_param.py b/pytest_tornado/test/test_param.py
new file mode 100644
index 0000000..11602a4
--- /dev/null
+++ b/pytest_tornado/test/test_param.py
@@ -0,0 +1,73 @@
+import pytest
+from tornado import gen
+
+DUMMY_PARAMS = ['f00', 'bar']
+
+
+ at pytest.fixture(params=DUMMY_PARAMS)
+def _dummy(request):
+    return request.param
+
+
+ at pytest.mark.parametrize('input,expected', [
+    ('3+5', 8),
+    ('2+4', 6),
+])
+def test_eval(input, expected):
+    assert eval(input) == expected
+
+
+ at pytest.mark.parametrize('input,expected', [
+    ('3+5', 8),
+    ('2+4', 6),
+    pytest.mark.xfail(("6*9", 42)),
+])
+def test_eval_marking(input, expected):
+    assert eval(input) == expected
+
+
+ at pytest.mark.parametrize('input,expected', [
+    ('3+5', 8),
+    ('2+4', 6),
+])
+ at pytest.mark.gen_test
+def test_sync_eval_with_gen_test(input, expected):
+    assert eval(input) == expected
+
+
+ at pytest.mark.parametrize('input,expected', [
+    ('3+5', 8),
+    ('2+4', 6),
+])
+def test_eval_with_fixtures(input, io_loop, expected):
+    assert eval(input) == expected
+
+
+def test_param_fixture(_dummy):
+    assert _dummy in DUMMY_PARAMS
+
+
+ at pytest.mark.gen_test
+ at pytest.mark.parametrize('input,expected', [
+    ('3+5', 8),
+    ('2+4', 6),
+])
+def test_gen_test_parametrize(io_loop, input, expected):
+    yield gen.Task(io_loop.add_callback)
+    assert eval(input) == expected
+
+
+ at pytest.mark.parametrize('input,expected', [
+    ('3+5', 8),
+    ('2+4', 6),
+])
+ at pytest.mark.gen_test
+def test_gen_test_fixture_any_order(input, io_loop, expected):
+    yield gen.Task(io_loop.add_callback)
+    assert eval(input) == expected
+
+
+ at pytest.mark.gen_test
+def test_gen_test_param_fixture(io_loop, _dummy):
+    yield gen.Task(io_loop.add_callback)
+    assert _dummy in DUMMY_PARAMS
diff --git a/pytest_tornado/test/test_server.py b/pytest_tornado/test/test_server.py
new file mode 100644
index 0000000..6b6bb55
--- /dev/null
+++ b/pytest_tornado/test/test_server.py
@@ -0,0 +1,70 @@
+import functools
+import pytest
+import tornado.ioloop
+import tornado.web
+
+
+class MainHandler(tornado.web.RequestHandler):
+    def get(self):
+        self.write('Hello, world')
+
+
+application = tornado.web.Application([
+    (r'/', MainHandler),
+    (r'/f00', MainHandler),
+])
+
+
+ at pytest.fixture(scope='module')
+def app():
+    return application
+
+
+def _fetch(http_client, url):
+    return http_client.io_loop.run_sync(
+        functools.partial(http_client.fetch, url))
+
+
+def test_http_server(http_server):
+    status = {'done': False}
+
+    def _done():
+        status['done'] = True
+        http_server.io_loop.stop()
+
+    http_server.io_loop.add_callback(_done)
+    http_server.io_loop.start()
+
+    assert status['done']
+
+
+def test_http_client(http_client, base_url):
+    request = http_client.fetch(base_url)
+    request.add_done_callback(lambda future: http_client.io_loop.stop())
+    http_client.io_loop.start()
+
+    response = request.result()
+    assert response.code == 200
+
+
+def test_http_client_with_fetch_helper(http_client, base_url):
+    response = _fetch(http_client, base_url)
+    assert response.code == 200
+
+
+ at pytest.mark.gen_test
+def test_http_client_with_gen_test(http_client, base_url):
+    response = yield http_client.fetch(base_url)
+    assert response.code == 200
+
+
+ at pytest.mark.gen_test
+def test_get_url_with_path(http_client, base_url):
+    response = yield http_client.fetch('%s/f00' % base_url)
+    assert response.code == 200
+
+
+ at pytest.mark.gen_test
+def test_http_client_raises_on_404(http_client, base_url):
+    with pytest.raises(tornado.httpclient.HTTPError):
+        yield http_client.fetch('%s/bar' % base_url)
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..3c6e79c
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal=1
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..6e3561c
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,41 @@
+import os
+import io
+from setuptools import setup, find_packages
+
+
+cwd = os.path.abspath(os.path.dirname(__file__))
+
+with io.open(os.path.join(cwd, 'README.rst'), encoding='utf-8') as fd:
+    long_description = fd.read()
+
+
+setup(
+    name='pytest-tornado',
+    version='0.4.4',
+    description=('A py.test plugin providing fixtures and markers '
+                 'to simplify testing of asynchronous tornado applications.'),
+    long_description=long_description,
+    url='https://github.com/eugeniy/pytest-tornado',
+    author='Eugeniy Kalinin',
+    author_email='burump at gmail.com',
+    license='Apache License, Version 2.0',
+    classifiers=[
+        'Development Status :: 4 - Beta',
+        'Environment :: Plugins',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: Apache Software License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 3',
+        'Topic :: Software Development',
+        'Topic :: Software Development :: Testing',
+    ],
+    keywords=('pytest py.test tornado async asynchronous '
+              'testing unit tests plugin'),
+    packages=find_packages(),
+    install_requires=['pytest', 'tornado'],
+    entry_points={
+        'pytest11': ['tornado = pytest_tornado.plugin'],
+    },
+)

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/pytest-tornado.git



More information about the Python-modules-commits mailing list