mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-11-27 08:19:22 +03:00
Merge pull request #92 from Orange-OpenSource/feature/add-query-duration
Add query duration
This commit is contained in:
commit
f655b9c347
@ -1 +1 @@
|
||||
<div class="hurl-file"><div class="hurl-entry"><div class="request"><span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/large</span></span></div><div class="response"><span class="line"></span><span class="line"><span class="version">HTTP/1.0</span> <span class="status">200</span></span><span class="line"><span class="string">Content-Type</span><span>:</span> <span class="string">application/octet-stream</span></span><span class="line"><span class="string">Content-Length</span><span>:</span> <span class="string">536870912</span></span></div></div><span class="line"></span><span class="line"></span><span class="line"></span></div>
|
||||
<div class="hurl-file"><div class="hurl-entry"><div class="request"><span class="line"><span class="method">GET</span> <span class="url">http://localhost:8000/large</span></span></div><div class="response"><span class="line"></span><span class="line"><span class="version">HTTP/1.0</span> <span class="status">200</span></span><span class="line"><span class="string">Content-Type</span><span>:</span> <span class="string">application/octet-stream</span></span><span class="line"><span class="string">Content-Length</span><span>:</span> <span class="string">536870912</span></span><span class="line"></span><span class="line section-header">[Asserts]</span></span><span class="line"><span class="query-type">duration</span> <span class="predicate-type">less-than-or-equal</span> <span class="number">10000</span></span></div></div><span class="line"></span><span class="line"></span><span class="line"></span></div>
|
@ -4,5 +4,8 @@ HTTP/1.0 200
|
||||
Content-Type: application/octet-stream
|
||||
Content-Length: 536870912
|
||||
|
||||
[Asserts]
|
||||
duration lessThanOrEquals 10000 # Duration in ms
|
||||
|
||||
|
||||
|
||||
|
@ -1 +1 @@
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/large"},"response":{"version":"HTTP/1.0","status":200,"headers":[{"name":"Content-Type","value":"application/octet-stream"},{"name":"Content-Length","value":"536870912"}]}}]}
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/large"},"response":{"version":"HTTP/1.0","status":200,"headers":[{"name":"Content-Type","value":"application/octet-stream"},{"name":"Content-Length","value":"536870912"}],"asserts":[{"query":{"type":"duration"},"predicate":{"type":"less-than-or-equal","value":"10000"}}]}}]}
|
@ -23,6 +23,7 @@ use curl::easy;
|
||||
use encoding::all::ISO_8859_1;
|
||||
use encoding::{DecoderTrap, Encoding};
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
use super::core::*;
|
||||
use super::request::*;
|
||||
@ -161,6 +162,7 @@ impl Client {
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let start = Instant::now();
|
||||
let mut status_lines = vec![];
|
||||
let mut headers = vec![];
|
||||
let mut body = Vec::<u8>::new();
|
||||
@ -237,6 +239,7 @@ impl Client {
|
||||
|
||||
return self.execute(&request, redirect_count);
|
||||
}
|
||||
let duration = start.elapsed();
|
||||
self.redirect_count = redirect_count;
|
||||
self.reset();
|
||||
|
||||
@ -245,6 +248,7 @@ impl Client {
|
||||
status,
|
||||
headers,
|
||||
body,
|
||||
duration,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
use core::fmt;
|
||||
use std::time::Duration;
|
||||
|
||||
use super::core::*;
|
||||
|
||||
@ -26,6 +27,7 @@ pub struct Response {
|
||||
pub status: u32,
|
||||
pub headers: Vec<Header>,
|
||||
pub body: Vec<u8>,
|
||||
pub duration: Duration,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@ -97,6 +99,7 @@ pub mod tests {
|
||||
},
|
||||
],
|
||||
body: String::into_bytes(String::from("Hello World!")),
|
||||
duration: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,6 +114,7 @@ pub mod tests {
|
||||
body: String::into_bytes(String::from(
|
||||
"<html><head><meta charset=\"UTF-8\"></head><body><br></body></html>",
|
||||
)),
|
||||
duration: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,6 +138,7 @@ xxx
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
duration: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,6 +166,7 @@ xxx
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
duration: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,6 +195,7 @@ xxx
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
duration: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,6 +217,7 @@ xxx
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
duration: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,6 +236,7 @@ xxx
|
||||
},
|
||||
],
|
||||
body: vec![255],
|
||||
duration: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -241,6 +250,7 @@ xxx
|
||||
value: "12".to_string(),
|
||||
}],
|
||||
body: vec![],
|
||||
duration: Default::default(),
|
||||
};
|
||||
assert_eq!(
|
||||
response.get_header_values("Content-Length".to_string()),
|
||||
|
@ -138,6 +138,7 @@ pub mod tests {
|
||||
status: 200,
|
||||
headers: vec![],
|
||||
body: vec![],
|
||||
duration: Default::default(),
|
||||
};
|
||||
assert_eq!(response.content_encoding().unwrap(), vec![]);
|
||||
|
||||
@ -149,6 +150,7 @@ pub mod tests {
|
||||
value: "xx".to_string(),
|
||||
}],
|
||||
body: vec![],
|
||||
duration: Default::default(),
|
||||
};
|
||||
assert_eq!(
|
||||
response.content_encoding().err().unwrap(),
|
||||
@ -163,6 +165,7 @@ pub mod tests {
|
||||
value: "br".to_string(),
|
||||
}],
|
||||
body: vec![],
|
||||
duration: Default::default(),
|
||||
};
|
||||
assert_eq!(response.content_encoding().unwrap(), vec![Encoding::Brotli]);
|
||||
}
|
||||
@ -177,6 +180,7 @@ pub mod tests {
|
||||
value: "br, identity".to_string(),
|
||||
}],
|
||||
body: vec![],
|
||||
duration: Default::default(),
|
||||
};
|
||||
assert_eq!(
|
||||
response.content_encoding().unwrap(),
|
||||
@ -197,6 +201,7 @@ pub mod tests {
|
||||
0x21, 0x2c, 0x00, 0x04, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c,
|
||||
0x64, 0x21,
|
||||
],
|
||||
duration: Default::default(),
|
||||
};
|
||||
assert_eq!(response.uncompress_body().unwrap(), b"Hello World!");
|
||||
|
||||
@ -211,6 +216,7 @@ pub mod tests {
|
||||
0x21, 0x2c, 0x00, 0x04, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c,
|
||||
0x64, 0x21,
|
||||
],
|
||||
duration: Default::default(),
|
||||
};
|
||||
assert_eq!(response.uncompress_body().unwrap(), b"Hello World!");
|
||||
|
||||
@ -219,6 +225,7 @@ pub mod tests {
|
||||
status: 200,
|
||||
headers: vec![],
|
||||
body: b"Hello World!".to_vec(),
|
||||
duration: Default::default(),
|
||||
};
|
||||
assert_eq!(response.uncompress_body().unwrap(), b"Hello World!");
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
*
|
||||
*/
|
||||
use std::collections::HashMap;
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::http;
|
||||
use crate::http::HttpError;
|
||||
@ -100,7 +99,6 @@ pub fn run(
|
||||
log_verbose("");
|
||||
log_request(log_verbose, &http_request);
|
||||
|
||||
let start = Instant::now();
|
||||
let http_response = match http_client.execute(&http_request, 0) {
|
||||
Ok(response) => response,
|
||||
Err(http_error) => {
|
||||
@ -140,8 +138,8 @@ pub fn run(
|
||||
}
|
||||
};
|
||||
|
||||
let time_in_ms = start.elapsed().as_millis();
|
||||
log_verbose(format!("Response Time: {}ms", time_in_ms).as_str());
|
||||
let time_in_ms = http_response.duration.as_millis();
|
||||
log_verbose(format!("Response Time: {}ms", time_in_ms.to_string()).as_str());
|
||||
|
||||
let captures = match entry.response.clone() {
|
||||
None => vec![],
|
||||
|
@ -121,6 +121,7 @@ pub mod tests {
|
||||
status: 200,
|
||||
headers: vec![],
|
||||
body: b"Hello World!".to_vec(),
|
||||
duration: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,6 +134,7 @@ pub mod tests {
|
||||
value: "text/plain; charset=utf-8".to_string(),
|
||||
}],
|
||||
body: vec![0x63, 0x61, 0x66, 0xc3, 0xa9],
|
||||
duration: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,6 +147,7 @@ pub mod tests {
|
||||
value: "text/plain; charset=ISO-8859-1".to_string(),
|
||||
}],
|
||||
body: vec![0x63, 0x61, 0x66, 0xe9],
|
||||
duration: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,6 +195,7 @@ pub mod tests {
|
||||
value: "test/plain; charset=xxx".to_string()
|
||||
}],
|
||||
body: b"Hello World!".to_vec(),
|
||||
duration: Default::default()
|
||||
}
|
||||
.encoding()
|
||||
.err()
|
||||
@ -210,6 +214,7 @@ pub mod tests {
|
||||
status: 200,
|
||||
headers: vec![],
|
||||
body: vec![0x63, 0x61, 0x66, 0xe9],
|
||||
duration: Default::default()
|
||||
}
|
||||
.text()
|
||||
.err()
|
||||
@ -228,6 +233,7 @@ pub mod tests {
|
||||
value: "text/plain; charset=ISO-8859-1".to_string()
|
||||
}],
|
||||
body: vec![0x63, 0x61, 0x66, 0xc3, 0xa9],
|
||||
duration: Default::default()
|
||||
}
|
||||
.text()
|
||||
.unwrap(),
|
||||
|
@ -20,6 +20,7 @@ use crate::http::*;
|
||||
|
||||
use super::cookie::*;
|
||||
use super::core::*;
|
||||
use std::time::Duration;
|
||||
|
||||
type ParseError = String;
|
||||
|
||||
@ -208,11 +209,15 @@ pub fn parse_response(value: serde_json::Value) -> Result<Response, ParseError>
|
||||
_ => vec![],
|
||||
};
|
||||
|
||||
// TODO: Check if you need it
|
||||
let duration = Duration::new(0, 0);
|
||||
|
||||
Ok(Response {
|
||||
version,
|
||||
status,
|
||||
headers,
|
||||
body: vec![],
|
||||
duration,
|
||||
})
|
||||
} else {
|
||||
Err("expecting an object for the response".to_string())
|
||||
@ -461,6 +466,7 @@ mod tests {
|
||||
},
|
||||
],
|
||||
body: vec![],
|
||||
duration: Default::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -200,6 +200,9 @@ pub fn eval_query(
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
QueryValue::Duration {} => Ok(Some(Value::Integer(
|
||||
http_response.duration.as_millis() as i64
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,6 +348,7 @@ pub mod tests {
|
||||
"#
|
||||
.to_string(),
|
||||
),
|
||||
duration: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -550,6 +554,7 @@ pub mod tests {
|
||||
}
|
||||
],
|
||||
body: vec![],
|
||||
duration: Default::default()
|
||||
};
|
||||
|
||||
// cookie "LSID"
|
||||
@ -781,6 +786,7 @@ pub mod tests {
|
||||
status: 0,
|
||||
headers: vec![],
|
||||
body: vec![200],
|
||||
duration: Default::default(),
|
||||
};
|
||||
let error = eval_query(xpath_users(), &variables, http_response)
|
||||
.err()
|
||||
@ -932,6 +938,7 @@ pub mod tests {
|
||||
status: 0,
|
||||
headers: vec![],
|
||||
body: String::into_bytes(String::from("xxx")),
|
||||
duration: Default::default(),
|
||||
};
|
||||
let error = eval_query(jsonpath_success(), &variables, http_response)
|
||||
.err()
|
||||
@ -948,6 +955,7 @@ pub mod tests {
|
||||
status: 0,
|
||||
headers: vec![],
|
||||
body: String::into_bytes(String::from("{}")),
|
||||
duration: Default::default(),
|
||||
};
|
||||
//assert_eq!(jsonpath_success().eval(http_response).unwrap(), Value::List(vec![]));
|
||||
assert_eq!(
|
||||
|
@ -322,6 +322,7 @@ pub enum QueryValue {
|
||||
space0: Whitespace,
|
||||
name: Template,
|
||||
},
|
||||
Duration {},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -55,6 +55,7 @@ fn query_value(reader: &mut Reader) -> ParseResult<'static, QueryValue> {
|
||||
jsonpath_query,
|
||||
regex_query,
|
||||
variable_query,
|
||||
duration_query,
|
||||
],
|
||||
reader,
|
||||
)
|
||||
@ -148,6 +149,11 @@ fn regex_subquery(reader: &mut Reader) -> ParseResult<'static, SubqueryValue> {
|
||||
Ok(SubqueryValue::Regex { space0, expr })
|
||||
}
|
||||
|
||||
fn duration_query(reader: &mut Reader) -> ParseResult<'static, QueryValue> {
|
||||
try_literal("duration", reader)?;
|
||||
Ok(QueryValue::Duration {})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -372,6 +372,9 @@ impl Htmlable for QueryValue {
|
||||
format!("<span class=\"string\">\"{}\"</span>", name.to_html()).as_str(),
|
||||
);
|
||||
}
|
||||
QueryValue::Duration {} => {
|
||||
buffer.push_str("<span class=\"query-type\">duration</span>");
|
||||
}
|
||||
}
|
||||
buffer
|
||||
}
|
||||
|
@ -287,6 +287,9 @@ impl ToJson for QueryValue {
|
||||
attributes.push(("type".to_string(), JValue::String("variable".to_string())));
|
||||
attributes.push(("name".to_string(), JValue::String(name.to_string())));
|
||||
}
|
||||
QueryValue::Duration {} => {
|
||||
attributes.push(("type".to_string(), JValue::String("duration".to_string())));
|
||||
}
|
||||
};
|
||||
JValue::Object(attributes)
|
||||
}
|
||||
|
@ -467,6 +467,7 @@ impl Tokenizable for Query {
|
||||
add_tokens(&mut tokens, space0.tokenize());
|
||||
add_tokens(&mut tokens, name.tokenize());
|
||||
}
|
||||
QueryValue::Duration {} => tokens.push(Token::QueryType(String::from("duration"))),
|
||||
}
|
||||
tokens
|
||||
}
|
||||
|
@ -305,6 +305,7 @@ impl Lintable<QueryValue> for QueryValue {
|
||||
name: name.clone(),
|
||||
space0: one_whitespace(),
|
||||
},
|
||||
QueryValue::Duration {} => QueryValue::Duration {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user