Skip to main content

HTTP server integration for testing

Project description

gocept.httpserverlayer

This package provides an HTTP server for testing your application with normal HTTP clients (e.g. a real browser). This is done using test layers, which are a feature of zope.testrunner.

gocept.httpserverlayer uses plone.testing for the test layer implementation, and exposes the following resources (accessible in your test case as self.layer[RESOURCE_NAME]):

http_host:

The hostname of the HTTP server (Default: localhost)

http_port:

The port of the HTTP server (Default: 0, which means chosen automatically by the operating system)

http_address:

hostname:port, convenient to use in URLs (e.g. 'http://user:password@%s/path' % self.layer['http_address'])

This package is compatible with Python version 3.6, 3.7, 3.8, and 3.9.

WSGI

This test layer takes a WSGI callable and runs it in a temporary HTTP server:

import gocept.httpserverlayer.wsgi
from mypackage import App
import unittest

HTTP_LAYER = gocept.httpserverlayer.wsgi.Layer()
HTTP_LAYER.wsgi_app = App()

class WSGIExample(unittest.TestCase):

    layer = HTTP_LAYER

    def test_something(self):
        r = urllib.urlopen('http://{0.layer[http_address]}/'.format(self))
        self.assertIn('Hello world', r.read())

You can also have a base layer provide the WSGI callable (in the wsgi_app resource):

import gocept.httpserverlayer.wsgi
from mypackage import App
import plone.testing

class WSGILayer(plone.testing.Layer):

    def setUp(self):
        self['wsgi_app'] = App()

WSGI_LAYER = WSGILayer()

HTTP_LAYER = gocept.httpserverlayer.wsgi.Layer(
    name='HTTPLayer', bases=(WSGI_LAYER,))

Static files

This test layer serves up the contents of a directory:

import gocept.httpserverlayer.static
import pkg_resources
import unittest

HTTP_LAYER = gocept.httpserverlayer.static.Layer(
    pkg_resources.resource_filename('my.package.tests', 'fixtures'))

class DirecoryExample(unittest.TestCase):

    layer = HTTP_LAYER

    def test_something(self):
        r = urllib.urlopen('http://{0.layer[http_address]}/'.format(self))
        self.assertIn('Hello world', r.read())

If you don’t pass in a directory, a temporary directory will be created/removed automatically. The directory is provided in the documentroot resource. For convenience, a layer instance is already provided as STATIC_FILES:

import gocept.httpserverlayer.static
import os.path
import unittest

HTTP_LAYER = gocept.httpserverlayer.static.STATIC_FILES

class TemporaryExample(unittest.TestCase):

    layer = HTTP_LAYER

    def test_something(self):
        path = os.path.join(self.testlayer['documentroot'], 'index')
        with open(path, 'w') as f:
            f.write('Hello World!')
        r = urllib.urlopen(
            'http://{0.layer[http_address]}/index'.format(self))
        self.assertIn('Hello world', r.read())

Custom request handler

This test layer allows you to provide your own HTTP request handler for very fine-grained control:

import gocept.httpserverlayer.custom
import unittest

class RequestHandler(gocept.httpserverlayer.custom.RequestHandler):

    response_code = 200
    response_body = ''
    posts_received = []

    def do_POST(self):
        length = int(self.headers['content-length'])
        self.posts_received.append(dict(
            path=self.path,
            data=self.rfile.read(length),
            headers=self.headers,
        ))
        self.send_response(self.response_code)
        self.end_headers()
        self.wfile.write(self.response_body)

HTTP_LAYER = gocept.httpserverlayer.custom.Layer(RequestHandler)

class POSTExample(unittest.TestCase):

    layer = HTTP_LAYER

    def test_something(self):
        urllib.urlopen('http://{0.layer[http_address]}/'.format(self),
                       urllib.urlencode({'foo': 'bar'}))
        self.assertEqual(
            'foo=bar',
            self.layer['request_handler'].posts_received[0]['data'])

Framework integration

gocept.httpserverlayer also provides integration with some web frameworks. Different frameworks require different dependencies; this is handled via setuptools extras of gocept.httpserverlayer (e.g. for Grok integration you need to require gocept.httpserverlayer[zopeappwsgi]).

