Skip to main content

httptest

Tests codecov

HTTP testing inspired by golang's httptest package. Supports wrapping asyncio coroutine functions (async def).

Usage

Context Manager

import unittest
import urllib.request

import httptest

class TestHTTPServer(httptest.Handler):

    def do_GET(self):
        contents = "what up".encode()
        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.send_header("Content-length", len(contents))
        self.end_headers()
        self.wfile.write(contents)

def main():
    with httptest.Server(TestHTTPServer) as ts:
        with urllib.request.urlopen(ts.url()) as f:
            assert f.read().decode('utf-8') == "what up"

if __name__ == '__main__':
    main()

Simple HTTP Server Handler

import unittest
import urllib.request

import httptest

class TestHTTPServer(httptest.Handler):

    def do_GET(self):
        contents = "what up".encode()
        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.send_header("Content-length", len(contents))
        self.end_headers()
        self.wfile.write(contents)

class TestHTTPTestMethods(unittest.TestCase):

    @httptest.Server(TestHTTPServer)
    def test_call_response(self, ts=httptest.NoServer()):
        with urllib.request.urlopen(ts.url()) as f:
            self.assertEqual(f.read().decode('utf-8'), "what up")

if __name__ == '__main__':
    unittest.main()

Serve Files

import pathlib
import unittest
import http.server
import urllib.request

import httptest

FILE_PATH = pathlib.Path(__file__)

class TestHTTPTestMethods(unittest.TestCase):

    @httptest.Server(
        lambda *args: http.server.SimpleHTTPRequestHandler(
            *args, directory=FILE_PATH.parent
        )
    )
    def test_call_response(self, ts=httptest.NoServer()):
        with urllib.request.urlopen(ts.url() + FILE_PATH.name) as f:
            self.assertEqual(f.read().decode('utf-8'), FILE_PATH.read_text())

if __name__ == '__main__':
    unittest.main()

Asyncio Support

Asyncio support for the unittest package hasn't yet landed in Python. python/issue32972. It should land in 3.8, check it out here.

If you want a quick way to add asyncio test cases you can import the helper from intel/dffml.

import sys
import unittest
import urllib.request
if sys.version_info.minor == 3 \
        and sys.version_info.minor <= 7:
    from dffml.util.asynctestcase import AsyncTestCase
else:
    # In Python 3.8
    from unittest import IsolatedAsyncioTestCase as AsyncTestCase

import httptest

class TestHTTPServer(httptest.Handler):

    def do_GET(self):
        contents = "what up".encode()
        self.send_response(200)
        self.send_header("Content-type", "text/plain")
        self.send_header("Content-length", len(contents))
        self.end_headers()
        self.wfile.write(contents)

class TestHTTPTestMethods(AsyncTestCase):

    @httptest.Server(TestHTTPServer)
    async def test_call_response(self, ts=httptest.NoServer()):
        with urllib.request.urlopen(ts.url()) as f:
            self.assertEqual(f.read().decode('utf-8'), "what up")

if __name__ == '__main__':
    unittest.main()

In your project's setup.py, add dffml in tests_require.

setup(
    name='your_package',
    ...
    tests_require=[
        'httptest>=0.1.0',
        'dffml>=0.4.0.post0'
    ]
)

Auto Install

If you're making a python package, you'll want to add httptest to your setup.py file's tests_require section.

This way, when your run python setup.py test setuptools will install httptest for you in a package local directory, if it's not already installed.

setup(
    name='your_package',
    ...
    tests_require=[
        'httptest>=0.1.0'
    ]
)

OIDC Server

Start server httptest-oidc

$ python -m httptest.oidc \
    --issuer https://this-service.example.com \
    --audience https://relying-party.example.com \
    --addr 0.0.0.0 \
    --port 8000 \
    --subject test-subject \
    --private-key-pem-path private-key.pem \
    --token-path token.jwt

Make requests

$ curl -H "Authorization: Bearer $(curl https://this-service.example.com/token | jq -r token)" -v https://relying-party.example.com
$ curl -H "Authorization: Bearer $(cat token.jwt)" -v https://relying-party.example.com

