Run tests against local httpbin instance via pytest-httpbin.

This commit is contained in:
Jakub Roztocil 2014-06-28 16:35:57 +02:00
parent 79329ed1c6
commit 2a72ae23d5
19 changed files with 300 additions and 263 deletions

View File

@ -105,8 +105,13 @@ class HTTPRequest(HTTPMessage):
if 'Host' not in self._orig.headers: if 'Host' not in self._orig.headers:
headers['Host'] = url.netloc.split('@')[-1] headers['Host'] = url.netloc.split('@')[-1]
headers = ['%s: %s' % (name, value) headers = [
for name, value in headers.items()] '%s: %s' % (
name,
value if isinstance(value, str) else value.decode('utf8')
)
for name, value in headers.items()
]
headers.insert(0, request_line) headers.insert(0, request_line)
headers = '\r\n'.join(headers).strip() headers = '\r\n'.join(headers).strip()

View File

@ -2,4 +2,5 @@ tox
pytest pytest
pytest-xdist pytest-xdist
pytest-cov pytest-cov
pytest-httpbin
docutils docutils

View File

@ -26,6 +26,7 @@ class PyTest(TestCommand):
tests_require = [ tests_require = [
'pytest', 'pytest',
'pytest-httpbin',
] ]

View File

@ -2,42 +2,45 @@
import requests import requests
import pytest import pytest
from utils import http, httpbin, HTTP_OK from utils import http, add_auth, HTTP_OK
import httpie.input import httpie.input
class TestAuth: class TestAuth:
def test_basic_auth(self): def test_basic_auth(self, httpbin):
r = http('--auth=user:password', r = http('--auth=user:password',
'GET', httpbin('/basic-auth/user/password')) 'GET', httpbin.url + '/basic-auth/user/password')
assert HTTP_OK in r assert HTTP_OK in r
assert r.json == {'authenticated': True, 'user': 'user'} assert r.json == {'authenticated': True, 'user': 'user'}
@pytest.mark.skipif( @pytest.mark.skipif(
requests.__version__ == '0.13.6', requests.__version__ == '0.13.6',
reason='Redirects with prefetch=False are broken in Requests 0.13.6') reason='Redirects with prefetch=False are broken in Requests 0.13.6')
def test_digest_auth(self): def test_digest_auth(self, httpbin):
r = http('--auth-type=digest', '--auth=user:password', r = http('--auth-type=digest', '--auth=user:password',
'GET', httpbin('/digest-auth/auth/user/password')) 'GET', httpbin.url + '/digest-auth/auth/user/password')
assert HTTP_OK in r assert HTTP_OK in r
assert r.json == {'authenticated': True, 'user': 'user'} assert r.json == {'authenticated': True, 'user': 'user'}
def test_password_prompt(self): def test_password_prompt(self, httpbin):
httpie.input.AuthCredentials._getpass = lambda self, prompt: 'password' httpie.input.AuthCredentials._getpass = lambda self, prompt: 'password'
r = http('--auth', 'user', 'GET', httpbin('/basic-auth/user/password')) r = http('--auth', 'user',
'GET', httpbin.url + '/basic-auth/user/password')
assert HTTP_OK in r assert HTTP_OK in r
assert r.json == {'authenticated': True, 'user': 'user'} assert r.json == {'authenticated': True, 'user': 'user'}
def test_credentials_in_url(self): def test_credentials_in_url(self, httpbin):
url = httpbin('/basic-auth/user/password', auth='user:password') url = add_auth(httpbin.url + '/basic-auth/user/password',
auth='user:password')
r = http('GET', url) r = http('GET', url)
assert HTTP_OK in r assert HTTP_OK in r
assert r.json == {'authenticated': True, 'user': 'user'} assert r.json == {'authenticated': True, 'user': 'user'}
def test_credentials_in_url_auth_flag_has_priority(self): def test_credentials_in_url_auth_flag_has_priority(self, httpbin):
"""When credentials are passed in URL and via -a at the same time, """When credentials are passed in URL and via -a at the same time,
then the ones from -a are used.""" then the ones from -a are used."""
url = httpbin('/basic-auth/user/password', auth='user:wrong') url = add_auth(httpbin.url + '/basic-auth/user/password',
auth='user:wrong')
r = http('--auth=user:password', 'GET', url) r = http('--auth=user:password', 'GET', url)
assert HTTP_OK in r assert HTTP_OK in r
assert r.json == {'authenticated': True, 'user': 'user'} assert r.json == {'authenticated': True, 'user': 'user'}

View File

@ -1,30 +1,30 @@
"""Tests for dealing with binary request and response data.""" """Tests for dealing with binary request and response data."""
from httpie.compat import urlopen from httpie.compat import urlopen
from httpie.output.streams import BINARY_SUPPRESSED_NOTICE from httpie.output.streams import BINARY_SUPPRESSED_NOTICE
from utils import TestEnvironment, http, httpbin from utils import TestEnvironment, http
from fixtures import BIN_FILE_PATH, BIN_FILE_CONTENT, BIN_FILE_PATH_ARG from fixtures import BIN_FILE_PATH, BIN_FILE_CONTENT, BIN_FILE_PATH_ARG
class TestBinaryRequestData: class TestBinaryRequestData:
def test_binary_stdin(self): def test_binary_stdin(self, httpbin):
with open(BIN_FILE_PATH, 'rb') as stdin: with open(BIN_FILE_PATH, 'rb') as stdin:
env = TestEnvironment( env = TestEnvironment(
stdin=stdin, stdin=stdin,
stdin_isatty=False, stdin_isatty=False,
stdout_isatty=False stdout_isatty=False
) )
r = http('--print=B', 'POST', httpbin('/post'), env=env) r = http('--print=B', 'POST', httpbin.url + '/post', env=env)
assert r == BIN_FILE_CONTENT assert r == BIN_FILE_CONTENT
def test_binary_file_path(self): def test_binary_file_path(self, httpbin):
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False) env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('--print=B', 'POST', httpbin('/post'), r = http('--print=B', 'POST', httpbin.url + '/post',
'@' + BIN_FILE_PATH_ARG, env=env, ) '@' + BIN_FILE_PATH_ARG, env=env, )
assert r == BIN_FILE_CONTENT assert r == BIN_FILE_CONTENT
def test_binary_file_form(self): def test_binary_file_form(self, httpbin):
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False) env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('--print=B', '--form', 'POST', httpbin('/post'), r = http('--print=B', '--form', 'POST', httpbin.url + '/post',
'test@' + BIN_FILE_PATH_ARG, env=env) 'test@' + BIN_FILE_PATH_ARG, env=env)
assert bytes(BIN_FILE_CONTENT) in bytes(r) assert bytes(BIN_FILE_CONTENT) in bytes(r)

View File