Zope 3 / ZTK / Grok (zope.app.wsgi)

Requires gocept.httpserverlayer[zopeappwsgi]

If your ZTK application uses zope.app.wsgi.testlayer (which is the recommended test setup for Grok, for example), you can use gocept.httpserverlayer.zopeappwsgi.Layer to create a WSGI app that integrates ZODB isolation, and gocept.httpserverlayer.wsgi.Layer to provide the actual HTTP server. No special TestCase is required, unittest.TestCase is enough.

The zopeappwsgi.Layer expects to find the current ZODB in the plone.testing resource zodbDB (which is used by plone.testing.zodb.EMPTY_ZODB), or you can inherit and override get_current_zodb. Here’s an example setup for Grok (which uses zope.app.appsetup.testlayer.ZODBLayer):

import gocept.httpserverlayer.wsgi
import gocept.httpserverlayer.zopeappwsgi
import unittest
import zope.app.appsetup.testlayer

ZODB_LAYER = zope.app.appsetup.testlayer.ZODBLayer(
    gocept.httpserverlayer.zopeappwsgi, 'testing.zcml')

class WSGILayer(gocept.httpserverlayer.zopeappwsgi.Layer):

    defaultBases = (ZODB_LAYER,)

    def get_current_zodb(self):
        return ZODB_LAYER.db

WSGI_LAYER = WSGILayer()

HTTP_LAYER = gocept.httpserverlayer.wsgi.Layer(
    name='HTTPLayer', bases=(WSGI_LAYER,))

class GrokExample(unittest.TestCase):

    layer = HTTP_LAYER

    def test(self):
        r = urllib.urlopen('http://%s/' % self.layer['http_address'])
        self.assertIn('Hello world', r.read())

Zope via WSGI

If your Zope setup supports WSGI, you can use the WSGI integration instead of a specialised Zope integration to run your tests.

You might see an exception complaining about the Connection header. To fix this issue you can use an additional middleware around your WSGI application: gocept.httpserverlayer.wsgi.FixupMiddleware.

Zope / Plone via plone.testing.zope

Requires gocept.httpserverlayer[plonetestingzope].

gocept.httpserverlayer provides a plone.testing.Layer at gocept.httpserverlayer.plonetestingzope.HTTP_SERVER that you can mix and match with your base layers. No special TestCase is required, unittest.TestCase is enough.

For a plain Zope application this might look like this (uses plone.testing[zope]):

import gocept.httpserverlayer.plonetestingzope
import plone.testing
import plone.testing.zope

class Layer(plone.testing.Layer):

    defaultBases = (plone.testing.zope.STARTUP,)

    def setUp(self):
        zope.configuration.xmlconfig.file(
            'testing.zcml', package=mypackage,
            context=self['configurationContext'])

ZOPE_LAYER = Layer()

HTTP_LAYER = plone.testing.Layer(
    name='HTTPLayer',
    bases=(ZOPE_LAYER,
           gocept.httpserverlayer.plonetestingzope.HTTP_SERVER))

Developing gocept.httpserverlayer

Author:

gocept <mail@gocept.com>

PyPI page:

https://pypi.org/project/gocept.httpserverlayer/

Issue tracker:

https://github.com/gocept/gocept.httpserverlayer/issues

Source code:

https://github.com/gocept/gocept.httpserverlayer

Current change log:

https://raw.githubusercontent.com/gocept/gocept.httpserverlayer/master/CHANGES.rst

Run tests:

Use tox, for info see: https://pypi.org/project/tox/

Change log for gocept.httpserverlayer

4.0 (2021-04-07)

  • Drop support for Python 2.

  • Add support for Python 3.8 and 3.9.

  • Migrate to GitHub and GitHub Actions.

3.2 (2019-04-03)

  • Fix usage of pending deprecated Thread.isAlive().

3.1 (2019-01-15)

  • Create a wheel of the package.

  • Add support for Python 3.7.

3.0 (2018-06-29)

  • Add support for Python 3.6.

  • Drop support for Zope 2.x

  • Rename the setup.py extra plonetestingz2 into plonetestingzope.

  • Rename the module .plonetestingz2 into .plonetestingzope.

