1
0
mirror of https://github.com/httpie/cli.git synced 2025-08-10 22:42:05 +02:00

Remove automatic config file creation to avoid concurrency issues.

Close #788
Close #812
This commit is contained in:
Jakub Roztocil
2019-12-02 17:43:16 +01:00
parent f0058eeaee
commit f202f338a4
11 changed files with 178 additions and 141 deletions

View File

@@ -1,6 +1,5 @@
from httpie import __version__
from utils import MockEnvironment, http, HTTP_OK
from httpie.context import Environment
from httpie.config import Config
from utils import HTTP_OK, MockEnvironment, http
def test_default_options(httpbin):
@@ -8,15 +7,33 @@ def test_default_options(httpbin):
env.config['default_options'] = ['--form']
env.config.save()
r = http(httpbin.url + '/post', 'foo=bar', env=env)
assert r.json['form'] == {"foo": "bar"}
assert r.json['form'] == {
"foo": "bar"
}
def test_config_dir_not_writeable(httpbin):
r = http(httpbin + '/get', env=MockEnvironment(
config_dir='/',
create_temp_config_dir=False,
))
def test_config_file_not_valid(httpbin):
env = MockEnvironment()
env.create_temp_config_dir()
with (env.config_dir / Config.FILENAME).open('w') as f:
f.write('{invalid json}')
r = http(httpbin + '/get', env=env)
assert HTTP_OK in r
assert 'http: warning' in r.stderr
assert 'invalid config file' in r.stderr
def test_config_file_not_inaccessible(httpbin):
env = MockEnvironment()
env.create_temp_config_dir()
config_path = env.config_dir / Config.FILENAME
assert not config_path.exists()
config_path.touch(0o000)
assert config_path.exists()
r = http(httpbin + '/get', env=env)
assert HTTP_OK in r
assert 'http: warning' in r.stderr
assert 'cannot read config file' in r.stderr
def test_default_options_overwrite(httpbin):
@@ -24,9 +41,6 @@ def test_default_options_overwrite(httpbin):
env.config['default_options'] = ['--form']
env.config.save()
r = http('--json', httpbin.url + '/post', 'foo=bar', env=env)
assert r.json['json'] == {"foo": "bar"}
def test_current_version():
version = MockEnvironment().config['__meta__']['httpie']
assert version == __version__
assert r.json['json'] == {
"foo": "bar"
}

View File

@@ -4,37 +4,30 @@ from requests import Request
from requests.exceptions import ConnectionError
from httpie.status import ExitStatus
from httpie.core import main
from utils import HTTP_OK, http
error_msg = None
@mock.patch('httpie.core.program')
def test_error(program):
exc = ConnectionError('Connection aborted')
exc.request = Request(method='GET', url='http://www.google.com')
program.side_effect = exc
r = http('www.google.com', tolerate_error_exit_status=True)
assert r.exit_status == ExitStatus.ERROR
assert (
'ConnectionError: '
'Connection aborted while doing a GET request to URL: '
'http://www.google.com'
) in r.stderr
@mock.patch('httpie.core.program')
def test_error(get_response):
def error(msg, *args, **kwargs):
global error_msg
error_msg = msg % args
def test_error_traceback(program):
exc = ConnectionError('Connection aborted')
exc.request = Request(method='GET', url='http://www.google.com')
get_response.side_effect = exc
ret = main(['http', '--ignore-stdin', 'www.google.com'], custom_log_error=error)
assert ret == ExitStatus.ERROR
assert error_msg == (
'ConnectionError: '
'Connection aborted while doing a GET request to URL: '
'http://www.google.com')
@mock.patch('httpie.core.program')
def test_error_traceback(get_response):
exc = ConnectionError('Connection aborted')
exc.request = Request(method='GET', url='http://www.google.com')
get_response.side_effect = exc
program.side_effect = exc
with raises(ConnectionError):
main(['http', '--ignore-stdin', '--traceback', 'www.google.com'])
http('--traceback', 'www.google.com')
def test_max_headers_limit(httpbin_both):

View File

@@ -6,7 +6,7 @@ import time
import json
import tempfile
from pathlib import Path
from typing import Optional
from typing import Optional, Union
from httpie.status import ExitStatus
from httpie.config import Config
@@ -18,6 +18,7 @@ TESTS_ROOT = os.path.abspath(os.path.dirname(__file__))
CRLF = '\r\n'
COLOR = '\x1b['
HTTP_OK = '200 OK'
# noinspection GrazieInspection
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'
@@ -62,10 +63,13 @@ class MockEnvironment(Environment):
def config(self) -> Config:
if (self._create_temp_config_dir
and self._temp_dir not in self.config_dir.parents):
self.config_dir = mk_config_dir()
self._delete_config_dir = True
self.create_temp_config_dir()
return super().config
def create_temp_config_dir(self):
self.config_dir = mk_config_dir()
self._delete_config_dir = True
def cleanup(self):
self.stdout.close()
self.stderr.close()
@@ -75,6 +79,7 @@ class MockEnvironment(Environment):
rmtree(self.config_dir)
def __del__(self):
# noinspection PyBroadException
try:
self.cleanup()
except Exception:
@@ -83,7 +88,7 @@ class MockEnvironment(Environment):
class BaseCLIResponse:
"""
Represents the result of simulated `$ http' invocation via `http()`.
Represents the result of simulated `$ http' invocation via `http()`.
Holds and provides access to:
@@ -113,8 +118,8 @@ class StrCLIResponse(str, BaseCLIResponse):
@property
def json(self) -> Optional[dict]:
"""
Return deserialized JSON body, if one included in the output
and is parsable.
Return deserialized the request or response JSON body,
if one (and only one) included in the output and is parsable.
"""
if not hasattr(self, '_json'):
@@ -147,7 +152,12 @@ class ExitStatusError(Exception):
pass
def http(*args, program_name='http', **kwargs):
def http(
*args,
program_name='http',
tolerate_error_exit_status=False,
**kwargs,
) -> Union[StrCLIResponse, BytesCLIResponse]:
# noinspection PyUnresolvedReferences
"""
Run HTTPie and capture stderr/out and exit status.
@@ -188,7 +198,6 @@ def http(*args, program_name='http', **kwargs):
True
"""
tolerate_error_exit_status = kwargs.pop('tolerate_error_exit_status', False)
env = kwargs.get('env')
if not env:
env = kwargs['env'] = MockEnvironment()
@@ -200,7 +209,8 @@ def http(*args, program_name='http', **kwargs):
args_with_config_defaults = args + env.config.default_options
add_to_args = []
if '--debug' not in args_with_config_defaults:
if not tolerate_error_exit_status and '--traceback' not in args_with_config_defaults:
if (not tolerate_error_exit_status
and '--traceback' not in args_with_config_defaults):
add_to_args.append('--traceback')
if not any('--timeout' in arg for arg in args_with_config_defaults):
add_to_args.append('--timeout=3')
@@ -228,7 +238,8 @@ def http(*args, program_name='http', **kwargs):
sys.stderr.write(stderr.read())
raise
else:
if not tolerate_error_exit_status and exit_status != ExitStatus.SUCCESS:
if (not tolerate_error_exit_status
and exit_status != ExitStatus.SUCCESS):
dump_stderr()
raise ExitStatusError(
'httpie.core.main() unexpectedly returned'