Add delay CLI option

This commit is contained in:
Fabrice Reix 2023-09-13 14:40:04 +02:00
parent 0d79aa9e71
commit 11628d4766
No known key found for this signature in database
GPG Key ID: BF5213154B2E7155
22 changed files with 68 additions and 13 deletions

View File

@ -204,6 +204,11 @@ The file will be written using the Netscape cookie file format.
Combined with [`-b, --cookie`](#cookie), you can simulate a cookie storage between successive Hurl runs.
### --delay <milliseconds> {#delay}
Sets delay before each request.
### --error-format <FORMAT> {#error-format}
Control the format of error message (short by default or long)

View File

@ -1,5 +1,6 @@
* Options:
* continue on error: false
* delay: 0ms
* follow redirect: false
* insecure: false
* max redirect: 50

View File

@ -1,5 +1,6 @@
* Options:
* continue on error: false
* delay: 0ms
* follow redirect: false
* insecure: false
* max redirect: 50

View File

@ -1,5 +1,6 @@
* Options:
* continue on error: false
* delay: 0ms
* follow redirect: false
* insecure: false
* max redirect: 50

View File

@ -2,8 +2,10 @@
GET http://localhost:8000/delay-init
HTTP 200
# This request must reach the server at least 1000ms after the first request
# This request must reach the server at least 1000ms after the previous request
GET http://localhost:8000/delay
HTTP 200
# This request must reach the server at least 1000ms after the previous request
GET http://localhost:8000/delay
[Options]
delay: 1000
HTTP 200

View File

@ -1,3 +1,3 @@
Set-StrictMode -Version latest
$ErrorActionPreference = 'Stop'
hurl tests_ok/delay.hurl --verbose
hurl tests_ok/delay.hurl --delay 1000 --verbose

View File

@ -1,18 +1,20 @@
from app import app
from datetime import datetime
init = None
last = None
@app.route("/delay-init")
def delay_init():
global init
init = datetime.now()
global last
last = datetime.now()
return ""
@app.route("/delay")
def delay():
diff = (datetime.now() - init).total_seconds()
global last
diff = (datetime.now() - last).total_seconds()
assert diff > 1
last = datetime.now()
return ""

View File

@ -1,3 +1,3 @@
#!/bin/bash
set -Eeuo pipefail
hurl tests_ok/delay.hurl --verbose
hurl tests_ok/delay.hurl --delay 1000 --verbose

View File

@ -1,5 +1,6 @@
* Options:
* continue on error: false
* delay: 0ms
* follow redirect: false
* insecure: false
* max redirect: 50

View File

@ -0,0 +1,9 @@
# First, start a timer
GET http://localhost:8000/delay-init
HTTP 200
# This request must reach the server at least 1000ms after the first request
GET http://localhost:8000/delay
[Options]
delay: 1000
HTTP 200

View File

@ -0,0 +1,3 @@
Set-StrictMode -Version latest
$ErrorActionPreference = 'Stop'
hurl tests_ok/delay_option.hurl --verbose

View File

@ -0,0 +1,3 @@
#!/bin/bash
set -Eeuo pipefail
hurl tests_ok/delay_option.hurl --verbose

View File

@ -1,5 +1,6 @@
* Options:
* continue on error: false
* delay: 0ms
* follow redirect: false
* insecure: false
* max redirect: 50

View File

@ -1,5 +1,6 @@
* Options:
* continue on error: false
* delay: 0ms
* follow redirect: false
* insecure: false
* max redirect: 50

View File

@ -1,5 +1,6 @@
* Options:
* continue on error: false
* delay: 0ms
* follow redirect: false
* insecure: false
* max redirect: 50

View File

@ -1,5 +1,6 @@
* Options:
* continue on error: false
* delay: 0ms
* follow redirect: false
* insecure: false
* max redirect: 50

View File

@ -1,5 +1,6 @@
* Options:
* continue on error: false
* delay: 0ms
* follow redirect: true
* insecure: false
* max redirect: 50

View File

@ -110,6 +110,16 @@ pub fn cookies_output_file() -> clap::Arg {
.num_args(1)
}
pub fn delay() -> clap::Arg {
clap::Arg::new("delay")
.long("delay")
.value_name("milliseconds")
.help("Sets delay before each request.")
.default_value("0")
.value_parser(value_parser!(u64))
.num_args(1)
}
pub fn error_format() -> clap::Arg {
clap::Arg::new("error_format")
.long("error-format")

View File

@ -123,6 +123,11 @@ pub fn cookie_output_file(arg_matches: &ArgMatches) -> Option<String> {
get::<String>(arg_matches, "cookies_output_file")
}
pub fn delay(arg_matches: &ArgMatches) -> Duration {
let millis = get::<u64>(arg_matches, "delay").unwrap();
Duration::from_millis(millis)
}
pub fn error_format(arg_matches: &ArgMatches) -> ErrorFormat {
let error_format = get::<String>(arg_matches, "error_format");
match error_format.as_deref() {

View File

@ -47,6 +47,7 @@ pub struct Options {
pub continue_on_error: bool,
pub cookie_input_file: Option<String>,
pub cookie_output_file: Option<String>,
pub delay: Duration,
pub error_format: ErrorFormat,
pub file_root: Option<String>,
pub follow_location: bool,
@ -137,6 +138,7 @@ pub fn parse() -> Result<Options, OptionsError> {
.arg(commands::continue_on_error())
.arg(commands::cookies_input_file())
.arg(commands::cookies_output_file())
.arg(commands::delay())
.arg(commands::error_format())
.arg(commands::fail_at_end())
.arg(commands::file_root())
@ -202,6 +204,7 @@ fn parse_matches(arg_matches: &ArgMatches) -> Result<Options, OptionsError> {
let continue_on_error = matches::continue_on_error(arg_matches);
let cookie_input_file = matches::cookie_input_file(arg_matches);
let cookie_output_file = matches::cookie_output_file(arg_matches);
let delay = matches::delay(arg_matches);
let error_format = matches::error_format(arg_matches);
let file_root = matches::file_root(arg_matches);
let follow_location = matches::follow_location(arg_matches);
@ -244,6 +247,7 @@ fn parse_matches(arg_matches: &ArgMatches) -> Result<Options, OptionsError> {
continue_on_error,
cookie_input_file,
cookie_output_file,
delay,
error_format,
file_root,
follow_location,
@ -304,6 +308,7 @@ impl Options {
let user_agent = self.user_agent.clone();
let compressed = self.compressed;
let continue_on_error = self.continue_on_error;
let delay = self.delay;
let file_root = match self.file_root {
Some(ref filename) => Path::new(filename),
None => {
@ -338,6 +343,7 @@ impl Options {
.cacert_file(cacert_file)
.client_cert_file(client_cert_file)
.client_key_file(client_key_file)
.delay(delay)
.compressed(compressed)
.connect_timeout(connect_timeout)
.connects_to(&connects_to)

View File

@ -68,11 +68,9 @@ fn main() {
// We'll use a more advanced logger for rich error report when running Hurl files.
let verbose = opts.verbose || opts.very_verbose || opts.interactive;
let base_logger = BaseLogger::new(opts.color, verbose);
let current_dir = env::current_dir();
let current_dir = unwrap_or_exit(current_dir, EXIT_ERROR_UNDEFINED, &base_logger);
let current_dir = current_dir.as_path();
let start = Instant::now();
let mut runs = vec![];
@ -99,7 +97,6 @@ fn main() {
let total = opts.input_files.len();
logger.test_running(current + 1, total);
// Run our Hurl file now
let hurl_result = execute(&content, filename, current_dir, &opts);
let hurl_result = match hurl_result {
@ -125,7 +122,6 @@ fn main() {
);
unwrap_or_exit(result, EXIT_ERROR_RUNTIME, &base_logger);
}
if matches!(opts.output_type, cli::OutputType::Json) {
let result = output::write_json(&hurl_result, &content, filename, &opts.output);
unwrap_or_exit(result, EXIT_ERROR_RUNTIME, &base_logger);

View File

@ -335,6 +335,11 @@ fn log_run_info(
)
.as_str(),
);
// FIXME: the cast to u64 seems not necessary.
// If we dont cast from u128 and try to format! or println!
// we have a segfault on Alpine Docker images and Rust 1.68.0, whereas it was
// ok with Rust >= 1.67.0.
logger.debug(format!(" delay: {}ms", runner_options.delay.as_millis() as u64).as_str());
logger.debug(format!(" follow redirect: {}", runner_options.follow_location).as_str());
logger.debug(format!(" insecure: {}", runner_options.insecure).as_str());
if let Some(n) = runner_options.max_redirect {