You've already forked httpie-cli
							
							
				mirror of
				https://github.com/httpie/cli.git
				synced 2025-10-30 23:47:52 +02:00 
			
		
		
		
	Run tests against local httpbin instance via pytest-httpbin.
This commit is contained in:
		| @@ -105,8 +105,13 @@ class HTTPRequest(HTTPMessage): | ||||
|         if 'Host' not in self._orig.headers: | ||||
|             headers['Host'] = url.netloc.split('@')[-1] | ||||
|  | ||||
|         headers = ['%s: %s' % (name, value) | ||||
|                    for name, value in headers.items()] | ||||
|         headers = [ | ||||
|             '%s: %s' % ( | ||||
|                 name, | ||||
|                 value if isinstance(value, str) else value.decode('utf8') | ||||
|             ) | ||||
|             for name, value in headers.items() | ||||
|         ] | ||||
|  | ||||
|         headers.insert(0, request_line) | ||||
|         headers = '\r\n'.join(headers).strip() | ||||
|   | ||||
| @@ -2,4 +2,5 @@ tox | ||||
| pytest | ||||
| pytest-xdist | ||||
| pytest-cov | ||||
| pytest-httpbin | ||||
| docutils | ||||
|   | ||||
							
								
								
									
										1
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								setup.py
									
									
									
									
									
								
							| @@ -26,6 +26,7 @@ class PyTest(TestCommand): | ||||
