Final touches for #1088 (#1091)

* 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:
Jakub Roztocil 2021-06-15 14:48:44 +02:00 committed by GitHub
parent 2d55c01c7e
commit 07a0359316
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 96 additions and 64 deletions

View File

@ -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

View File

@ -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
View File

@ -0,0 +1,6 @@
# https://editorconfig.org
[{*.txt, *.json}]
trim_trailing_whitespace = false
insert_final_newline = false

View File

@ -1,4 +1,4 @@
{
"name": "Jakub Roztočil",
"unicode": "χρυσαφὶ 太陽 เลิศ ♜♞♝♛♚♝♞♜ оживлённым तान्यहानि 有朋"
}
}

View File

@ -1 +1 @@
[one line of UTF8-encoded unicode text] χρυσαφὶ 太陽 เลิศ ♜♞♝♛♚♝♞♜ оживлённым तान्यहानि 有朋 ஸ்றீனிவாஸ ٱلرَّحْمـَبنِ
[one line of UTF8-encoded unicode text] χρυσαφὶ 太陽 เลิศ ♜♞♝♛♚♝♞♜ оживлённым तान्यहानि 有朋 ஸ்றீனிவாஸ ٱلرَّحْمـَبنِ

View File

@ -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,
])

View File

@ -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)

View File

@ -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',
]

View File

@ -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}')

View 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
]