Cache Server

Run the caceh server and use it's URL in place of the upstream URL whatever you want to intercept on

$ httptest-cache --state-dir .cache/httptest --addr 0.0.0.0 --port 7000 http://localhost:8000
Serving on http://localhost:7000

Inspect cached objects in the cache dir

$ python -c 'import sys, pathlib, pickle, pprint; pprint.pprint(pickle.loads(pathlib.Path(sys.argv[-1]).read_bytes()).headers)' .cache/httptest/f31bc77712e808fffdab85a33631e414f25715588b1a026d6b8a4e0171b67e99859ab71b1933c93b0078d1e47da9a929.request.pickle
{'Accept': '*/*',
 'Accept-encoding': 'gzip',
 'Connection': 'close',
 'Content-length': '8159',
 'Content-type': 'application/json',
 'Host': 'localhost:45709',
 'Request-hmac': '1700084205.d96d4f546acedddc142b1168642a74c738685d1ac4aa07984e9a1850bb73ddee',
 'User-agent': 'GitHub-Hookshot/dc69923',
 'X-as': '',
 'X-country': '',
 'X-forwarded-for': '10.56.101.48',
 'X-forwarded-proto': 'https',
 'X-github-delivery': '12dac8d6-83ff-11ee-97c9-119c09045ae0',
 'X-github-event': 'push',
 'X-github-hook-id': '443288828',
 'X-github-hook-installation-target-id': '621131680',
 'X-github-hook-installation-target-type': 'repository',
 'X-github-request-id': '1271:336E:974AC:15C2D2:655539ED',
 'X-glb-edge-region': 'iad',
 'X-glb-edge-site': 'ash1-iad',
 'X-glb-via': 'hostname=glb-proxy-1c66317.ash1-iad.github.net site=ash1-iad '
              'region=iad service=kube-public t=1700084205.902',
 'X-haproxy-ssl-fc-cipher': 'TLS_AES_128_GCM_SHA256',
 'X-haproxy-ssl-fc-protocol': 'TLSv1.3',
 'X-haproxy-ssl-fc-use-keysize': '128',
 'X-real-ip': '10.56.101.48',
 'X-region': '',
 'X-request-start': 't=1700084205915930',
 'X-ssl-ja3-hash': '7a15285d4efc355608b304698cd7f9ab'}

Examples

See the examples/ directory for more examples.

Metadata

Release files for httptest 2.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for httptest 2.1.1
File Size Uploaded
httptest-2.1.1.tar.gz 19.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for httptest 2.1.1
File Interpreter ABI Platform
httptest-2.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 31.2 kB

Release files / httptest-2.1.1.tar.gz

Download URL httptest-2.1.1.tar.gz
Size 19.1 kB
Tags Source
SHA-256 checksum
How to use checksums
a473681c2c280422a3fb61e6d631835ba1bc53ca1d90b256838d348b17ab73e7
BLAKE2b-256 checksum
How to use checksums
cf904c5c980f576ceceac43264f2f10a505124cfa8dfc0a16b3d4abcfbe54dbf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.10.12

Release files / httptest-2.1.1-py3-none-any.whl

Download URL httptest-2.1.1-py3-none-any.whl
Size 12.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
74e5fed152c6982a1bbb79549ceb142251d467825e20d4677096c1412e94aa81
BLAKE2b-256 checksum
How to use checksums
39840ecd7e95b7485a7b1b378aad8ac50e389934bdac734100ca519a28fa20a3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.10.12

Release history Release notifications | RSS feed

This release

2.1.1 This release

2 release files

2.1.0

2 release files

2.0.1

2 release files

0.2.0

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.0.15

1 release file

0.0.14

1 release file

0.0.13

1 release file

0.0.12

1 release file

0.0.11

1 release file

0.0.10

1 release file

0.0.9

1 release file

0.0.8

1 release file

0.0.7

2 release files

0.0.6

1 release file

0.0.5

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page