|  | ||||
| tests_require = [ | ||||
|     'pytest', | ||||
|     'pytest-httpbin', | ||||
| ] | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -2,42 +2,45 @@ | ||||
| import requests | ||||
| import pytest | ||||
|  | ||||
| from utils import http, httpbin, HTTP_OK | ||||
| from utils import http, add_auth, HTTP_OK | ||||
| import httpie.input | ||||
|  | ||||
|  | ||||
| class TestAuth: | ||||
|     def test_basic_auth(self): | ||||
|     def test_basic_auth(self, httpbin): | ||||
|         r = http('--auth=user:password', | ||||
|                  'GET', httpbin('/basic-auth/user/password')) | ||||
|                  'GET', httpbin.url + '/basic-auth/user/password') | ||||
|         assert HTTP_OK in r | ||||
|         assert r.json == {'authenticated': True, 'user': 'user'} | ||||
|  | ||||
|     @pytest.mark.skipif( | ||||
|         requests.__version__ == '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', | ||||
|                  'GET', httpbin('/digest-auth/auth/user/password')) | ||||
|                  'GET', httpbin.url + '/digest-auth/auth/user/password') | ||||
|         assert HTTP_OK in r | ||||
|         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' | ||||
|         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 r.json == {'authenticated': True, 'user': 'user'} | ||||
|  | ||||
|     def test_credentials_in_url(self): | ||||
|         url = httpbin('/basic-auth/user/password', auth='user:password') | ||||
|     def test_credentials_in_url(self, httpbin): | ||||
|         url = add_auth(httpbin.url + '/basic-auth/user/password', | ||||
|                        auth='user:password') | ||||
|         r = http('GET', url) | ||||
|         assert HTTP_OK in r | ||||
|         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, | ||||
|          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) | ||||
|         assert HTTP_OK in r | ||||
|         assert r.json == {'authenticated': True, 'user': 'user'} | ||||
|   | ||||
| @@ -1,30 +1,30 @@ | ||||
| """Tests for dealing with binary request and response data.""" | ||||
| from httpie.compat import urlopen | ||||
| 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 | ||||
|  | ||||
|  | ||||
| class TestBinaryRequestData: | ||||
|     def test_binary_stdin(self): | ||||
|     def test_binary_stdin(self, httpbin): | ||||
|         with open(BIN_FILE_PATH, 'rb') as stdin: | ||||
|             env = TestEnvironment( | ||||
|                 stdin=stdin, | ||||
|                 stdin_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 | ||||
|  | ||||
|     def test_binary_file_path(self): | ||||
|     def test_binary_file_path(self, httpbin): | ||||
|         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, ) | ||||
|         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) | ||||
|         r = http('--print=B', '--form', 'POST', httpbin('/post'), | ||||
|         r = http('--print=B', '--form', 'POST', httpbin.url + '/post', | ||||
|                  'test@' + BIN_FILE_PATH_ARG, env=env) | ||||
|         assert bytes(BIN_FILE_CONTENT) in bytes(r) | ||||
|  | ||||
|   | ||||
| @@ -9,7 +9,7 @@ from httpie import input | ||||
| from httpie.input import KeyValue, KeyValueArgType | ||||
| from httpie import ExitStatus | ||||
| from httpie.cli import parser | ||||
| from utils import TestEnvironment, http, httpbin, HTTP_OK | ||||
| from utils import TestEnvironment, http, HTTP_OK | ||||
| from fixtures import ( | ||||
|     FILE_PATH_ARG, JSON_FILE_PATH_ARG, | ||||
|     JSON_FILE_CONTENT, FILE_CONTENT, FILE_PATH | ||||
| @@ -93,27 +93,28 @@ class TestItemParsing: | ||||
|  | ||||
|  | ||||
| class TestQuerystring: | ||||
|     def test_query_string_params_in_url(self): | ||||
|         r = http('--print=Hhb', 'GET', httpbin('/get?a=1&b=2')) | ||||
|     def test_query_string_params_in_url(self, httpbin): | ||||
|         r = http('--print=Hhb', 'GET', httpbin.url + '/get?a=1&b=2') | ||||
|         path = '/get?a=1&b=2' | ||||
|         url = httpbin(path) | ||||
|         url = httpbin.url + path | ||||
|         assert HTTP_OK in r | ||||
|         assert 'GET %s HTTP/1.1' % path in r | ||||
|         assert '"url": "%s"' % url in r | ||||
|  | ||||
|     def test_query_string_params_items(self): | ||||
|         r = http('--print=Hhb', 'GET', httpbin('/get'), 'a==1', 'b==2') | ||||
|         path = '/get?a=1&b=2' | ||||
|         url = httpbin(path) | ||||
|     def test_query_string_params_items(self, httpbin): | ||||
|         r = http('--print=Hhb', 'GET', httpbin.url + '/get', 'a==1') | ||||
|         path = '/get?a=1' | ||||
|         url = httpbin.url + path | ||||
|         assert HTTP_OK in r | ||||
|         assert 'GET %s HTTP/1.1' % path in r | ||||
|         assert '"url": "%s"' % url in r | ||||
|  | ||||
|     def test_query_string_params_in_url_and_items_with_duplicates(self): | ||||
|         r = http('--print=Hhb', 'GET', httpbin('/get?a=1&a=1'), | ||||
|                  'a==1', 'a==1', 'b==2') | ||||
|         path = '/get?a=1&a=1&a=1&a=1&b=2' | ||||
|         url = httpbin(path) | ||||
|     def test_query_string_params_in_url_and_items_with_duplicates(self, | ||||
|                                                                   httpbin): | ||||
|         r = http('--print=Hhb', 'GET', | ||||
|                  httpbin.url + '/get?a=1&a=1', 'a==1', 'a==1') | ||||
|         path = '/get?a=1&a=1&a=1&a=1' | ||||
|         url = httpbin.url + path | ||||
|         assert HTTP_OK in r | ||||
|         assert 'GET %s HTTP/1.1' % path in r | ||||
|         assert '"url": "%s"' % url in r | ||||
| @@ -257,12 +258,13 @@ class TestArgumentParser: | ||||
|  | ||||
|  | ||||
| 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 | ||||
|  | ||||
|     def test_invalid_no_options(self): | ||||
|         r = http('--no-war', 'GET', httpbin('/get'), | ||||
|     def test_invalid_no_options(self, httpbin): | ||||
|         r = http('--no-war', 'GET', httpbin.url + '/get', | ||||
|                  error_exit_ok=True) | ||||
|         assert r.exit_status == 1 | ||||
|         assert 'unrecognized arguments: --no-war' in r.stderr | ||||
| @@ -270,16 +272,18 @@ class TestNoOptions: | ||||
|  | ||||
|  | ||||
| class TestIgnoreStdin: | ||||
|     def test_ignore_stdin(self): | ||||
|  | ||||
|     def test_ignore_stdin(self, httpbin): | ||||
|         with open(FILE_PATH) as f: | ||||
|             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 'GET /get HTTP' in r, "Don't default to POST." | ||||
|         assert FILE_CONTENT not in r, "Don't send stdin data." | ||||
|  | ||||
|     def test_ignore_stdin_cannot_prompt_password(self): | ||||
|         r = http('--ignore-stdin', '--auth=no-password', httpbin('/get'), | ||||
|     def test_ignore_stdin_cannot_prompt_password(self, httpbin): | ||||
|         r = http('--ignore-stdin', '--auth=no-password', httpbin.url + '/get', | ||||
|                  error_exit_ok=True) | ||||
|         assert r.exit_status == ExitStatus.ERROR | ||||
|         assert 'because --ignore-stdin' in r.stderr | ||||
|   | ||||
| @@ -2,34 +2,34 @@ | ||||
| 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 | ||||
|  | ||||
|  | ||||
| class TestImplicitHTTPMethod: | ||||
|     def test_implicit_GET(self): | ||||
|         r = http(httpbin('/get')) | ||||
|     def test_implicit_GET(self, httpbin): | ||||
|         r = http(httpbin.url + '/get') | ||||
|         assert HTTP_OK in r | ||||
|  | ||||
|     def test_implicit_GET_with_headers(self): | ||||
|         r = http(httpbin('/headers'), 'Foo:bar') | ||||
|     def test_implicit_GET_with_headers(self, httpbin): | ||||
|         r = http(httpbin.url + '/headers', 'Foo:bar') | ||||
|         assert HTTP_OK in r | ||||
|         assert r.json['headers']['Foo'] == 'bar' | ||||
|  | ||||
|     def test_implicit_POST_json(self): | ||||
|         r = http(httpbin('/post'), 'hello=world') | ||||
|     def test_implicit_POST_json(self, httpbin): | ||||
|         r = http(httpbin.url + '/post', 'hello=world') | ||||
|         assert HTTP_OK in r | ||||
|         assert r.json['json'] == {'hello': 'world'} | ||||
|  | ||||
|     def test_implicit_POST_form(self): | ||||
|         r = http('--form', httpbin('/post'), 'foo=bar') | ||||
|     def test_implicit_POST_form(self, httpbin): | ||||
|         r = http('--form', httpbin.url + '/post', 'foo=bar') | ||||
|         assert HTTP_OK in r | ||||
|         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: | ||||
|             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 | ||||
|  | ||||
|  | ||||
| @@ -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 | ||||
|         r = http('GET', httpbin('/headers')) | ||||
|         r = http('GET', httpbin.url + '/headers') | ||||
|         assert HTTP_OK in r | ||||
|         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. | ||||
|         r = http('POST', httpbin('/post')) | ||||
|         r = http('POST', httpbin.url + '/post') | ||||
|         assert HTTP_OK in r | ||||
|         assert '"Accept": "*/*"' in r | ||||
|         assert '"Content-Type": "application/json' not in r | ||||
|  | ||||
|     def test_POST_with_data_auto_JSON_headers(self): | ||||
|         r = http('POST', httpbin('/post'), 'a=b') | ||||
|     def test_POST_with_data_auto_JSON_headers(self, httpbin): | ||||
|         r = http('POST', httpbin.url + '/post', 'a=b') | ||||
|         assert HTTP_OK in r | ||||
|         assert '"Accept": "application/json"' 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. | ||||
|         r = http('POST', httpbin('/post'), 'a=b') | ||||
|         r = http('POST', httpbin.url + '/post', 'a=b') | ||||
|         assert HTTP_OK in r | ||||
|         assert '"Accept": "application/json"' in r, r | ||||
|         assert '"Content-Type": "application/json; charset=utf-8' in r | ||||
|  | ||||
|     def test_POST_explicit_JSON_auto_JSON_accept(self): | ||||
|         r = http('--json', 'POST', httpbin('/post')) | ||||
|     def test_POST_explicit_JSON_auto_JSON_accept(self, httpbin): | ||||
|         r = http('--json', 'POST', httpbin.url + '/post') | ||||
|         assert HTTP_OK in r | ||||
|         assert r.json['headers']['Accept'] == 'application/json' | ||||
|         # Make sure Content-Type gets set even with no data. | ||||
|         # https://github.com/jakubroztocil/httpie/issues/137 | ||||
|         assert 'application/json' in r.json['headers']['Content-Type'] | ||||
|  | ||||
|     def test_GET_explicit_JSON_explicit_headers(self): | ||||
|         r = http('--json', 'GET', httpbin('/headers'), | ||||
|     def test_GET_explicit_JSON_explicit_headers(self, httpbin): | ||||
|         r = http('--json', 'GET', httpbin.url + '/headers', | ||||
|                  'Accept:application/xml', | ||||
|                  'Content-Type:application/xml') | ||||
|         assert HTTP_OK in r | ||||
|         assert '"Accept": "application/xml"' in r | ||||
|         assert '"Content-Type": "application/xml"' in r | ||||
|  | ||||
|     def test_POST_form_auto_Content_Type(self): | ||||
|         r = http('--form', 'POST', httpbin('/post')) | ||||
|     def test_POST_form_auto_Content_Type(self, httpbin): | ||||
|         r = http('--form', 'POST', httpbin.url + '/post') | ||||
|         assert HTTP_OK in r | ||||
|         assert '"Content-Type": "application/x-www-form-urlencoded' in r | ||||
|  | ||||
|     def test_POST_form_Content_Type_override(self): | ||||
|         r = http('--form', 'POST', httpbin('/post'), | ||||
|     def test_POST_form_Content_Type_override(self, httpbin): | ||||
|         r = http('--form', 'POST', httpbin.url + '/post', | ||||
|                  'Content-Type:application/xml') | ||||
|         assert HTTP_OK 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) | ||||
|         r = http('GET', httpbin('/get'), env=env) | ||||
|         r = http('GET', httpbin.url + '/get', env=env) | ||||
|         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) | ||||
|         r = http('--print=h', 'GET', httpbin('/get'), env=env) | ||||
|         r = http('--print=h', 'GET', httpbin.url + '/get', env=env) | ||||
|         assert HTTP_OK in r | ||||
|   | ||||
| @@ -9,7 +9,7 @@ from httpie.downloads import ( | ||||
|     parse_content_range, filename_from_content_disposition, filename_from_url, | ||||
|     get_unique_filename, ContentRangeError, Download, | ||||
| ) | ||||
| from utils import httpbin, http, TestEnvironment | ||||
| from utils import http, TestEnvironment | ||||
|  | ||||
|  | ||||
| class Response(object): | ||||
| @@ -94,8 +94,8 @@ class TestDownloadUtils: | ||||
| class TestDownloads: | ||||
|     # TODO: more tests | ||||
|  | ||||
|     def test_actual_download(self): | ||||
|         url = httpbin('/robots.txt') | ||||
|     def test_actual_download(self, httpbin): | ||||
|         url = httpbin.url + '/robots.txt' | ||||
|         body = urlopen(url).read().decode() | ||||
|         env = TestEnvironment(stdin_isatty=True, stdout_isatty=False) | ||||
|         r = http('--download', url, env=env) | ||||
| @@ -104,11 +104,11 @@ class TestDownloads: | ||||
|         assert 'Done' in r.stderr | ||||
|         assert body == r | ||||
|  | ||||
|     def test_download_with_Content_Length(self): | ||||
|     def test_download_with_Content_Length(self, httpbin): | ||||
|         devnull = open(os.devnull, 'w') | ||||
|         download = Download(output_file=devnull, progress_file=devnull) | ||||
|         download.start(Response( | ||||
|             url=httpbin('/'), | ||||
|             url=httpbin.url + '/', | ||||
|             headers={'Content-Length': 10} | ||||
|         )) | ||||
|         time.sleep(1.1) | ||||
| @@ -118,20 +118,20 @@ class TestDownloads: | ||||
|         download.finish() | ||||
|         assert not download.interrupted | ||||
|  | ||||
|     def test_download_no_Content_Length(self): | ||||
|     def test_download_no_Content_Length(self, httpbin): | ||||
|         devnull = open(os.devnull, 'w') | ||||
|         download = Download(output_file=devnull, progress_file=devnull) | ||||
|         download.start(Response(url=httpbin('/'))) | ||||
|         download.start(Response(url=httpbin.url + '/')) | ||||
|         time.sleep(1.1) | ||||
|         download.chunk_downloaded(b'12345') | ||||
|         download.finish() | ||||
|         assert not download.interrupted | ||||
|  | ||||
|     def test_download_interrupted(self): | ||||
|     def test_download_interrupted(self, httpbin): | ||||
|         devnull = open(os.devnull, 'w') | ||||
|         download = Download(output_file=devnull, progress_file=devnull) | ||||
|         download.start(Response( | ||||
|             url=httpbin('/'), | ||||
|             url=httpbin.url + '/', | ||||
|             headers={'Content-Length': 5} | ||||
|         )) | ||||
|         download.chunk_downloaded(b'1234') | ||||
|   | ||||
| @@ -2,18 +2,18 @@ import requests | ||||
| import pytest | ||||
|  | ||||
| from httpie import ExitStatus | ||||
| from utils import TestEnvironment, http, httpbin, HTTP_OK | ||||
| from utils import TestEnvironment, http, HTTP_OK | ||||
|  | ||||
|  | ||||
| class TestExitStatus: | ||||
|     def test_ok_response_exits_0(self): | ||||
|         r = http('GET', httpbin('/status/200')) | ||||
|     def test_ok_response_exits_0(self, httpbin): | ||||
|         r = http('GET', httpbin.url + '/status/200') | ||||
|         assert HTTP_OK in r | ||||
|         assert r.exit_status == ExitStatus.OK | ||||
|  | ||||
|     def test_error_response_exits_0_without_check_status(self): | ||||
|         r = http('GET', httpbin('/status/500')) | ||||
|         assert 'HTTP/1.1 500' in r | ||||
|     def test_error_response_exits_0_without_check_status(self, httpbin): | ||||
|         r = http('GET', httpbin.url + '/status/500') | ||||
|         assert '500 INTERNAL SERVER ERRO' in r | ||||
|         assert r.exit_status == ExitStatus.OK | ||||
|         assert not r.stderr | ||||
|  | ||||
| @@ -21,40 +21,43 @@ class TestExitStatus: | ||||
|         tuple(map(int, requests.__version__.split('.'))) < (2, 3, 0), | ||||
|         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) | ||||
|         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) | ||||
|         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) | ||||
|         assert 'HTTP/1.1 301' in r | ||||
|         assert '301 MOVED PERMANENTLY' in r | ||||
|         assert r.exit_status == ExitStatus.ERROR_HTTP_3XX | ||||
|         assert '301 moved permanently' in r.stderr.lower() | ||||
|  | ||||
|     @pytest.mark.skipif( | ||||
|         requests.__version__ == '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): | ||||
|         r = http('--check-status', '--follow', 'GET', httpbin('/status/301'), | ||||
|     def test_3xx_check_status_redirects_allowed_exits_0(self, httpbin): | ||||
|         r = http('--check-status', '--follow', | ||||
|                  'GET', httpbin.url + '/status/301', | ||||
|                  error_exit_ok=True) | ||||
|         # 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 | ||||
|  | ||||
|     def test_4xx_check_status_exits_4(self): | ||||
|         r = http('--check-status', 'GET', httpbin('/status/401'), | ||||
|     def test_4xx_check_status_exits_4(self, httpbin): | ||||
|         r = http('--check-status', 'GET', httpbin.url + '/status/401', | ||||
|                  error_exit_ok=True) | ||||
|         assert 'HTTP/1.1 401' in r | ||||
|         assert '401 UNAUTHORIZED' in r | ||||
|         assert r.exit_status == ExitStatus.ERROR_HTTP_4XX | ||||
|         # Also stderr should be empty since stdout isn't redirected. | ||||
|         assert not r.stderr | ||||
|  | ||||
|     def test_5xx_check_status_exits_5(self): | ||||
|         r = http('--check-status', 'GET', httpbin('/status/500'), | ||||
|     def test_5xx_check_status_exits_5(self, httpbin): | ||||
|         r = http('--check-status', 'GET', httpbin.url + '/status/500', | ||||
|                  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 | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| """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 | ||||
| import httpie | ||||
|  | ||||
| @@ -23,43 +23,43 @@ class TestHTTPie: | ||||
|         # FIXME: py3 has version in stdout, py2 in stderr | ||||
|         assert httpie.__version__ == r.stderr.strip() + r.strip() | ||||
|  | ||||
|     def test_GET(self): | ||||
|         r = http('GET', httpbin('/get')) | ||||
|     def test_GET(self, httpbin): | ||||
|         r = http('GET', httpbin.url + '/get') | ||||
|         assert HTTP_OK in r | ||||
|  | ||||
|     def test_DELETE(self): | ||||
|         r = http('DELETE', httpbin('/delete')) | ||||
|     def test_DELETE(self, httpbin): | ||||
|         r = http('DELETE', httpbin.url + '/delete') | ||||
|         assert HTTP_OK in r | ||||
|  | ||||
|     def test_PUT(self): | ||||
|         r = http('PUT', httpbin('/put'), 'foo=bar') | ||||
|     def test_PUT(self, httpbin): | ||||
|         r = http('PUT', httpbin.url + '/put', 'foo=bar') | ||||
|         assert HTTP_OK in r | ||||
|         assert r'\"foo\": \"bar\"' in r | ||||
|         assert r.json['json']['foo'] == 'bar' | ||||
|  | ||||
|     def test_POST_JSON_data(self): | ||||
|         r = http('POST', httpbin('/post'), 'foo=bar') | ||||
|     def test_POST_JSON_data(self, httpbin): | ||||
|         r = http('POST', httpbin.url + '/post', 'foo=bar') | ||||
|         assert HTTP_OK in r | ||||
|         assert r'\"foo\": \"bar\"' in r | ||||
|         assert r.json['json']['foo'] == 'bar' | ||||
|  | ||||
|     def test_POST_form(self): | ||||
|         r = http('--form', 'POST', httpbin('/post'), 'foo=bar') | ||||
|     def test_POST_form(self, httpbin): | ||||
|         r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar') | ||||
|         assert HTTP_OK in r | ||||
|         assert '"foo": "bar"' in r | ||||
|  | ||||
|     def test_POST_form_multiple_values(self): | ||||
|         r = http('--form', 'POST', httpbin('/post'), 'foo=bar', 'foo=baz') | ||||
|     def test_POST_form_multiple_values(self, httpbin): | ||||
|         r = http('--form', 'POST', httpbin.url + '/post', 'foo=bar', 'foo=baz') | ||||
|         assert HTTP_OK in r | ||||
|         assert r.json['form'] == {'foo': ['bar', 'baz']} | ||||
|  | ||||
|     def test_POST_stdin(self): | ||||
|     def test_POST_stdin(self, httpbin): | ||||
|         with open(FILE_PATH) as f: | ||||
|             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 FILE_CONTENT in r | ||||
|  | ||||
|     def test_headers(self): | ||||
|         r = http('GET', httpbin('/headers'), 'Foo:bar') | ||||
|     def test_headers(self, httpbin): | ||||
|         r = http('GET', httpbin.url + '/headers', 'Foo:bar') | ||||
|         assert HTTP_OK in r | ||||
|         assert '"User-Agent": "HTTPie' in r, r | ||||
|         assert '"Foo": "bar"' in r | ||||
|   | ||||
| @@ -2,27 +2,28 @@ import pytest | ||||
|  | ||||
| from httpie import ExitStatus | ||||
| 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: | ||||
|     def test_verbose(self): | ||||
|         r = http('--verbose', 'GET', httpbin('/get'), 'test-header:__test__') | ||||
|     def test_verbose(self, httpbin): | ||||
|         r = http('--verbose', | ||||
|                  'GET', httpbin.url + '/get', 'test-header:__test__') | ||||
|         assert HTTP_OK in r | ||||
|         assert r.count('__test__') == 2 | ||||
|  | ||||
|     def test_verbose_form(self): | ||||
|     def test_verbose_form(self, httpbin): | ||||
|         # 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') | ||||
|         assert HTTP_OK in r | ||||
|         assert 'A=B&C=D' in r | ||||
|  | ||||
|     def test_verbose_json(self): | ||||
|         r = http('--verbose', 'POST', httpbin('/post'), 'foo=bar', 'baz=bar') | ||||
|     def test_verbose_json(self, httpbin): | ||||
|         r = http('--verbose', | ||||
|                  'POST', httpbin.url + '/post', 'foo=bar', 'baz=bar') | ||||
|         assert HTTP_OK in r | ||||
|         assert '"baz": "bar"' in r  # request | ||||
|         assert r'\"baz\": \"bar\"' in r  # response | ||||
|         assert '"baz": "bar"' in r | ||||
|  | ||||
|  | ||||
| class TestColors: | ||||
| @@ -47,45 +48,47 @@ class TestColors: | ||||
| class TestPrettyOptions: | ||||
|     """Test the --pretty flag handling.""" | ||||
|  | ||||
|     def test_pretty_enabled_by_default(self): | ||||
|     def test_pretty_enabled_by_default(self, httpbin): | ||||
|         env = TestEnvironment(colors=256) | ||||
|         r = http('GET', httpbin('/get'), env=env) | ||||
|         r = http('GET', httpbin.url + '/get', env=env) | ||||
|         assert COLOR in r | ||||
|  | ||||
|     def test_pretty_enabled_by_default_unless_stdout_redirected(self): | ||||
|         r = http('GET', httpbin('/get')) | ||||
|     def test_pretty_enabled_by_default_unless_stdout_redirected(self, httpbin): | ||||
|         r = http('GET', httpbin.url + '/get') | ||||
|         assert COLOR not in r | ||||
|  | ||||
|     def test_force_pretty(self): | ||||
|     def test_force_pretty(self, httpbin): | ||||
|         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 | ||||
|  | ||||
|     def test_force_ugly(self): | ||||
|         r = http('--pretty=none', 'GET', httpbin('/get')) | ||||
|     def test_force_ugly(self, httpbin): | ||||
|         r = http('--pretty=none', 'GET', httpbin.url + '/get') | ||||
|         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 | ||||
|         match any lexer. | ||||
|  | ||||
|         """ | ||||
|         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) | ||||
|         assert COLOR in r | ||||
|  | ||||
|     def test_colors_option(self): | ||||
|     def test_colors_option(self, httpbin): | ||||
|         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) | ||||
|         # Tests that the JSON data isn't formatted. | ||||
|         assert not r.strip().count('\n') | ||||
|         assert COLOR in r | ||||
|  | ||||
|     def test_format_option(self): | ||||
|     def test_format_option(self, httpbin): | ||||
|         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) | ||||
|         # Tests that the JSON data is formatted. | ||||
|         assert r.strip().count('\n') == 2 | ||||
| @@ -110,24 +113,24 @@ class TestLineEndings: | ||||
|         assert CRLF not in body | ||||
|         return body | ||||
|  | ||||
|     def test_CRLF_headers_only(self): | ||||
|         r = http('--headers', 'GET', httpbin('/get')) | ||||
|     def test_CRLF_headers_only(self, httpbin): | ||||
|         r = http('--headers', 'GET', httpbin.url + '/get') | ||||
|         body = self._validate_crlf(r) | ||||
|         assert not body, 'Garbage after headers: %r' % r | ||||
|  | ||||
|     def test_CRLF_ugly_response(self): | ||||
|         r = http('--pretty=none', 'GET', httpbin('/get')) | ||||
|     def test_CRLF_ugly_response(self, httpbin): | ||||
|         r = http('--pretty=none', 'GET', httpbin.url + '/get') | ||||
|         self._validate_crlf(r) | ||||
|  | ||||
|     def test_CRLF_formatted_response(self): | ||||
|         r = http('--pretty=format', 'GET', httpbin('/get')) | ||||
|     def test_CRLF_formatted_response(self, httpbin): | ||||
|         r = http('--pretty=format', 'GET', httpbin.url + '/get') | ||||
|         assert r.exit_status == ExitStatus.OK | ||||
|         self._validate_crlf(r) | ||||
|  | ||||
|     def test_CRLF_ugly_request(self): | ||||
|         r = http('--pretty=none', '--print=HB', 'GET', httpbin('/get')) | ||||
|     def test_CRLF_ugly_request(self, httpbin): | ||||
|         r = http('--pretty=none', '--print=HB', 'GET', httpbin.url + '/get') | ||||
|         self._validate_crlf(r) | ||||
|  | ||||
|     def test_CRLF_formatted_request(self): | ||||
|         r = http('--pretty=format', '--print=HB', 'GET', httpbin('/get')) | ||||
|     def test_CRLF_formatted_request(self, httpbin): | ||||
|         r = http('--pretty=format', '--print=HB', 'GET', httpbin.url + '/get') | ||||
|         self._validate_crlf(r) | ||||
|   | ||||
| @@ -4,14 +4,14 @@ import socket | ||||
| from utils import http, HTTP_OK | ||||
|  | ||||
|  | ||||
| def test_Host_header_overwrite(): | ||||
| def test_Host_header_overwrite(httpbin): | ||||
|     """ | ||||
|     https://github.com/jakubroztocil/httpie/issues/235 | ||||
|  | ||||
|     """ | ||||
|     host = 'httpbin.org' | ||||
|     url = 'http://{httpbin_ip}/get'.format( | ||||
|         httpbin_ip=socket.gethostbyname(host)) | ||||
|     r = http('--print=hH', url, 'host:{}'.format(host)) | ||||
|     url = httpbin.url + '/get' | ||||
|     r = http('--print=hH', url, 'host:{0}'.format(host)) | ||||
|     assert HTTP_OK in r | ||||
|     assert r.lower().count('host:') == 1 | ||||
|     assert 'host: {0}'.format(host) in r | ||||
|   | ||||
| @@ -3,12 +3,14 @@ import os | ||||
| import shutil | ||||
|  | ||||
| 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 | ||||
|  | ||||
|  | ||||
| class SessionTestBase(object): | ||||
|     def setup_method(self, method): | ||||
|  | ||||
|     def start_session(self, httpbin): | ||||
|         """Create and reuse a unique config dir for each test.""" | ||||
|         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, | ||||
|         authorization, and response cookies. | ||||
|  | ||||
|         """ | ||||
|         super(TestSessionFlow, self).setup_method(method) | ||||
|         super(TestSessionFlow, self).start_session(httpbin) | ||||
|         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()) | ||||
|         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. | ||||
|         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 r2.json['headers']['Hello'] == 'World' | ||||
|         assert r2.json['headers']['Cookie'] == 'hello=world' | ||||
|         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. | ||||
|         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 | ||||
|  | ||||
|         # Make a request modifying the session data. | ||||
|         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()) | ||||
|         assert HTTP_OK in r3 | ||||
|  | ||||
|         # 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 r4.json['headers']['Hello'] == 'World2' | ||||
|         assert r4.json['headers']['Cookie'] == 'hello=world2' | ||||
|         assert (r2.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. | ||||
|         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 | ||||
|  | ||||
|         # Make a request modifying the session data but | ||||
|         # with --session-read-only. | ||||
|         r3 = http('--follow', '--session-read-only=test', | ||||
|                   '--auth=username:password2', 'GET', | ||||
|                   httpbin('/cookies/set?hello=world2'), 'Hello:World2', | ||||
|                   httpbin.url + '/cookies/set?hello=world2', 'Hello:World2', | ||||
|                   env=self.env()) | ||||
|         assert HTTP_OK in r3 | ||||
|  | ||||
|         # 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 | ||||
|  | ||||
|         # Origin can differ on Travis. | ||||
|         del r2.json['origin'], r4.json['origin'] | ||||
|         # 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. | ||||
|         assert r2.json == r4.json | ||||
| @@ -102,51 +107,58 @@ class TestSessionFlow(SessionTestBase): | ||||
| class TestSession(SessionTestBase): | ||||
|     """Stand-alone session tests.""" | ||||
|  | ||||
|     def test_session_ignored_header_prefixes(self): | ||||
|         r1 = http('--session=test', 'GET', httpbin('/get'), | ||||
|     def test_session_ignored_header_prefixes(self, httpbin): | ||||
|         self.start_session(httpbin) | ||||
|         r1 = http('--session=test', 'GET', httpbin.url + '/get', | ||||
|                   'Content-Type: text/plain', | ||||
|                   'If-Unmodified-Since: Sat, 29 Oct 1994 19:43:31 GMT', | ||||
|                   env=self.env()) | ||||
|         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 'Content-Type' not in r2.json['headers'] | ||||
|         assert no_content_type(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') | ||||
|         r1 = http('--session=' + session_path, 'GET', httpbin('/get'), | ||||
|         r1 = http('--session=' + session_path, 'GET', httpbin.url + '/get', | ||||
|                   'Foo:Bar', env=self.env()) | ||||
|         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()) | ||||
|         assert HTTP_OK in r2 | ||||
|         assert r2.json['headers']['Foo'] == 'Bar' | ||||
|  | ||||
|     def test_session_unicode(self): | ||||
|         r1 = http('--session=test', '--auth', u'test:' + UNICODE, | ||||
|                   'GET', httpbin('/get'), | ||||
|                   u'Test:%s' % UNICODE, | ||||
|     def test_session_unicode(self, httpbin): | ||||
|         self.start_session(httpbin) | ||||
|  | ||||
|         r1 = http('--session=test', u'--auth=test:' + UNICODE, | ||||
|                   'GET', httpbin.url + '/get', u'Test:%s' % UNICODE, | ||||
|                   env=self.env()) | ||||
|         assert HTTP_OK in r1 | ||||
|  | ||||
|         r2 = http('--session=test', '--verbose', 'GET', | ||||
|                   httpbin('/get'), env=self.env()) | ||||
|                   httpbin.url + '/get', env=self.env()) | ||||
|         assert HTTP_OK in r2 | ||||
|  | ||||
|         # FIXME: Authorization *sometimes* is not present on Python3 | ||||
|         assert (r2.json['headers']['Authorization'] | ||||
|                 == HTTPBasicAuth.make_header(u'test', UNICODE)) | ||||
|         # httpbin doesn't interpret utf8 headers | ||||
|         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 | ||||
|         r1 = http('--session=test', httpbin('/headers'), 'User-Agent:custom', | ||||
|         r1 = http('--session=test', | ||||
|                   httpbin.url + '/headers', 'User-Agent:custom', | ||||
|                   env=self.env()) | ||||
|         assert HTTP_OK in r1 | ||||
|         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 r2.json['headers']['User-Agent'] == 'custom' | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import pytest | ||||
|  | ||||
| from httpie.compat import is_windows | ||||
| 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 | ||||
|  | ||||
|  | ||||
| @@ -11,26 +11,26 @@ class TestStream: | ||||
|  | ||||
|     @pytest.mark.skipif(is_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.""" | ||||
|         with open(BIN_FILE_PATH, 'rb') as f: | ||||
|             env = TestEnvironment(colors=256, stdin=f, | ||||
|                                   stdin_isatty=False, | ||||
|                                   stdout_isatty=False) | ||||
|             r = http('--verbose', '--pretty=all', '--stream', 'GET', | ||||
|                      httpbin('/get'), env=env) | ||||
|                      httpbin.url + '/get', env=env) | ||||
|         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 | ||||
|         redirected terminal output.""" | ||||
|         with open(BIN_FILE_PATH, 'rb') as f: | ||||
|             env = TestEnvironment(stdin=f, stdin_isatty=False) | ||||
|             r = http('--pretty=none', '--stream', '--verbose', 'GET', | ||||
|                      httpbin('/get'), env=env) | ||||
|                      httpbin.url + '/get', env=env) | ||||
|         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 | ||||
|         redirected terminal output.""" | ||||
|         with open(BIN_FILE_PATH, 'rb') as f: | ||||
| @@ -38,5 +38,5 @@ class TestStream: | ||||
|                                   stdin_isatty=False, | ||||
|                                   stdin=f) | ||||
|             r = http('--pretty=none', '--stream', '--verbose', 'GET', | ||||
|                      httpbin('/get'), env=env) | ||||
|                      httpbin.url + '/get', env=env) | ||||
|         assert BIN_FILE_CONTENT in r | ||||
|   | ||||
| @@ -3,85 +3,85 @@ | ||||
| Various unicode handling related tests. | ||||
|  | ||||
| """ | ||||
| from utils import http, httpbin, HTTP_OK | ||||
| from utils import http, HTTP_OK | ||||
| from fixtures import UNICODE | ||||
|  | ||||
|  | ||||
| class TestUnicode: | ||||
|  | ||||
|     def test_unicode_headers(self): | ||||
|     def test_unicode_headers(self, httpbin): | ||||
|         # 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 | ||||
|  | ||||
|     def test_unicode_headers_verbose(self): | ||||
|     def test_unicode_headers_verbose(self, httpbin): | ||||
|         # 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 UNICODE in r | ||||
|  | ||||
|     def test_unicode_form_item(self): | ||||
|         r = http('--form', 'POST', httpbin('/post'), u'test=%s' % UNICODE) | ||||
|     def test_unicode_form_item(self, httpbin): | ||||
|         r = http('--form', 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) | ||||
|         assert HTTP_OK in r | ||||
|         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', | ||||
|                  'POST', httpbin('/post'), u'test=%s' % UNICODE) | ||||
|                  'POST', httpbin.url + '/post', u'test=%s' % UNICODE) | ||||
|         assert HTTP_OK in r | ||||
|         assert UNICODE in r | ||||
|  | ||||
|     def test_unicode_json_item(self): | ||||
|         r = http('--json', 'POST', httpbin('/post'), u'test=%s' % UNICODE) | ||||
|     def test_unicode_json_item(self, httpbin): | ||||
|         r = http('--json', 'POST', httpbin.url + '/post', u'test=%s' % UNICODE) | ||||
|         assert HTTP_OK in r | ||||
|         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', | ||||
|                  'POST', httpbin('/post'), u'test=%s' % UNICODE) | ||||
|                  'POST', httpbin.url + '/post', u'test=%s' % UNICODE) | ||||
|         assert HTTP_OK in r | ||||
|         assert UNICODE in r | ||||
|  | ||||
|     def test_unicode_raw_json_item(self): | ||||
|         r = http('--json', 'POST', httpbin('/post'), | ||||
|     def test_unicode_raw_json_item(self, httpbin): | ||||
|         r = http('--json', 'POST', httpbin.url + '/post', | ||||
|                  u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE)) | ||||
|         assert HTTP_OK in r | ||||
|         assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} | ||||
|  | ||||
|     def test_unicode_raw_json_item_verbose(self): | ||||
|         r = http('--json', 'POST', httpbin('/post'), | ||||
|     def test_unicode_raw_json_item_verbose(self, httpbin): | ||||
|         r = http('--json', 'POST', httpbin.url + '/post', | ||||
|                  u'test:={ "%s" : [ "%s" ] }' % (UNICODE, UNICODE)) | ||||
|         assert HTTP_OK in r | ||||
|         assert r.json['json'] == {'test': {UNICODE: [UNICODE]}} | ||||
|  | ||||
|     def test_unicode_url_query_arg_item(self): | ||||
|         r = http(httpbin('/get'), u'test==%s' % UNICODE) | ||||
|     def test_unicode_url_query_arg_item(self, httpbin): | ||||
|         r = http(httpbin.url + '/get', u'test==%s' % UNICODE) | ||||
|         assert HTTP_OK in r | ||||
|         assert r.json['args'] == {'test': UNICODE}, r | ||||
|  | ||||
|     def test_unicode_url_query_arg_item_verbose(self): | ||||
|         r = http('--verbose', httpbin('/get'), u'test==%s' % UNICODE) | ||||
|     def test_unicode_url_query_arg_item_verbose(self, httpbin): | ||||
|         r = http('--verbose', httpbin.url + '/get', u'test==%s' % UNICODE) | ||||
|         assert HTTP_OK in r | ||||
|         assert UNICODE in r | ||||
|  | ||||
|     def test_unicode_url(self): | ||||
|         r = http(httpbin(u'/get?test=' + UNICODE)) | ||||
|     def test_unicode_url(self, httpbin): | ||||
|         r = http(httpbin.url + u'/get?test=' + UNICODE) | ||||
|         assert HTTP_OK in r | ||||
|         assert r.json['args'] == {'test': UNICODE} | ||||
|  | ||||
|     # 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 | ||||
|  | ||||
|     def test_unicode_basic_auth(self): | ||||
|     def test_unicode_basic_auth(self, httpbin): | ||||
|         # it doesn't really authenticate us because httpbin | ||||
|         # doesn't interpret the utf8-encoded auth | ||||
|         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 | ||||
|         # doesn't interpret the utf8-encoded auth | ||||
|         http('--auth-type=digest', | ||||
|              '--auth', u'test:%s' % UNICODE, | ||||
|              httpbin(u'/digest-auth/auth/test/' + UNICODE)) | ||||
|              httpbin.url + u'/digest-auth/auth/test/' + UNICODE) | ||||
|   | ||||
| @@ -3,23 +3,25 @@ import os | ||||
| import pytest | ||||
|  | ||||
| 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 | ||||
|  | ||||
|  | ||||
| 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): | ||||
|         r = http('--form', '--verbose', 'POST', httpbin('/post'), | ||||
|     def test_non_existent_file_raises_parse_error(self, httpbin): | ||||
|         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') | ||||
|         assert HTTP_OK in r | ||||
|         assert 'Content-Disposition: form-data; name="foo"' in r | ||||
|         assert 'Content-Disposition: form-data; name="test-file";' \ | ||||
|                ' 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 | ||||
|  | ||||
|  | ||||
| @@ -29,27 +31,32 @@ class TestRequestBodyFromFilePath: | ||||
|  | ||||
|     """ | ||||
|  | ||||
|     def test_request_body_from_file_by_path(self): | ||||
|         r = http('--verbose', 'POST', httpbin('/post'), '@' + FILE_PATH_ARG) | ||||
|     def test_request_body_from_file_by_path(self, httpbin): | ||||
|         r = http('--verbose', | ||||
|                  'POST', httpbin.url + '/post', '@' + FILE_PATH_ARG) | ||||
|         assert HTTP_OK in r | ||||
|         assert FILE_CONTENT in r, r | ||||
|         assert '"Content-Type": "text/plain"' in r | ||||
|  | ||||
|     def test_request_body_from_file_by_path_with_explicit_content_type(self): | ||||
|         r = http('POST', httpbin('/post'), '@' + FILE_PATH_ARG, | ||||
|                  'Content-Type:x-foo/bar') | ||||
|     def test_request_body_from_file_by_path_with_explicit_content_type( | ||||
|             self, httpbin): | ||||
|         r = http('--verbose', | ||||
|                  'POST', httpbin.url + '/post', '@' + FILE_PATH_ARG, | ||||
|                  'Content-Type:text/plain; charset=utf8') | ||||
|         assert HTTP_OK 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) | ||||
|         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) | ||||
|         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) | ||||
|         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) | ||||
|         assert 'cannot be mixed' in r.stderr | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import tempfile | ||||
| import pytest | ||||
| from httpie.context import Environment | ||||
|  | ||||
| from utils import TestEnvironment, http, httpbin | ||||
| from utils import TestEnvironment, http | ||||
| from httpie.compat import is_windows | ||||
|  | ||||
|  | ||||
| @@ -13,17 +13,17 @@ class TestWindowsOnly: | ||||
|  | ||||
|     @pytest.mark.skipif(True, | ||||
|                         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. | ||||
|         http(httpbin('/get'), env=Environment()) | ||||
|         http(httpbin.url + '/get', env=Environment()) | ||||
|  | ||||
|  | ||||
| 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) | ||||
|         output_file = os.path.join( | ||||
|             tempfile.gettempdir(), '__httpie_test_output__') | ||||
|         r = http('--output', output_file, | ||||
|                  '--pretty=all', 'GET', httpbin('/get'), | ||||
|                  '--pretty=all', 'GET', httpbin.url + '/get', | ||||
|                  env=env, error_exit_ok=True) | ||||
|         assert 'Only terminal output can be colorized on Windows' in r.stderr | ||||
|   | ||||
| @@ -20,7 +20,7 @@ TESTS_ROOT = os.path.abspath(os.path.dirname(__file__)) | ||||
|  | ||||
| CRLF = '\r\n' | ||||
| COLOR = '\x1b[' | ||||
| HTTP_OK = 'HTTP/1.1 200' | ||||
| HTTP_OK = '200 OK' | ||||
| HTTP_OK_COLOR = ( | ||||
|     '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' | ||||
| @@ -28,22 +28,19 @@ HTTP_OK_COLOR = ( | ||||
| ) | ||||
|  | ||||
|  | ||||
| def httpbin(path, auth=None, | ||||
|             base=os.environ.get('HTTPBIN_URL', 'http://httpbin.org')): | ||||
|     """ | ||||
|     Return a fully-qualified httpbin URL for `path`. | ||||
| def no_content_type(headers): | ||||
|     return ( | ||||
|         'Content-Type' not in headers | ||||
|         # 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') | ||||
|     'http://user:password@httpbin.org/get' | ||||
|  | ||||
|     """ | ||||
|     if auth: | ||||
|         proto, rest = base.split('://', 1) | ||||
|         base = proto + '://' + auth + '@' + rest | ||||
|     return base.rstrip('/') + path | ||||
| def add_auth(url, auth): | ||||
|     proto, rest = url.split('://', 1) | ||||
|     return proto + '://' + auth + '@' + rest | ||||
|  | ||||
|  | ||||
| class TestEnvironment(Environment): | ||||
| @@ -104,7 +101,7 @@ def http(*args, **kwargs): | ||||
|  | ||||
|     $ 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 | ||||
|         True | ||||
|         >>> r.exit_status | ||||
|   | ||||
		Reference in New Issue
	
	Block a user