2.2 (2016-12-02)

  • Ensure compatibility with setuptools >= 30.0.

2.1 (2016-12-01)

2.0 (2016-04-12)

  • Drop support for:

    • zope.app.testing (extras_require: [zopeapptesting])

    • Testing.ZopeTestCase (extras_require: [zope2testcase])

    • plone.app.testing (extras_require: [test_plonetestingz2])

    • Products.PloneTestCase (extras_require: [plonetestcase])

  • Drop support for Python 2.6.

  • Use tox as testrunner.

  • Remove zc.buildout infrastructure.

1.5.3 (2015-01-09)

  • Don’t overwrite self.port when it was 0.

1.5.2 (2014-05-22)

  • Silence “error 32: Broken pipe” errors in custom.Layer, too.

1.5.1 (2014-02-10)

  • Silence “error 32: Broken pipe” errors in wsgi.Layer, they just mean the client closed the connection prematurely, which is as harmless as it is normal.

1.5.0 (2013-11-07)

  • Make it possible to dictate the hostname for the httpserver via environment variable GOCEPT_HTTP_APP_HOST. You will need this if you run your tests in a selenium grid on different machines.

1.4.1 (2013-10-01)

  • 1.4.0 was a brown-bag, let’s try again.

1.4.0 (2013-10-01)

  • Make HTTP server and thread objects used by layers available as a resource.

1.3.0 (2013-07-18)

  • Replace dependency on distribute with setuptools, since the projects have merged.

1.2.1 (2013-02-07)

  • Fix custom layer test tear down.

1.2 (2013-02-06)

  • Fixed tests run on MacOS.

  • Use the server_address instead of server_name of HTTPServer to be compatible with MacOS.

  • Dropped compatability with Zope < 2.12.

  • Removed customized HTTPServer, the BaseHTTPServer.HTTPServer does everything we need.

1.1 (2013-02-03)

  • Add custom.Layer that uses a BaseHTTPServer with a custom RequestHandler, and static.Layer that server the contents of a directory.

  • Dropped compatability with Python < 2.6.

1.0.1 (2012-12-21)

  • Avoid the property.setter spelling in the wsgi layer’s code for Python 2.5 compatibility.

  • Conditionally require wsgiref to make the wsgi layer work with Python 2.4.

  • Fixed an import in the plonetestcase layer’s tests.

1.0 (2012-12-19)

initial release (extracted from gocept.selenium-1.0)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gocept.httpserverlayer-4.0.tar.gz (18.4 kB view details)

Uploaded Source

Built Distribution

gocept.httpserverlayer-4.0-py3-none-any.whl (19.8 kB view details)

Uploaded Python 3

File details

Details for the file gocept.httpserverlayer-4.0.tar.gz.

File metadata

  • Download URL: gocept.httpserverlayer-4.0.tar.gz
  • Upload date:
  • Size: 18.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/None requests/2.22.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.7.10

File hashes

Hashes for gocept.httpserverlayer-4.0.tar.gz
Algorithm Hash digest
SHA256 611b14999da08e5ad6eebd6ce835bd1bd12e2221cf4ce22cc669ec602e152bbd
MD5 29e5436a6ac218e312b44f7bf5a5282d
BLAKE2b-256 e38572e1a57776c8c8cefab1a305972ec0f284eef6b6ba81decc1b053d0c1bd2

See more details on using hashes here.

File details

Details for the file gocept.httpserverlayer-4.0-py3-none-any.whl.

File metadata

  • Download URL: gocept.httpserverlayer-4.0-py3-none-any.whl
  • Upload date:
  • Size: 19.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/None requests/2.22.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.32.2 CPython/3.7.10

File hashes

Hashes for gocept.httpserverlayer-4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ea99b2993016bceb472b35f282984e1b28775388bb3ddcb84ea2bbce78cef426
MD5 418877ce8fc9d99bc9fb176a30f80035
BLAKE2b-256 0ae8bc6bf464dffa4a6c5c0ed8688740aab739a0a2215723ebb5ddecbd92209e

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page