Merge pull request #92 from Orange-OpenSource/feature/add-query-duration

Add query duration
This commit is contained in:
Fabrice Reix 2020-11-22 09:11:59 +01:00 committed by GitHub
commit f655b9c347
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 63 additions and 6 deletions

View File

@ -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>

View File

@ -4,5 +4,8 @@ HTTP/1.0 200
Content-Type: application/octet-stream
Content-Length: 536870912
[Asserts]
duration lessThanOrEquals 10000 # Duration in ms

View File

@ -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"}}]}}]}

View File

@ -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,
})
}

View File

@ -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()),

View File

@ -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!");
}

View File

@ -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![],

View File

@ -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(),

View File

@ -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()
}
);
}

View File

@ -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!(

View File

@ -322,6 +322,7 @@ pub enum QueryValue {
space0: Whitespace,
name: Template,
},
Duration {},
}
#[derive(Clone, Debug, PartialEq, Eq)]

View File

@ -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::*;

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -305,6 +305,7 @@ impl Lintable<QueryValue> for QueryValue {
name: name.clone(),
space0: one_whitespace(),
},
QueryValue::Duration {} => QueryValue::Duration {},
}
}
}