[Python-modules-commits] [pytest-httpbin] 01/06: Imported Upstream version 0.1.1

Daniel Stender danstender-guest at moszumanska.debian.org
Thu Nov 19 17:31:11 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-httpbin.

commit 98d7365a5755073a515e51820773c10e4235f474
Author: Daniel Stender <debian at danielstender.com>
Date:   Thu Nov 19 18:11:34 2015 +0100

    Imported Upstream version 0.1.1
---
 .travis.yml                     |  11 +++
 DESCRIPTION.rst                 |  30 +++++++
 MANIFEST.in                     |   3 +
 README.md                       | 168 ++++++++++++++++++++++++++++++++++++++++
 pytest_httpbin/__init__.py      |  14 ++++
 pytest_httpbin/certs.py         |  21 +++++
 pytest_httpbin/certs/cacert.pem |  63 +++++++++++++++
 pytest_httpbin/certs/cert.pem   |  73 +++++++++++++++++
 pytest_httpbin/certs/key.pem    |  28 +++++++
 pytest_httpbin/plugin.py        |  41 ++++++++++
 pytest_httpbin/serve.py         |  95 +++++++++++++++++++++++
 pytest_httpbin/version.py       |   1 +
 runtests.sh                     |   3 +
 setup.cfg                       |   5 ++
 setup.py                        |  61 +++++++++++++++
 tests/conftest.py               |   6 ++
 tests/test_httpbin.py           |  53 +++++++++++++
 tests/test_server.py            |  62 +++++++++++++++
 tests/util.py                   |  30 +++++++
 tox.ini                         |   9 +++
 20 files changed, 777 insertions(+)

diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2e736a4
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,11 @@
+language: python
+sudo: false
+python:
+- 2.6
+- 2.7
+- 3.4
+- pypy
+install:
+- pip install requests
+- python setup.py install
+script: ./runtests.sh
diff --git a/DESCRIPTION.rst b/DESCRIPTION.rst
new file mode 100644
index 0000000..4e0cba8
--- /dev/null
+++ b/DESCRIPTION.rst
@@ -0,0 +1,30 @@
+pytest-httpbin
+==============
+
+httpbin is an amazing web service for testing HTTP libraries. It has several
+great endpoints that can test pretty much everything you need in a HTTP
+library. The only problem is: maybe you don't want to wait for your tests to
+travel across the Internet and back to make assertions against a remote web
+service.
+
+Enter pytest-httpbin. Pytest-httpbin creates a pytest "fixture" that is
+dependency-injected into your tests. It automatically starts up a HTTP server
+in a separate thread running httpbin and provides your test with the URL in the
+fixture. Check out this example:
+
+.. code-block:: python
+
+    def test_that_my_library_works_kinda_ok(httpbin):
+        assert requests.get(httpbin.url + '/get/').status_code == 200
+
+This replaces a test that might have looked like this before:
+
+.. code-block:: python
+
+    def test_that_my_library_works_kinda_ok():
+        assert requests.get('http://httpbin.org/get').status_code == 200
+
+pytest-httpbin also supports https and includes its own CA cert you can use.
+Check out `the full documentation`_ on the github page.
+
+.. _the full documentation: https://github.com/kevin1024/pytest-httpbin
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..68a01e1
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,3 @@
+# If using Python 2.6 or less, then have to include package data, even though
+# it's already declared in setup.py
+include pytest_httpbin/certs/*
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..03c4adb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,168 @@
+# pytest-httpbin
+
+[![Build Status](https://travis-ci.org/kevin1024/pytest-httpbin.svg?branch=master)](https://travis-ci.org/kevin1024/pytest-httpbin)
+
+[httpbin](https://httpbin.org/) is an amazing web service for testing HTTP libraries.  It has several great endpoints that can test pretty much everything you need in a HTTP library.  The only problem is: maybe you don't want to wait for your tests to travel across the Internet and back to make assertions against a remote web service (speed), and maybe you want to work offline (convenience).
+
+Enter **pytest-httpbin**.  Pytest-httpbin creates a [pytest fixture](http://pytest.org/latest/fixture.html) that is dependency-injected into your tests.  It automatically starts up a HTTP server in a separate thread running httpbin and provides your test with the URL in the fixture.  Check out this example:
+
+```python
+def test_that_my_library_works_kinda_ok(httpbin):
+    assert requests.get(httpbin.url + '/get').status_code == 200
+```
+
+This replaces a test that might have looked like this before:
+
+```python
+def test_that_my_library_works_kinda_ok():
+    assert requests.get('http://httpbin.org/get').status_code == 200
+```
+
+If you're making a lot of requests to httpbin, it can radically speed up your tests.
+
+![demo](http://i.imgur.com/heNOQLP.gif)
+
+
+# HTTPS support
+
+pytest-httpbin also supports HTTPS:
+
+```python
+def test_that_my_library_works_kinda_ok(httpbin_secure):
+    assert requests.get(httpbin_secure.url + '/get/').status_code == 200
+```
+
+It's actually starting 2 web servers in separate threads in the background: one HTTP and one HTTPS. The servers are started on a random port, on the loopback interface on your machine. Pytest-httpbin includes a self-signed certificate.  If your library verifies certificates against a CA (and it should), you'll have to add the CA from pytest-httpbin.  The path to the pytest-httpbin CA bundle can by found like this `python -m pytest_httpbin.certs`.
+
+For example in requests, you can set the `REQUESTS_CA_BUNDLE` python path.  You can run your tests like this:
+
+```bash
+REQUESTS_CA_BUNDLE=`python -m pytest_httpbin.certs` py.test tests/
+```
+
+# API of the injected object
+
+The injected object has the following attributes:
+
+  * url
+  * port
+  * host
+
+and the following methods:
+
+  * join(string): Returns the results of calling `urlparse.urljoin` with the url from the injected server automatically applied as the first argument.  You supply the second argument
+
+Also, I defined `__add__` on the object to append to `httpbin.url`.  This means you can do stuff like `httpbin + '/get'` instead of `httpbin.url + '/get'`.
+
+## Testing both HTTP and HTTPS endpoints with one test
+
+If you ever find yourself needing to test both the http and https version of and endpoint, you can use the `httpbin_both` funcarg like this:
+
+
+```python
+def test_that_my_library_works_kinda_ok(httpbin_both):
+    assert requests.get(httpbin_both.url + '/get/').status_code == 200
+```
+
+Through the magic of pytest parametrization, this function will actually execute twice: once with an http url and once with an https url.
+
+## Using pytest-httpbin with unittest-style test cases
+
+I have provided 2 additional fixtures to make testing with class-based tests easier.  I have also provided a couple decorators that provide some syntactic sugar around the pytest method of adding the fixtures to class-based tests.  Just add the `use_class_based_httpbin` and/or `use_class_based_httpbin_secure` class decorators to your class, and then you can access httpbin using self.httpbin and self.httpbin_secure.
+
+```python
+import pytest_httpbin
+
+ at pytest_httpbin.use_class_based_httpbin
+ at pytest_httpbin.use_class_based_httpbin_secure
+class TestClassBassedTests(unittest.TestCase):
+    def test_http(self):
+        assert requests.get(self.httpbin.url + '/get').response
+
+    def test_http_secure(self):
+        assert requests.get(self.httpbin_secure.url + '/get').response
+```
+
+## Installation
+
+All you need to do is this:
+
+```bash
+pip install pytest-httpbin
+```
+
+and your tests executed by pytest all will have access to the `httpbin` and `httpbin_secure` funcargs.  Cool right?
+
+## Support and dependencies
+
+pytest-httpbin suports Python 2.6, 2.7, 3.4, and pypy.  It will automatically install httpbin and flask when you install it from pypi.
+
+## Running the pytest-httpbin test suite
+
+If you want to run pytest-httpbin's test suite, you'll need to install requests and pytest, and then use the ./runtests.sh script.
+
+```bash
+pip install pytest
+/.runtests.sh
+```
+
+Also, you can use tox to run the tests on all supported python versions:
+
+```bash
+pip install tox
+tox
+```
+
+## Changelog
+
+* 0.1.1:
+  * Fix weird hang with SSL on pypy (again)
+* 0.1.0:
+  * Update server to use multithreaded werkzeug server
+* 0.0.7:
+  * Update the certificates (they expired)
+* 0.0.6:
+  * Fix an issue where pypy was hanging when a request was made with an invalid
+    certificate
+* 0.0.5:
+  * Fix broken version parsing in 0.0.4
+* 0.0.4:
+  * **Bad release: Broken version parsing**
+  * Fix `BadStatusLine` error that occurs when sending multiple requests
+    in a single session (PR #16). Thanks @msabramo!
+  * Fix #9 ("Can't be installed at the same time than pytest?") (PR
+    #14). Thanks @msabramo!
+  * Add `httpbin_ca_bundle` pytest fixture. With this fixture there is
+    no need to specify the bundle on every request, as it will
+    automatically set `REQUESTS_CA_BUNDLE` if using
+    [requests](http://docs.python-requests.org/). And you don't have to
+    care about where it is located (PR #8). Thanks @t-8ch!
+* 0.0.3: Add a couple test fixtures to make testing old class-based test suites
+  easier
+* 0.0.2: Fixed a couple bugs with the wsgiref server to bring behavior in line
+  with httpbin.org, thanks @jakubroztocil for the bug reports
+* 0.0.1: Initial release
+
+## License
+
+The MIT License (MIT)
+
+Copyright (c) 2014-2015 Kevin McCarthy
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/pytest_httpbin/__init__.py b/pytest_httpbin/__init__.py
new file mode 100644
index 0000000..cf3d818
--- /dev/null
+++ b/pytest_httpbin/__init__.py
@@ -0,0 +1,14 @@
+import os
+
+import pytest
+
+
+here = os.path.dirname(__file__)
+version_file = os.path.join(here, "version.py")
+
+with open(version_file) as f:
+    code = compile(f.read(), version_file, 'exec')
+    exec(code)
+
+use_class_based_httpbin = pytest.mark.usefixtures("class_based_httpbin")
+use_class_based_httpbin_secure = pytest.mark.usefixtures("class_based_httpbin_secure")
diff --git a/pytest_httpbin/certs.py b/pytest_httpbin/certs.py
new file mode 100644
index 0000000..c099cfa
--- /dev/null
+++ b/pytest_httpbin/certs.py
@@ -0,0 +1,21 @@
+"""
+certs.py
+~~~~~~~~
+
+This module returns the preferred default CA certificate bundle.
+
+If you are packaging pytest-httpbin, e.g., for a Linux distribution or a
+managed environment, you can change the definition of where() to return a
+separately packaged CA bundle.
+"""
+
+import os.path
+
+
+def where():
+    """Return the preferred certificate bundle."""
+    # vendored bundle inside Requests
+    return os.path.join(os.path.dirname(__file__), 'certs', 'cacert.pem')
+
+if __name__ == '__main__':
+    print(where())
diff --git a/pytest_httpbin/certs/cacert.pem b/pytest_httpbin/certs/cacert.pem
new file mode 100644
index 0000000..d9a47aa
--- /dev/null
+++ b/pytest_httpbin/certs/cacert.pem
@@ -0,0 +1,63 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            dd:39:30:16:60:55:90:7c
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, ST=Hawaii, O=kevin1024, CN=pytest-httpbin Certificate Authority
+        Validity
+            Not Before: Jun 26 18:16:59 2015 GMT
+            Not After : Jun 18 18:16:59 2045 GMT
+        Subject: C=US, ST=Hawaii, O=kevin1024, CN=pytest-httpbin Certificate Authority
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (1024 bit)
+                Modulus (1024 bit):
+                    00:bd:80:fd:e4:96:0e:3b:5e:35:9b:83:00:34:88:
+                    64:5a:50:53:0e:1d:94:76:c9:dc:e7:b5:59:1e:d4:
+                    82:55:36:a6:b4:41:2c:60:ad:76:f0:cd:42:a0:0f:
+                    4a:1c:0d:d7:29:da:c3:d9:c0:ea:f1:48:e0:66:4d:
+                    4b:7c:ff:d6:5e:e0:73:89:53:8b:6e:6c:57:7d:bd:
+                    e9:d0:46:39:5d:85:a5:f1:3a:d4:3d:83:19:03:44:
+                    93:71:2c:5e:d7:61:8e:db:cc:80:d0:f1:c0:47:bf:
+                    98:8f:06:40:e1:f7:41:ee:ed:a7:57:0d:a6:4c:26:
+                    75:8e:f1:78:d3:80:ad:9c:e9
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                AE:05:EF:BD:A9:CE:BB:A6:D8:0E:EB:C4:8C:72:2F:13:E5:CD:AA:CA
+            X509v3 Authority Key Identifier: 
+                keyid:AE:05:EF:BD:A9:CE:BB:A6:D8:0E:EB:C4:8C:72:2F:13:E5:CD:AA:CA
+                DirName:/C=US/ST=Hawaii/O=kevin1024/CN=pytest-httpbin Certificate Authority
+                serial:DD:39:30:16:60:55:90:7C
+
+            X509v3 Basic Constraints: 
+                CA:TRUE
+    Signature Algorithm: sha1WithRSAEncryption
+        bc:0c:b4:21:03:bf:35:bf:88:9f:de:06:23:f4:e3:8f:bc:34:
+        b5:8b:af:bf:31:5d:17:44:2c:72:c9:88:25:d1:c7:d0:1c:70:
+        06:82:a5:fa:fa:d7:b9:16:64:c2:08:54:1e:4c:93:9f:22:4e:
+        e5:4f:a7:71:e5:6e:14:31:e9:41:e2:33:23:8b:c8:01:c3:2a:
+        66:a8:d8:df:ef:ee:7b:bb:84:f4:78:a6:ca:8f:29:aa:d5:fa:
+        8a:73:94:0c:32:53:c8:93:bd:fc:c4:60:4d:9a:80:4f:c6:d4:
+        27:44:a2:37:63:6c:97:04:ce:e3:6a:6f:d3:84:0d:b4:74:1f:
+        49:eb
+-----BEGIN CERTIFICATE-----
+MIIDBzCCAnCgAwIBAgIJAN05MBZgVZB8MA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
+BAYTAlVTMQ8wDQYDVQQIEwZIYXdhaWkxEjAQBgNVBAoTCWtldmluMTAyNDEtMCsG
+A1UEAxMkcHl0ZXN0LWh0dHBiaW4gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTE1
+MDYyNjE4MTY1OVoXDTQ1MDYxODE4MTY1OVowYTELMAkGA1UEBhMCVVMxDzANBgNV
+BAgTBkhhd2FpaTESMBAGA1UEChMJa2V2aW4xMDI0MS0wKwYDVQQDEyRweXRlc3Qt
+aHR0cGJpbiBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBAL2A/eSWDjteNZuDADSIZFpQUw4dlHbJ3Oe1WR7UglU2prRBLGCt
+dvDNQqAPShwN1ynaw9nA6vFI4GZNS3z/1l7gc4lTi25sV3296dBGOV2FpfE61D2D
+GQNEk3EsXtdhjtvMgNDxwEe/mI8GQOH3Qe7tp1cNpkwmdY7xeNOArZzpAgMBAAGj
+gcYwgcMwHQYDVR0OBBYEFK4F772pzrum2A7rxIxyLxPlzarKMIGTBgNVHSMEgYsw
+gYiAFK4F772pzrum2A7rxIxyLxPlzarKoWWkYzBhMQswCQYDVQQGEwJVUzEPMA0G
+A1UECBMGSGF3YWlpMRIwEAYDVQQKEwlrZXZpbjEwMjQxLTArBgNVBAMTJHB5dGVz
+dC1odHRwYmluIENlcnRpZmljYXRlIEF1dGhvcml0eYIJAN05MBZgVZB8MAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAvAy0IQO/Nb+In94GI/Tjj7w0tYuv
+vzFdF0QscsmIJdHH0BxwBoKl+vrXuRZkwghUHkyTnyJO5U+nceVuFDHpQeIzI4vI
+AcMqZqjY3+/ue7uE9Himyo8pqtX6inOUDDJTyJO9/MRgTZqAT8bUJ0SiN2NslwTO
+42pv04QNtHQfSes=
+-----END CERTIFICATE-----
diff --git a/pytest_httpbin/certs/cert.pem b/pytest_httpbin/certs/cert.pem
new file mode 100644
index 0000000..5d4452b
--- /dev/null
+++ b/pytest_httpbin/certs/cert.pem
@@ -0,0 +1,73 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            dd:39:30:16:60:55:90:7e
+        Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, ST=Hawaii, O=kevin1024, CN=pytest-httpbin Certificate Authority
+        Validity
+            Not Before: Jun 26 18:20:35 2015 GMT
+            Not After : Jun 23 18:20:35 2025 GMT
+        Subject: C=US, ST=Hawaii, O=kevin1024, OU=kevin1024, CN=127.0.0.1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+            RSA Public Key: (2048 bit)
+                Modulus (2048 bit):
+                    00:ce:b4:0f:0b:86:17:68:24:6f:7c:25:32:73:81:
+                    bd:55:38:05:ae:09:29:00:c0:f1:99:30:5a:7f:05:
+                    9f:e7:e9:d3:ce:d0:dd:4f:73:c8:bf:65:04:94:e5:
+                    11:8e:1d:91:f0:88:85:3e:48:d3:09:5b:3f:8f:97:
+                    95:34:bf:8d:00:cb:70:d2:c1:2b:34:dd:99:1d:86:
+                    9b:90:54:a5:de:18:c4:03:3d:53:f0:dd:cc:6d:ec:
+                    fb:b9:93:ab:19:85:05:63:2d:34:a6:47:42:71:3b:
+                    e4:1e:4a:4c:d9:60:d4:6b:d6:51:a8:4a:30:70:2e:
+                    6c:62:a2:34:da:cf:30:34:97:a4:9d:17:72:0b:b2:
+                    37:69:e2:ca:b6:d5:9f:46:c5:eb:cf:dc:46:b0:fe:
+                    ef:37:5e:4f:eb:f3:50:4d:2c:4e:c2:0c:e4:0c:63:
+                    c2:d8:ab:a3:d6:a0:12:bf:d6:fc:3f:b6:4c:dc:2b:
+                    9b:c5:ae:83:4d:3b:3c:19:85:50:88:82:a2:5f:ff:
+                    de:98:60:fc:12:3a:55:c3:4f:0a:e9:1f:aa:12:cb:
+                    f8:ce:14:d6:ed:89:ff:c7:ea:3b:fe:97:87:54:eb:
+                    62:de:cd:ef:6b:e2:9e:47:82:77:55:59:4f:b8:ad:
+                    1b:e0:9d:1a:28:16:9f:6a:cb:b2:44:f9:65:c3:c4:
+                    03:09
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            Netscape Comment: 
+                OpenSSL Generated Certificate
+            X509v3 Subject Key Identifier: 
+                1E:28:41:6B:12:03:41:29:64:0D:E5:C3:E3:F7:9E:82:0C:66:1E:B9
+            X509v3 Authority Key Identifier: 
+                keyid:AE:05:EF:BD:A9:CE:BB:A6:D8:0E:EB:C4:8C:72:2F:13:E5:CD:AA:CA
+
+    Signature Algorithm: sha1WithRSAEncryption
+        67:8c:6d:a1:2f:b3:35:87:a3:c0:04:92:5d:8a:8b:f8:51:6e:
+        94:88:59:ed:66:b2:54:b0:a2:3d:7a:05:ee:19:17:a6:0b:3b:
+        20:f7:d2:73:2c:f0:b9:ad:2e:5d:45:11:5d:8d:33:5c:69:7f:
+        4a:c5:8c:10:3e:35:b4:39:d7:52:66:bc:02:d8:4d:d0:ba:a1:
+        ae:55:f5:36:01:17:97:40:1a:9d:6a:e0:b8:33:be:2d:98:b7:
+        5b:92:6a:77:a7:d9:f5:5b:a4:5f:fa:aa:5b:c1:6b:4d:0c:b7:
+        5a:4c:47:b2:f7:90:a3:ff:6f:8c:fd:f2:60:38:53:29:71:48:
+        d7:69
+-----BEGIN CERTIFICATE-----
+MIIDODCCAqGgAwIBAgIJAN05MBZgVZB+MA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
+BAYTAlVTMQ8wDQYDVQQIEwZIYXdhaWkxEjAQBgNVBAoTCWtldmluMTAyNDEtMCsG
+A1UEAxMkcHl0ZXN0LWh0dHBiaW4gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTE1
+MDYyNjE4MjAzNVoXDTI1MDYyMzE4MjAzNVowWjELMAkGA1UEBhMCVVMxDzANBgNV
+BAgTBkhhd2FpaTESMBAGA1UEChMJa2V2aW4xMDI0MRIwEAYDVQQLEwlrZXZpbjEw
+MjQxEjAQBgNVBAMTCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAM60DwuGF2gkb3wlMnOBvVU4Ba4JKQDA8ZkwWn8Fn+fp087Q3U9zyL9l
+BJTlEY4dkfCIhT5I0wlbP4+XlTS/jQDLcNLBKzTdmR2Gm5BUpd4YxAM9U/DdzG3s
++7mTqxmFBWMtNKZHQnE75B5KTNlg1GvWUahKMHAubGKiNNrPMDSXpJ0XcguyN2ni
+yrbVn0bF68/cRrD+7zdeT+vzUE0sTsIM5Axjwtiro9agEr/W/D+2TNwrm8Wug007
+PBmFUIiCol//3phg/BI6VcNPCukfqhLL+M4U1u2J/8fqO/6Xh1TrYt7N72vinkeC
+d1VZT7itG+CdGigWn2rLskT5ZcPEAwkCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglg
+hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O
+BBYEFB4oQWsSA0EpZA3lw+P3noIMZh65MB8GA1UdIwQYMBaAFK4F772pzrum2A7r
+xIxyLxPlzarKMA0GCSqGSIb3DQEBBQUAA4GBAGeMbaEvszWHo8AEkl2Ki/hRbpSI
+We1mslSwoj16Be4ZF6YLOyD30nMs8LmtLl1FEV2NM1xpf0rFjBA+NbQ511JmvALY
+TdC6oa5V9TYBF5dAGp1q4Lgzvi2Yt1uSanen2fVbpF/6qlvBa00Mt1pMR7L3kKP/
+b4z98mA4UylxSNdp
+-----END CERTIFICATE-----
diff --git a/pytest_httpbin/certs/key.pem b/pytest_httpbin/certs/key.pem
new file mode 100644
index 0000000..041c4b6
--- /dev/null
+++ b/pytest_httpbin/certs/key.pem
@@ -0,0 +1,28 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAzrQPC4YXaCRvfCUyc4G9VTgFrgkpAMDxmTBafwWf5+nTztDd
+T3PIv2UElOURjh2R8IiFPkjTCVs/j5eVNL+NAMtw0sErNN2ZHYabkFSl3hjEAz1T
+8N3Mbez7uZOrGYUFYy00pkdCcTvkHkpM2WDUa9ZRqEowcC5sYqI02s8wNJeknRdy
+C7I3aeLKttWfRsXrz9xGsP7vN15P6/NQTSxOwgzkDGPC2Kuj1qASv9b8P7ZM3Cub
+xa6DTTs8GYVQiIKiX//emGD8EjpVw08K6R+qEsv4zhTW7Yn/x+o7/peHVOti3s3v
+a+KeR4J3VVlPuK0b4J0aKBafasuyRPllw8QDCQIDAQABAoIBAQCJ//iTbwCtjLXJ
+omPebd3jyTUxjfgMAsTJy1h/uVea06ePSi6W3uxFq8G1ToG76c4HUn3yqVgLxRnY
+WhFJWCFhSHGYo1KfRtr0tWuinoDmmI40w3sJMmtLcI5WxVnT/dUs839VC/o18xBH
+kL9h2Z24KSv3OSDBpJzD9Rtogi7izK8DSQoANBMDEmPPJ5UJBLPjdZn04i6BYZCM
+U/+ZADHKXbq6I+7RAcbPJbkvrbBEP234KZvIdw1eIAIZufQBQuDhnwS0Fi9iY/EP
+awoYa9HLgFjh+iprhwh+2SDyIp8DA+4HrY1tXAyzCqjgLn/X8wifOUrZECYj1i65
+EOiryxMBAoGBAPjmvIwBRxnr1OsKX3gCFoZr+Zu5RjACD9IOSV17cv7glZQVfXBR
+REDBoL7CmZrhsW4zBK0YWz30Dx7TGBniTFJ3e8IZJ7Th8PSOhIRYWqqFQ78YBHFi
+VcpPOBswy1i8BM9FE0GyF1zusmz8Ak2hFr/IHVkIqHwWvkTI6gGhbJ2RAoGBANSZ
+OqEWJKbRX9nuRqSdROqLOtUgWXZ78yvcQaaifyZHEFSKZZjc5MXT96lVd1PyGGAY
+uyjAqdd5LiwsS9Rw1cuC5fix2ihH5KFq7EnEJA/zdy91YdO6xmAyBOtjuTHsNj93
+if4ilib290/mRKXeI1zpzzWHsvL9Az5spqlkljH5AoGAfln7ewMnCfSbCJoibrR4
+pNJpSvEZvUM+rr6L5cXGUbbGl/70x7CpekoRBOWavnI19SA3Dnvfzap4hohYosMr
+RW3cSGMmsf9Ep5E1mk2T8R5njrltf/WQYXwnmj4B7FC+DE4fgWkbzRRrRUIFFU1i
+VAcNRuZLSXruKdLoX92HWtECgYEAhpTlf3n0A8JBKkVjZOvF56/xs19CIvY+LsLE
+sIbndMTBurLNs+IJ1I3llsVqv7Je6d5eBGNKYQPuTbpQ2o//V1Bq4m88CgnQ2rpE
+EEJhDdPy3BEzt4Ph9p1Tbet4HflJMg4rRbyBTvNCBctgI5wmyLeeG2Xmy1mNhyPi
+sRLi3YkCgYEAiHMsniJc1gZBevjtnqGTPdUo0syAnkZ7RUk/Piur/c0Altkgu5vK
+I7p3DbkHBAMDjpAZs1kpfmR4sTYKke+IQDxj2pOZEyYnmQxlGdy8xxoE9dWQeDeg
+Le+R83OAKjU4LHpH7hhJMR8X60MJaWC1BDACFO35kqIzvtCYxgEoOiI=
+-----END RSA PRIVATE KEY-----
+
diff --git a/pytest_httpbin/plugin.py b/pytest_httpbin/plugin.py
new file mode 100644
index 0000000..4eb9b51
--- /dev/null
+++ b/pytest_httpbin/plugin.py
@@ -0,0 +1,41 @@
+from __future__ import absolute_import
+import pytest
+from httpbin import app as httpbin_app
+from . import serve, certs
+
+ at pytest.fixture(scope='session')
+def httpbin(request):
+    server = serve.Server(application=httpbin_app)
+    server.start()
+    request.addfinalizer(server.stop)
+    return server
+
+
+ at pytest.fixture(scope='session')
+def httpbin_secure(request):
+    server = serve.SecureServer(application=httpbin_app)
+    server.start()
+    request.addfinalizer(server.stop)
+    return server
+
+
+ at pytest.fixture(scope='session', params=['http', 'https'])
+def httpbin_both(request, httpbin, httpbin_secure):
+    if request.param == 'http':
+        return httpbin
+    elif request.param == 'https':
+        return httpbin_secure
+
+
+ at pytest.fixture(scope='class')
+def class_based_httpbin(request, httpbin):
+    request.cls.httpbin = httpbin
+
+ at pytest.fixture(scope='class')
+def class_based_httpbin_secure(request, httpbin_secure):
+    request.cls.httpbin_secure = httpbin_secure
+
+
+ at pytest.fixture(scope='function')
+def httpbin_ca_bundle(monkeypatch):
+    monkeypatch.setenv('REQUESTS_CA_BUNDLE', certs.where())
diff --git a/pytest_httpbin/serve.py b/pytest_httpbin/serve.py
new file mode 100644
index 0000000..59a8c17
--- /dev/null
+++ b/pytest_httpbin/serve.py
@@ -0,0 +1,95 @@
+import os
+import pytest_httpbin
+import threading
+import ssl
+from werkzeug.serving import ThreadedWSGIServer, load_ssl_context, WSGIRequestHandler
+from six.moves.urllib.parse import urljoin
+
+CERT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'certs')
+
+class Handler(WSGIRequestHandler):
+    server_version = 'pytest-httpbin/' + pytest_httpbin.__version__
+
+    def make_environ(self):
+        """
+        werkzeug server adds content-type text/plain to everything, this
+        removes it if it's not actually in the headers.
+        """
+        # Note: Can't use super since this is an oldstyle class in python 2.x
+        environ = super(Handler, self).make_environ().copy()
+        if self.headers.get('content-type') is None:
+            del environ['CONTENT_TYPE']
+        return environ
+
+class ThreadedWSGIServerWithSSLTimeout(ThreadedWSGIServer):
+    """
+    This whole subclass exists just to set the ssl timeout before wrapping the
+    socket.  That's because on pypy, if there's an SSL failure opening the
+    connection, it will hang forever.
+    """
+
+    def __init__(self, *args, **kwargs):
+        self.protocol = kwargs.pop('protocol')
+        super(ThreadedWSGIServerWithSSLTimeout, self).__init__(*args, **kwargs)
+
+    def finish_request(self, request, client_address):
+        """
+        Negotiates SSL and then mimics BaseServer behavior.
+        """
+        if self.protocol == 'https':
+            request.settimeout(1.0)
+            ssock = ssl.wrap_socket(
+                request,
+                keyfile=os.path.join(CERT_DIR, 'key.pem'),
+                certfile=os.path.join(CERT_DIR, 'cert.pem'),
+                server_side=True
+            )
+            self.RequestHandlerClass(ssock, client_address, self)
+        else:
+            self.RequestHandlerClass(request, client_address, self)
+
+class Server(threading.Thread):
+    """
+    HTTP server running a WSGI application in its own thread.
+    """
+
+    def __init__(self, host='127.0.0.1', port=0, application=None, protocol='http', **kwargs):
+        self.app = application
+        self._server = ThreadedWSGIServerWithSSLTimeout(
+            host,
+            port,
+            self.app,
+            handler=Handler,
+            protocol=protocol,
+            **kwargs
+        )
+        self.host = self._server.server_address[0]
+        self.port = self._server.server_address[1]
+        self.protocol = protocol
+
+        super(Server, self).__init__(
+            name=self.__class__,
+            target=self._server.serve_forever,
+        )
+
+    def __del__(self):
+        self.stop()
+
+    def __add__(self, other):
+        return self.url + other
+
+    def stop(self):
+        self._server.shutdown()
+
+    @property
+    def url(self):
+        return '{0}://{1}:{2}'.format(self.protocol, self.host, self.port)
+
+    def join(self, url, allow_fragments=True):
+        return urljoin(self.url, url, allow_fragments=allow_fragments)
+
+
+class SecureServer(Server):
+    def __init__(self, host='127.0.0.1', port=0, application=None, **kwargs):
+        super(SecureServer, self).__init__(host, port, application, protocol='https', **kwargs)
+        self.protocol = 'https'
diff --git a/pytest_httpbin/version.py b/pytest_httpbin/version.py
new file mode 100644
index 0000000..df9144c
--- /dev/null
+++ b/pytest_httpbin/version.py
@@ -0,0 +1 @@
+__version__ = '0.1.1'
diff --git a/runtests.sh b/runtests.sh
new file mode 100755
index 0000000..6115f03
--- /dev/null
+++ b/runtests.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+py.test $1 -v -s
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..79bc678
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[bdist_wheel]
+# This flag says that the code is written to work on both Python 2 and Python
+# 3. If at all possible, it is good practice to do this. If you cannot, you
+# will need to generate wheels for each Python version that you support.
+universal=1
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..11c649c
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,61 @@
+from setuptools import setup, find_packages
+import codecs
+import os
+import re
+
+with open("pytest_httpbin/version.py") as f:
+    code = compile(f.read(), "pytest_httpbin/version.py", 'exec')
+    exec(code)
+
+here = os.path.abspath(os.path.dirname(__file__))
+
+# Get the long description from the relevant file
+with codecs.open(os.path.join(here, 'DESCRIPTION.rst'), encoding='utf-8') as f:
+    long_description = f.read()
+
+setup(
+    name="pytest-httpbin",
+
+    # There are various approaches to referencing the version. For a discussion,
+    # see http://packaging.python.org/en/latest/tutorial.html#version
+    version=__version__,
+
+    description="Easily test your HTTP library against a local copy of httpbin",
+    long_description=long_description,
+
+    # The project URL.
+    url='https://github.com/kevin1024/pytest-httpbin',
+
+    # Author details
+    author='Kevin McCarthy',
+    author_email='me at kevinmccarthy.org',
+
+    # Choose your license
+    license='MIT',
+
+    classifiers=[
+        'Development Status :: 3 - Alpha',
+        'Intended Audience :: Developers',
+        'Topic :: Software Development :: Testing',
+        'Topic :: Software Development :: Libraries',
+        'License :: OSI Approved :: MIT License',
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 2.6',
+        'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3',
+        'Programming Language :: Python :: 3.4',
+    ],
+
+    # What does your project relate to?
+    keywords='pytest-httpbin testing pytest httpbin',
+    packages=find_packages(exclude=["contrib", "docs", "tests*"]),
+    include_package_data = True, # include files listed in MANIFEST.in
+    install_requires = ['Flask','decorator','httpbin','six'],
+
+    # the following makes a plugin available to pytest
+    entry_points = {
+        'pytest11': [
+            'httpbin = pytest_httpbin.plugin',
+        ]
+    },
+)
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000..0d5df6d
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,6 @@
+import pytest
+
+from pytest_httpbin.plugin import httpbin_ca_bundle
+
+
+pytest.fixture(autouse=True)(httpbin_ca_bundle)
diff --git a/tests/test_httpbin.py b/tests/test_httpbin.py
new file mode 100644
index 0000000..35eddbf
--- /dev/null
+++ b/tests/test_httpbin.py
@@ -0,0 +1,53 @@
+import unittest
+import requests
+import pytest_httpbin
+
+
+def test_httpbin_gets_injected(httpbin):
+    assert httpbin.url
+
+
+def test_httpbin_accepts_get_requests(httpbin):
+    assert requests.get(httpbin.url + '/get').status_code == 200
+
+
+def test_httpbin_secure_accepts_get_requests(httpbin_secure):
+    assert requests.get(httpbin_secure.url + '/get').status_code == 200
+
+
+def test_httpbin_secure_accepts_lots_of_get_requests(httpbin_secure):
+    for i in range(10):
+        assert requests.get(httpbin_secure.url + '/get').status_code == 200
+
+
+def test_httpbin_accepts_lots_of_get_requests_in_single_session(httpbin):
+    session = requests.Session()
+
+    for i in range(10):
+        assert session.get(httpbin.url + '/get').status_code == 200
+
+
+def test_httpbin_both(httpbin_both):
+    # this test will get called twice, once with an http url, once with an
+    # https url
+    assert requests.get(httpbin_both.url + '/get').status_code == 200
+
+
+def test_httpbin_join(httpbin):
+    assert httpbin.join('foo') == httpbin.url + '/foo'
+
+
+def test_httpbin_str(httpbin):
+    assert httpbin + '/foo' == httpbin.url + '/foo'
+
+def test_chunked_encoding(httpbin_both):
+    assert requests.get(httpbin_both.url + '/stream/20').status_code == 200
+
+ at pytest_httpbin.use_class_based_httpbin
+ at pytest_httpbin.use_class_based_httpbin_secure
+class TestClassBassedTests(unittest.TestCase):
+    def test_http(self):
+        assert requests.get(self.httpbin.url + '/get').status_code == 200
+
+    def test_http_secure(self):
+        assert requests.get(self.httpbin_secure.url + '/get').status_code == 200
diff --git a/tests/test_server.py b/tests/test_server.py
new file mode 100644
index 0000000..38d5c65
--- /dev/null
+++ b/tests/test_server.py
@@ -0,0 +1,62 @@
+# coding=utf8
+# -*- coding: utf8 -*-
+# vim: set fileencoding=utf8 :
+
+import requests
+import pytest
+from util import get_raw_http_response
+
+try:
+    from multiprocessing.pool import ThreadPool
+except ImportError:
+    ThreadPool = None
+
+
+def test_content_type_header_not_automatically_added(httpbin):
+    """
+    The server was automatically adding this for some reason, see issue #5
+    """
+    resp = requests.get(httpbin + '/headers').json()['headers']
+    assert 'Content-Type' not in resp
+
+
+def test_unicode_data(httpbin):
+    """
+    UTF-8 was not getting recognized for what it was and being encoded as if it
+    was binary, see issue #7
+    """
+    resp = requests.post(
+        httpbin + '/post',
+        data=u'оживлённым'.encode('utf-8'),
+        headers={
+            'content-type': 'text/html; charset=utf-8',
+        }
+    )
+    assert resp.json()['data'] == u'оживлённым'
+
+
+
+def test_server_should_handle_concurrent_connections(httpbin):
+    url = httpbin + '/get'
+    session = requests.Session()
+
+    def do_request(i):
+        r = session.get(url)
+    if ThreadPool is not None:
+        pool = ThreadPool(processes=50)
+        pool.map(do_request, range(100))
+
+
+def test_dont_crash_on_certificate_problems(httpbin_secure):
+    with pytest.raises(Exception):
+        # this request used to hang
+        requests.get(
+            httpbin_secure + '/get',
+            verify = True,
+            cert=__file__
+        )
+    # and this request would never happen
+    requests.get(
+        httpbin_secure + '/get',
+        verify = True,
+    )
diff --git a/tests/util.py b/tests/util.py
new file mode 100644
index 0000000..23063db
--- /dev/null
+++ b/tests/util.py
@@ -0,0 +1,30 @@
+import socket
+
+
+def get_raw_http_response(host, port, path):
+
+    CRLF = b"\r\n"
+
+    request = [
+        b"GET " + path.encode('ascii') + b" HTTP/1.1",
+        b"Host: " + host.encode('ascii'),
+        b"Connection: Close",
+        b"",
+        b"",
+    ]
+
+    # Connect to the server
+    s = socket.socket()
+    s.connect((host, port))
+
+    # Send an HTTP request
+    s.send(CRLF.join(request))
+
+    # Get the response (in several parts, if necessary)
+    response = b''
+    buffer = s.recv(4096)
+    while buffer:
+        response += buffer
+        buffer = s.recv(4096)
+
+    return response
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..472b865
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,9 @@
+# content of: tox.ini , put in same dir as setup.py
+
+[tox]
+envlist = py26, py27, py33, py34, pypy
+
+[testenv]
+deps = pytest
+       requests
+commands = ./runtests.sh {posargs:tests/}

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



More information about the Python-modules-commits mailing list