mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-12-24 19:42:07 +03:00
Add Retry Type
This commit is contained in:
parent
b5277b3349
commit
a149635409
@ -22,6 +22,7 @@ use crate::cli::OutputType;
|
||||
use atty::Stream;
|
||||
use clap::ArgMatches;
|
||||
use hurl::runner::Value;
|
||||
use hurl_core::ast::Retry;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
@ -243,10 +244,11 @@ pub fn resolves(arg_matches: &ArgMatches) -> Vec<String> {
|
||||
get_strings(arg_matches, "resolve").unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn retry(arg_matches: &ArgMatches) -> Option<usize> {
|
||||
pub fn retry(arg_matches: &ArgMatches) -> Retry {
|
||||
match get::<i32>(arg_matches, "retry").unwrap() {
|
||||
r if r == -1 => None,
|
||||
r => Some(r as usize),
|
||||
r if r == -1 => Retry::Infinite,
|
||||
r if r == 0 => Retry::None,
|
||||
r => Retry::Finite(r as usize),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ use clap::ArgMatches;
|
||||
use hurl::libcurl_version_info;
|
||||
use hurl::util::logger::{LoggerOptions, LoggerOptionsBuilder, Verbosity};
|
||||
use hurl::util::path::ContextDir;
|
||||
use hurl_core::ast::Entry;
|
||||
use hurl_core::ast::{Entry, Retry};
|
||||
|
||||
use crate::cli;
|
||||
use crate::runner::{RunnerOptions, RunnerOptionsBuilder, Value};
|
||||
@ -63,7 +63,7 @@ pub struct Options {
|
||||
pub progress_bar: bool,
|
||||
pub proxy: Option<String>,
|
||||
pub resolves: Vec<String>,
|
||||
pub retry: Option<usize>,
|
||||
pub retry: Retry,
|
||||
pub retry_interval: Duration,
|
||||
pub ssl_no_revoke: bool,
|
||||
pub test: bool,
|
||||
|
@ -15,6 +15,7 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
use hurl_core::ast::Retry;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -32,7 +33,7 @@ pub struct ClientOptions {
|
||||
pub no_proxy: Option<String>,
|
||||
pub proxy: Option<String>,
|
||||
pub resolves: Vec<String>,
|
||||
pub retry: Option<usize>,
|
||||
pub retry: Retry,
|
||||
pub ssl_no_revoke: bool,
|
||||
pub timeout: Duration,
|
||||
pub user: Option<String>,
|
||||
@ -62,7 +63,7 @@ impl Default for ClientOptions {
|
||||
no_proxy: None,
|
||||
proxy: None,
|
||||
resolves: vec![],
|
||||
retry: Some(0),
|
||||
retry: Retry::None,
|
||||
ssl_no_revoke: false,
|
||||
timeout: Duration::from_secs(300),
|
||||
user: None,
|
||||
@ -167,7 +168,7 @@ mod tests {
|
||||
"foo.com:80:192.168.0.1".to_string(),
|
||||
"bar.com:443:127.0.0.1".to_string()
|
||||
],
|
||||
retry: Some(0),
|
||||
retry: Retry::None,
|
||||
ssl_no_revoke: false,
|
||||
timeout: Duration::from_secs(10),
|
||||
connect_timeout: Duration::from_secs(20),
|
||||
|
@ -335,7 +335,7 @@ pub fn get_entry_options(
|
||||
logger.debug(format!("max-redirs: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::Retry(option) => {
|
||||
runner_options.retry = Some(option.value);
|
||||
runner_options.retry = option.value;
|
||||
logger.debug(format!("retry: {}", option.value).as_str());
|
||||
}
|
||||
EntryOption::RetryInterval(option) => {
|
||||
|
@ -157,25 +157,26 @@ pub fn run(
|
||||
Ok(options) => (options.retry, options.retry_interval),
|
||||
Err(_) => (runner_options.retry, runner_options.retry_interval),
|
||||
};
|
||||
let retry_max_reached = match retry_opts {
|
||||
Some(r) => retry_count > r,
|
||||
None => false,
|
||||
// The retry threshold can only reached with a finite positive number of retries
|
||||
let retry_max_reached = if let Retry::Finite(r) = retry_opts {
|
||||
retry_count > r
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let retry = retry_opts.is_some() && !retry_max_reached && has_error;
|
||||
|
||||
// If `retry_max_reached` is true, we print now a warning, before displaying
|
||||
// any assert error so any potential error is the last thing displayed to the user.
|
||||
// If `retry_max_reached` is not true (for instance `retry`is true, or there is no error
|
||||
// we first log the error and a potential warning about retrying.
|
||||
logger.test_erase_line();
|
||||
if retry_max_reached && retry_opts != Some(0) {
|
||||
if retry_max_reached {
|
||||
logger.debug_important("Retry max count reached, no more retry");
|
||||
logger.debug("");
|
||||
}
|
||||
|
||||
let retry = !matches!(retry_opts, Retry::None) && !retry_max_reached && has_error;
|
||||
if has_error {
|
||||
log_errors(&entry_result, content, retry, &logger);
|
||||
}
|
||||
|
||||
entries.push(entry_result);
|
||||
|
||||
if retry {
|
||||
@ -323,10 +324,7 @@ fn log_run_info(
|
||||
if let Some(proxy) = &runner_options.proxy {
|
||||
logger.debug(format!(" proxy: {proxy}").as_str());
|
||||
}
|
||||
match runner_options.retry {
|
||||
None => logger.debug(" retry: indefinitely".to_string().as_str()),
|
||||
Some(n) => logger.debug(format!(" retry: {n}").as_str()),
|
||||
}
|
||||
logger.debug(format!(" retry: {}", runner_options.retry).as_str());
|
||||
if !variables.is_empty() {
|
||||
logger.debug_important("Variables:");
|
||||
for (name, value) in variables.iter() {
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
use std::time::Duration;
|
||||
|
||||
use hurl_core::ast::Entry;
|
||||
use hurl_core::ast::{Entry, Retry};
|
||||
|
||||
use crate::util::path::ContextDir;
|
||||
|
||||
@ -40,7 +40,7 @@ pub struct RunnerOptionsBuilder {
|
||||
pre_entry: Option<fn(Entry) -> bool>,
|
||||
proxy: Option<String>,
|
||||
resolves: Vec<String>,
|
||||
retry: Option<usize>,
|
||||
retry: Retry,
|
||||
retry_interval: Duration,
|
||||
ssl_no_revoke: bool,
|
||||
timeout: Duration,
|
||||
@ -70,7 +70,7 @@ impl Default for RunnerOptionsBuilder {
|
||||
pre_entry: None,
|
||||
proxy: None,
|
||||
resolves: vec![],
|
||||
retry: Some(0),
|
||||
retry: Retry::None,
|
||||
retry_interval: Duration::from_millis(1000),
|
||||
ssl_no_revoke: false,
|
||||
timeout: Duration::from_secs(300),
|
||||
@ -218,7 +218,7 @@ impl RunnerOptionsBuilder {
|
||||
/// Sets maximum number of retries.
|
||||
///
|
||||
/// Default is 0.
|
||||
pub fn retry(&mut self, retry: Option<usize>) -> &mut Self {
|
||||
pub fn retry(&mut self, retry: Retry) -> &mut Self {
|
||||
self.retry = retry;
|
||||
self
|
||||
}
|
||||
@ -314,7 +314,7 @@ pub struct RunnerOptions {
|
||||
pub(crate) pre_entry: Option<fn(Entry) -> bool>,
|
||||
pub(crate) proxy: Option<String>,
|
||||
pub(crate) resolves: Vec<String>,
|
||||
pub(crate) retry: Option<usize>,
|
||||
pub(crate) retry: Retry,
|
||||
pub(crate) retry_interval: Duration,
|
||||
pub(crate) ssl_no_revoke: bool,
|
||||
pub(crate) timeout: Duration,
|
||||
|
@ -21,6 +21,7 @@ use hurl::runner::{
|
||||
};
|
||||
use hurl::util::logger::LoggerOptionsBuilder;
|
||||
use hurl::util::path::ContextDir;
|
||||
use hurl_core::ast::Retry;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
|
||||
@ -108,7 +109,7 @@ fn simple_sample() {
|
||||
.post_entry(None)
|
||||
.pre_entry(None)
|
||||
.proxy(None)
|
||||
.retry(Some(0))
|
||||
.retry(Retry::None)
|
||||
.retry_interval(Duration::from_secs(1))
|
||||
.timeout(Duration::from_secs(300))
|
||||
.to_entry(None)
|
||||
|
@ -796,7 +796,7 @@ pub struct RetryOption {
|
||||
pub space0: Whitespace,
|
||||
pub space1: Whitespace,
|
||||
pub space2: Whitespace,
|
||||
pub value: usize,
|
||||
pub value: Retry,
|
||||
pub line_terminator0: LineTerminator,
|
||||
}
|
||||
|
||||
@ -910,3 +910,10 @@ pub enum FilterValue {
|
||||
UrlDecode,
|
||||
UrlEncode,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
|
||||
pub enum Retry {
|
||||
None,
|
||||
Finite(usize),
|
||||
Infinite,
|
||||
}
|
||||
|
@ -238,6 +238,17 @@ impl PredicateFuncValue {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Retry {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let value = match self {
|
||||
Retry::None => 0,
|
||||
Retry::Finite(n) => *n as i32,
|
||||
Retry::Infinite => -1,
|
||||
};
|
||||
write!(f, "{}", value)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -316,7 +316,7 @@ impl HtmlFormatter {
|
||||
self.fmt_space(&option.space1);
|
||||
self.buffer.push(':');
|
||||
self.fmt_space(&option.space2);
|
||||
self.fmt_number(option.value);
|
||||
self.fmt_retry(option.value);
|
||||
self.fmt_span_close();
|
||||
self.fmt_lt(&option.line_terminator0);
|
||||
}
|
||||
@ -929,6 +929,14 @@ impl HtmlFormatter {
|
||||
self.fmt_lt(line_terminator);
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_retry(&mut self, retry: Retry) {
|
||||
match retry {
|
||||
Retry::Finite(n) => self.fmt_span("number", &n.to_string()),
|
||||
Retry::Infinite => self.fmt_span("number", "-1"),
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn escape_xml(s: &str) -> String {
|
||||
|
@ -537,22 +537,38 @@ fn option_retry(reader: &mut Reader) -> ParseResult<'static, EntryOption> {
|
||||
let space1 = zero_or_more_spaces(reader)?;
|
||||
try_literal(":", reader)?;
|
||||
let space2 = zero_or_more_spaces(reader)?;
|
||||
let value = nonrecover(natural, reader)?;
|
||||
let value = retry(reader)?;
|
||||
let line_terminator0 = line_terminator(reader)?;
|
||||
|
||||
// FIXME: try to not unwrap redirect value
|
||||
// and returns an error if not possible
|
||||
let option = RetryOption {
|
||||
line_terminators,
|
||||
space0,
|
||||
space1,
|
||||
space2,
|
||||
value: usize::try_from(value).unwrap(),
|
||||
value,
|
||||
line_terminator0,
|
||||
};
|
||||
Ok(EntryOption::Retry(option))
|
||||
}
|
||||
|
||||
fn retry(reader: &mut Reader) -> ParseResult<Retry> {
|
||||
let pos = reader.state.pos.clone();
|
||||
let value = nonrecover(integer, reader)?;
|
||||
if value == -1 {
|
||||
Ok(Retry::Infinite)
|
||||
} else if value == 0 {
|
||||
Ok(Retry::None)
|
||||
} else if value > 0 {
|
||||
Ok(Retry::Finite(value as usize))
|
||||
} else {
|
||||
Err(Error {
|
||||
pos,
|
||||
recoverable: false,
|
||||
inner: ParseError::Expecting {
|
||||
value: "Expecting a retry value".to_string(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
fn option_retry_interval(reader: &mut Reader) -> ParseResult<'static, EntryOption> {
|
||||
let line_terminators = optional_line_terminators(reader)?;
|
||||
let space0 = zero_or_more_spaces(reader)?;
|
||||
|
@ -1024,16 +1024,28 @@ impl Tokenizable for RetryOption {
|
||||
.collect(),
|
||||
);
|
||||
tokens.append(&mut self.space0.tokenize());
|
||||
tokens.push(Token::String("retry-max-count".to_string()));
|
||||
tokens.append(&mut self.space1.tokenize());
|
||||
tokens.push(Token::Colon(String::from(":")));
|
||||
tokens.append(&mut self.space2.tokenize());
|
||||
tokens.push(Token::Number(self.value.to_string()));
|
||||
if !matches!(self.value, Retry::None) {
|
||||
tokens.push(Token::String("retry".to_string()));
|
||||
tokens.append(&mut self.space1.tokenize());
|
||||
tokens.push(Token::Colon(String::from(":")));
|
||||
tokens.append(&mut self.space2.tokenize());
|
||||
tokens.append(&mut self.value.tokenize());
|
||||
}
|
||||
tokens.append(&mut self.line_terminator0.tokenize());
|
||||
tokens
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizable for Retry {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
match self {
|
||||
Retry::None => vec![Token::Number("0".to_string())],
|
||||
Retry::Finite(n) => vec![Token::Number(n.to_string())],
|
||||
Retry::Infinite => vec![Token::Number("-1".to_string())],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Tokenizable for RetryIntervalOption {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
let mut tokens: Vec<Token> = vec![];
|
||||
|
Loading…
Reference in New Issue
Block a user