mirror of
https://github.com/httpie/cli.git
synced 2024-11-25 09:13:25 +01:00
* Make sure there’s no trailing \n in test files for easier output inspection * Refactor output matching test utils * More robust `test_http_307_allow_redirect_post_verbose()` * Changelog * Mention HTTP 307 Temporary Redirect re-post behaviour in README
This commit is contained in:
parent
2d55c01c7e
commit
07a0359316
@ -9,9 +9,10 @@ This project adheres to `Semantic Versioning <https://semver.org/>`_.
|
|||||||
|
|
||||||
`2.5.0-dev`_ (unreleased)
|
`2.5.0-dev`_ (unreleased)
|
||||||
-------------------------
|
-------------------------
|
||||||
* Fixed ``--continue --download`` with a single byte to be downloaded left. (`#1032`_)
|
|
||||||
* Added ``--raw`` to allow specifying the raw request body without extra processing as
|
* Added ``--raw`` to allow specifying the raw request body without extra processing as
|
||||||
an alternative to ``stdin``. (`#534`_)
|
an alternative to ``stdin``. (`#534`_)
|
||||||
|
* Fixed ``--continue --download`` with a single byte to be downloaded left. (`#1032`_)
|
||||||
|
* Fixed ``--verbose`` HTTP 307 redirects with streamed request body. (`#1088`_)
|
||||||
|
|
||||||
|
|
||||||
`2.4.0`_ (2021-02-06)
|
`2.4.0`_ (2021-02-06)
|
||||||
@ -477,6 +478,7 @@ This project adheres to `Semantic Versioning <https://semver.org/>`_.
|
|||||||
.. _#128: https://github.com/httpie/httpie/issues/128
|
.. _#128: https://github.com/httpie/httpie/issues/128
|
||||||
.. _#201: https://github.com/httpie/httpie/issues/201
|
.. _#201: https://github.com/httpie/httpie/issues/201
|
||||||
.. _#488: https://github.com/httpie/httpie/issues/488
|
.. _#488: https://github.com/httpie/httpie/issues/488
|
||||||
|
.. _#534: https://github.com/httpie/httpie/issues/534
|
||||||
.. _#668: https://github.com/httpie/httpie/issues/668
|
.. _#668: https://github.com/httpie/httpie/issues/668
|
||||||
.. _#684: https://github.com/httpie/httpie/issues/684
|
.. _#684: https://github.com/httpie/httpie/issues/684
|
||||||
.. _#718: https://github.com/httpie/httpie/issues/718
|
.. _#718: https://github.com/httpie/httpie/issues/718
|
||||||
@ -500,3 +502,4 @@ This project adheres to `Semantic Versioning <https://semver.org/>`_.
|
|||||||
.. _#1026: https://github.com/httpie/httpie/issues/1026
|
.. _#1026: https://github.com/httpie/httpie/issues/1026
|
||||||
.. _#1029: https://github.com/httpie/httpie/issues/1029
|
.. _#1029: https://github.com/httpie/httpie/issues/1029
|
||||||
.. _#1032: https://github.com/httpie/httpie/issues/1032
|
.. _#1032: https://github.com/httpie/httpie/issues/1032
|
||||||
|
.. _#1088: https://github.com/httpie/httpie/issues/1088
|
||||||
|
@ -1071,6 +1071,10 @@ and show the final response instead, use the ``--follow, -F`` option:
|
|||||||
$ http --follow pie.dev/redirect/3
|
$ http --follow pie.dev/redirect/3
|
||||||
|
|
||||||
|
|
||||||
|
With ``HTTP 307 Temporary Redirect``, the method and the body of the original request
|
||||||
|
are reused to perform the redirected request. Otherwise a body-less ``GET`` request is performed.
|
||||||
|
|
||||||
|
|
||||||
Showing intermediary redirect responses
|
Showing intermediary redirect responses
|
||||||
---------------------------------------
|
---------------------------------------
|
||||||
|
|
||||||
|
6
tests/fixtures/.editorconfig
vendored
Normal file
6
tests/fixtures/.editorconfig
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# https://editorconfig.org
|
||||||
|
|
||||||
|
[{*.txt, *.json}]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
insert_final_newline = false
|
||||||
|
|
@ -2,8 +2,9 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from httpie.status import ExitStatus
|
from httpie.status import ExitStatus
|
||||||
from .fixtures import FILE_PATH_ARG
|
from .fixtures import FILE_PATH_ARG, FILE_CONTENT
|
||||||
from .utils import http, HTTP_OK
|
from .utils import http, HTTP_OK
|
||||||
|
from .utils.matching import assert_output_matches, Expect, ExpectSequence
|
||||||
|
|
||||||
|
|
||||||
def test_follow_all_redirects_shown(httpbin):
|
def test_follow_all_redirects_shown(httpbin):
|
||||||
@ -73,4 +74,11 @@ def test_http_307_allow_redirect_post_verbose(httpbin):
|
|||||||
'@' + FILE_PATH_ARG)
|
'@' + FILE_PATH_ARG)
|
||||||
assert r.count('POST /redirect-to') == 1
|
assert r.count('POST /redirect-to') == 1
|
||||||
assert r.count('POST /post') == 1
|
assert r.count('POST /post') == 1
|
||||||
|
assert r.count(FILE_CONTENT) == 3 # two requests + final response contain it
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
|
assert_output_matches(r, [
|
||||||
|
*ExpectSequence.TERMINAL_REQUEST,
|
||||||
|
Expect.RESPONSE_HEADERS,
|
||||||
|
Expect.SEPARATOR,
|
||||||
|
*ExpectSequence.TERMINAL_EXCHANGE,
|
||||||
|
])
|
||||||
|
@ -9,45 +9,10 @@ TODO: cover more scenarios
|
|||||||
* streamed uploads
|
* streamed uploads
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from .utils.matching import assert_output_matches, Expect
|
from .utils.matching import assert_output_matches, Expect, ExpectSequence
|
||||||
from .utils import http, HTTP_OK, MockEnvironment
|
from .utils import http, HTTP_OK, MockEnvironment
|
||||||
|
|
||||||
|
|
||||||
RAW_REQUEST = [
|
|
||||||
Expect.REQUEST_HEADERS,
|
|
||||||
Expect.BODY,
|
|
||||||
]
|
|
||||||
RAW_RESPONSE = [
|
|
||||||
Expect.RESPONSE_HEADERS,
|
|
||||||
Expect.BODY,
|
|
||||||
]
|
|
||||||
RAW_EXCHANGE = [
|
|
||||||
*RAW_REQUEST,
|
|
||||||
Expect.SEPARATOR, # Good choice?
|
|
||||||
*RAW_RESPONSE,
|
|
||||||
]
|
|
||||||
RAW_BODY = [
|
|
||||||
Expect.BODY,
|
|
||||||
]
|
|
||||||
|
|
||||||
TERMINAL_REQUEST = [
|
|
||||||
*RAW_REQUEST,
|
|
||||||
Expect.SEPARATOR,
|
|
||||||
]
|
|
||||||
TERMINAL_RESPONSE = [
|
|
||||||
*RAW_RESPONSE,
|
|
||||||
Expect.SEPARATOR,
|
|
||||||
]
|
|
||||||
TERMINAL_EXCHANGE = [
|
|
||||||
*TERMINAL_REQUEST,
|
|
||||||
*TERMINAL_RESPONSE,
|
|
||||||
]
|
|
||||||
TERMINAL_BODY = [
|
|
||||||
RAW_BODY,
|
|
||||||
Expect.SEPARATOR
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def test_headers():
|
def test_headers():
|
||||||
r = http('--print=H', '--offline', 'pie.dev')
|
r = http('--print=H', '--offline', 'pie.dev')
|
||||||
assert_output_matches(r, [Expect.REQUEST_HEADERS])
|
assert_output_matches(r, [Expect.REQUEST_HEADERS])
|
||||||
@ -60,17 +25,17 @@ def test_redirected_headers():
|
|||||||
|
|
||||||
def test_terminal_headers_and_body():
|
def test_terminal_headers_and_body():
|
||||||
r = http('--print=HB', '--offline', 'pie.dev', 'AAA=BBB')
|
r = http('--print=HB', '--offline', 'pie.dev', 'AAA=BBB')
|
||||||
assert_output_matches(r, TERMINAL_REQUEST)
|
assert_output_matches(r, ExpectSequence.TERMINAL_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
def test_terminal_request_headers_response_body(httpbin):
|
def test_terminal_request_headers_response_body(httpbin):
|
||||||
r = http('--print=Hb', httpbin + '/get')
|
r = http('--print=Hb', httpbin + '/get')
|
||||||
assert_output_matches(r, TERMINAL_REQUEST)
|
assert_output_matches(r, ExpectSequence.TERMINAL_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
def test_raw_request_headers_response_body(httpbin):
|
def test_raw_request_headers_response_body(httpbin):
|
||||||
r = http('--print=Hb', httpbin + '/get', env=MockEnvironment(stdout_isatty=False))
|
r = http('--print=Hb', httpbin + '/get', env=MockEnvironment(stdout_isatty=False))
|
||||||
assert_output_matches(r, RAW_REQUEST)
|
assert_output_matches(r, ExpectSequence.RAW_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
def test_terminal_request_headers_response_headers(httpbin):
|
def test_terminal_request_headers_response_headers(httpbin):
|
||||||
@ -93,29 +58,29 @@ def test_raw_headers_and_body():
|
|||||||
'--print=HB', '--offline', 'pie.dev', 'AAA=BBB',
|
'--print=HB', '--offline', 'pie.dev', 'AAA=BBB',
|
||||||
env=MockEnvironment(stdout_isatty=False),
|
env=MockEnvironment(stdout_isatty=False),
|
||||||
)
|
)
|
||||||
assert_output_matches(r, RAW_REQUEST)
|
assert_output_matches(r, ExpectSequence.RAW_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
def test_raw_body():
|
def test_raw_body():
|
||||||
r = http('--print=B', '--offline', 'pie.dev', 'AAA=BBB', env=MockEnvironment(stdout_isatty=False))
|
r = http('--print=B', '--offline', 'pie.dev', 'AAA=BBB', env=MockEnvironment(stdout_isatty=False))
|
||||||
assert_output_matches(r, RAW_BODY)
|
assert_output_matches(r, ExpectSequence.RAW_BODY)
|
||||||
|
|
||||||
|
|
||||||
def test_raw_exchange(httpbin):
|
def test_raw_exchange(httpbin):
|
||||||
r = http('--verbose', httpbin + '/post', 'a=b', env=MockEnvironment(stdout_isatty=False))
|
r = http('--verbose', httpbin + '/post', 'a=b', env=MockEnvironment(stdout_isatty=False))
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
assert_output_matches(r, RAW_EXCHANGE)
|
assert_output_matches(r, ExpectSequence.RAW_EXCHANGE)
|
||||||
|
|
||||||
|
|
||||||
def test_terminal_exchange(httpbin):
|
def test_terminal_exchange(httpbin):
|
||||||
r = http('--verbose', httpbin + '/post', 'a=b')
|
r = http('--verbose', httpbin + '/post', 'a=b')
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
assert_output_matches(r, TERMINAL_EXCHANGE)
|
assert_output_matches(r, ExpectSequence.TERMINAL_EXCHANGE)
|
||||||
|
|
||||||
|
|
||||||
def test_headers_multipart_body_separator():
|
def test_headers_multipart_body_separator():
|
||||||
r = http('--print=HB', '--multipart', '--offline', 'pie.dev', 'AAA=BBB')
|
r = http('--print=HB', '--multipart', '--offline', 'pie.dev', 'AAA=BBB')
|
||||||
assert_output_matches(r, TERMINAL_REQUEST)
|
assert_output_matches(r, ExpectSequence.TERMINAL_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
def test_redirected_headers_multipart_no_separator():
|
def test_redirected_headers_multipart_no_separator():
|
||||||
@ -123,16 +88,16 @@ def test_redirected_headers_multipart_no_separator():
|
|||||||
'--print=HB', '--multipart', '--offline', 'pie.dev', 'AAA=BBB',
|
'--print=HB', '--multipart', '--offline', 'pie.dev', 'AAA=BBB',
|
||||||
env=MockEnvironment(stdout_isatty=False),
|
env=MockEnvironment(stdout_isatty=False),
|
||||||
)
|
)
|
||||||
assert_output_matches(r, RAW_REQUEST)
|
assert_output_matches(r, ExpectSequence.RAW_REQUEST)
|
||||||
|
|
||||||
|
|
||||||
def test_verbose_chunked(httpbin_with_chunked_support):
|
def test_verbose_chunked(httpbin_with_chunked_support):
|
||||||
r = http('--verbose', '--chunked', httpbin_with_chunked_support + '/post', 'hello=world')
|
r = http('--verbose', '--chunked', httpbin_with_chunked_support + '/post', 'hello=world')
|
||||||
assert HTTP_OK in r
|
assert HTTP_OK in r
|
||||||
assert 'Transfer-Encoding: chunked' in r
|
assert 'Transfer-Encoding: chunked' in r
|
||||||
assert_output_matches(r, TERMINAL_EXCHANGE)
|
assert_output_matches(r, ExpectSequence.TERMINAL_EXCHANGE)
|
||||||
|
|
||||||
|
|
||||||
def test_request_headers_response_body(httpbin):
|
def test_request_headers_response_body(httpbin):
|
||||||
r = http('--print=Hb', httpbin + '/get')
|
r = http('--print=Hb', httpbin + '/get')
|
||||||
assert_output_matches(r, TERMINAL_REQUEST)
|
assert_output_matches(r, ExpectSequence.TERMINAL_REQUEST)
|
||||||
|
@ -1,14 +1,20 @@
|
|||||||
|
"""
|
||||||
|
Utilities for testing output composition.
|
||||||
|
|
||||||
|
"""
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from .parsing import OutputMatchingError, expect_tokens, Expect
|
from .parsing import OutputMatchingError, expect_tokens
|
||||||
|
from .tokens import Expect, ExpectSequence
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'assert_output_matches',
|
'assert_output_matches',
|
||||||
'assert_output_does_not_match',
|
'assert_output_does_not_match',
|
||||||
'Expect',
|
'Expect',
|
||||||
|
'ExpectSequence',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,22 +1,11 @@
|
|||||||
import re
|
import re
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
from enum import Enum, auto
|
|
||||||
|
|
||||||
from httpie.output.writer import MESSAGE_SEPARATOR
|
from httpie.output.writer import MESSAGE_SEPARATOR
|
||||||
|
from .tokens import Expect
|
||||||
from ...utils import CRLF
|
from ...utils import CRLF
|
||||||
|
|
||||||
|
|
||||||
class Expect(Enum):
|
|
||||||
"""
|
|
||||||
Predefined token types we can expect in the output.
|
|
||||||
|
|
||||||
"""
|
|
||||||
REQUEST_HEADERS = auto()
|
|
||||||
RESPONSE_HEADERS = auto()
|
|
||||||
BODY = auto()
|
|
||||||
SEPARATOR = auto()
|
|
||||||
|
|
||||||
|
|
||||||
SEPARATOR_RE = re.compile(f'^{MESSAGE_SEPARATOR}')
|
SEPARATOR_RE = re.compile(f'^{MESSAGE_SEPARATOR}')
|
||||||
|
|
||||||
|
|
||||||
|
51
tests/utils/matching/tokens.py
Normal file
51
tests/utils/matching/tokens.py
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
from enum import Enum, auto
|
||||||
|
|
||||||
|
|
||||||
|
class Expect(Enum):
|
||||||
|
"""
|
||||||
|
Predefined token types we can expect in the output.
|
||||||
|
|
||||||
|
"""
|
||||||
|
REQUEST_HEADERS = auto()
|
||||||
|
RESPONSE_HEADERS = auto()
|
||||||
|
BODY = auto()
|
||||||
|
SEPARATOR = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class ExpectSequence:
|
||||||
|
"""
|
||||||
|
Standard combined chunks. These predefined requests and responses assume a body.
|
||||||
|
|
||||||
|
"""
|
||||||
|
RAW_REQUEST = [
|
||||||
|
Expect.REQUEST_HEADERS,
|
||||||
|
Expect.BODY,
|
||||||
|
]
|
||||||
|
RAW_RESPONSE = [
|
||||||
|
Expect.RESPONSE_HEADERS,
|
||||||
|
Expect.BODY,
|
||||||
|
]
|
||||||
|
RAW_EXCHANGE = [
|
||||||
|
*RAW_REQUEST,
|
||||||
|
Expect.SEPARATOR, # Good choice?
|
||||||
|
*RAW_RESPONSE,
|
||||||
|
]
|
||||||
|
RAW_BODY = [
|
||||||
|
Expect.BODY,
|
||||||
|
]
|
||||||
|
TERMINAL_REQUEST = [
|
||||||
|
*RAW_REQUEST,
|
||||||
|
Expect.SEPARATOR,
|
||||||
|
]
|
||||||
|
TERMINAL_RESPONSE = [
|
||||||
|
*RAW_RESPONSE,
|
||||||
|
Expect.SEPARATOR,
|
||||||
|
]
|
||||||
|
TERMINAL_EXCHANGE = [
|
||||||
|
*TERMINAL_REQUEST,
|
||||||
|
*TERMINAL_RESPONSE,
|
||||||
|
]
|
||||||
|
TERMINAL_BODY = [
|
||||||
|
RAW_BODY,
|
||||||
|
Expect.SEPARATOR
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user