@ -9,7 +9,7 @@ from httpie import input
from httpie.input import KeyValue, KeyValueArgType from httpie.input import KeyValue, KeyValueArgType
from httpie import ExitStatus from httpie import ExitStatus
from httpie.cli import parser from httpie.cli import parser
from utils import TestEnvironment, http, httpbin, HTTP_OK from utils import TestEnvironment, http, HTTP_OK
from fixtures import ( from fixtures import (
FILE_PATH_ARG, JSON_FILE_PATH_ARG, FILE_PATH_ARG, JSON_FILE_PATH_ARG,
JSON_FILE_CONTENT, FILE_CONTENT, FILE_PATH JSON_FILE_CONTENT, FILE_CONTENT, FILE_PATH
@ -93,27 +93,28 @@ class TestItemParsing:
class TestQuerystring: class TestQuerystring:
def test_query_string_params_in_url(self): def test_query_string_params_in_url(self, httpbin):
r = http('--print=Hhb', 'GET', httpbin('/get?a=1&b=2')) r = http('--print=Hhb', 'GET', httpbin.url + '/get?a=1&b=2')
path = '/get?a=1&b=2' path = '/get?a=1&b=2'
url = httpbin(path) url = httpbin.url + path
assert HTTP_OK in r assert HTTP_OK in r
assert 'GET %s HTTP/1.1' % path in r assert 'GET %s HTTP/1.1' % path in r
assert '"url": "%s"' % url in r assert '"url": "%s"' % url in r
def test_query_string_params_items(self): def test_query_string_params_items(self, httpbin):
r = http('--print=Hhb', 'GET', httpbin('/get'), 'a==1', 'b==2') r = http('--print=Hhb', 'GET', httpbin.url + '/get', 'a==1')
path = '/get?a=1&b=2' path = '/get?a=1'
url = httpbin(path) url = httpbin.url + path
assert HTTP_OK in r assert HTTP_OK in r
assert 'GET %s HTTP/1.1' % path in r assert 'GET %s HTTP/1.1' % path in r
assert '"url": "%s"' % url in r assert '"url": "%s"' % url in r
def test_query_string_params_in_url_and_items_with_duplicates(self): def test_query_string_params_in_url_and_items_with_duplicates(self,
r = http('--print=Hhb', 'GET', httpbin('/get?a=1&a=1'), httpbin):
'a==1', 'a==1', 'b==2') r = http('--print=Hhb', 'GET',
path = '/get?a=1&a=1&a=1&a=1&b=2' httpbin.url + '/get?a=1&a=1', 'a==1', 'a==1')
url = httpbin(path) path = '/get?a=1&a=1&a=1&a=1'
url = httpbin.url + path
assert HTTP_OK in r assert HTTP_OK in r
assert 'GET %s HTTP/1.1' % path in r assert 'GET %s HTTP/1.1' % path in r
assert '"url": "%s"' % url in r assert '"url": "%s"' % url in r
@ -257,12 +258,13 @@ class TestArgumentParser:
class TestNoOptions: class TestNoOptions:
def test_valid_no_options(self):
r = http('--verbose', '--no-verbose', 'GET', httpbin('/get')) def test_valid_no_options(self, httpbin):
r = http('--verbose', '--no-verbose', 'GET', httpbin.url + '/get')
assert 'GET /get HTTP/1.1' not in r assert 'GET /get HTTP/1.1' not in r
def test_invalid_no_options(self): def test_invalid_no_options(self, httpbin):
r = http('--no-war', 'GET', httpbin('/get'), r = http('--no-war', 'GET', httpbin.url + '/get',
error_exit_ok=True) error_exit_ok=True)
assert r.exit_status == 1 assert r.exit_status == 1
assert 'unrecognized arguments: --no-war' in r.stderr assert 'unrecognized arguments: --no-war' in r.stderr
@ -270,16 +272,18 @@ class TestNoOptions:
class TestIgnoreStdin: class TestIgnoreStdin:
def test_ignore_stdin(self):
def test_ignore_stdin(self, httpbin):
with open(FILE_PATH) as f: with open(FILE_PATH) as f:
env = TestEnvironment(stdin=f, stdin_isatty=False) env = TestEnvironment(stdin=f, stdin_isatty=False)
r = http('--ignore-stdin', '--verbose', httpbin('/get'), env=env) r = http('--ignore-stdin', '--verbose', httpbin.url + '/get',
env=env)
assert HTTP_OK in r assert HTTP_OK in r
assert 'GET /get HTTP' in r, "Don't default to POST." assert 'GET /get HTTP' in r, "Don't default to POST."
assert FILE_CONTENT not in r, "Don't send stdin data." assert FILE_CONTENT not in r, "Don't send stdin data."
def test_ignore_stdin_cannot_prompt_password(self): def test_ignore_stdin_cannot_prompt_password(self, httpbin):
r = http('--ignore-stdin', '--auth=no-password', httpbin('/get'), r = http('--ignore-stdin', '--auth=no-password', httpbin.url + '/get',
error_exit_ok=True) error_exit_ok=True)
assert r.exit_status == ExitStatus.ERROR assert r.exit_status == ExitStatus.ERROR
assert 'because --ignore-stdin' in r.stderr assert 'because --ignore-stdin' in r.stderr

View File

@ -2,34 +2,34 @@
Tests for the provided defaults regarding HTTP method, and --json vs. --form. Tests for the provided defaults regarding HTTP method, and --json vs. --form.
""" """
from utils import TestEnvironment, http, httpbin, HTTP_OK from utils import TestEnvironment, http, HTTP_OK, no_content_type
from fixtures import FILE_PATH from fixtures import FILE_PATH
class TestImplicitHTTPMethod: class TestImplicitHTTPMethod:
def test_implicit_GET(self): def test_implicit_GET(self, httpbin):
r = http(httpbin('/get')) r = http(httpbin.url + '/get')
assert HTTP_OK in r assert HTTP_OK in r
def test_implicit_GET_with_headers(self): def test_implicit_GET_with_headers(self, httpbin):
r = http(httpbin('/headers'), 'Foo:bar') r = http(httpbin.url + '/headers', 'Foo:bar')
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['headers']['Foo'] == 'bar' assert r.json['headers']['Foo'] == 'bar'
def test_implicit_POST_json(self): def test_implicit_POST_json(self, httpbin):
r = http(httpbin('/post'), 'hello=world') r = http(httpbin.url + '/post', 'hello=world')
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['json'] == {'hello': 'world'} assert r.json['json'] == {'hello': 'world'}
def test_implicit_POST_form(self): def test_implicit_POST_form(self, httpbin):
r = http('--form', httpbin('/post'), 'foo=bar') r = http('--form', httpbin.url + '/post', 'foo=bar')
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['form'] == {'foo': 'bar'} assert r.json['form'] == {'foo': 'bar'}
def test_implicit_POST_stdin(self): def test_implicit_POST_stdin(self, httpbin):
with open(FILE_PATH) as f: with open(FILE_PATH) as f:
env = TestEnvironment(stdin_isatty=False, stdin=f) env = TestEnvironment(stdin_isatty=False, stdin=f)
r = http('--form', httpbin('/post'), env=env) r = http('--form', httpbin.url + '/post', env=env)
assert HTTP_OK in r assert HTTP_OK in r
@ -41,66 +41,66 @@ class TestAutoContentTypeAndAcceptHeaders:
""" """
def test_GET_no_data_no_auto_headers(self): def test_GET_no_data_no_auto_headers(self, httpbin):
# https://github.com/jakubroztocil/httpie/issues/62 # https://github.com/jakubroztocil/httpie/issues/62
r = http('GET', httpbin('/headers')) r = http('GET', httpbin.url + '/headers')
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['headers']['Accept'] == '*/*' assert r.json['headers']['Accept'] == '*/*'
assert 'Content-Type' not in r.json['headers'] assert no_content_type(r.json['headers'])
def test_POST_no_data_no_auto_headers(self): def test_POST_no_data_no_auto_headers(self, httpbin):
# JSON headers shouldn't be automatically set for POST with no data. # JSON headers shouldn't be automatically set for POST with no data.
r = http('POST', httpbin('/post')) r = http('POST', httpbin.url + '/post')
assert HTTP_OK in r assert HTTP_OK in r
assert '"Accept": "*/*"' in r assert '"Accept": "*/*"' in r
assert '"Content-Type": "application/json' not in r assert '"Content-Type": "application/json' not in r
def test_POST_with_data_auto_JSON_headers(self): def test_POST_with_data_auto_JSON_headers(self, httpbin):
r = http('POST', httpbin('/post'), 'a=b') r = http('POST', httpbin.url + '/post', 'a=b')
assert HTTP_OK in r assert HTTP_OK in r
assert '"Accept": "application/json"' in r assert '"Accept": "application/json"' in r
assert '"Content-Type": "application/json; charset=utf-8' in r assert '"Content-Type": "application/json; charset=utf-8' in r
def test_GET_with_data_auto_JSON_headers(self): def test_GET_with_data_auto_JSON_headers(self, httpbin):
# JSON headers should automatically be set also for GET with data. # JSON headers should automatically be set also for GET with data.
r = http('POST', httpbin('/post'), 'a=b') r = http('POST', httpbin.url + '/post', 'a=b')
assert HTTP_OK in r assert HTTP_OK in r
assert '"Accept": "application/json"' in r, r assert '"Accept": "application/json"' in r, r
assert '"Content-Type": "application/json; charset=utf-8' in r assert '"Content-Type": "application/json; charset=utf-8' in r
def test_POST_explicit_JSON_auto_JSON_accept(self): def test_POST_explicit_JSON_auto_JSON_accept(self, httpbin):
r = http('--json', 'POST', httpbin('/post')) r = http('--json', 'POST', httpbin.url + '/post')
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['headers']['Accept'] == 'application/json' assert r.json['headers']['Accept'] == 'application/json'
# Make sure Content-Type gets set even with no data. # Make sure Content-Type gets set even with no data.
# https://github.com/jakubroztocil/httpie/issues/137 # https://github.com/jakubroztocil/httpie/issues/137
assert 'application/json' in r.json['headers']['Content-Type'] assert 'application/json' in r.json['headers']['Content-Type']
def test_GET_explicit_JSON_explicit_headers(self): def test_GET_explicit_JSON_explicit_headers(self, httpbin):
r = http('--json', 'GET', httpbin('/headers'), r = http('--json', 'GET', httpbin.url + '/headers',
'Accept:application/xml', 'Accept:application/xml',
'Content-Type:application/xml') 'Content-Type:application/xml')
assert HTTP_OK in r assert HTTP_OK in r
assert '"Accept": "application/xml"' in r assert '"Accept": "application/xml"' in r
assert '"Content-Type": "application/xml"' in r assert '"Content-Type": "application/xml"' in r
def test_POST_form_auto_Content_Type(self): def test_POST_form_auto_Content_Type(self, httpbin):
r = http('--form', 'POST', httpbin('/post')) r = http('--form', 'POST', httpbin.url + '/post')
assert HTTP_OK in r assert HTTP_OK in r
assert '"Content-Type": "application/x-www-form-urlencoded' in r assert '"Content-Type": "application/x-www-form-urlencoded' in r
def test_POST_form_Content_Type_override(self): def test_POST_form_Content_Type_override(self, httpbin):
r = http('--form', 'POST', httpbin('/post'), r = http('--form', 'POST', httpbin.url + '/post',
'Content-Type:application/xml') 'Content-Type:application/xml')
assert HTTP_OK in r assert HTTP_OK in r
assert '"Content-Type": "application/xml"' in r assert '"Content-Type": "application/xml"' in r
def test_print_only_body_when_stdout_redirected_by_default(self): def test_print_only_body_when_stdout_redirected_by_default(self, httpbin):
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False) env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('GET', httpbin('/get'), env=env) r = http('GET', httpbin.url + '/get', env=env)
assert 'HTTP/' not in r assert 'HTTP/' not in r
def test_print_overridable_when_stdout_redirected(self): def test_print_overridable_when_stdout_redirected(self, httpbin):
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False) env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('--print=h', 'GET', httpbin('/get'), env=env) r = http('--print=h', 'GET', httpbin.url + '/get', env=env)
assert HTTP_OK in r assert HTTP_OK in r

