mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-12-24 19:42:07 +03:00
Update output
Can now be on the following: - Binary response body - JSON - Textual Summary
This commit is contained in:
parent
359f153e63
commit
dd98920f80
@ -2,13 +2,10 @@
|
|||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
def check(expected, actual):
|
||||||
def check_file(expected_file, actual_file):
|
expected_test = json.loads(expected)
|
||||||
expected_tests = json.loads(open(expected_file).read())
|
actual_test = json.loads(actual)
|
||||||
actual_tests = json.loads(open(actual_file).read())
|
check_output(expected_test, actual_test)
|
||||||
assert len(expected_tests) == 1
|
|
||||||
assert len(actual_tests) == 1
|
|
||||||
check_output(expected_tests[0], actual_tests[0])
|
|
||||||
|
|
||||||
|
|
||||||
def check_output(expected_test, actual_test):
|
def check_output(expected_test, actual_test):
|
||||||
@ -77,7 +74,9 @@ def main():
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
expected_file = sys.argv[1]
|
expected_file = sys.argv[1]
|
||||||
actual_file = sys.argv[2]
|
actual_file = sys.argv[2]
|
||||||
check_file(expected_file, actual_file)
|
expected = open(expected_file).read()
|
||||||
|
actual = open(actual_file).read()
|
||||||
|
check_file(expected, actual)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -43,12 +43,9 @@ def test(hurl_file):
|
|||||||
options = open(options_file).read().strip().split(' ')
|
options = open(options_file).read().strip().split(' ')
|
||||||
if os.path.exists(curl_file):
|
if os.path.exists(curl_file):
|
||||||
options.append('--verbose')
|
options.append('--verbose')
|
||||||
|
|
||||||
if os.path.exists(json_output_file):
|
|
||||||
json_output_actual_file = os.path.join(tempfile.mkdtemp(), 'output.json')
|
|
||||||
options.append('--json')
|
|
||||||
options.append(json_output_actual_file)
|
|
||||||
|
|
||||||
|
if os.path.exists(json_output_file):
|
||||||
|
options.append('--json')
|
||||||
|
|
||||||
cmd = ['hurl', hurl_file] + options
|
cmd = ['hurl', hurl_file] + options
|
||||||
print(' '.join(cmd))
|
print(' '.join(cmd))
|
||||||
@ -75,6 +72,12 @@ def test(hurl_file):
|
|||||||
print(f'actual: <{actual}>\nexpected: <{expected}>')
|
print(f'actual: <{actual}>\nexpected: <{expected}>')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# stdout (json)
|
||||||
|
if os.path.exists(json_output_file):
|
||||||
|
expected = open(json_output_file).read()
|
||||||
|
actual = result.stdout
|
||||||
|
check_json_output.check(expected, actual)
|
||||||
|
|
||||||
# stderr
|
# stderr
|
||||||
f = hurl_file.replace('.hurl', '.' + get_os() + '.err')
|
f = hurl_file.replace('.hurl', '.' + get_os() + '.err')
|
||||||
if os.path.exists(f):
|
if os.path.exists(f):
|
||||||
@ -119,9 +122,6 @@ def test(hurl_file):
|
|||||||
print('actual: %s' % actual_commands[i])
|
print('actual: %s' % actual_commands[i])
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if os.path.exists(json_output_file):
|
|
||||||
check_json_output.check_file(json_output_file, json_output_actual_file)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
for hurl_file in sys.argv[1:]:
|
for hurl_file in sys.argv[1:]:
|
||||||
|
@ -1,71 +1,69 @@
|
|||||||
[
|
{
|
||||||
{
|
"filename": "tests/assert_header.hurl",
|
||||||
"filename": "tests/assert_header.hurl",
|
"entries": [
|
||||||
"entries": [
|
{
|
||||||
{
|
"request": {
|
||||||
"request": {
|
"method": "GET",
|
||||||
"method": "GET",
|
"url": "http://localhost:8000/assert-header"
|
||||||
"url": "http://localhost:8000/assert-header"
|
},
|
||||||
|
"response": {
|
||||||
|
"httpVersion": "HTTP/1.0",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
"asserts": [
|
||||||
|
{
|
||||||
|
"line": 2,
|
||||||
|
"success": true
|
||||||
},
|
},
|
||||||
"response": {
|
{
|
||||||
"httpVersion": "HTTP/1.0",
|
"line": 2,
|
||||||
"status": 200
|
"success": true
|
||||||
},
|
},
|
||||||
"asserts": [
|
{
|
||||||
{
|
"line": 3,
|
||||||
"line": 2,
|
"success": true
|
||||||
"success": true
|
},
|
||||||
},
|
{
|
||||||
{
|
"line": 4,
|
||||||
"line": 2,
|
"success": true
|
||||||
"success": true
|
},
|
||||||
},
|
{
|
||||||
{
|
"line": 5,
|
||||||
"line": 3,
|
"success": true
|
||||||
"success": true
|
},
|
||||||
},
|
{
|
||||||
{
|
"line": 7,
|
||||||
"line": 4,
|
"success": true
|
||||||
"success": true
|
},
|
||||||
},
|
{
|
||||||
{
|
"line": 8,
|
||||||
"line": 5,
|
"success": true
|
||||||
"success": true
|
},
|
||||||
},
|
{
|
||||||
{
|
"line": 9,
|
||||||
"line": 7,
|
"success": true
|
||||||
"success": true
|
},
|
||||||
},
|
{
|
||||||
{
|
"line": 10,
|
||||||
"line": 8,
|
"success": true
|
||||||
"success": true
|
},
|
||||||
},
|
{
|
||||||
{
|
"line": 11,
|
||||||
"line": 9,
|
"success": true
|
||||||
"success": true
|
},
|
||||||
},
|
{
|
||||||
{
|
"line": 12,
|
||||||
"line": 10,
|
"success": true
|
||||||
"success": true
|
},
|
||||||
},
|
{
|
||||||
{
|
"line": 13,
|
||||||
"line": 11,
|
"success": true
|
||||||
"success": true
|
},
|
||||||
},
|
{
|
||||||
{
|
"line": 14,
|
||||||
"line": 12,
|
"success": true
|
||||||
"success": true
|
}
|
||||||
},
|
]
|
||||||
{
|
}
|
||||||
"line": 13,
|
]
|
||||||
"success": true
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"line": 14,
|
|
||||||
"success": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
@ -1,32 +1,31 @@
|
|||||||
[
|
{
|
||||||
{
|
"filename": "tests/error_assert_match_utf8.hurl",
|
||||||
"filename": "tests/error_assert_match_utf8.hurl",
|
"entries": [
|
||||||
"entries": [
|
{
|
||||||
{
|
"request": {
|
||||||
"request": {
|
"method": "GET",
|
||||||
"method": "GET",
|
"url": "http://localhost:8000/error-assert/match-utf8"
|
||||||
"url": "http://localhost:8000/error-assert/match-utf8"
|
},
|
||||||
|
"response": {
|
||||||
|
"httpVersion": "HTTP/1.0",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
"asserts": [
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"line": 2
|
||||||
},
|
},
|
||||||
"response": {
|
{
|
||||||
"httpVersion": "HTTP/1.0",
|
"success": true,
|
||||||
"status": 200
|
"line": 2
|
||||||
},
|
},
|
||||||
"asserts": [
|
{
|
||||||
{
|
"success": false,
|
||||||
"success": true,
|
"message": "Invalid Decoding\n --> tests/error_assert_match_utf8.hurl:4:1\n |\n 4 | body matches \".*\"\n | ^^^^ The body can not be decoded with charset 'utf-8'\n |",
|
||||||
"line": 2
|
"line": 4
|
||||||
},
|
}
|
||||||
{
|
]
|
||||||
"success": true,
|
}
|
||||||
"line": 2
|
]
|
||||||
},
|
}
|
||||||
{
|
|
||||||
"success": false,
|
|
||||||
"message": "Invalid Decoding\n --> tests/error_assert_match_utf8.hurl:4:1\n |\n 4 | body matches \".*\"\n | ^^^^ The body can not be decoded with charset 'utf-8'\n |",
|
|
||||||
"line": 4
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
@ -1,28 +1,26 @@
|
|||||||
[
|
{
|
||||||
{
|
"filename": "tests/error_assert_status.hurl",
|
||||||
"filename": "tests/error_assert_status.hurl",
|
"entries": [
|
||||||
"entries": [
|
{
|
||||||
{
|
"request": {
|
||||||
"request": {
|
"method": "GET",
|
||||||
"method": "GET",
|
"url": "http://localhost:8000/not_found"
|
||||||
"url": "http://localhost:8000/not_found"
|
},
|
||||||
|
"response": {
|
||||||
|
"httpVersion": "HTTP/1.0",
|
||||||
|
"status": 404
|
||||||
|
},
|
||||||
|
"asserts": [
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"line": 2
|
||||||
},
|
},
|
||||||
"response": {
|
{
|
||||||
"httpVersion": "HTTP/1.0",
|
"success": false,
|
||||||
"status": 404
|
"message": "Assert Status\n --> tests/error_assert_status.hurl:2:10\n |\n 2 | HTTP/1.0 200\n | ^^^ actual value is <404>\n |",
|
||||||
},
|
"line": 2
|
||||||
"asserts": [
|
}
|
||||||
{
|
]
|
||||||
"success": true,
|
}
|
||||||
"line": 2
|
]
|
||||||
},
|
}
|
||||||
{
|
|
||||||
"success": false,
|
|
||||||
"message": "Assert Status\n --> tests/error_assert_status.hurl:2:10\n |\n 2 | HTTP/1.0 200\n | ^^^ actual value is <404>\n |",
|
|
||||||
"line": 2
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/error-assert-template-variable-not-found"},"response":{"version":"HTTP/1.0","status":200,"asserts":[{"query":{"type":"header","name":"content-type"},"predicate":{"type":"equal","value":"{{content_type}}"}}]}}]}
|
@ -1,32 +1,30 @@
|
|||||||
[
|
{
|
||||||
{
|
"filename": "tests/error_assert_template_variable_not_found.hurl",
|
||||||
"filename": "tests/error_assert_template_variable_not_found.hurl",
|
"entries": [
|
||||||
"entries": [
|
{
|
||||||
{
|
"request": {
|
||||||
"request": {
|
"method": "GET",
|
||||||
"method": "GET",
|
"url": "http://localhost:8000/error-assert-template-variable-not-found"
|
||||||
"url": "http://localhost:8000/error-assert-template-variable-not-found"
|
},
|
||||||
|
"response": {
|
||||||
|
"httpVersion": "HTTP/1.0",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
"asserts": [
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"line": 2
|
||||||
},
|
},
|
||||||
"response": {
|
{
|
||||||
"httpVersion": "HTTP/1.0",
|
"success": true,
|
||||||
"status": 200
|
"line": 2
|
||||||
},
|
},
|
||||||
"asserts": [
|
{
|
||||||
{
|
"success": false,
|
||||||
"success": true,
|
"message": "Undefined Variable\n --> tests/error_assert_template_variable_not_found.hurl:4:33\n |\n 4 | header \"content-type\" equals \"{{content_type}}\"\n | ^^^^^^^^^^^^ You must set the variable content_type\n |",
|
||||||
"line": 2
|
"line": 4
|
||||||
},
|
}
|
||||||
{
|
]
|
||||||
"success": true,
|
}
|
||||||
"line": 2
|
]
|
||||||
},
|
}
|
||||||
{
|
|
||||||
"success": false,
|
|
||||||
"message": "Undefined Variable\n --> tests/error_assert_template_variable_not_found.hurl:4:33\n |\n 4 | header \"content-type\" equals \"{{content_type}}\"\n | ^^^^^^^^^^^^ You must set the variable content_type\n |",
|
|
||||||
"line": 4
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
@ -1,67 +1,65 @@
|
|||||||
[
|
{
|
||||||
{
|
"filename": "tests/error_assert_value_error.hurl",
|
||||||
"filename": "tests/error_assert_value_error.hurl",
|
"entries": [
|
||||||
"entries": [
|
{
|
||||||
{
|
"request": {
|
||||||
"request": {
|
"method": "GET",
|
||||||
"method": "GET",
|
"url": "http://localhost:8000/error-assert-value"
|
||||||
"url": "http://localhost:8000/error-assert-value"
|
},
|
||||||
|
"response": {
|
||||||
|
"httpVersion": "HTTP/1.0",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
"asserts": [
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"line": 2
|
||||||
},
|
},
|
||||||
"response": {
|
{
|
||||||
"httpVersion": "HTTP/1.0",
|
"success": true,
|
||||||
"status": 200
|
"line": 2
|
||||||
},
|
},
|
||||||
"asserts": [
|
{
|
||||||
{
|
"success": false,
|
||||||
"success": true,
|
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:4:0\n |\n 4 | header \"content-type\" equals \"XXX\"\n | actual: string <text/html; charset=utf-8>\n | expected: string <XXX>\n |",
|
||||||
"line": 2
|
"line": 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"success": true,
|
"success": false,
|
||||||
"line": 2
|
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:5:0\n |\n 5 | header \"content-type\" notEquals \"text/html; charset=utf-8\"\n | actual: string <text/html; charset=utf-8>\n | expected: string <text/html; charset=utf-8>\n |",
|
||||||
},
|
"line": 5
|
||||||
{
|
},
|
||||||
"success": false,
|
{
|
||||||
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:4:0\n |\n 4 | header \"content-type\" equals \"XXX\"\n | actual: string <text/html; charset=utf-8>\n | expected: string <XXX>\n |",
|
"success": false,
|
||||||
"line": 4
|
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:6:0\n |\n 6 | jsonpath \"$.id\" equals \"000001\"\n | actual: none\n | expected: string <000001>\n |",
|
||||||
},
|
"line": 6
|
||||||
{
|
},
|
||||||
"success": false,
|
{
|
||||||
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:5:0\n |\n 5 | header \"content-type\" notEquals \"text/html; charset=utf-8\"\n | actual: string <text/html; charset=utf-8>\n | expected: string <text/html; charset=utf-8>\n |",
|
"success": false,
|
||||||
"line": 5
|
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:7:0\n |\n 7 | jsonpath \"$.values\" includes 100\n | actual: [int <1>, int <2>, int <3>]\n | expected: includes int <100>\n |",
|
||||||
},
|
"line": 7
|
||||||
{
|
},
|
||||||
"success": false,
|
{
|
||||||
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:6:0\n |\n 6 | jsonpath \"$.id\" equals \"000001\"\n | actual: none\n | expected: string <000001>\n |",
|
"success": false,
|
||||||
"line": 6
|
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:8:0\n |\n 8 | jsonpath \"$.values\" not contains \"Hello\"\n | actual: [int <1>, int <2>, int <3>]\n | expected: not contains string <Hello>\n | >>> types between actual and expected are not consistent\n |",
|
||||||
},
|
"line": 8
|
||||||
{
|
},
|
||||||
"success": false,
|
{
|
||||||
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:7:0\n |\n 7 | jsonpath \"$.values\" includes 100\n | actual: [int <1>, int <2>, int <3>]\n | expected: includes int <100>\n |",
|
"success": false,
|
||||||
"line": 7
|
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:9:0\n |\n 9 | jsonpath \"$.count\" greaterThan 5\n | actual: int <2>\n | expected: greater than int <5>\n |",
|
||||||
},
|
"line": 9
|
||||||
{
|
},
|
||||||
"success": false,
|
{
|
||||||
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:8:0\n |\n 8 | jsonpath \"$.values\" not contains \"Hello\"\n | actual: [int <1>, int <2>, int <3>]\n | expected: not contains string <Hello>\n | >>> types between actual and expected are not consistent\n |",
|
"success": false,
|
||||||
"line": 8
|
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:10:0\n |\n10 | jsonpath \"$.count\" isFloat\n | actual: int <2>\n | expected: float\n |",
|
||||||
},
|
"line": 10
|
||||||
{
|
},
|
||||||
"success": false,
|
{
|
||||||
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:9:0\n |\n 9 | jsonpath \"$.count\" greaterThan 5\n | actual: int <2>\n | expected: greater than int <5>\n |",
|
"success": false,
|
||||||
"line": 9
|
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:11:0\n |\n11 | bytes contains hex,00;\n | actual: byte array <7b202276616c756573223a205b312c322c335d2c2022636f756e74223a20327d>\n | expected: contains byte array <00>\n |",
|
||||||
},
|
"line": 11
|
||||||
{
|
}
|
||||||
"success": false,
|
]
|
||||||
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:10:0\n |\n10 | jsonpath \"$.count\" isFloat\n | actual: int <2>\n | expected: float\n |",
|
}
|
||||||
"line": 10
|
]
|
||||||
},
|
}
|
||||||
{
|
|
||||||
"success": false,
|
|
||||||
"message": "Assert Failure\n --> tests/error_assert_value_error.hurl:11:0\n |\n11 | bytes contains hex,00;\n | actual: byte array <7b202276616c756573223a205b312c322c335d2c2022636f756e74223a20327d>\n | expected: contains byte array <00>\n |",
|
|
||||||
"line": 11
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
@ -1,32 +1,30 @@
|
|||||||
[
|
{
|
||||||
{
|
"filename": "tests/error_query_header_not_found.hurl",
|
||||||
"filename": "tests/error_query_header_not_found.hurl",
|
"entries": [
|
||||||
"entries": [
|
{
|
||||||
{
|
"request": {
|
||||||
"request": {
|
"method": "GET",
|
||||||
"method": "GET",
|
"url": "http://localhost:8000/error-query-header-not-found"
|
||||||
"url": "http://localhost:8000/error-query-header-not-found"
|
},
|
||||||
|
"response": {
|
||||||
|
"httpVersion": "HTTP/1.0",
|
||||||
|
"status": 200
|
||||||
|
},
|
||||||
|
"asserts": [
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"line": 2
|
||||||
},
|
},
|
||||||
"response": {
|
{
|
||||||
"httpVersion": "HTTP/1.0",
|
"success": true,
|
||||||
"status": 200
|
"line": 2
|
||||||
},
|
},
|
||||||
"asserts": [
|
{
|
||||||
{
|
"success": false,
|
||||||
"success": true,
|
"message": "Header not Found\n --> tests/error_query_header_not_found.hurl:3:1\n |\n 3 | Custom: XXX\n | ^^^^^^ This header has not been found in the response\n |",
|
||||||
"line": 2
|
"line": 3
|
||||||
},
|
}
|
||||||
{
|
]
|
||||||
"success": true,
|
}
|
||||||
"line": 2
|
]
|
||||||
},
|
}
|
||||||
{
|
|
||||||
"success": false,
|
|
||||||
"message": "Header not Found\n --> tests/error_query_header_not_found.hurl:3:1\n |\n 3 | Custom: XXX\n | ^^^^^^ This header has not been found in the response\n |",
|
|
||||||
"line": 3
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"filename": "tests/hello.hurl",
|
|
||||||
"entries": [
|
|
||||||
{
|
|
||||||
"request": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "http://localhost:8000/hello"
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"httpVersion": "HTTP/1.0",
|
|
||||||
"status": 200
|
|
||||||
},
|
|
||||||
"asserts": [
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"line": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"line": 2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"line": 3
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"request": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "http://localhost:8000/hello"
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"httpVersion": "HTTP/1.0",
|
|
||||||
"status": 200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"request": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "http://localhost:8000/hello"
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"httpVersion": "HTTP/1.0",
|
|
||||||
"status": 200
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"request": {
|
|
||||||
"method": "GET",
|
|
||||||
"url": "http://localhost:8000/hello"
|
|
||||||
},
|
|
||||||
"response": {
|
|
||||||
"httpVersion": "HTTP/1.0",
|
|
||||||
"status": 200
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"success": true
|
|
||||||
}
|
|
||||||
]
|
|
@ -1 +0,0 @@
|
|||||||
0
|
|
@ -1,5 +0,0 @@
|
|||||||
GET http://localhost:8000/test-mode
|
|
||||||
HTTP/1.0 200
|
|
||||||
```Hello World!```
|
|
||||||
|
|
||||||
|
|
@ -1 +0,0 @@
|
|||||||
--test
|
|
@ -1,10 +0,0 @@
|
|||||||
from tests import app
|
|
||||||
from flask import request
|
|
||||||
|
|
||||||
@app.route("/test-mode")
|
|
||||||
def test_mode():
|
|
||||||
assert 'Content-Type' not in request.headers
|
|
||||||
assert 'Content-Length' not in request.headers
|
|
||||||
assert len(request.data) == 0
|
|
||||||
return 'Hello World!'
|
|
||||||
|
|
@ -26,7 +26,7 @@ pub use self::logger::{
|
|||||||
pub use self::options::app;
|
pub use self::options::app;
|
||||||
pub use self::options::output_color;
|
pub use self::options::output_color;
|
||||||
pub use self::options::parse_options;
|
pub use self::options::parse_options;
|
||||||
pub use self::options::CliOptions;
|
pub use self::options::{CliOptions, OutputType};
|
||||||
pub use self::variables::parse as parse_variable;
|
pub use self::variables::parse as parse_variable;
|
||||||
|
|
||||||
mod fs;
|
mod fs;
|
||||||
|
@ -28,16 +28,6 @@ use std::io::{BufRead, BufReader};
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
#[cfg(target_family = "unix")]
|
|
||||||
pub fn dev_null() -> String {
|
|
||||||
"/dev/null".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_family = "windows")]
|
|
||||||
pub fn dev_null() -> String {
|
|
||||||
"nul".to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct CliOptions {
|
pub struct CliOptions {
|
||||||
pub cacert_file: Option<String>,
|
pub cacert_file: Option<String>,
|
||||||
@ -54,14 +44,13 @@ pub struct CliOptions {
|
|||||||
pub include: bool,
|
pub include: bool,
|
||||||
pub insecure: bool,
|
pub insecure: bool,
|
||||||
pub interactive: bool,
|
pub interactive: bool,
|
||||||
pub json_file: Option<PathBuf>,
|
|
||||||
pub junit_file: Option<PathBuf>,
|
pub junit_file: Option<PathBuf>,
|
||||||
pub max_redirect: Option<usize>,
|
pub max_redirect: Option<usize>,
|
||||||
pub no_proxy: Option<String>,
|
pub no_proxy: Option<String>,
|
||||||
pub output: Option<String>,
|
pub output: Option<String>,
|
||||||
|
pub output_type: OutputType,
|
||||||
pub progress: bool,
|
pub progress: bool,
|
||||||
pub proxy: Option<String>,
|
pub proxy: Option<String>,
|
||||||
pub summary: bool,
|
|
||||||
pub timeout: Duration,
|
pub timeout: Duration,
|
||||||
pub to_entry: Option<usize>,
|
pub to_entry: Option<usize>,
|
||||||
pub user: Option<String>,
|
pub user: Option<String>,
|
||||||
@ -69,6 +58,12 @@ pub struct CliOptions {
|
|||||||
pub verbose: bool,
|
pub verbose: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum OutputType {
|
||||||
|
ResponseBody,
|
||||||
|
Summary,
|
||||||
|
Json,
|
||||||
|
}
|
||||||
pub fn app() -> App<'static, 'static> {
|
pub fn app() -> App<'static, 'static> {
|
||||||
App::new("hurl")
|
App::new("hurl")
|
||||||
.about("Run hurl FILE(s) or standard input")
|
.about("Run hurl FILE(s) or standard input")
|
||||||
@ -169,9 +164,8 @@ pub fn app() -> App<'static, 'static> {
|
|||||||
.arg(
|
.arg(
|
||||||
clap::Arg::with_name("json")
|
clap::Arg::with_name("json")
|
||||||
.long("json")
|
.long("json")
|
||||||
.value_name("FILE")
|
.conflicts_with("summary")
|
||||||
.help("Write full session(s) to json file")
|
.help("Write full session(s) to json output"),
|
||||||
.takes_value(true),
|
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
clap::Arg::with_name("junit")
|
clap::Arg::with_name("junit")
|
||||||
@ -237,12 +231,13 @@ pub fn app() -> App<'static, 'static> {
|
|||||||
.arg(
|
.arg(
|
||||||
clap::Arg::with_name("summary")
|
clap::Arg::with_name("summary")
|
||||||
.long("summary")
|
.long("summary")
|
||||||
|
.conflicts_with("json")
|
||||||
.help("Print test metrics at the end of the run"),
|
.help("Print test metrics at the end of the run"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
clap::Arg::with_name("test")
|
clap::Arg::with_name("test")
|
||||||
.long("test")
|
.long("test")
|
||||||
.help("Activate test mode; equals --output /dev/null --progress --summary"),
|
.help("This option has been deprecated. It will be removed in the next release"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
clap::Arg::with_name("to_entry")
|
clap::Arg::with_name("to_entry")
|
||||||
@ -355,12 +350,6 @@ pub fn parse_options(matches: ArgMatches) -> Result<CliOptions, CliError> {
|
|||||||
let include = matches.is_present("include");
|
let include = matches.is_present("include");
|
||||||
let insecure = matches.is_present("insecure");
|
let insecure = matches.is_present("insecure");
|
||||||
let interactive = matches.is_present("interactive");
|
let interactive = matches.is_present("interactive");
|
||||||
let json_file = if let Some(filename) = matches.value_of("json") {
|
|
||||||
let path = Path::new(filename);
|
|
||||||
Some(path.to_path_buf())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let junit_file = if let Some(filename) = matches.value_of("junit") {
|
let junit_file = if let Some(filename) = matches.value_of("junit") {
|
||||||
let path = Path::new(filename);
|
let path = Path::new(filename);
|
||||||
Some(path.to_path_buf())
|
Some(path.to_path_buf())
|
||||||
@ -380,16 +369,24 @@ pub fn parse_options(matches: ArgMatches) -> Result<CliOptions, CliError> {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
let no_proxy = matches.value_of("proxy").map(|x| x.to_string());
|
let no_proxy = matches.value_of("proxy").map(|x| x.to_string());
|
||||||
let output = if let Some(filename) = matches.value_of("output") {
|
let output = matches
|
||||||
Some(filename.to_string())
|
.value_of("output")
|
||||||
} else if matches.is_present("test") {
|
.map(|filename| filename.to_string());
|
||||||
Some(dev_null())
|
let output_type = if matches.is_present("summary") {
|
||||||
|
OutputType::Summary
|
||||||
|
} else if matches.is_present("json") {
|
||||||
|
OutputType::Json
|
||||||
} else {
|
} else {
|
||||||
None
|
OutputType::ResponseBody
|
||||||
};
|
};
|
||||||
let progress = matches.is_present("progress") || matches.is_present("test");
|
let progress = matches.is_present("progress") || matches.is_present("test");
|
||||||
let proxy = matches.value_of("proxy").map(|x| x.to_string());
|
let proxy = matches.value_of("proxy").map(|x| x.to_string());
|
||||||
let summary = matches.is_present("summary") || matches.is_present("test");
|
|
||||||
|
if matches.is_present("test") {
|
||||||
|
eprintln!("The option --test is deprecated");
|
||||||
|
eprintln!("It will be removed in the next version");
|
||||||
|
}
|
||||||
|
|
||||||
let timeout = match matches.value_of("max_time") {
|
let timeout = match matches.value_of("max_time") {
|
||||||
None => ClientOptions::default().timeout,
|
None => ClientOptions::default().timeout,
|
||||||
Some(s) => match s.parse::<u64>() {
|
Some(s) => match s.parse::<u64>() {
|
||||||
@ -422,13 +419,12 @@ pub fn parse_options(matches: ArgMatches) -> Result<CliOptions, CliError> {
|
|||||||
insecure,
|
insecure,
|
||||||
interactive,
|
interactive,
|
||||||
junit_file,
|
junit_file,
|
||||||
json_file,
|
|
||||||
max_redirect,
|
max_redirect,
|
||||||
no_proxy,
|
no_proxy,
|
||||||
output,
|
output,
|
||||||
|
output_type,
|
||||||
progress,
|
progress,
|
||||||
proxy,
|
proxy,
|
||||||
summary,
|
|
||||||
timeout,
|
timeout,
|
||||||
to_entry,
|
to_entry,
|
||||||
user,
|
user,
|
||||||
|
@ -27,9 +27,8 @@ use colored::*;
|
|||||||
|
|
||||||
use curl::Version;
|
use curl::Version;
|
||||||
use hurl::cli;
|
use hurl::cli;
|
||||||
use hurl::cli::{CliError, CliOptions};
|
use hurl::cli::{CliError, CliOptions, OutputType};
|
||||||
use hurl::http;
|
use hurl::http;
|
||||||
use hurl::json;
|
|
||||||
use hurl::report;
|
use hurl::report;
|
||||||
use hurl::runner;
|
use hurl::runner;
|
||||||
use hurl::runner::{HurlResult, RunnerOptions};
|
use hurl::runner::{HurlResult, RunnerOptions};
|
||||||
@ -292,11 +291,6 @@ fn main() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let mut json_results = vec![];
|
|
||||||
|
|
||||||
if let Some(file_path) = cli_options.json_file.clone() {
|
|
||||||
json_results = unwrap_or_exit(&log_error_message, json::parse_json(file_path));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (current, filename) in filenames.iter().enumerate() {
|
for (current, filename) in filenames.iter().enumerate() {
|
||||||
let contents = match cli::read_to_string(filename) {
|
let contents = match cli::read_to_string(filename) {
|
||||||
@ -368,10 +362,13 @@ fn main() {
|
|||||||
response.body
|
response.body
|
||||||
};
|
};
|
||||||
output.append(&mut body.clone());
|
output.append(&mut body.clone());
|
||||||
unwrap_or_exit(
|
|
||||||
&log_error_message,
|
if matches!(cli_options.output_type, OutputType::ResponseBody) {
|
||||||
write_output(output, cli_options.output.clone()),
|
unwrap_or_exit(
|
||||||
);
|
&log_error_message,
|
||||||
|
write_output(output, cli_options.output.clone()),
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cli::log_info("no response has been received");
|
cli::log_info("no response has been received");
|
||||||
}
|
}
|
||||||
@ -390,25 +387,20 @@ fn main() {
|
|||||||
|
|
||||||
hurl_results.push(hurl_result.clone());
|
hurl_results.push(hurl_result.clone());
|
||||||
|
|
||||||
if cli_options.json_file.is_some() {
|
if matches!(cli_options.output_type, OutputType::Json) {
|
||||||
let lines: Vec<String> = regex::Regex::new(r"\n|\r\n")
|
let lines: Vec<String> = regex::Regex::new(r"\n|\r\n")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.split(&contents)
|
.split(&contents)
|
||||||
.map(|l| l.to_string())
|
.map(|l| l.to_string())
|
||||||
.collect();
|
.collect();
|
||||||
let json_result = hurl_result.to_json(&lines);
|
let json_result = hurl_result.to_json(&lines);
|
||||||
json_results.push(json_result);
|
let serialized = serde_json::to_string(&json_result).unwrap();
|
||||||
|
unwrap_or_exit(
|
||||||
|
&log_error_message,
|
||||||
|
write_output(serialized.into_bytes(), cli_options.output.clone()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let duration = start.elapsed().as_millis();
|
|
||||||
|
|
||||||
if let Some(file_path) = cli_options.json_file.clone() {
|
|
||||||
log_verbose(format!("Writing json report to {}", file_path.display()).as_str());
|
|
||||||
unwrap_or_exit(
|
|
||||||
&log_error_message,
|
|
||||||
json::write_json_report(file_path, json_results),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(junit_path) = cli_options.junit_file {
|
if let Some(junit_path) = cli_options.junit_file {
|
||||||
log_verbose(format!("Writing Junit report to {}", junit_path.display()).as_str());
|
log_verbose(format!("Writing Junit report to {}", junit_path.display()).as_str());
|
||||||
@ -438,8 +430,13 @@ fn main() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if cli_options.summary {
|
if matches!(cli_options.output_type, OutputType::Summary) {
|
||||||
print_summary(duration, hurl_results.clone())
|
let duration = start.elapsed().as_millis();
|
||||||
|
let summary = get_summary(duration, hurl_results.clone());
|
||||||
|
unwrap_or_exit(
|
||||||
|
&log_error_message,
|
||||||
|
write_output(summary.into_bytes(), cli_options.output.clone()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::process::exit(exit_code(hurl_results));
|
std::process::exit(exit_code(hurl_results));
|
||||||
@ -558,23 +555,32 @@ fn write_cookies_file(file_path: PathBuf, hurl_results: Vec<HurlResult>) -> Resu
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_summary(duration: u128, hurl_results: Vec<HurlResult>) {
|
fn get_summary(duration: u128, hurl_results: Vec<HurlResult>) -> String {
|
||||||
let total = hurl_results.len();
|
let total = hurl_results.len();
|
||||||
let success = hurl_results.iter().filter(|r| r.success).count();
|
let success = hurl_results.iter().filter(|r| r.success).count();
|
||||||
let failed = total - success;
|
let failed = total - success;
|
||||||
eprintln!("--------------------------------------------------------------------------------");
|
let mut s =
|
||||||
eprintln!("Executed: {}", total);
|
"--------------------------------------------------------------------------------\n"
|
||||||
eprintln!(
|
.to_string();
|
||||||
"Succeeded: {} ({:.1}%)",
|
s.push_str(format!("Executed: {}\n", total).as_str());
|
||||||
success,
|
s.push_str(
|
||||||
100.0 * success as f32 / total as f32
|
format!(
|
||||||
|
"Succeeded: {} ({:.1}%)\n",
|
||||||
|
success,
|
||||||
|
100.0 * success as f32 / total as f32
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
);
|
);
|
||||||
eprintln!(
|
s.push_str(
|
||||||
"Failed: {} ({:.1}%)",
|
format!(
|
||||||
failed,
|
"Failed: {} ({:.1}%)\n",
|
||||||
100.0 * failed as f32 / total as f32
|
failed,
|
||||||
|
100.0 * failed as f32 / total as f32
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
);
|
);
|
||||||
eprintln!("Duration: {}ms", duration);
|
s.push_str(format!("Duration: {}ms\n", duration).as_str());
|
||||||
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_version_info() -> String {
|
fn get_version_info() -> String {
|
||||||
|
Loading…
Reference in New Issue
Block a user