Yay, tests are passing

This commit is contained in:
Marc Abramowitz
2014-11-25 08:31:58 -08:00
parent 272476db16
commit 8e04e6f09d
9 changed files with 221 additions and 0 deletions

2
pytest.ini Normal file
View File

@@ -0,0 +1,2 @@
[pytest]
addopts = --tb=short

View File

@@ -0,0 +1,3 @@
from .adapters import UnixAdapter
__all__ = ['UnixAdapter']

View File

@@ -0,0 +1,54 @@
import socket
from requests.adapters import HTTPAdapter
from requests.compat import urlparse, unquote
from requests.packages.urllib3.connection import HTTPConnection
from requests.packages.urllib3.connectionpool import HTTPConnectionPool
# The following was adapted from some code from docker-py
# https://github.com/docker/docker-py/blob/master/docker/unixconn/unixconn.py
class UnixHTTPConnection(HTTPConnection):
def __init__(self, unix_socket_url, timeout=60):
"""Create an HTTP connection to a unix domain socket
:param unix_socket_url: A URL with a scheme of 'http+unix' and the
netloc is a percent-encoded path to a unix domain socket. E.g.:
'http+unix://%2Ftmp%2Fprofilesvc.sock/status/pid'
"""
HTTPConnection.__init__(self, 'localhost', timeout=timeout)
self.unix_socket_url = unix_socket_url
self.timeout = timeout
def connect(self):
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.settimeout(self.timeout)
socket_path = unquote(urlparse(self.unix_socket_url).netloc)
sock.connect(socket_path)
self.sock = sock
def request(self, method, url, **kwargs):
url = urlparse(url).path
HTTPConnection.request(self, method, url, **kwargs)
class UnixHTTPConnectionPool(HTTPConnectionPool):
def __init__(self, socket_path, timeout=60):
HTTPConnectionPool.__init__(self, 'localhost', timeout=timeout)
self.socket_path = socket_path
self.timeout = timeout
def _new_conn(self):
return UnixHTTPConnection(self.socket_path, self.timeout)
class UnixAdapter(HTTPAdapter):
def __init__(self, timeout=60):
super(UnixAdapter, self).__init__()
self.timeout = timeout
def get_connection(self, socket_path, proxies=None):
if proxies:
raise ValueError('%s does not support specifying proxies'
% self.__class__.__name__)
return UnixHTTPConnectionPool(socket_path, self.timeout)

View File

@@ -0,0 +1,80 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Tests for requests_unixsocket"""
import multiprocessing
import os
import uuid
import pytest
import requests
import waitress
from requests_unixsocket import UnixAdapter
@pytest.fixture
def wsgiapp():
def _wsgiapp(environ, start_response):
start_response(
'200 OK',
[('X-Transport', 'unix domain socket'),
('X-Socket-Path', environ['SERVER_PORT']),
('X-Requested-Path', environ['PATH_INFO'])])
return ['Hello world!']
return _wsgiapp
@pytest.fixture
def usock_process(wsgiapp):
class UnixSocketServerProcess(multiprocessing.Process):
def __init__(self, *args, **kwargs):
super(UnixSocketServerProcess, self).__init__(*args, **kwargs)
self.unix_socket = self.get_tempfile_name()
def get_tempfile_name(self):
# I'd rather use tempfile.NamedTemporaryFile but IDNA limits
# the hostname to 63 characters and we'll get a "InvalidURL:
# URL has an invalid label" error if we exceed that.
args = (os.stat(__file__).st_ino,
os.getpid(),
uuid.uuid4().hex[-8:])
return '/tmp/test_requests.%s_%s_%s' % args
def run(self):
waitress.serve(wsgiapp, unix_socket=self.unix_socket)
return UnixSocketServerProcess()
def test_unix_domain_adapter_ok(usock_process):
from requests.compat import quote_plus
usock_process.start()
try:
session = requests.Session()
session.mount('http+unix://', UnixAdapter())
urlencoded_socket_name = quote_plus(usock_process.unix_socket)
url = 'http+unix://%s/path/to/page' % urlencoded_socket_name
r = session.get(url)
assert r.status_code == 200
assert r.headers['server'] == 'waitress'
assert r.headers['X-Transport'] == 'unix domain socket'
assert r.headers['X-Requested-Path'] == '/path/to/page'
assert r.headers['X-Socket-Path'] == usock_process.unix_socket
assert isinstance(r.connection, UnixAdapter)
assert r.url == url
assert r.text == 'Hello world!'
finally:
usock_process.terminate()
def test_unix_domain_adapter_connection_error():
session = requests.Session()
session.mount('http+unix://', UnixAdapter())
with pytest.raises(requests.ConnectionError):
session.get('http+unix://socket_does_not_exist/path/to/page')

1
requirements.txt Normal file
View File

@@ -0,0 +1 @@
requests>=1.1

28
setup.cfg Normal file
View File

@@ -0,0 +1,28 @@
[metadata]
name = requests-unixsocket
author = Marc Abramowitz
author-email = marc@marc-abramowitz.com
summary = Use requests to talk HTTP via a UNIX domain socket
description-file = README.rst
license = Apache-2
home-page = https://github.com/msabramo/requests-unixsocket
# home-page = https://requests-unixsocket.readthedocs.org/
classifier =
Development Status :: 3 - Alpha
Intended Audience :: Developers
Intended Audience :: Information Technology
License :: OSI Approved :: Apache Software License
Operating System :: OS Independent
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 2.6
Programming Language :: Python :: 3
Programming Language :: Python :: 3.3
test_suite = requests_unixsocket.tests
[files]
packages = requests_unixsocket
[wheel]
universal = 1

8
setup.py Executable file
View File

@@ -0,0 +1,8 @@
#!/usr/bin/env python
from setuptools import setup
setup(
setup_requires=['pbr'],
pbr=True,
)

2
test-requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
pytest
waitress

43
tox.ini Normal file
View File

@@ -0,0 +1,43 @@
[tox]
envlist = py26, py27, py33, py34, pypy, pep8
[testenv]
commands = py.test {posargs:requests_unixsocket/tests}
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
[testenv:pep8]
commands = flake8 requests_unixsocket
deps =
flake8
{[testenv]deps}
[testenv:venv]
commands = {posargs}
[testenv:coverage]
commands =
coverage erase
coverage run --source requests_unixsocket -m py.test requests_unixsocket/tests
coverage html
deps =
coverage
{[testenv]deps}
[testenv:doctest]
# note this only works under python 3 because of unicode literals
commands =
python -m doctest README.rst
[testenv:sphinx-doctest]
# note this only works under python 3 because of unicode literals
commands =
mkdir build/sphinx/doctest
sphinx-build -b doctest docs build/sphinx/doctest
deps =
pbr
{[testenv]deps}
[testenv:docs]
commands = python setup.py build_sphinx