View File

@ -9,7 +9,7 @@ from httpie.downloads import (
parse_content_range, filename_from_content_disposition, filename_from_url, parse_content_range, filename_from_content_disposition, filename_from_url,
get_unique_filename, ContentRangeError, Download, get_unique_filename, ContentRangeError, Download,
) )
from utils import httpbin, http, TestEnvironment from utils import http, TestEnvironment
class Response(object): class Response(object):
@ -94,8 +94,8 @@ class TestDownloadUtils:
class TestDownloads: class TestDownloads:
# TODO: more tests # TODO: more tests
def test_actual_download(self): def test_actual_download(self, httpbin):
url = httpbin('/robots.txt') url = httpbin.url + '/robots.txt'
body = urlopen(url).read().decode() body = urlopen(url).read().decode()
env = TestEnvironment(stdin_isatty=True, stdout_isatty=False) env = TestEnvironment(stdin_isatty=True, stdout_isatty=False)
r = http('--download', url, env=env) r = http('--download', url, env=env)
@ -104,11 +104,11 @@ class TestDownloads:
assert 'Done' in r.stderr assert 'Done' in r.stderr
assert body == r assert body == r
def test_download_with_Content_Length(self): def test_download_with_Content_Length(self, httpbin):
devnull = open(os.devnull, 'w') devnull = open(os.devnull, 'w')
download = Download(output_file=devnull, progress_file=devnull) download = Download(output_file=devnull, progress_file=devnull)
download.start(Response( download.start(Response(
url=httpbin('/'), url=httpbin.url + '/',
headers={'Content-Length': 10} headers={'Content-Length': 10}
)) ))
time.sleep(1.1) time.sleep(1.1)
@ -118,20 +118,20 @@ class TestDownloads:
download.finish() download.finish()
assert not download.interrupted assert not download.interrupted
def test_download_no_Content_Length(self): def test_download_no_Content_Length(self, httpbin):
devnull = open(os.devnull, 'w') devnull = open(os.devnull, 'w')
download = Download(output_file=devnull, progress_file=devnull) download = Download(output_file=devnull, progress_file=devnull)
download.start(Response(url=httpbin('/'))) download.start(Response(url=httpbin.url + '/'))
time.sleep(1.1) time.sleep(1.1)
download.chunk_downloaded(b'12345') download.chunk_downloaded(b'12345')
download.finish() download.finish()
assert not download.interrupted assert not download.interrupted
def test_download_interrupted(self): def test_download_interrupted(self, httpbin):
devnull = open(os.devnull, 'w') devnull = open(os.devnull, 'w')
download = Download(output_file=devnull, progress_file=devnull) download = Download(output_file=devnull, progress_file=devnull)
download.start(Response( download.start(Response(
url=httpbin('/'), url=httpbin.url + '/',
headers={'Content-Length': 5} headers={'Content-Length': 5}
)) ))
download.chunk_downloaded(b'1234') download.chunk_downloaded(b'1234')

View File

