2021-08-05 14:37:08 +02:00
|
|
|
import json
|
|
|
|
|
2014-04-24 16:17:04 +03:00
|
|
|
import pytest
|
2021-08-05 14:37:08 +02:00
|
|
|
import responses
|
2021-12-08 17:49:12 +02:00
|
|
|
from unittest.mock import Mock
|
2014-04-24 16:17:04 +03:00
|
|
|
|
2014-04-24 15:07:31 +03:00
|
|
|
from httpie.compat import is_windows
|
2021-08-05 14:37:08 +02:00
|
|
|
from httpie.cli.constants import PRETTY_MAP
|
2014-04-27 01:07:13 +03:00
|
|
|
from httpie.output.streams import BINARY_SUPPRESSED_NOTICE
|
2021-08-05 14:37:08 +02:00
|
|
|
from httpie.plugins import ConverterPlugin
|
|
|
|
from httpie.plugins.registry import plugin_manager
|
|
|
|
|
2021-10-06 17:27:07 +02:00
|
|
|
from .utils import StdinBytesIO, http, MockEnvironment, DUMMY_URL
|
2021-12-23 21:05:58 +02:00
|
|
|
from .fixtures import (
|
|
|
|
ASCII_FILE_CONTENT,
|
|
|
|
BIN_FILE_CONTENT,
|
|
|
|
BIN_FILE_PATH,
|
|
|
|
FILE_CONTENT as UNICODE_FILE_CONTENT
|
|
|
|
)
|
2014-04-24 15:07:31 +03:00
|
|
|
|
2021-08-05 14:37:08 +02:00
|
|
|
PRETTY_OPTIONS = list(PRETTY_MAP.keys())
|
|
|
|
|
|
|
|
|
|
|
|
class SortJSONConverterPlugin(ConverterPlugin):
|
|
|
|
@classmethod
|
|
|
|
def supports(cls, mime):
|
|
|
|
return mime == 'json/bytes'
|
|
|
|
|
|
|
|
def convert(self, body):
|
|
|
|
body = body.lstrip(b'\x00')
|
|
|
|
data = json.loads(body)
|
|
|
|
return 'application/json', json.dumps(data, sort_keys=True)
|
|
|
|
|
2014-04-24 15:07:31 +03:00
|
|
|
|
2016-03-03 12:47:12 +02:00
|
|
|
# GET because httpbin 500s with binary POST body.
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.skipif(is_windows,
|
|
|
|
reason='Pretty redirect not supported under Windows')
|
|
|
|
def test_pretty_redirected_stream(httpbin):
|
|
|
|
"""Test that --stream works with prettified redirected output."""
|
2020-09-28 12:16:57 +02:00
|
|
|
env = MockEnvironment(
|
|
|
|
colors=256,
|
|
|
|
stdin=StdinBytesIO(BIN_FILE_PATH.read_bytes()),
|
|
|
|
stdin_isatty=False,
|
|
|
|
stdout_isatty=False,
|
|
|
|
)
|
|
|
|
r = http('--verbose', '--pretty=all', '--stream', 'GET',
|
2024-03-04 19:12:18 +02:00
|
|
|
httpbin + '/get', env=env)
|
2016-03-03 12:47:12 +02:00
|
|
|
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
|
|
|
|
|
|
|
|
2021-08-05 14:37:08 +02:00
|
|
|
def test_pretty_stream_ensure_full_stream_is_retrieved(httpbin):
|
|
|
|
env = MockEnvironment(
|
|
|
|
stdin=StdinBytesIO(),
|
|
|
|
stdin_isatty=False,
|
|
|
|
stdout_isatty=False,
|
|
|
|
)
|
|
|
|
r = http('--pretty=format', '--stream', 'GET',
|
2024-03-04 19:12:18 +02:00
|
|
|
httpbin + '/stream/3', env=env)
|
2021-08-05 14:37:08 +02:00
|
|
|
assert r.count('/stream/3') == 3
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize('pretty', PRETTY_OPTIONS)
|
|
|
|
@pytest.mark.parametrize('stream', [True, False])
|
|
|
|
@responses.activate
|
|
|
|
def test_pretty_options_with_and_without_stream_with_converter(pretty, stream):
|
|
|
|
plugin_manager.register(SortJSONConverterPlugin)
|
|
|
|
try:
|
|
|
|
# Cover PluginManager.__repr__()
|
|
|
|
assert 'SortJSONConverterPlugin' in str(plugin_manager)
|
|
|
|
|
|
|
|
body = b'\x00{"foo":42,\n"bar":"baz"}'
|
2021-10-06 17:27:07 +02:00
|
|
|
responses.add(responses.GET, DUMMY_URL, body=body,
|
2021-08-05 14:37:08 +02:00
|
|
|
stream=True, content_type='json/bytes')
|
|
|
|
|
2021-10-06 17:27:07 +02:00
|
|
|
args = ['--pretty=' + pretty, 'GET', DUMMY_URL]
|
2021-08-05 14:37:08 +02:00
|
|
|
if stream:
|
|
|
|
args.insert(0, '--stream')
|
|
|
|
r = http(*args)
|
|
|
|
|
|
|
|
assert 'json/bytes' in r
|
|
|
|
if pretty == 'none':
|
|
|
|
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
|
|
|
else:
|
|
|
|
# Ensure the plugin was effectively used and the resulting JSON is sorted
|
|
|
|
assert '"bar": "baz",' in r
|
|
|
|
assert '"foo": 42' in r
|
|
|
|
finally:
|
|
|
|
plugin_manager.unregister(SortJSONConverterPlugin)
|
|
|
|
|
|
|
|
|
2016-03-03 12:47:12 +02:00
|
|
|
def test_encoded_stream(httpbin):
|
|
|
|
"""Test that --stream works with non-prettified
|
|
|
|
redirected terminal output."""
|
2020-09-28 12:16:57 +02:00
|
|
|
env = MockEnvironment(
|
|
|
|
stdin=StdinBytesIO(BIN_FILE_PATH.read_bytes()),
|
|
|
|
stdin_isatty=False,
|
|
|
|
)
|
|
|
|
r = http('--pretty=none', '--stream', '--verbose', 'GET',
|
2024-03-04 19:12:18 +02:00
|
|
|
httpbin + '/get', env=env)
|
2016-03-03 12:47:12 +02:00
|
|
|
assert BINARY_SUPPRESSED_NOTICE.decode() in r
|
|
|
|
|
|
|
|
|
|
|
|
def test_redirected_stream(httpbin):
|
|
|
|
"""Test that --stream works with non-prettified
|
|
|
|
redirected terminal output."""
|
2020-09-28 12:16:57 +02:00
|
|
|
env = MockEnvironment(
|
|
|
|
stdout_isatty=False,
|
|
|
|
stdin_isatty=False,
|
|
|
|
stdin=StdinBytesIO(BIN_FILE_PATH.read_bytes()),
|
|
|
|
)
|
|
|
|
r = http('--pretty=none', '--stream', '--verbose', 'GET',
|
2024-03-04 19:12:18 +02:00
|
|
|
httpbin + '/get', env=env)
|
2016-03-03 12:47:12 +02:00
|
|
|
assert BIN_FILE_CONTENT in r
|
2021-12-08 17:49:12 +02:00
|
|
|
|
|
|
|
|
|
|
|
# /drip endpoint produces 3 individual lines,
|
|
|
|
# if we set text/event-stream HTTPie should stream
|
|
|
|
# it by default. Otherwise, it will buffer and then
|
|
|
|
# print.
|
|
|
|
@pytest.mark.parametrize('extras, expected', [
|
|
|
|
(
|
|
|
|
['Accept:text/event-stream'],
|
|
|
|
3
|
|
|
|
),
|
2022-05-06 08:59:22 +02:00
|
|
|
(
|
|
|
|
['Accept:text/event-stream; charset=utf-8'],
|
|
|
|
3
|
|
|
|
),
|
2021-12-08 17:49:12 +02:00
|
|
|
(
|
|
|
|
['Accept:text/plain'],
|
|
|
|
1
|
|
|
|
)
|
|
|
|
])
|
|
|
|
def test_auto_streaming(http_server, extras, expected):
|
|
|
|
env = MockEnvironment()
|
|
|
|
env.stdout.write = Mock()
|
|
|
|
http(http_server + '/drip', *extras, env=env)
|
|
|
|
assert len([
|
|
|
|
call_arg
|
|
|
|
for call_arg in env.stdout.write.call_args_list
|
2022-04-14 16:43:10 +02:00
|
|
|
if 'test' in call_arg[0][0]
|
2021-12-08 17:49:12 +02:00
|
|
|
]) == expected
|
2021-12-23 21:05:58 +02:00
|
|
|
|
|
|
|
|
|
|
|
def test_streaming_encoding_detection(http_server):
|
|
|
|
r = http('--stream', http_server + '/stream/encoding/random')
|
|
|
|
assert ASCII_FILE_CONTENT in r
|
|
|
|
assert UNICODE_FILE_CONTENT in r
|