mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-30 00:37:52 +03:00
Add retry-max-count option.
This commit is contained in:
parent
d34647ca7e
commit
e85354f0eb
206
integration/tests_failed/retry_max_count.err.pattern
Normal file
206
integration/tests_failed/retry_max_count.err.pattern
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
* Options:
|
||||||
|
* fail fast: true
|
||||||
|
* follow redirect: false
|
||||||
|
* insecure: false
|
||||||
|
* max redirect: 50
|
||||||
|
* retry: true
|
||||||
|
* retry max count: 5
|
||||||
|
* ------------------------------------------------------------------------------
|
||||||
|
* Executing entry 1
|
||||||
|
*
|
||||||
|
* Cookie store:
|
||||||
|
*
|
||||||
|
* Request:
|
||||||
|
* GET http://localhost:8000/not-found
|
||||||
|
*
|
||||||
|
* Request can be run with the following curl command:
|
||||||
|
* curl 'http://localhost:8000/not-found'
|
||||||
|
*
|
||||||
|
> GET /not-found HTTP/1.1
|
||||||
|
> Host: localhost:8000
|
||||||
|
> Accept: */*
|
||||||
|
> User-Agent: hurl/~~~
|
||||||
|
>
|
||||||
|
* Response: (received 232 bytes in ~~~ ms)
|
||||||
|
*
|
||||||
|
< HTTP/1.0 404 NOT FOUND
|
||||||
|
< Content-Type: text/html; charset=utf-8
|
||||||
|
< Content-Length: 232
|
||||||
|
< Server: Flask Server
|
||||||
|
< Date: ~~~
|
||||||
|
<
|
||||||
|
*
|
||||||
|
* Assert status code
|
||||||
|
* --> tests_failed/retry_max_count.hurl:2:8
|
||||||
|
* |
|
||||||
|
* 2 | HTTP/* 200
|
||||||
|
* | ^^^ actual value is <404>
|
||||||
|
* |
|
||||||
|
*
|
||||||
|
* Retry entry 1 (x1 pause 100 ms)
|
||||||
|
* ------------------------------------------------------------------------------
|
||||||
|
* Executing entry 1
|
||||||
|
*
|
||||||
|
* Cookie store:
|
||||||
|
*
|
||||||
|
* Request:
|
||||||
|
* GET http://localhost:8000/not-found
|
||||||
|
*
|
||||||
|
* Request can be run with the following curl command:
|
||||||
|
* curl 'http://localhost:8000/not-found'
|
||||||
|
*
|
||||||
|
> GET /not-found HTTP/1.1
|
||||||
|
> Host: localhost:8000
|
||||||
|
> Accept: */*
|
||||||
|
> User-Agent: hurl/~~~
|
||||||
|
>
|
||||||
|
* Response: (received 232 bytes in ~~~ ms)
|
||||||
|
*
|
||||||
|
< HTTP/1.0 404 NOT FOUND
|
||||||
|
< Content-Type: text/html; charset=utf-8
|
||||||
|
< Content-Length: 232
|
||||||
|
< Server: Flask Server
|
||||||
|
< Date: ~~~
|
||||||
|
<
|
||||||
|
*
|
||||||
|
* Assert status code
|
||||||
|
* --> tests_failed/retry_max_count.hurl:2:8
|
||||||
|
* |
|
||||||
|
* 2 | HTTP/* 200
|
||||||
|
* | ^^^ actual value is <404>
|
||||||
|
* |
|
||||||
|
*
|
||||||
|
* Retry entry 1 (x2 pause 100 ms)
|
||||||
|
* ------------------------------------------------------------------------------
|
||||||
|
* Executing entry 1
|
||||||
|
*
|
||||||
|
* Cookie store:
|
||||||
|
*
|
||||||
|
* Request:
|
||||||
|
* GET http://localhost:8000/not-found
|
||||||
|
*
|
||||||
|
* Request can be run with the following curl command:
|
||||||
|
* curl 'http://localhost:8000/not-found'
|
||||||
|
*
|
||||||
|
> GET /not-found HTTP/1.1
|
||||||
|
> Host: localhost:8000
|
||||||
|
> Accept: */*
|
||||||
|
> User-Agent: hurl/~~~
|
||||||
|
>
|
||||||
|
* Response: (received 232 bytes in ~~~ ms)
|
||||||
|
*
|
||||||
|
< HTTP/1.0 404 NOT FOUND
|
||||||
|
< Content-Type: text/html; charset=utf-8
|
||||||
|
< Content-Length: 232
|
||||||
|
< Server: Flask Server
|
||||||
|
< Date: ~~~
|
||||||
|
<
|
||||||
|
*
|
||||||
|
* Assert status code
|
||||||
|
* --> tests_failed/retry_max_count.hurl:2:8
|
||||||
|
* |
|
||||||
|
* 2 | HTTP/* 200
|
||||||
|
* | ^^^ actual value is <404>
|
||||||
|
* |
|
||||||
|
*
|
||||||
|
* Retry entry 1 (x3 pause 100 ms)
|
||||||
|
* ------------------------------------------------------------------------------
|
||||||
|
* Executing entry 1
|
||||||
|
*
|
||||||
|
* Cookie store:
|
||||||
|
*
|
||||||
|
* Request:
|
||||||
|
* GET http://localhost:8000/not-found
|
||||||
|
*
|
||||||
|
* Request can be run with the following curl command:
|
||||||
|
* curl 'http://localhost:8000/not-found'
|
||||||
|
*
|
||||||
|
> GET /not-found HTTP/1.1
|
||||||
|
> Host: localhost:8000
|
||||||
|
> Accept: */*
|
||||||
|
> User-Agent: hurl/~~~
|
||||||
|
>
|
||||||
|
* Response: (received 232 bytes in ~~~ ms)
|
||||||
|
*
|
||||||
|
< HTTP/1.0 404 NOT FOUND
|
||||||
|
< Content-Type: text/html; charset=utf-8
|
||||||
|
< Content-Length: 232
|
||||||
|
< Server: Flask Server
|
||||||
|
< Date: ~~~
|
||||||
|
<
|
||||||
|
*
|
||||||
|
* Assert status code
|
||||||
|
* --> tests_failed/retry_max_count.hurl:2:8
|
||||||
|
* |
|
||||||
|
* 2 | HTTP/* 200
|
||||||
|
* | ^^^ actual value is <404>
|
||||||
|
* |
|
||||||
|
*
|
||||||
|
* Retry entry 1 (x4 pause 100 ms)
|
||||||
|
* ------------------------------------------------------------------------------
|
||||||
|
* Executing entry 1
|
||||||
|
*
|
||||||
|
* Cookie store:
|
||||||
|
*
|
||||||
|
* Request:
|
||||||
|
* GET http://localhost:8000/not-found
|
||||||
|
*
|
||||||
|
* Request can be run with the following curl command:
|
||||||
|
* curl 'http://localhost:8000/not-found'
|
||||||
|
*
|
||||||
|
> GET /not-found HTTP/1.1
|
||||||
|
> Host: localhost:8000
|
||||||
|
> Accept: */*
|
||||||
|
> User-Agent: hurl/~~~
|
||||||
|
>
|
||||||
|
* Response: (received 232 bytes in ~~~ ms)
|
||||||
|
*
|
||||||
|
< HTTP/1.0 404 NOT FOUND
|
||||||
|
< Content-Type: text/html; charset=utf-8
|
||||||
|
< Content-Length: 232
|
||||||
|
< Server: Flask Server
|
||||||
|
< Date: ~~~
|
||||||
|
<
|
||||||
|
*
|
||||||
|
* Assert status code
|
||||||
|
* --> tests_failed/retry_max_count.hurl:2:8
|
||||||
|
* |
|
||||||
|
* 2 | HTTP/* 200
|
||||||
|
* | ^^^ actual value is <404>
|
||||||
|
* |
|
||||||
|
*
|
||||||
|
* Retry entry 1 (x5 pause 100 ms)
|
||||||
|
* ------------------------------------------------------------------------------
|
||||||
|
* Executing entry 1
|
||||||
|
*
|
||||||
|
* Cookie store:
|
||||||
|
*
|
||||||
|
* Request:
|
||||||
|
* GET http://localhost:8000/not-found
|
||||||
|
*
|
||||||
|
* Request can be run with the following curl command:
|
||||||
|
* curl 'http://localhost:8000/not-found'
|
||||||
|
*
|
||||||
|
> GET /not-found HTTP/1.1
|
||||||
|
> Host: localhost:8000
|
||||||
|
> Accept: */*
|
||||||
|
> User-Agent: hurl/~~~
|
||||||
|
>
|
||||||
|
* Response: (received 232 bytes in ~~ ms)
|
||||||
|
*
|
||||||
|
< HTTP/1.0 404 NOT FOUND
|
||||||
|
< Content-Type: text/html; charset=utf-8
|
||||||
|
< Content-Length: 232
|
||||||
|
< Server: Flask Server
|
||||||
|
< Date: ~~~
|
||||||
|
<
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Retry max count reached, no more retry
|
||||||
|
error: Assert status code
|
||||||
|
--> tests_failed/retry_max_count.hurl:2:8
|
||||||
|
|
|
||||||
|
2 | HTTP/* 200
|
||||||
|
| ^^^ actual value is <404>
|
||||||
|
|
|
||||||
|
|
1
integration/tests_failed/retry_max_count.exit
Normal file
1
integration/tests_failed/retry_max_count.exit
Normal file
@ -0,0 +1 @@
|
|||||||
|
4
|
2
integration/tests_failed/retry_max_count.html
Normal file
2
integration/tests_failed/retry_max_count.html
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<pre><code class="language-hurl"><span class="hurl-entry"><span class="request"><span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/not-found</span></span>
|
||||||
|
</span><span class="response"><span class="line"><span class="version">HTTP/*</span> <span class="number">200</span></span></span></span></code></pre>
|
2
integration/tests_failed/retry_max_count.hurl
Normal file
2
integration/tests_failed/retry_max_count.hurl
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
GET http://localhost:8000/not-found
|
||||||
|
HTTP/* 200
|
6
integration/tests_failed/retry_max_count.options
Normal file
6
integration/tests_failed/retry_max_count.options
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
--retry
|
||||||
|
--retry-max-count
|
||||||
|
5
|
||||||
|
--retry-interval
|
||||||
|
100
|
||||||
|
--verbose
|
7
integration/tests_failed/retry_max_count.py
Normal file
7
integration/tests_failed/retry_max_count.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from app import app
|
||||||
|
from flask import request, abort
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/not-found")
|
||||||
|
def not_found():
|
||||||
|
abort(404)
|
@ -4,4 +4,5 @@
|
|||||||
[1;34m*[0m insecure: false
|
[1;34m*[0m insecure: false
|
||||||
[1;34m*[0m max redirect: 50
|
[1;34m*[0m max redirect: 50
|
||||||
[1;34m*[0m retry: false
|
[1;34m*[0m retry: false
|
||||||
|
[1;34m*[0m retry max count: 10
|
||||||
[1;33mwarning[0m: [1mNo entry have been executed for file tests_ok/color.hurl[0m
|
[1;33mwarning[0m: [1mNo entry have been executed for file tests_ok/color.hurl[0m
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
< Content-Type: text/html; charset=utf-8
|
< Content-Type: text/html; charset=utf-8
|
||||||
< Content-Length: 12
|
< Content-Length: 12
|
||||||
< Server: Flask Server
|
< Server: Flask Server
|
||||||
< Date: ~~~, ~~ ~~~ ~~~~ ~~:~~:~~ GMT
|
< Date: ~~~
|
||||||
<
|
<
|
||||||
*
|
*
|
||||||
* ------------------------------------------------------------------------------
|
* ------------------------------------------------------------------------------
|
||||||
@ -53,7 +53,7 @@
|
|||||||
< Content-Type: text/html; charset=utf-8
|
< Content-Type: text/html; charset=utf-8
|
||||||
< Content-Length: 12
|
< Content-Length: 12
|
||||||
< Server: Flask Server
|
< Server: Flask Server
|
||||||
< Date: ~~~, ~~ ~~~ ~~~~ ~~:~~:~~ GMT
|
< Date: ~~~
|
||||||
<
|
<
|
||||||
* Response body:
|
* Response body:
|
||||||
* Hello World!
|
* Hello World!
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
* insecure: false
|
* insecure: false
|
||||||
* max redirect: 50
|
* max redirect: 50
|
||||||
* retry: true
|
* retry: true
|
||||||
|
* retry max count: 10
|
||||||
* ------------------------------------------------------------------------------
|
* ------------------------------------------------------------------------------
|
||||||
* Executing entry 1
|
* Executing entry 1
|
||||||
*
|
*
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
* insecure: false
|
* insecure: false
|
||||||
* max redirect: 50
|
* max redirect: 50
|
||||||
* retry: false
|
* retry: false
|
||||||
|
* retry max count: 10
|
||||||
* ------------------------------------------------------------------------------
|
* ------------------------------------------------------------------------------
|
||||||
* Executing entry 1
|
* Executing entry 1
|
||||||
*
|
*
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
* insecure: false
|
* insecure: false
|
||||||
* max redirect: 50
|
* max redirect: 50
|
||||||
* retry: false
|
* retry: false
|
||||||
|
* retry max count: 10
|
||||||
* ------------------------------------------------------------------------------
|
* ------------------------------------------------------------------------------
|
||||||
* Executing entry 1
|
* Executing entry 1
|
||||||
*
|
*
|
||||||
@ -29,7 +30,7 @@
|
|||||||
< Content-Length: 205
|
< Content-Length: 205
|
||||||
< Location: http://localhost:8000/very-verbose/redirected
|
< Location: http://localhost:8000/very-verbose/redirected
|
||||||
< Server: Flask Server
|
< Server: Flask Server
|
||||||
< Date: ~~~, ~~ ~~~ ~~~~ ~~:~~:~~ GMT
|
< Date: ~~~
|
||||||
<
|
<
|
||||||
* Response body:
|
* Response body:
|
||||||
* <html>
|
* <html>
|
||||||
@ -59,7 +60,7 @@
|
|||||||
< Content-Type: text/html; charset=utf-8
|
< Content-Type: text/html; charset=utf-8
|
||||||
< Content-Length: 11
|
< Content-Length: 11
|
||||||
< Server: Flask Server
|
< Server: Flask Server
|
||||||
< Date: ~~~, ~~ ~~~ ~~~~ ~~:~~:~~ GMT
|
< Date: ~~~
|
||||||
<
|
<
|
||||||
* Response body:
|
* Response body:
|
||||||
* Redirected.
|
* Redirected.
|
||||||
@ -88,7 +89,7 @@
|
|||||||
< Content-Type: text/html; charset=ISO-8859-1
|
< Content-Type: text/html; charset=ISO-8859-1
|
||||||
< Content-Length: 4
|
< Content-Length: 4
|
||||||
< Server: Flask Server
|
< Server: Flask Server
|
||||||
< Date: ~~~, ~~ ~~~ ~~~~ ~~:~~:~~ GMT
|
< Date: ~~~
|
||||||
<
|
<
|
||||||
* Response body:
|
* Response body:
|
||||||
* café
|
* café
|
||||||
@ -127,7 +128,7 @@
|
|||||||
< Content-Length: 17
|
< Content-Length: 17
|
||||||
< Content-Encoding: br
|
< Content-Encoding: br
|
||||||
< Server: Flask Server
|
< Server: Flask Server
|
||||||
< Date: ~~~, ~~ ~~~ ~~~~ ~~:~~:~~ GMT
|
< Date: ~~~
|
||||||
<
|
<
|
||||||
* Response body:
|
* Response body:
|
||||||
* Hello World!
|
* Hello World!
|
||||||
@ -156,7 +157,7 @@
|
|||||||
< Content-Type: image/jpeg
|
< Content-Type: image/jpeg
|
||||||
< Content-Length: 25992
|
< Content-Length: 25992
|
||||||
< Server: Flask Server
|
< Server: Flask Server
|
||||||
< Date: ~~~, ~~ ~~~ ~~~~ ~~:~~:~~ GMT
|
< Date: ~~~
|
||||||
<
|
<
|
||||||
* Response body:
|
* Response body:
|
||||||
* Bytes <f198388ba26c2c53005f24643826384f15ba905b8ca070a470b61885c6639f8bbfe63fcee5fb498a630249e499e4eddcc9ca793406c14d02c97107e09c7af57a...>
|
* Bytes <f198388ba26c2c53005f24643826384f15ba905b8ca070a470b61885c6639f8bbfe63fcee5fb498a630249e499e4eddcc9ca793406c14d02c97107e09c7af57a...>
|
||||||
@ -191,7 +192,7 @@
|
|||||||
< Content-Type: text/html; charset=utf-8
|
< Content-Type: text/html; charset=utf-8
|
||||||
< Content-Length: 0
|
< Content-Length: 0
|
||||||
< Server: Flask Server
|
< Server: Flask Server
|
||||||
< Date: ~~~, ~~ ~~~ ~~~~ ~~:~~:~~ GMT
|
< Date: ~~~
|
||||||
<
|
<
|
||||||
* Response body:
|
* Response body:
|
||||||
*
|
*
|
||||||
@ -222,7 +223,7 @@
|
|||||||
< Content-Type: text/html; charset=utf-8
|
< Content-Type: text/html; charset=utf-8
|
||||||
< Content-Length: 4
|
< Content-Length: 4
|
||||||
< Server: Flask Server
|
< Server: Flask Server
|
||||||
< Date: ~~~, ~~ ~~~ ~~~~ ~~:~~:~~ GMT
|
< Date: ~~~
|
||||||
<
|
<
|
||||||
* Response body:
|
* Response body:
|
||||||
* Done
|
* Done
|
||||||
|
@ -56,6 +56,7 @@ pub struct CliOptions {
|
|||||||
pub proxy: Option<String>,
|
pub proxy: Option<String>,
|
||||||
pub retry: bool,
|
pub retry: bool,
|
||||||
pub retry_interval: Duration,
|
pub retry_interval: Duration,
|
||||||
|
pub retry_max_count: Option<usize>,
|
||||||
pub test: bool,
|
pub test: bool,
|
||||||
pub timeout: Duration,
|
pub timeout: Duration,
|
||||||
pub to_entry: Option<usize>,
|
pub to_entry: Option<usize>,
|
||||||
@ -77,6 +78,7 @@ pub fn app(version: &str) -> Command {
|
|||||||
let ClientOptions {
|
let ClientOptions {
|
||||||
connect_timeout: default_connect_timeout,
|
connect_timeout: default_connect_timeout,
|
||||||
max_redirect: default_max_redirect,
|
max_redirect: default_max_redirect,
|
||||||
|
retry_max_count: default_retry_max_count,
|
||||||
timeout: default_timeout,
|
timeout: default_timeout,
|
||||||
..
|
..
|
||||||
} = ClientOptions::default();
|
} = ClientOptions::default();
|
||||||
@ -84,6 +86,7 @@ pub fn app(version: &str) -> Command {
|
|||||||
let default_connect_timeout = default_connect_timeout.as_secs();
|
let default_connect_timeout = default_connect_timeout.as_secs();
|
||||||
let default_max_redirect = default_max_redirect.unwrap();
|
let default_max_redirect = default_max_redirect.unwrap();
|
||||||
let default_timeout = default_timeout.as_secs();
|
let default_timeout = default_timeout.as_secs();
|
||||||
|
let default_retry_max_count = default_retry_max_count.unwrap();
|
||||||
|
|
||||||
Command::new("hurl")
|
Command::new("hurl")
|
||||||
.about("Run Hurl file(s) or standard input")
|
.about("Run Hurl file(s) or standard input")
|
||||||
@ -289,6 +292,16 @@ pub fn app(version: &str) -> Command {
|
|||||||
.default_value("1000")
|
.default_value("1000")
|
||||||
.num_args(1)
|
.num_args(1)
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
clap::Arg::new("retry_max_count")
|
||||||
|
.long("retry-max-count")
|
||||||
|
.value_name("NUM")
|
||||||
|
.help("Maximum number of retries, -1 for unlimited retries")
|
||||||
|
.default_value(default_retry_max_count.to_string())
|
||||||
|
.allow_hyphen_values(true)
|
||||||
|
.value_parser(value_parser!(i32).range(-1..))
|
||||||
|
.num_args(1)
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
clap::Arg::new("test")
|
clap::Arg::new("test")
|
||||||
.long("test")
|
.long("test")
|
||||||
@ -421,6 +434,11 @@ pub fn parse_options(matches: &ArgMatches) -> Result<CliOptions, CliError> {
|
|||||||
let retry = has_flag(matches, "retry");
|
let retry = has_flag(matches, "retry");
|
||||||
let retry_interval = get::<u64>(matches, "retry_interval").unwrap();
|
let retry_interval = get::<u64>(matches, "retry_interval").unwrap();
|
||||||
let retry_interval = Duration::from_millis(retry_interval);
|
let retry_interval = Duration::from_millis(retry_interval);
|
||||||
|
let retry_max_count = get::<i32>(matches, "retry_max_count").unwrap();
|
||||||
|
let retry_max_count = match retry_max_count {
|
||||||
|
r if r == -1 => None,
|
||||||
|
r => Some(r as usize),
|
||||||
|
};
|
||||||
let timeout = get::<u64>(matches, "max_time").unwrap();
|
let timeout = get::<u64>(matches, "max_time").unwrap();
|
||||||
let timeout = Duration::from_secs(timeout);
|
let timeout = Duration::from_secs(timeout);
|
||||||
let to_entry = get::<u32>(matches, "to_entry").map(|x| x as usize);
|
let to_entry = get::<u32>(matches, "to_entry").map(|x| x as usize);
|
||||||
@ -454,6 +472,7 @@ pub fn parse_options(matches: &ArgMatches) -> Result<CliOptions, CliError> {
|
|||||||
proxy,
|
proxy,
|
||||||
retry,
|
retry,
|
||||||
retry_interval,
|
retry_interval,
|
||||||
|
retry_max_count,
|
||||||
test,
|
test,
|
||||||
timeout,
|
timeout,
|
||||||
to_entry,
|
to_entry,
|
||||||
|
@ -27,6 +27,7 @@ pub struct ClientOptions {
|
|||||||
pub no_proxy: Option<String>,
|
pub no_proxy: Option<String>,
|
||||||
pub verbosity: Option<Verbosity>,
|
pub verbosity: Option<Verbosity>,
|
||||||
pub insecure: bool,
|
pub insecure: bool,
|
||||||
|
pub retry_max_count: Option<usize>,
|
||||||
pub timeout: Duration,
|
pub timeout: Duration,
|
||||||
pub connect_timeout: Duration,
|
pub connect_timeout: Duration,
|
||||||
pub user: Option<String>,
|
pub user: Option<String>,
|
||||||
@ -51,6 +52,7 @@ impl Default for ClientOptions {
|
|||||||
no_proxy: None,
|
no_proxy: None,
|
||||||
verbosity: None,
|
verbosity: None,
|
||||||
insecure: false,
|
insecure: false,
|
||||||
|
retry_max_count: Some(10),
|
||||||
timeout: Duration::from_secs(300),
|
timeout: Duration::from_secs(300),
|
||||||
connect_timeout: Duration::from_secs(300),
|
connect_timeout: Duration::from_secs(300),
|
||||||
user: None,
|
user: None,
|
||||||
@ -135,6 +137,7 @@ mod tests {
|
|||||||
no_proxy: None,
|
no_proxy: None,
|
||||||
verbosity: None,
|
verbosity: None,
|
||||||
insecure: true,
|
insecure: true,
|
||||||
|
retry_max_count: Some(10),
|
||||||
timeout: Duration::from_secs(10),
|
timeout: Duration::from_secs(10),
|
||||||
connect_timeout: Duration::from_secs(20),
|
connect_timeout: Duration::from_secs(20),
|
||||||
user: Some("user:password".to_string()),
|
user: Some("user:password".to_string()),
|
||||||
|
@ -114,6 +114,9 @@ fn execute(
|
|||||||
logger.debug(format!(" proxy: {}", proxy).as_str());
|
logger.debug(format!(" proxy: {}", proxy).as_str());
|
||||||
}
|
}
|
||||||
logger.debug(format!(" retry: {}", cli_options.retry).as_str());
|
logger.debug(format!(" retry: {}", cli_options.retry).as_str());
|
||||||
|
if let Some(n) = cli_options.retry_max_count {
|
||||||
|
logger.debug(format!(" retry max count: {}", n).as_str());
|
||||||
|
}
|
||||||
if !cli_options.variables.is_empty() {
|
if !cli_options.variables.is_empty() {
|
||||||
logger.debug_important("Variables:");
|
logger.debug_important("Variables:");
|
||||||
for (name, value) in cli_options.variables.clone() {
|
for (name, value) in cli_options.variables.clone() {
|
||||||
@ -170,6 +173,7 @@ fn execute(
|
|||||||
let to_entry = cli_options.to_entry;
|
let to_entry = cli_options.to_entry;
|
||||||
let retry = cli_options.retry;
|
let retry = cli_options.retry;
|
||||||
let retry_interval = cli_options.retry_interval;
|
let retry_interval = cli_options.retry_interval;
|
||||||
|
let retry_max_count = cli_options.retry_max_count;
|
||||||
let ignore_asserts = cli_options.ignore_asserts;
|
let ignore_asserts = cli_options.ignore_asserts;
|
||||||
let very_verbose = cli_options.very_verbose;
|
let very_verbose = cli_options.very_verbose;
|
||||||
let runner_options = RunnerOptions {
|
let runner_options = RunnerOptions {
|
||||||
@ -189,6 +193,7 @@ fn execute(
|
|||||||
proxy,
|
proxy,
|
||||||
retry,
|
retry,
|
||||||
retry_interval,
|
retry_interval,
|
||||||
|
retry_max_count,
|
||||||
timeout,
|
timeout,
|
||||||
to_entry,
|
to_entry,
|
||||||
user,
|
user,
|
||||||
@ -213,12 +218,7 @@ fn execute(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unwraps a result or exit with message.
|
/// Unwraps a `result` or exit with message.
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * result - Something to unwrap
|
|
||||||
/// * logger - A logger to log the error
|
|
||||||
fn unwrap_or_exit<T>(result: Result<T, CliError>, code: i32, logger: &BaseLogger) -> T {
|
fn unwrap_or_exit<T>(result: Result<T, CliError>, code: i32, logger: &BaseLogger) -> T {
|
||||||
match result {
|
match result {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
|
@ -42,6 +42,7 @@ pub struct RunnerOptions {
|
|||||||
pub proxy: Option<String>,
|
pub proxy: Option<String>,
|
||||||
pub retry: bool,
|
pub retry: bool,
|
||||||
pub retry_interval: Duration,
|
pub retry_interval: Duration,
|
||||||
|
pub retry_max_count: Option<usize>,
|
||||||
pub timeout: Duration,
|
pub timeout: Duration,
|
||||||
pub to_entry: Option<usize>,
|
pub to_entry: Option<usize>,
|
||||||
pub user: Option<String>,
|
pub user: Option<String>,
|
||||||
@ -75,6 +76,7 @@ impl Default for RunnerOptions {
|
|||||||
proxy: None,
|
proxy: None,
|
||||||
retry: false,
|
retry: false,
|
||||||
retry_interval: Duration::from_millis(1000),
|
retry_interval: Duration::from_millis(1000),
|
||||||
|
retry_max_count: Some(10),
|
||||||
timeout: Duration::from_secs(300),
|
timeout: Duration::from_secs(300),
|
||||||
to_entry: None,
|
to_entry: None,
|
||||||
user: None,
|
user: None,
|
||||||
|
@ -209,6 +209,7 @@ impl From<&RunnerOptions> for ClientOptions {
|
|||||||
Verbosity::VeryVerbose => http::Verbosity::VeryVerbose,
|
Verbosity::VeryVerbose => http::Verbosity::VeryVerbose,
|
||||||
}),
|
}),
|
||||||
insecure: runner_options.insecure,
|
insecure: runner_options.insecure,
|
||||||
|
retry_max_count: runner_options.retry_max_count,
|
||||||
timeout: runner_options.timeout,
|
timeout: runner_options.timeout,
|
||||||
connect_timeout: runner_options.connect_timeout,
|
connect_timeout: runner_options.connect_timeout,
|
||||||
user: runner_options.user.clone(),
|
user: runner_options.user.clone(),
|
||||||
|
@ -90,7 +90,7 @@ pub fn run(
|
|||||||
let mut entries = vec![];
|
let mut entries = vec![];
|
||||||
let mut variables = variables.clone();
|
let mut variables = variables.clone();
|
||||||
let mut entry_index = 1;
|
let mut entry_index = 1;
|
||||||
let mut retry_count = 0;
|
let mut retry_count = 1;
|
||||||
let n = if let Some(to_entry) = runner_options.to_entry {
|
let n = if let Some(to_entry) = runner_options.to_entry {
|
||||||
to_entry
|
to_entry
|
||||||
} else {
|
} else {
|
||||||
@ -104,13 +104,6 @@ pub fn run(
|
|||||||
}
|
}
|
||||||
let entry = &hurl_file.entries[entry_index - 1];
|
let entry = &hurl_file.entries[entry_index - 1];
|
||||||
|
|
||||||
if let Some(pre_entry) = runner_options.pre_entry {
|
|
||||||
let exit = pre_entry(entry.clone());
|
|
||||||
if exit {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We compute these new overridden options for this entry, before entering into the `run`
|
// We compute these new overridden options for this entry, before entering into the `run`
|
||||||
// function because entry options can modify the logger and we want the preamble
|
// function because entry options can modify the logger and we want the preamble
|
||||||
// "Executing entry..." to be displayed based on the entry level verbosity.
|
// "Executing entry..." to be displayed based on the entry level verbosity.
|
||||||
@ -122,35 +115,51 @@ pub fn run(
|
|||||||
logger.content,
|
logger.content,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(pre_entry) = runner_options.pre_entry {
|
||||||
|
let exit = pre_entry(entry.clone());
|
||||||
|
if exit {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logger.debug_important(
|
logger.debug_important(
|
||||||
"------------------------------------------------------------------------------",
|
"------------------------------------------------------------------------------",
|
||||||
);
|
);
|
||||||
logger.debug_important(format!("Executing entry {}", entry_index).as_str());
|
logger.debug_important(format!("Executing entry {}", entry_index).as_str());
|
||||||
|
|
||||||
let entry_result =
|
let options_result =
|
||||||
match entry::get_entry_options(entry, runner_options, &mut variables, logger) {
|
entry::get_entry_options(entry, runner_options, &mut variables, logger);
|
||||||
Ok(runner_options) => entry::run(
|
let entry_result = match options_result {
|
||||||
entry,
|
Ok(options) => entry::run(
|
||||||
entry_index,
|
entry,
|
||||||
http_client,
|
entry_index,
|
||||||
&mut variables,
|
http_client,
|
||||||
&runner_options,
|
&mut variables,
|
||||||
logger,
|
&options,
|
||||||
),
|
logger,
|
||||||
Err(error) => EntryResult {
|
),
|
||||||
entry_index,
|
Err(error) => EntryResult {
|
||||||
calls: vec![],
|
entry_index,
|
||||||
captures: vec![],
|
calls: vec![],
|
||||||
asserts: vec![],
|
captures: vec![],
|
||||||
errors: vec![error],
|
asserts: vec![],
|
||||||
time_in_ms: 0,
|
errors: vec![error],
|
||||||
compressed: false,
|
time_in_ms: 0,
|
||||||
},
|
compressed: false,
|
||||||
};
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// Check if we need to retry.
|
// Check if we need to retry.
|
||||||
let has_error = !entry_result.errors.is_empty();
|
let has_error = !entry_result.errors.is_empty();
|
||||||
let retry = runner_options.retry && has_error;
|
let retry_max_reached = match runner_options.retry_max_count {
|
||||||
|
None => false,
|
||||||
|
Some(r) => retry_count > r,
|
||||||
|
};
|
||||||
|
if retry_max_reached {
|
||||||
|
logger.debug("");
|
||||||
|
logger.debug_important("Retry max count reached, no more retry");
|
||||||
|
}
|
||||||
|
let retry = runner_options.retry && !retry_max_reached && has_error;
|
||||||
|
|
||||||
// If we're going to retry the entry, we log error only in verbose. Otherwise,
|
// If we're going to retry the entry, we log error only in verbose. Otherwise,
|
||||||
// we log error on stderr.
|
// we log error on stderr.
|
||||||
@ -170,15 +179,13 @@ pub fn run(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if runner_options.retry && has_error {
|
if retry {
|
||||||
let delay = runner_options.retry_interval.as_millis();
|
let delay = runner_options.retry_interval.as_millis();
|
||||||
logger.debug("");
|
logger.debug("");
|
||||||
logger.debug_important(
|
logger.debug_important(
|
||||||
format!(
|
format!(
|
||||||
"Retry entry {} (x{} pause {} ms)",
|
"Retry entry {} (x{} pause {} ms)",
|
||||||
entry_index,
|
entry_index, retry_count, delay
|
||||||
retry_count + 1,
|
|
||||||
delay
|
|
||||||
)
|
)
|
||||||
.as_str(),
|
.as_str(),
|
||||||
);
|
);
|
||||||
@ -192,7 +199,7 @@ pub fn run(
|
|||||||
|
|
||||||
// We pass to the next entry
|
// We pass to the next entry
|
||||||
entry_index += 1;
|
entry_index += 1;
|
||||||
retry_count = 0;
|
retry_count = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let time_in_ms = start.elapsed().as_millis();
|
let time_in_ms = start.elapsed().as_millis();
|
||||||
|
Loading…
Reference in New Issue
Block a user