@ -2,18 +2,18 @@ import requests
import pytest import pytest
from httpie import ExitStatus from httpie import ExitStatus
from utils import TestEnvironment, http, httpbin, HTTP_OK from utils import TestEnvironment, http, HTTP_OK
class TestExitStatus: class TestExitStatus:
def test_ok_response_exits_0(self): def test_ok_response_exits_0(self, httpbin):
r = http('GET', httpbin('/status/200')) r = http('GET', httpbin.url + '/status/200')
assert HTTP_OK in r assert HTTP_OK in r
assert r.exit_status == ExitStatus.OK assert r.exit_status == ExitStatus.OK
def test_error_response_exits_0_without_check_status(self): def test_error_response_exits_0_without_check_status(self, httpbin):
r = http('GET', httpbin('/status/500')) r = http('GET', httpbin.url + '/status/500')
assert 'HTTP/1.1 500' in r assert '500 INTERNAL SERVER ERRO' in r
assert r.exit_status == ExitStatus.OK assert r.exit_status == ExitStatus.OK
assert not r.stderr assert not r.stderr
@ -21,40 +21,43 @@ class TestExitStatus:
tuple(map(int, requests.__version__.split('.'))) < (2, 3, 0), tuple(map(int, requests.__version__.split('.'))) < (2, 3, 0),
reason='timeout broken in requests prior v2.3.0 (#185)' reason='timeout broken in requests prior v2.3.0 (#185)'
) )
def test_timeout_exit_status(self): def test_timeout_exit_status(self, httpbin):
r = http('--timeout=0.5', 'GET', httpbin('/delay/1'), r = http('--timeout=0.5', 'GET', httpbin.url + '/delay/1',
error_exit_ok=True) error_exit_ok=True)
assert r.exit_status == ExitStatus.ERROR_TIMEOUT assert r.exit_status == ExitStatus.ERROR_TIMEOUT
def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected(self): def test_3xx_check_status_exits_3_and_stderr_when_stdout_redirected(
self, httpbin):
env = TestEnvironment(stdout_isatty=False) env = TestEnvironment(stdout_isatty=False)
r = http('--check-status', '--headers', 'GET', httpbin('/status/301'), r = http('--check-status', '--headers',
'GET', httpbin.url + '/status/301',
env=env, error_exit_ok=True) env=env, error_exit_ok=True)
assert 'HTTP/1.1 301' in r assert '301 MOVED PERMANENTLY' in r
assert r.exit_status == ExitStatus.ERROR_HTTP_3XX assert r.exit_status == ExitStatus.ERROR_HTTP_3XX
assert '301 moved permanently' in r.stderr.lower() assert '301 moved permanently' in r.stderr.lower()
@pytest.mark.skipif( @pytest.mark.skipif(
requests.__version__ == '0.13.6', requests.__version__ == '0.13.6',
reason='Redirects with prefetch=False are broken in Requests 0.13.6') reason='Redirects with prefetch=False are broken in Requests 0.13.6')
def test_3xx_check_status_redirects_allowed_exits_0(self): def test_3xx_check_status_redirects_allowed_exits_0(self, httpbin):
r = http('--check-status', '--follow', 'GET', httpbin('/status/301'), r = http('--check-status', '--follow',
'GET', httpbin.url + '/status/301',
error_exit_ok=True) error_exit_ok=True)
# The redirect will be followed so 200 is expected. # The redirect will be followed so 200 is expected.
assert 'HTTP/1.1 200 OK' in r assert HTTP_OK in r
assert r.exit_status == ExitStatus.OK assert r.exit_status == ExitStatus.OK
def test_4xx_check_status_exits_4(self): def test_4xx_check_status_exits_4(self, httpbin):
r = http('--check-status', 'GET', httpbin('/status/401'), r = http('--check-status', 'GET', httpbin.url + '/status/401',
error_exit_ok=True) error_exit_ok=True)
assert 'HTTP/1.1 401' in r assert '401 UNAUTHORIZED' in r
assert r.exit_status == ExitStatus.ERROR_HTTP_4XX assert r.exit_status == ExitStatus.ERROR_HTTP_4XX
# Also stderr should be empty since stdout isn't redirected. # Also stderr should be empty since stdout isn't redirected.
assert not r.stderr assert not r.stderr
def test_5xx_check_status_exits_5(self): def test_5xx_check_status_exits_5(self, httpbin):
r = http('--check-status', 'GET', httpbin('/status/500'), r = http('--check-status', 'GET', httpbin.url + '/status/500',
error_exit_ok=True) error_exit_ok=True)
assert 'HTTP/1.1 500' in r assert '500 INTERNAL SERVER ERROR' in r
assert r.exit_status == ExitStatus.ERROR_HTTP_5XX assert r.exit_status == ExitStatus.ERROR_HTTP_5XX

View File

@ -1,5 +1,5 @@
"""High-level tests.""" """High-level tests."""
from utils import TestEnvironment, http, httpbin, HTTP_OK from utils import TestEnvironment, http, HTTP_OK
from fixtures import FILE_PATH, FILE_CONTENT from fixtures import FILE_PATH, FILE_CONTENT
import httpie import httpie
@ -23,43 +23,43 @@ class TestHTTPie:
# FIXME: py3 has version in stdout, py2 in stderr # FIXME: py3 has version in stdout, py2 in stderr
assert httpie.__version__ == r.stderr.strip() + r.strip() assert httpie.__version__ == r.stderr.strip() + r.strip()
def test_GET(self): def test_GET(self, httpbin):
r = http('GET', httpbin('/get')) r = http('GET', httpbin.url + '/get')
assert HTTP_OK in r assert HTTP_OK in r
def test_DELETE(self): def test_DELETE(self, httpbin):
r = http('DELETE', httpbin('/delete')) r = http('DELETE', httpbin.url + '/delete')
assert HTTP_OK in r assert HTTP_OK in r
def test_PUT(self): def test_PUT(self, httpbin):
r = http('PUT', httpbin('/put'), 'foo=bar') r = http('PUT', httpbin.url + '/put', 'foo=bar')
assert HTTP_OK in r assert HTTP_OK in r
assert r'\"foo\": \"bar\"' in r assert r.json['json']['foo'] == 'bar'
def test_POST_JSON_data(self): def test_POST_JSON_data(self, httpbin):
r = http('POST', httpbin('/post'), 'foo=bar') r = http('POST', httpbin.url + '/post', 'foo=bar')
assert HTTP_OK in r assert HTTP_OK in r
assert r'\"foo\": \"bar\"' in r assert r.json['json']['foo'] == 'bar'
def test_POST_form(self): def test_POST_form(self, httpbin):
r = http('--form', 'POST', httpbin('/post'), 'foo=bar') r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar')
assert HTTP_OK in r assert HTTP_OK in r
assert '"foo": "bar"' in r assert '"foo": "bar"' in r
def test_POST_form_multiple_values(self): def test_POST_form_multiple_values(self, httpbin):
r = http('--form', 'POST', httpbin('/post'), 'foo=bar', 'foo=baz') r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar', 'foo=baz')
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['form'] == {'foo': ['bar', 'baz']} assert r.json['form'] == {'foo': ['bar', 'baz']}
def test_POST_stdin(self): def test_POST_stdin(self, httpbin):
with open(FILE_PATH) as f: with open(FILE_PATH) as f:
env = TestEnvironment(stdin=f, stdin_isatty=False) env = TestEnvironment(stdin=f, stdin_isatty=False)
r = http('--form', 'POST', httpbin('/post'), env=env) r = http('--form', 'POST', httpbin.url + '/post', env=env)
assert HTTP_OK in r assert HTTP_OK in r
assert FILE_CONTENT in r assert FILE_CONTENT in r
def test_headers(self): def test_headers(self, httpbin):
r = http('GET', httpbin('/headers'), 'Foo:bar') r = http('GET', httpbin.url + '/headers', 'Foo:bar')
assert HTTP_OK in r assert HTTP_OK in r
assert '"User-Agent": "HTTPie' in r, r assert '"User-Agent": "HTTPie' in r, r
assert '"Foo": "bar"' in r assert '"Foo": "bar"' in r

View File

