mirror of
https://github.com/httpie/cli.git
synced 2024-11-25 01:03:27 +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)
|
||||
-------------------------
|
||||
* 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
|
||||
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)
|
||||
@ -477,6 +478,7 @@ This project adheres to `Semantic Versioning <https://semver.org/>`_.
|
||||
.. _#128: https://github.com/httpie/httpie/issues/128
|
||||
.. _#201: https://github.com/httpie/httpie/issues/201
|
||||
.. _#488: https://github.com/httpie/httpie/issues/488
|
||||
.. _#534: https://github.com/httpie/httpie/issues/534
|
||||
.. _#668: https://github.com/httpie/httpie/issues/668
|
||||
.. _#684: https://github.com/httpie/httpie/issues/684
|
||||
.. _#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
|
||||
.. _#1029: https://github.com/httpie/httpie/issues/1029
|
||||
.. _#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
|
||||
|
||||
|
||||
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
|
||||
---------------------------------------
|
||||
|
||||
|
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
|
||||
|
||||
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.matching import assert_output_matches, Expect, ExpectSequence
|
||||
|
||||
|
||||
def test_follow_all_redirects_shown(httpbin):
|
||||
@ -73,4 +74,11 @@ def test_http_307_allow_redirect_post_verbose(httpbin):
|
||||
'@' + FILE_PATH_ARG)
|
||||
assert r.count('POST /redirect-to') == 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_output_matches(r, [
|
||||
*ExpectSequence.TERMINAL_REQUEST,
|
||||
Expect.RESPONSE_HEADERS,
|
||||
Expect.SEPARATOR,
|
||||
*ExpectSequence.TERMINAL_EXCHANGE,
|
||||
])
|
||||
|
@ -9,45 +9,10 @@ TODO: cover more scenarios
|
||||
* 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
|
||||
|
||||
|
||||
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():
|
||||
r = http('--print=H', '--offline', 'pie.dev')
|
||||
assert_output_matches(r, [Expect.REQUEST_HEADERS])
|
||||
@ -60,17 +25,17 @@ def test_redirected_headers():
|
||||
|
||||
def test_terminal_headers_and_body():
|
||||
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):
|
||||
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):
|
||||
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):
|
||||
@ -93,29 +58,29 @@ def test_raw_headers_and_body():
|
||||
'--print=HB', '--offline', 'pie.dev', 'AAA=BBB',
|
||||
env=MockEnvironment(stdout_isatty=False),
|
||||
)
|
||||
assert_output_matches(r, RAW_REQUEST)
|
||||
assert_output_matches(r, ExpectSequence.RAW_REQUEST)
|
||||
|
||||
|
||||
def test_raw_body():
|
||||
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):
|
||||
r = http('--verbose', httpbin + '/post', 'a=b', env=MockEnvironment(stdout_isatty=False))
|
||||
assert HTTP_OK in r
|
||||
assert_output_matches(r, RAW_EXCHANGE)
|
||||
assert_output_matches(r, ExpectSequence.RAW_EXCHANGE)
|
||||
|
||||
|
||||
def test_terminal_exchange(httpbin):
|
||||
r = http('--verbose', httpbin + '/post', 'a=b')
|
||||
assert HTTP_OK in r
|
||||
assert_output_matches(r, TERMINAL_EXCHANGE)
|
||||
assert_output_matches(r, ExpectSequence.TERMINAL_EXCHANGE)
|
||||
|
||||
|
||||
def test_headers_multipart_body_separator():
|
||||
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():
|
||||
@ -123,16 +88,16 @@ def test_redirected_headers_multipart_no_separator():
|
||||
'--print=HB', '--multipart', '--offline', 'pie.dev', 'AAA=BBB',
|
||||
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):
|
||||
r = http('--verbose', '--chunked', httpbin_with_chunked_support + '/post', 'hello=world')
|
||||
assert HTTP_OK 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):
|
||||
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
|
||||
|
||||
import pytest
|
||||
|
||||
from .parsing import OutputMatchingError, expect_tokens, Expect
|
||||
from .parsing import OutputMatchingError, expect_tokens
|
||||
from .tokens import Expect, ExpectSequence
|
||||
|
||||
|
||||
__all__ = [
|
||||
'assert_output_matches',
|
||||
'assert_output_does_not_match',
|
||||
'Expect',
|
||||
'ExpectSequence',
|
||||
]
|
||||
|
||||
|
||||
|
@ -1,22 +1,11 @@
|
||||
import re
|
||||
from typing import Iterable
|
||||
from enum import Enum, auto
|
||||
|
||||
from httpie.output.writer import MESSAGE_SEPARATOR
|
||||
from .tokens import Expect
|
||||
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}')
|
||||
|
||||
|
||||
|
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