Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Call, Certificate, Cookie, Header, Request, Response, Timings, Version public #1549

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions packages/hurl/src/http/timings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ use std::time::Duration;
use crate::http::easy_ext;

/// Timing information for an HTTP transfer.
///
/// See [`easy_ext::namelookup_time_t`], [`easy_ext::connect_time_t`], [`easy_ext::app_connect_time_t`],
/// [`easy_ext::pre_transfert_time_t`], [`easy_ext::start_transfert_time_t`] and [`easy_ext::total_time_t`]
/// for [`TimingInfo`] fields definition.
// See [`easy_ext::namelookup_time_t`], [`easy_ext::connect_time_t`], [`easy_ext::app_connect_time_t`],
// [`easy_ext::pre_transfert_time_t`], [`easy_ext::start_transfert_time_t`] and [`easy_ext::total_time_t`]
// for [`TimingInfo`] fields definition.
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct Timings {
pub begin_call: DateTime<Utc>,
Expand Down
4 changes: 2 additions & 2 deletions packages/hurl/src/jsonpath/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
//! Note that other implementations (such as the Java lib <https://github.com/json-path/JsonPath>) also distinguish between node value (definite path) and collection (indefinite path).
//!
//! Note that the only selectors returning a scalar are:
//! - array index selector ($.store.book[2])
//! - object key selector ($.store.bicycle.color/$.store.bicycle['color'])
//! - array index selector (`$.store.book[2]`)
//! - object key selector (`$.store.bicycle.color/$.store.bicycle['color']`)
//!
//! This will make testing the value a bit easier.
//!
Expand Down
5 changes: 5 additions & 0 deletions packages/hurl/src/runner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ pub use self::hurl_file::run;
pub use self::runner_options::{RunnerOptions, RunnerOptionsBuilder};
pub use self::value::Value;

// We only expose specific structs from the module `http`.
// We don't want to expose the whole internal HTTP client, but needs those structs as
// they're exposed through `EntryResult`.
pub use crate::http::{Call, Certificate, Cookie, Header, Request, Response, Timings, Version};

mod assert;
mod body;
mod capture;
Expand Down
143 changes: 143 additions & 0 deletions packages/hurl/tests/sample.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* Hurl (https://hurl.dev)
* Copyright (C) 2023 Orange
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
use hurl::runner;
use hurl::runner::{Call, EntryResult, HurlResult, Request, Response, Verbosity, Version};
use hurl::util::logger::LoggerBuilder;
use hurl::util::path::ContextDir;
use std::collections::HashMap;
use std::time::Duration;

#[test]
fn simple_sample() {
// The purpose of the check_* functions:
// - assert against hard coded values
// - check that function parameters type are public through the hurl crate
fn check_result(result: &HurlResult) {
assert_eq!(result.success, true);
assert_eq!(result.cookies.len(), 0);
assert_eq!(result.entries.len(), 1);
assert!(result.time_in_ms < 1000);
}

fn check_entry(entry: &EntryResult) {
assert_eq!(entry.entry_index, 1);
assert_eq!(entry.calls.len(), 1);
assert_eq!(entry.captures.len(), 1);
assert_eq!(entry.asserts.len(), 3); // HTTP version + status code + implicit body
assert_eq!(entry.errors.len(), 0);
assert!(entry.time_in_ms < 1000);
assert!(!entry.compressed);
}

fn check_call(_: &Call) {}

fn check_request(request: &Request) {
assert_eq!(request.url, "http://localhost:8000/hello");
assert_eq!(request.method, "GET");
let header_names = request
.headers
.iter()
.map(|h| h.name.clone())
.collect::<Vec<_>>();
assert!(header_names.contains(&"Accept".to_string()));
assert!(header_names.contains(&"Host".to_string()));
assert!(header_names.contains(&"User-Agent".to_string()));
assert_eq!(request.body.len(), 0);
}

fn check_response(response: &Response) {
assert_eq!(response.version, Version::Http11);
assert_eq!(response.status, 200);
assert_eq!(response.headers.len(), 6);
let header_names = response
.headers
.iter()
.map(|h| h.name.clone())
.collect::<Vec<_>>();
assert!(header_names.contains(&"Connection".to_string()));
assert!(header_names.contains(&"Content-Length".to_string()));
assert!(header_names.contains(&"Content-Type".to_string()));
assert!(header_names.contains(&"Date".to_string()));
assert!(header_names.contains(&"Server".to_string())); // There are two 'Server' HTTP headers
assert_eq!(response.body.len(), 12);
assert!(response.duration < Duration::from_secs(1));
assert_eq!(response.url, "http://localhost:8000/hello");
assert!(response.certificate.is_none());
}

let content = r#"
GET http://localhost:8000/hello
HTTP 200
[Captures]
data: body
`Hello World!`
"#;

let filename = "-";

let logger = LoggerBuilder::new()
.color(false)
.verbose(false)
.filename(filename)
.build();

// Define runner options
let runner_options = runner::RunnerOptionsBuilder::new()
.cacert_file(None)
.compressed(false)
.connect_timeout(Duration::from_secs(300))
.context_dir(&ContextDir::default())
.cookie_input_file(None)
.fail_fast(false)
.follow_location(false)
.ignore_asserts(false)
.insecure(false)
.max_redirect(None)
.no_proxy(None)
.post_entry(None)
.pre_entry(None)
.proxy(None)
.retry(false)
.retry_interval(Duration::from_secs(1))
.retry_max_count(Some(10))
.timeout(Duration::from_secs(300))
.to_entry(None)
.user(None)
.user_agent(None)
.verbosity(Some(Verbosity::VeryVerbose))
.build();

// Set variables
let variables = HashMap::default();

// Run the hurl file and check data:
let result = runner::run(&content, &runner_options, &variables, &logger).unwrap();
check_result(&result);

let entry = result.entries.first().unwrap();
check_entry(&entry);

let call = entry.calls.first().unwrap();
check_call(&call);

let request = &call.request;
check_request(&request);

let response = &call.response;
check_response(&response);
}