@ -2,27 +2,28 @@ import pytest
from httpie import ExitStatus from httpie import ExitStatus
from httpie.output.formatters.colors import get_lexer from httpie.output.formatters.colors import get_lexer
from utils import TestEnvironment, http, httpbin, HTTP_OK, COLOR, CRLF from utils import TestEnvironment, http, HTTP_OK, COLOR, CRLF
class TestVerboseFlag: class TestVerboseFlag:
def test_verbose(self): def test_verbose(self, httpbin):
r = http('--verbose', 'GET', httpbin('/get'), 'test-header:__test__') r = http('--verbose',
'GET', httpbin.url + '/get', 'test-header:__test__')
assert HTTP_OK in r assert HTTP_OK in r
assert r.count('__test__') == 2 assert r.count('__test__') == 2
def test_verbose_form(self): def test_verbose_form(self, httpbin):
# https://github.com/jakubroztocil/httpie/issues/53 # https://github.com/jakubroztocil/httpie/issues/53
r = http('--verbose', '--form', 'POST', httpbin('/post'), r = http('--verbose', '--form', 'POST', httpbin.url + '/post',
'A=B', 'C=D') 'A=B', 'C=D')
assert HTTP_OK in r assert HTTP_OK in r
assert 'A=B&C=D' in r assert 'A=B&C=D' in r
def test_verbose_json(self): def test_verbose_json(self, httpbin):
r = http('--verbose', 'POST', httpbin('/post'), 'foo=bar', 'baz=bar') r = http('--verbose',
'POST', httpbin.url + '/post', 'foo=bar', 'baz=bar')
assert HTTP_OK in r assert HTTP_OK in r
assert '"baz": "bar"' in r # request assert '"baz": "bar"' in r
assert r'\"baz\": \"bar\"' in r # response
class TestColors: class TestColors:
@ -47,45 +48,47 @@ class TestColors:
class TestPrettyOptions: class TestPrettyOptions:
"""Test the --pretty flag handling.""" """Test the --pretty flag handling."""
def test_pretty_enabled_by_default(self): def test_pretty_enabled_by_default(self, httpbin):
env = TestEnvironment(colors=256) env = TestEnvironment(colors=256)
r = http('GET', httpbin('/get'), env=env) r = http('GET', httpbin.url + '/get', env=env)
assert COLOR in r assert COLOR in r
def test_pretty_enabled_by_default_unless_stdout_redirected(self): def test_pretty_enabled_by_default_unless_stdout_redirected(self, httpbin):
r = http('GET', httpbin('/get')) r = http('GET', httpbin.url + '/get')
assert COLOR not in r assert COLOR not in r
def test_force_pretty(self): def test_force_pretty(self, httpbin):
env = TestEnvironment(stdout_isatty=False, colors=256) env = TestEnvironment(stdout_isatty=False, colors=256)
r = http('--pretty=all', 'GET', httpbin('/get'), env=env, ) r = http('--pretty=all', 'GET', httpbin.url + '/get', env=env, )
assert COLOR in r assert COLOR in r
def test_force_ugly(self): def test_force_ugly(self, httpbin):
r = http('--pretty=none', 'GET', httpbin('/get')) r = http('--pretty=none', 'GET', httpbin.url + '/get')
assert COLOR not in r assert COLOR not in r
def test_subtype_based_pygments_lexer_match(self): def test_subtype_based_pygments_lexer_match(self, httpbin):
"""Test that media subtype is used if type/subtype doesn't """Test that media subtype is used if type/subtype doesn't
match any lexer. match any lexer.
""" """
env = TestEnvironment(colors=256) env = TestEnvironment(colors=256)
r = http('--print=B', '--pretty=all', httpbin('/post'), r = http('--print=B', '--pretty=all', httpbin.url + '/post',
'Content-Type:text/foo+json', 'a=b', env=env) 'Content-Type:text/foo+json', 'a=b', env=env)
assert COLOR in r assert COLOR in r
def test_colors_option(self): def test_colors_option(self, httpbin):
env = TestEnvironment(colors=256) env = TestEnvironment(colors=256)
r = http('--print=B', '--pretty=colors', 'GET', httpbin('/get'), 'a=b', r = http('--print=B', '--pretty=colors',
'GET', httpbin.url + '/get', 'a=b',
env=env) env=env)
# Tests that the JSON data isn't formatted. # Tests that the JSON data isn't formatted.
assert not r.strip().count('\n') assert not r.strip().count('\n')
assert COLOR in r assert COLOR in r
def test_format_option(self): def test_format_option(self, httpbin):
env = TestEnvironment(colors=256) env = TestEnvironment(colors=256)
r = http('--print=B', '--pretty=format', 'GET', httpbin('/get'), 'a=b', r = http('--print=B', '--pretty=format',
'GET', httpbin.url + '/get', 'a=b',
env=env) env=env)
# Tests that the JSON data is formatted. # Tests that the JSON data is formatted.
assert r.strip().count('\n') == 2 assert r.strip().count('\n') == 2
@ -110,24 +113,24 @@ class TestLineEndings:
assert CRLF not in body assert CRLF not in body
return body return body
def test_CRLF_headers_only(self): def test_CRLF_headers_only(self, httpbin):
r = http('--headers', 'GET', httpbin('/get')) r = http('--headers', 'GET', httpbin.url + '/get')
body = self._validate_crlf(r) body = self._validate_crlf(r)
assert not body, 'Garbage after headers: %r' % r assert not body, 'Garbage after headers: %r' % r
def test_CRLF_ugly_response(self): def test_CRLF_ugly_response(self, httpbin):
r = http('--pretty=none', 'GET', httpbin('/get')) r = http('--pretty=none', 'GET', httpbin.url + '/get')
self._validate_crlf(r) self._validate_crlf(r)
def test_CRLF_formatted_response(self): def test_CRLF_formatted_response(self, httpbin):
r = http('--pretty=format', 'GET', httpbin('/get')) r = http('--pretty=format', 'GET', httpbin.url + '/get')
assert r.exit_status == ExitStatus.OK assert r.exit_status == ExitStatus.OK
self._validate_crlf(r) self._validate_crlf(r)
def test_CRLF_ugly_request(self): def test_CRLF_ugly_request(self, httpbin):
r = http('--pretty=none', '--print=HB', 'GET', httpbin('/get')) r = http('--pretty=none', '--print=HB', 'GET', httpbin.url + '/get')
self._validate_crlf(r) self._validate_crlf(r)
def test_CRLF_formatted_request(self): def test_CRLF_formatted_request(self, httpbin):
r = http('--pretty=format', '--print=HB', 'GET', httpbin('/get')) r = http('--pretty=format', '--print=HB', 'GET', httpbin.url + '/get')
self._validate_crlf(r) self._validate_crlf(r)

View File

@ -4,14 +4,14 @@ import socket
from utils import http, HTTP_OK from utils import http, HTTP_OK
def test_Host_header_overwrite(): def test_Host_header_overwrite(httpbin):
""" """
https://github.com/jakubroztocil/httpie/issues/235 https://github.com/jakubroztocil/httpie/issues/235
""" """
host = 'httpbin.org' host = 'httpbin.org'
url = 'http://{httpbin_ip}/get'.format( url = httpbin.url + '/get'
httpbin_ip=socket.gethostbyname(host)) r = http('--print=hH', url, 'host:{0}'.format(host))
r = http('--print=hH', url, 'host:{}'.format(host))
assert HTTP_OK in r assert HTTP_OK in r
assert r.lower().count('host:') == 1 assert r.lower().count('host:') == 1
assert 'host: {0}'.format(host) in r

View File

