Skip to main content
Help us improve PyPI by participating in user testing. All experience levels needed!

HTTP server for testing environments

Project description

On-demand HTTP server for use in test environments where mocking underlying calls isn’t an option or where it’s necessary to have an actual HTTP server listening on a socket (e.g. testing IPv6 connectivity). Multiple HTTP servers can be run concurrently, and by default the port number is the next available unused port.

Compatibility

Spoof was tested with the following versions of Python (2.6.x and 3.3.x omitted due to SSL compatibility issues):

  • 2.7.14
  • 3.4.7
  • 3.5.4
  • 3.6.4

Installation

Install from source:

python setup.py install

Install from PyPI:

pip install spoof

Example usage

import unittest
import spoof
import thing

class TestThing(unittest.TestCase):
  httpd = None
  httpd6 = None

  @classmethod
  def setUpClass(cls):
    # X509 certificates can be expensive to generate, so it should be done
    # infrequently.  Also, creating a new HTTP server instance with a new
    # port number for each and every test can starve a system of available
    # TCP/IP ports.  Because of this, creating an `HTTPServer` instance
    # should also be done infrequently, unless the port number is static.
    sslContext = spoof.SSLContext.selfSigned()
    cls.httpd = spoof.HTTPServer(sslContext=sslContext)
    cls.httpd.start()
    # IPv6-only, if needed; `HTTPServer` also accepts IPv6 addresses
    cls.httpd6 = spoof.HTTPServer6(sslContext=sslContext)
    cls.httpd6.start()

  @classmethod
  def tearDownClass(cls):
    cls.httpd.stop()
    cls.httpd6.stop()
    cls.httpd = None
    cls.httpd6 = None

  def setUp(self):
    # Calling `reset()` suffices to sanitize the HTTP server environment.
    self.httpd.reset()
    self.httpd.debug = False
    self.thing = thing.Thing(self.httpd.address, self.httpd.port)
    # or
    self.altThing = thing.AltThing(self.httpd.url)

  def tearDown(self):
    self.thing = None
    self.altThing = None

  def test_thingUsingSpoof(self):
    response1 = [200, [('Content-Type', 'application/json')], '{"id": 1111}']
    response2 = [200, [('Content-Type', 'application/json')], '{"id": 2222}']
    self.httpd.queueResponse(response1)
    self.httpd.queueResponse(response2)
    # HTTP debug logging, if needed
    self.httpd.debug = True
    self.thing.requiringTwoJSONresponses()
    lastRequest = self.httpd.requests[-1]
    expectedContent = '{"action": "rename", "old": 1111, "new": 2222}'
    self.assertEqual(expectedContent, lastRequest.content)

Squelching SSL warnings

Some libraries like Requests will complain loudly or refuse to connect to HTTP servers with a self-signed SSL certificate. The preferred way to handle this is to use the verify property in requests.Session to trust the certificate:

import requests
import spoof

cert, key = spoof.SSLContext.createSelfSignedCert()
sslContext = spoof.SSLContext.fromCertChain(cert, key)
httpd = spoof.HTTPServer(sslContext=sslContext)
httpd.queueResponse((200, (), 'OK'))
httpd.start()

# trust self-signed certificate
session = requests.Session()
session.verify = cert

response = session.get(httpd.url + '/uri/path')
print(response.status_code, response.content)
httpd.stop()

If verifying the certificate is not an option, another way to work around this is to monkeypatch the requests library in the testing code. For example:

import requests

certVerify = requests.adapters.HTTPAdapter.cert_verify
def certNoVerify(self, conn, url, verify, cert):
    return certVerify(self, conn, url, False, cert)
requests.adapters.HTTPAdapter.cert_verify = certNoVerify
requests.packages.urllib3.disable_warnings()

Another common case is libraries that leverage ssl directly. One way to work around this is to globally set the default context to unverified. For example:

import ssl

try:
    createUnverifiedHttpsContext = ssl._create_unverified_context
except AttributeError:
    # ignore if ssl context not verified by default
    pass
else:
    ssl._create_default_https_context = createUnverifiedHttpsContext

Release history Release notifications

This version
History Node

1.2.0

History Node

1.0.5

History Node

1.0.4

History Node

1.0.3

Download files

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

Filename, size & hash SHA256 hash help File type Python version Upload date
spoof-1.2.0-py2.py3-none-any.whl (12.1 kB) Copy SHA256 hash SHA256 Wheel py2.py3 Mar 7, 2018
spoof-1.2.0.tar.gz (16.5 kB) Copy SHA256 hash SHA256 Source None Mar 7, 2018

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging CloudAMQP CloudAMQP RabbitMQ AWS AWS Cloud computing Fastly Fastly CDN DigiCert DigiCert EV certificate StatusPage StatusPage Status page