@ -3,12 +3,14 @@ import os
import shutil import shutil
from httpie.plugins.builtin import HTTPBasicAuth from httpie.plugins.builtin import HTTPBasicAuth
from utils import TestEnvironment, mk_config_dir, http, httpbin, HTTP_OK from utils import TestEnvironment, mk_config_dir, http, HTTP_OK, \
no_content_type
from fixtures import UNICODE from fixtures import UNICODE
class SessionTestBase(object): class SessionTestBase(object):
def setup_method(self, method):
def start_session(self, httpbin):
"""Create and reuse a unique config dir for each test.""" """Create and reuse a unique config dir for each test."""
self.config_dir = mk_config_dir() self.config_dir = mk_config_dir()
@ -33,67 +35,70 @@ class TestSessionFlow(SessionTestBase):
""" """
def setup_method(self, method): def start_session(self, httpbin):
""" """
Start a full-blown session with a custom request header, Start a full-blown session with a custom request header,
authorization, and response cookies. authorization, and response cookies.
""" """
super(TestSessionFlow, self).setup_method(method) super(TestSessionFlow, self).start_session(httpbin)
r1 = http('--follow', '--session=test', '--auth=username:password', r1 = http('--follow', '--session=test', '--auth=username:password',
'GET', httpbin('/cookies/set?hello=world'), 'Hello:World', 'GET', httpbin.url + '/cookies/set?hello=world',
'Hello:World',
env=self.env()) env=self.env())
assert HTTP_OK in r1 assert HTTP_OK in r1
def test_session_created_and_reused(self): def test_session_created_and_reused(self, httpbin):
self.start_session(httpbin)
# Verify that the session created in setup_method() has been used. # Verify that the session created in setup_method() has been used.
r2 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) r2 = http('--session=test',
'GET', httpbin.url + '/get', env=self.env())
assert HTTP_OK in r2 assert HTTP_OK in r2
assert r2.json['headers']['Hello'] == 'World' assert r2.json['headers']['Hello'] == 'World'
assert r2.json['headers']['Cookie'] == 'hello=world' assert r2.json['headers']['Cookie'] == 'hello=world'
assert 'Basic ' in r2.json['headers']['Authorization'] assert 'Basic ' in r2.json['headers']['Authorization']
def test_session_update(self): def test_session_update(self, httpbin):
self.start_session(httpbin)
# Get a response to a request from the original session. # Get a response to a request from the original session.
r2 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env())
assert HTTP_OK in r2 assert HTTP_OK in r2
# Make a request modifying the session data. # Make a request modifying the session data.
r3 = http('--follow', '--session=test', '--auth=username:password2', r3 = http('--follow', '--session=test', '--auth=username:password2',
'GET', httpbin('/cookies/set?hello=world2'), 'Hello:World2', 'GET', httpbin.url + '/cookies/set?hello=world2', 'Hello:World2',
env=self.env()) env=self.env())
assert HTTP_OK in r3 assert HTTP_OK in r3
# Get a response to a request from the updated session. # Get a response to a request from the updated session.
r4 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) r4 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env())
assert HTTP_OK in r4 assert HTTP_OK in r4
assert r4.json['headers']['Hello'] == 'World2' assert r4.json['headers']['Hello'] == 'World2'
assert r4.json['headers']['Cookie'] == 'hello=world2' assert r4.json['headers']['Cookie'] == 'hello=world2'
assert (r2.json['headers']['Authorization'] != assert (r2.json['headers']['Authorization'] !=
r4.json['headers']['Authorization']) r4.json['headers']['Authorization'])
def test_session_read_only(self): def test_session_read_only(self, httpbin):
self.start_session(httpbin)
# Get a response from the original session. # Get a response from the original session.
r2 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env())
assert HTTP_OK in r2 assert HTTP_OK in r2
# Make a request modifying the session data but # Make a request modifying the session data but
# with --session-read-only. # with --session-read-only.
r3 = http('--follow', '--session-read-only=test', r3 = http('--follow', '--session-read-only=test',
'--auth=username:password2', 'GET', '--auth=username:password2', 'GET',
httpbin('/cookies/set?hello=world2'), 'Hello:World2', httpbin.url + '/cookies/set?hello=world2', 'Hello:World2',
env=self.env()) env=self.env())
assert HTTP_OK in r3 assert HTTP_OK in r3
# Get a response from the updated session. # Get a response from the updated session.
r4 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) r4 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env())
assert HTTP_OK in r4 assert HTTP_OK in r4
# Origin can differ on Travis. # Origin can differ on Travis.
del r2.json['origin'], r4.json['origin'] del r2.json['origin'], r4.json['origin']
# Different for each request. # Different for each request.
del r2.json['headers']['X-Request-Id']
del r4.json['headers']['X-Request-Id']
# Should be the same as before r3. # Should be the same as before r3.
assert r2.json == r4.json assert r2.json == r4.json
@ -102,51 +107,58 @@ class TestSessionFlow(SessionTestBase):
class TestSession(SessionTestBase): class TestSession(SessionTestBase):
"""Stand-alone session tests.""" """Stand-alone session tests."""
def test_session_ignored_header_prefixes(self): def test_session_ignored_header_prefixes(self, httpbin):
r1 = http('--session=test', 'GET', httpbin('/get'), self.start_session(httpbin)
r1 = http('--session=test', 'GET', httpbin.url + '/get',
'Content-Type: text/plain', 'Content-Type: text/plain',
'If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT', 'If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT',
env=self.env()) env=self.env())
assert HTTP_OK in r1 assert HTTP_OK in r1
r2 = http('--session=test', 'GET', httpbin('/get'), env=self.env()) r2 = http('--session=test', 'GET', httpbin.url + '/get', env=self.env())
assert HTTP_OK in r2 assert HTTP_OK in r2
assert 'Content-Type' not in r2.json['headers'] assert no_content_type(r2.json['headers'])
assert 'If-Unmodified-Since' not in r2.json['headers'] assert 'If-Unmodified-Since' not in r2.json['headers']
def test_session_by_path(self): def test_session_by_path(self, httpbin):
self.start_session(httpbin)
session_path = os.path.join(self.config_dir, 'session-by-path.json') session_path = os.path.join(self.config_dir, 'session-by-path.json')
r1 = http('--session=' + session_path, 'GET', httpbin('/get'), r1 = http('--session=' + session_path, 'GET', httpbin.url + '/get',
'Foo:Bar', env=self.env()) 'Foo:Bar', env=self.env())
assert HTTP_OK in r1 assert HTTP_OK in r1
r2 = http('--session=' + session_path, 'GET', httpbin('/get'), r2 = http('--session=' + session_path, 'GET', httpbin.url + '/get',
env=self.env()) env=self.env())
assert HTTP_OK in r2 assert HTTP_OK in r2
assert r2.json['headers']['Foo'] == 'Bar' assert r2.json['headers']['Foo'] == 'Bar'
def test_session_unicode(self): def test_session_unicode(self, httpbin):
r1 = http('--session=test', '--auth', u'test:' + UNICODE, self.start_session(httpbin)
'GET', httpbin('/get'),
u'Test:%s' % UNICODE, r1 = http('--session=test', u'--auth=test:' + UNICODE,
'GET', httpbin.url + '/get', u'Test:%s' % UNICODE,
env=self.env()) env=self.env())
assert HTTP_OK in r1 assert HTTP_OK in r1
r2 = http('--session=test', '--verbose', 'GET', r2 = http('--session=test', '--verbose', 'GET',
httpbin('/get'), env=self.env()) httpbin.url + '/get', env=self.env())
assert HTTP_OK in r2 assert HTTP_OK in r2
# FIXME: Authorization *sometimes* is not present on Python3
assert (r2.json['headers']['Authorization'] assert (r2.json['headers']['Authorization']
== HTTPBasicAuth.make_header(u'test', UNICODE)) == HTTPBasicAuth.make_header(u'test', UNICODE))
# httpbin doesn't interpret utf8 headers # httpbin doesn't interpret utf8 headers
assert UNICODE in r2 assert UNICODE in r2
def test_session_default_header_value_overwritten(self): def test_session_default_header_value_overwritten(self, httpbin):
self.start_session(httpbin)
# https://github.com/jakubroztocil/httpie/issues/180 # https://github.com/jakubroztocil/httpie/issues/180
r1 = http('--session=test', httpbin('/headers'), 'User-Agent:custom', r1 = http('--session=test',
httpbin.url + '/headers', 'User-Agent:custom',
env=self.env()) env=self.env())
assert HTTP_OK in r1 assert HTTP_OK in r1
assert r1.json['headers']['User-Agent'] == 'custom' assert r1.json['headers']['User-Agent'] == 'custom'
r2 = http('--session=test', httpbin('/headers'), env=self.env()) r2 = http('--session=test', httpbin.url + '/headers', env=self.env())
assert HTTP_OK in r2 assert HTTP_OK in r2
assert r2.json['headers']['User-Agent'] == 'custom' assert r2.json['headers']['User-Agent'] == 'custom'

View File

@ -2,7 +2,7 @@ import pytest
from httpie.compat import is_windows from httpie.compat import is_windows
from httpie.output.streams import BINARY_SUPPRESSED_NOTICE from httpie.output.streams import BINARY_SUPPRESSED_NOTICE
from utils import http, httpbin, TestEnvironment from utils import http, TestEnvironment
from fixtures import BIN_FILE_CONTENT, BIN_FILE_PATH from fixtures import BIN_FILE_CONTENT, BIN_FILE_PATH
@ -11,26 +11,26 @@ class TestStream:
@pytest.mark.skipif(is_windows, @pytest.mark.skipif(is_windows,
reason='Pretty redirect not supported under Windows') reason='Pretty redirect not supported under Windows')
def test_pretty_redirected_stream(self): def test_pretty_redirected_stream(self, httpbin):
"""Test that --stream works with prettified redirected output.""" """Test that --stream works with prettified redirected output."""
with open(BIN_FILE_PATH, 'rb') as f: with open(BIN_FILE_PATH, 'rb') as f:
env = TestEnvironment(colors=256, stdin=f, env = TestEnvironment(colors=256, stdin=f,
stdin_isatty=False, stdin_isatty=False,
stdout_isatty=False) stdout_isatty=False)
r = http('--verbose', '--pretty=all', '--stream', 'GET', r = http('--verbose', '--pretty=all', '--stream', 'GET',
httpbin('/get'), env=env) httpbin.url + '/get', env=env)
assert BINARY_SUPPRESSED_NOTICE.decode() in r assert BINARY_SUPPRESSED_NOTICE.decode() in r
def test_encoded_stream(self): def test_encoded_stream(self, httpbin):
"""Test that --stream works with non-prettified """Test that --stream works with non-prettified
redirected terminal output.""" redirected terminal output."""
with open(BIN_FILE_PATH, 'rb') as f: with open(BIN_FILE_PATH, 'rb') as f:
env = TestEnvironment(stdin=f, stdin_isatty=False) env = TestEnvironment(stdin=f, stdin_isatty=False)
r = http('--pretty=none', '--stream', '--verbose', 'GET', r = http('--pretty=none', '--stream', '--verbose', 'GET',
httpbin('/get'), env=env) httpbin.url + '/get', env=env)
assert BINARY_SUPPRESSED_NOTICE.decode() in r assert BINARY_SUPPRESSED_NOTICE.decode() in r
def test_redirected_stream(self): def test_redirected_stream(self, httpbin):
"""Test that --stream works with non-prettified """Test that --stream works with non-prettified
redirected terminal output.""" redirected terminal output."""
with open(BIN_FILE_PATH, 'rb') as f: with open(BIN_FILE_PATH, 'rb') as f:
@ -38,5 +38,5 @@ class TestStream:
stdin_isatty=False, stdin_isatty=False,
stdin=f) stdin=f)
r = http('--pretty=none', '--stream', '--verbose', 'GET', r = http('--pretty=none', '--stream', '--verbose', 'GET',
httpbin('/get'), env=env) httpbin.url + '/get', env=env)
assert BIN_FILE_CONTENT in r assert BIN_FILE_CONTENT in r

View File

@ -3,85 +3,85 @@
Various unicode handling related tests. Various unicode handling related tests.
""" """
from utils import http, httpbin, HTTP_OK from utils import http, HTTP_OK
from fixtures import UNICODE from fixtures import UNICODE
class TestUnicode: class TestUnicode:
def test_unicode_headers(self): def test_unicode_headers(self, httpbin):
# httpbin doesn't interpret utf8 headers # httpbin doesn't interpret utf8 headers
r = http(httpbin('/headers'), u'Test:%s' % UNICODE) r = http(httpbin.url + '/headers', u'Test:%s' % UNICODE)
assert HTTP_OK in r assert HTTP_OK in r
def test_unicode_headers_verbose(self): def test_unicode_headers_verbose(self, httpbin):
# httpbin doesn't interpret utf8 headers # httpbin doesn't interpret utf8 headers
r = http('--verbose', httpbin('/headers'), u'Test:%s' % UNICODE) r = http('--verbose', httpbin.url + '/headers', u'Test:%s' % UNICODE)
assert HTTP_OK in r assert HTTP_OK in r
assert UNICODE in r assert UNICODE in r
def test_unicode_form_item(self): def test_unicode_form_item(self, httpbin):
r = http('--form', 'POST', httpbin('/post'), u'test=%s' % UNICODE) r = http('--form', 'POST', httpbin.url + '/post', u'test=%s' % UNICODE)
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['form'] == {'test': UNICODE} assert r.json['form'] == {'test': UNICODE}
def test_unicode_form_item_verbose(self): def test_unicode_form_item_verbose(self, httpbin):
r = http('--verbose', '--form', r = http('--verbose', '--form',
'POST', httpbin('/post'), u'test=%s' % UNICODE) 'POST', httpbin.url + '/post', u'test=%s' % UNICODE)
assert HTTP_OK in r assert HTTP_OK in r
assert UNICODE in r assert UNICODE in r
def test_unicode_json_item(self): def test_unicode_json_item(self, httpbin):
r = http('--json', 'POST', httpbin('/post'), u'test=%s' % UNICODE) r = http('--json', 'POST', httpbin.url + '/post', u'test=%s' % UNICODE)
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['json'] == {'test': UNICODE} assert r.json['json'] == {'test': UNICODE}
def test_unicode_json_item_verbose(self): def test_unicode_json_item_verbose(self, httpbin):
r = http('--verbose', '--json', r = http('--verbose', '--json',
'POST', httpbin('/post'), u'test=%s' % UNICODE) 'POST', httpbin.url + '/post', u'test=%s' % UNICODE)
assert HTTP_OK in r assert HTTP_OK in r
assert UNICODE in r assert UNICODE in r
def test_unicode_raw_json_item(self): def test_unicode_raw_json_item(self, httpbin):
r = http('--json', 'POST', httpbin('/post'), r = http('--json', 'POST', httpbin.url + '/post',
u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE)) u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE))
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} assert r.json['json'] == {'test': {UNICODE: [UNICODE]}}
def test_unicode_raw_json_item_verbose(self): def test_unicode_raw_json_item_verbose(self, httpbin):
r = http('--json', 'POST', httpbin('/post'), r = http('--json', 'POST', httpbin.url + '/post',
u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE)) u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE))
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} assert r.json['json'] == {'test': {UNICODE: [UNICODE]}}
def test_unicode_url_query_arg_item(self): def test_unicode_url_query_arg_item(self, httpbin):
r = http(httpbin('/get'), u'test==%s' % UNICODE) r = http(httpbin.url + '/get', u'test==%s' % UNICODE)
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['args'] == {'test': UNICODE}, r assert r.json['args'] == {'test': UNICODE}, r
def test_unicode_url_query_arg_item_verbose(self): def test_unicode_url_query_arg_item_verbose(self, httpbin):
r = http('--verbose', httpbin('/get'), u'test==%s' % UNICODE) r = http('--verbose', httpbin.url + '/get', u'test==%s' % UNICODE)
assert HTTP_OK in r assert HTTP_OK in r
assert UNICODE in r assert UNICODE in r
def test_unicode_url(self): def test_unicode_url(self, httpbin):
r = http(httpbin(u'/get?test=' + UNICODE)) r = http(httpbin.url + u'/get?test=' + UNICODE)
assert HTTP_OK in r assert HTTP_OK in r
assert r.json['args'] == {'test': UNICODE} assert r.json['args'] == {'test': UNICODE}
# def test_unicode_url_verbose(self): # def test_unicode_url_verbose(self):
# r = http(httpbin('--verbose', u'/get?test=' + UNICODE)) # r = http(httpbin.url + '--verbose', u'/get?test=' + UNICODE)
# assert HTTP_OK in r # assert HTTP_OK in r
def test_unicode_basic_auth(self): def test_unicode_basic_auth(self, httpbin):
# it doesn't really authenticate us because httpbin # it doesn't really authenticate us because httpbin
# doesn't interpret the utf8-encoded auth # doesn't interpret the utf8-encoded auth
http('--verbose', '--auth', u'test:%s' % UNICODE, http('--verbose', '--auth', u'test:%s' % UNICODE,
httpbin(u'/basic-auth/test/' + UNICODE)) httpbin.url + u'/basic-auth/test/' + UNICODE)
def test_unicode_digest_auth(self): def test_unicode_digest_auth(self, httpbin):
# it doesn't really authenticate us because httpbin # it doesn't really authenticate us because httpbin
# doesn't interpret the utf8-encoded auth # doesn't interpret the utf8-encoded auth
http('--auth-type=digest', http('--auth-type=digest',
'--auth', u'test:%s' % UNICODE, '--auth', u'test:%s' % UNICODE,
httpbin(u'/digest-auth/auth/test/' + UNICODE)) httpbin.url + u'/digest-auth/auth/test/' + UNICODE)

View File

@ -3,23 +3,25 @@ import os
import pytest import pytest
from httpie.input import ParseError from httpie.input import ParseError
from utils import TestEnvironment, http, httpbin, HTTP_OK from utils import TestEnvironment, http, HTTP_OK
from fixtures import FILE_PATH_ARG, FILE_PATH, FILE_CONTENT from fixtures import FILE_PATH_ARG, FILE_PATH, FILE_CONTENT
class TestMultipartFormDataFileUpload: class TestMultipartFormDataFileUpload:
def test_non_existent_file_raises_parse_error(self):
with pytest.raises(ParseError):
http('--form', 'POST', httpbin('/post'), 'foo@/__does_not_exist__')
def test_upload_ok(self): def test_non_existent_file_raises_parse_error(self, httpbin):
r = http('--form', '--verbose', 'POST', httpbin('/post'), with pytest.raises(ParseError):
http('--form',
'POST', httpbin.url + '/post', 'foo@/__does_not_exist__')
def test_upload_ok(self, httpbin):
r = http('--form', '--verbose', 'POST', httpbin.url + '/post',
'test-file@%s' % FILE_PATH_ARG, 'foo=bar') 'test-file@%s' % FILE_PATH_ARG, 'foo=bar')
assert HTTP_OK in r assert HTTP_OK in r
assert 'Content-Disposition: form-data; name="foo"' in r assert 'Content-Disposition: form-data; name="foo"' in r
assert 'Content-Disposition: form-data; name="test-file";' \ assert 'Content-Disposition: form-data; name="test-file";' \
' filename="%s"' % os.path.basename(FILE_PATH) in r ' filename="%s"' % os.path.basename(FILE_PATH) in r
assert r.count(FILE_CONTENT) == 2 assert FILE_CONTENT in r
assert '"foo": "bar"' in r assert '"foo": "bar"' in r
@ -29,27 +31,32 @@ class TestRequestBodyFromFilePath:
""" """
def test_request_body_from_file_by_path(self): def test_request_body_from_file_by_path(self, httpbin):
r = http('--verbose', 'POST', httpbin('/post'), '@' + FILE_PATH_ARG) r = http('--verbose',
'POST', httpbin.url + '/post', '@' + FILE_PATH_ARG)
assert HTTP_OK in r assert HTTP_OK in r
assert FILE_CONTENT in r, r assert FILE_CONTENT in r, r
assert '"Content-Type": "text/plain"' in r assert '"Content-Type": "text/plain"' in r
def test_request_body_from_file_by_path_with_explicit_content_type(self): def test_request_body_from_file_by_path_with_explicit_content_type(
r = http('POST', httpbin('/post'), '@' + FILE_PATH_ARG, self, httpbin):
'Content-Type:x-foo/bar') r = http('--verbose',
'POST', httpbin.url + '/post', '@' + FILE_PATH_ARG,
'Content-Type:text/plain; charset=utf8')
assert HTTP_OK in r assert HTTP_OK in r
assert FILE_CONTENT in r assert FILE_CONTENT in r
assert '"Content-Type": "x-foo/bar"' in r assert 'Content-Type: text/plain; charset=utf8' in r
def test_request_body_from_file_by_path_no_field_name_allowed(self): def test_request_body_from_file_by_path_no_field_name_allowed(
self, httpbin):
env = TestEnvironment(stdin_isatty=True) env = TestEnvironment(stdin_isatty=True)
r = http('POST', httpbin('/post'), 'field-name@' + FILE_PATH_ARG, r = http('POST', httpbin.url + '/post', 'field-name@' + FILE_PATH_ARG,
env=env, error_exit_ok=True) env=env, error_exit_ok=True)
assert 'perhaps you meant --form?' in r.stderr assert 'perhaps you meant --form?' in r.stderr
def test_request_body_from_file_by_path_no_data_items_allowed(self): def test_request_body_from_file_by_path_no_data_items_allowed(
self, httpbin):
env = TestEnvironment(stdin_isatty=False) env = TestEnvironment(stdin_isatty=False)
r = http('POST', httpbin('/post'), '@' + FILE_PATH_ARG, 'foo=bar', r = http('POST', httpbin.url + '/post', '@' + FILE_PATH_ARG, 'foo=bar',
env=env, error_exit_ok=True) env=env, error_exit_ok=True)
assert 'cannot be mixed' in r.stderr assert 'cannot be mixed' in r.stderr

View File

@ -4,7 +4,7 @@ import tempfile
import pytest import pytest
from httpie.context import Environment from httpie.context import Environment
from utils import TestEnvironment, http, httpbin from utils import TestEnvironment, http
from httpie.compat import is_windows from httpie.compat import is_windows
@ -13,17 +13,17 @@ class TestWindowsOnly:
@pytest.mark.skipif(True, @pytest.mark.skipif(True,
reason='this test for some reason kills the process') reason='this test for some reason kills the process')
def test_windows_colorized_output(self): def test_windows_colorized_output(self, httpbin):
# Spits out the colorized output. # Spits out the colorized output.
http(httpbin('/get'), env=Environment()) http(httpbin.url + '/get', env=Environment())
class TestFakeWindows: class TestFakeWindows:
def test_output_file_pretty_not_allowed_on_windows(self): def test_output_file_pretty_not_allowed_on_windows(self, httpbin):
env = TestEnvironment(is_windows=True) env = TestEnvironment(is_windows=True)
output_file = os.path.join( output_file = os.path.join(
tempfile.gettempdir(), '__httpie_test_output__') tempfile.gettempdir(), '__httpie_test_output__')
r = http('--output', output_file, r = http('--output', output_file,
'--pretty=all', 'GET', httpbin('/get'), '--pretty=all', 'GET', httpbin.url + '/get',
env=env, error_exit_ok=True) env=env, error_exit_ok=True)
assert 'Only terminal output can be colorized on Windows' in r.stderr assert 'Only terminal output can be colorized on Windows' in r.stderr

View File

@ -20,7 +20,7 @@ TESTS_ROOT = os.path.abspath(os.path.dirname(__file__))
CRLF = '\r\n' CRLF = '\r\n'
COLOR = '\x1b[' COLOR = '\x1b['
HTTP_OK = 'HTTP/1.1 200' HTTP_OK = '200 OK'
HTTP_OK_COLOR = ( HTTP_OK_COLOR = (
'HTTP\x1b[39m\x1b[38;5;245m/\x1b[39m\x1b' 'HTTP\x1b[39m\x1b[38;5;245m/\x1b[39m\x1b'
'[38;5;37m1.1\x1b[39m\x1b[38;5;245m \x1b[39m\x1b[38;5;37m200' '[38;5;37m1.1\x1b[39m\x1b[38;5;245m \x1b[39m\x1b[38;5;37m200'
@ -28,22 +28,19 @@ HTTP_OK_COLOR = (
) )
def httpbin(path, auth=None, def no_content_type(headers):
base=os.environ.get('HTTPBIN_URL', 'http://httpbin.org')): return (
""" 'Content-Type' not in headers
Return a fully-qualified httpbin URL for `path`. # We need to do also this because of this issue:
# <https://github.com/kevin1024/pytest-httpbin/issues/5>
# TODO: remove this function once the issue is if fixed
or headers['Content-Type'] == 'text/plain'
)
>>> httpbin('/get')
'http://httpbin.org/get'
>>> httpbin('/get', auth='user:password') def add_auth(url, auth):
'http://user:password@httpbin.org/get' proto, rest = url.split('://', 1)
return proto + '://' + auth + '@' + rest
"""
if auth:
proto, rest = base.split('://', 1)
base = proto + '://' + auth + '@' + rest
return base.rstrip('/') + path
class TestEnvironment(Environment): class TestEnvironment(Environment):
@ -104,7 +101,7 @@ def http(*args, **kwargs):
$ http --auth=user:password GET httpbin.org/basic-auth/user/password $ http --auth=user:password GET httpbin.org/basic-auth/user/password
>>> r = http('-a', 'user:pw', httpbin('/basic-auth/user/pw')) >>> r = http('-a', 'user:pw', 'httpbin.org/basic-auth/user/pw')
>>> type(r) == StrCLIResponse >>> type(r) == StrCLIResponse
True True
>>> r.exit_status >>> r.exit_status

View File

@ -13,6 +13,7 @@ envlist = py26, py27, py34, pypy
deps = deps =
pytest pytest
pytest-xdist pytest-xdist
pytest-httpbin
commands = commands =
py.test -n 8 --doctest-modules --basetemp={envtmpdir} {posargs:./tests ./httpie} py.test -n 8 --doctest-modules --basetemp={envtmpdir} {posargs:./tests ./httpie}