diff --git a/integration/tests_failed/connect_timeout.err.pattern b/integration/tests_failed/connect_timeout.err.pattern new file mode 100644 index 000000000..7c938d1da --- /dev/null +++ b/integration/tests_failed/connect_timeout.err.pattern @@ -0,0 +1,7 @@ +error: HTTP connection + --> tests_failed/connect_timeout.hurl:1:5 + | + 1 | GET http://10.0.0.0 + | ^^^^^^^^^^^^^^^ (~~) ~~~ + | + diff --git a/integration/tests_failed/proxy_host.err b/integration/tests_failed/proxy_host.err new file mode 100644 index 000000000..7dd7a1916 --- /dev/null +++ b/integration/tests_failed/proxy_host.err @@ -0,0 +1,7 @@ +error: HTTP connection + --> tests_ok/hello.hurl:1:5 + | + 1 | GET http://localhost:8000/hello + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ (5) Could not resolve proxy: unknown + | + diff --git a/integration/tests_failed/proxy_host.exit b/integration/tests_failed/proxy_host.exit new file mode 100644 index 000000000..e440e5c84 --- /dev/null +++ b/integration/tests_failed/proxy_host.exit @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/integration/tests_failed/proxy_host.ps1 b/integration/tests_failed/proxy_host.ps1 new file mode 100644 index 000000000..9dc28a9c3 --- /dev/null +++ b/integration/tests_failed/proxy_host.ps1 @@ -0,0 +1,3 @@ +Set-StrictMode -Version latest +$ErrorActionPreference = 'Stop' +hurl --proxy unknown tests_ok/hello.hurl diff --git a/integration/tests_failed/proxy_host.sh b/integration/tests_failed/proxy_host.sh new file mode 100755 index 000000000..e4a4a547f --- /dev/null +++ b/integration/tests_failed/proxy_host.sh @@ -0,0 +1,3 @@ +#!/bin/bash +set -Eeuo pipefail +hurl --proxy unknown tests_ok/hello.hurl diff --git a/integration/tests_failed/proxy_port.err.pattern b/integration/tests_failed/proxy_port.err.pattern new file mode 100644 index 000000000..0c64bbcf8 --- /dev/null +++ b/integration/tests_failed/proxy_port.err.pattern @@ -0,0 +1,7 @@ +error: HTTP connection + --> tests_ok/hello.hurl:1:5 + | + 1 | GET http://localhost:8000/hello + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ (7) Failed to connect to localhost port 1111~~~ + | + diff --git a/integration/tests_failed/proxy_port.exit b/integration/tests_failed/proxy_port.exit new file mode 100644 index 000000000..e440e5c84 --- /dev/null +++ b/integration/tests_failed/proxy_port.exit @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/integration/tests_failed/proxy_port.hurl b/integration/tests_failed/proxy_port.hurl new file mode 100644 index 000000000..5d14e1b7c --- /dev/null +++ b/integration/tests_failed/proxy_port.hurl @@ -0,0 +1,2 @@ +GET http://localhost:8000/hello +HTTP 200 diff --git a/integration/tests_failed/proxy_port.ps1 b/integration/tests_failed/proxy_port.ps1 new file mode 100644 index 000000000..f24e4eea0 --- /dev/null +++ b/integration/tests_failed/proxy_port.ps1 @@ -0,0 +1,3 @@ +Set-StrictMode -Version latest +$ErrorActionPreference = 'Stop' +hurl --proxy localhost:1111 tests_ok/hello.hurl diff --git a/integration/tests_failed/proxy_port.sh b/integration/tests_failed/proxy_port.sh new file mode 100755 index 000000000..d54133d8a --- /dev/null +++ b/integration/tests_failed/proxy_port.sh @@ -0,0 +1,3 @@ +#!/bin/bash +set -Eeuo pipefail +hurl --proxy localhost:1111 tests_ok/hello.hurl diff --git a/integration/tests_failed/timeout.err.pattern b/integration/tests_failed/timeout.err.pattern new file mode 100644 index 000000000..c11a1aec1 --- /dev/null +++ b/integration/tests_failed/timeout.err.pattern @@ -0,0 +1,7 @@ +error: HTTP connection + --> tests_failed/timeout.hurl:1:5 + | + 1 | GET http://localhost:8000/timeout + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (28) Operation timed out after ~~~ milliseconds with 0 bytes received + | + diff --git a/integration/tests_ok/connect_to.curl b/integration/tests_ok/connect_to.curl index df1f17102..20130f96c 100644 --- a/integration/tests_ok/connect_to.curl +++ b/integration/tests_ok/connect_to.curl @@ -1,3 +1,3 @@ -curl --connect-to foo.com:80:localhost:8000 --connect-to bar.com:80:localhost:8000 --connect-to baz.com:80:localhost:8000 'http://foo.com/hello' -curl --connect-to foo.com:80:localhost:8000 --connect-to bar.com:80:localhost:8000 --connect-to baz.com:80:localhost:8000 'http://bar.com/hello' -curl --connect-to foo.com:80:localhost:8000 --connect-to bar.com:80:localhost:8000 --connect-to baz.com:80:localhost:8000 'http://baz.com/hello' \ No newline at end of file +curl --connect-to foo.com:80:localhost:8000 --connect-to bar.com:80:localhost:8000 --connect-to baz.com:80:localhost:8000 'http://foo.com/connect-to' +curl --connect-to foo.com:80:localhost:8000 --connect-to bar.com:80:localhost:8000 --connect-to baz.com:80:localhost:8000 'http://bar.com/connect-to' +curl --connect-to foo.com:80:localhost:8000 --connect-to bar.com:80:localhost:8000 --connect-to baz.com:80:localhost:8000 'http://baz.com/connect-to' \ No newline at end of file diff --git a/integration/tests_ok/connect_to.html b/integration/tests_ok/connect_to.html index d4c0a9e1a..e2b3b8bb8 100644 --- a/integration/tests_ok/connect_to.html +++ b/integration/tests_ok/connect_to.html @@ -1,14 +1,14 @@ -
GET http://foo.com/hello
+GET http://foo.com/connect-to
HTTP 200
`Hello World!`
-GET http://bar.com/hello
+GET http://bar.com/connect-to
HTTP 200
`Hello World!`
-GET http://baz.com/hello
+GET http://baz.com/connect-to
HTTP 200
`Hello World!`
diff --git a/integration/tests_ok/connect_to.hurl b/integration/tests_ok/connect_to.hurl
index d2a2f8827..264defa2a 100644
--- a/integration/tests_ok/connect_to.hurl
+++ b/integration/tests_ok/connect_to.hurl
@@ -1,13 +1,13 @@
-GET http://foo.com/hello
+GET http://foo.com/connect-to
HTTP 200
`Hello World!`
-GET http://bar.com/hello
+GET http://bar.com/connect-to
HTTP 200
`Hello World!`
-GET http://baz.com/hello
+GET http://baz.com/connect-to
HTTP 200
`Hello World!`
diff --git a/integration/tests_ok/connect_to.json b/integration/tests_ok/connect_to.json
index f99d9c17b..c641fc85f 100644
--- a/integration/tests_ok/connect_to.json
+++ b/integration/tests_ok/connect_to.json
@@ -1 +1 @@
-{"entries":[{"request":{"method":"GET","url":"http://foo.com/hello"},"response":{"status":200,"body":{"type":"text","value":"Hello World!"}}},{"request":{"method":"GET","url":"http://bar.com/hello"},"response":{"status":200,"body":{"type":"text","value":"Hello World!"}}},{"request":{"method":"GET","url":"http://baz.com/hello"},"response":{"status":200,"body":{"type":"text","value":"Hello World!"}}}]}
+{"entries":[{"request":{"method":"GET","url":"http://foo.com/connect-to"},"response":{"status":200,"body":{"type":"text","value":"Hello World!"}}},{"request":{"method":"GET","url":"http://bar.com/connect-to"},"response":{"status":200,"body":{"type":"text","value":"Hello World!"}}},{"request":{"method":"GET","url":"http://baz.com/connect-to"},"response":{"status":200,"body":{"type":"text","value":"Hello World!"}}}]}
diff --git a/integration/tests_ok/connect_to.py b/integration/tests_ok/connect_to.py
new file mode 100644
index 000000000..02d0c48fe
--- /dev/null
+++ b/integration/tests_ok/connect_to.py
@@ -0,0 +1,6 @@
+from app import app
+
+
+@app.route("/connect-to")
+def connect_to():
+ return "Hello World!"
diff --git a/integration/tests_ok/hello.html b/integration/tests_ok/hello.html
index 54697d45e..861dff384 100644
--- a/integration/tests_ok/hello.html
+++ b/integration/tests_ok/hello.html
@@ -1,5 +1,9 @@
GET http://localhost:8000/hello
HTTP 200
+Content-Type: text/html; charset=utf-8
+Content-Length: 12
+[Asserts]
+header "Date" exists
`Hello World!`
GET http://localhost:8000/hello
diff --git a/integration/tests_ok/hello.hurl b/integration/tests_ok/hello.hurl
index 2b703d96f..25f100430 100644
--- a/integration/tests_ok/hello.hurl
+++ b/integration/tests_ok/hello.hurl
@@ -1,5 +1,9 @@
GET http://localhost:8000/hello
HTTP 200
+Content-Type: text/html; charset=utf-8
+Content-Length: 12
+[Asserts]
+header "Date" exists
`Hello World!`
GET http://localhost:8000/hello
diff --git a/integration/tests_ok/hello.json b/integration/tests_ok/hello.json
index 7fc92d99c..3db084153 100644
--- a/integration/tests_ok/hello.json
+++ b/integration/tests_ok/hello.json
@@ -1 +1 @@
-{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"type":"text","value":"Hello World!"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"type":"file","filename":"data.txt"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"encoding":"base64","value":"SGVsbG8gV29ybGQh"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"encoding":"base64","value":"SGVsbG8gV29ybGQh"}}}]}
+{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"headers":[{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Content-Length","value":"12"}],"asserts":[{"query":{"type":"header","name":"Date"},"predicate":{"type":"exist"}}],"body":{"type":"text","value":"Hello World!"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"type":"file","filename":"data.txt"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"encoding":"base64","value":"SGVsbG8gV29ybGQh"}}},{"request":{"method":"GET","url":"http://localhost:8000/hello"},"response":{"status":200,"body":{"encoding":"base64","value":"SGVsbG8gV29ybGQh"}}}]}
diff --git a/integration/tests_ok/hello.py b/integration/tests_ok/hello.py
index 17fa078e6..ee53aca57 100644
--- a/integration/tests_ok/hello.py
+++ b/integration/tests_ok/hello.py
@@ -4,7 +4,9 @@ from flask import request
@app.route("/hello")
def hello():
- assert "Content-Type" not in request.headers
- assert "Content-Length" not in request.headers
+ assert len(request.headers) == 3
+ assert request.headers["Host"] == "localhost:8000"
+ assert request.headers["Accept"] == "*/*"
+ assert "User-Agent" in request.headers
assert len(request.data) == 0
return "Hello World!"
diff --git a/integration/tests_ok/multipart_form_data.py b/integration/tests_ok/multipart_form_data.py
index 4f30a8c90..fd7587e49 100644
--- a/integration/tests_ok/multipart_form_data.py
+++ b/integration/tests_ok/multipart_form_data.py
@@ -4,7 +4,6 @@ from flask import request
@app.route("/multipart-form-data", methods=["POST"])
def multipart_form_data():
-
assert request.form["key1"] == "value1"
assert "Expect" not in request.headers
diff --git a/integration/tests_ok/put.html b/integration/tests_ok/put.html
index a2f20424c..823d23573 100644
--- a/integration/tests_ok/put.html
+++ b/integration/tests_ok/put.html
@@ -1,4 +1,5 @@
PUT http://localhost:8000/put
HTTP 200
-
-
+[Asserts]
+body == ""
+
diff --git a/integration/tests_ok/put.hurl b/integration/tests_ok/put.hurl
index e5baaa30e..0c73bc631 100644
--- a/integration/tests_ok/put.hurl
+++ b/integration/tests_ok/put.hurl
@@ -1,3 +1,4 @@
PUT http://localhost:8000/put
HTTP 200
-
+[Asserts]
+body == ""
diff --git a/integration/tests_ok/put.json b/integration/tests_ok/put.json
index b0b9748db..77eddaf18 100644
--- a/integration/tests_ok/put.json
+++ b/integration/tests_ok/put.json
@@ -1 +1 @@
-{"entries":[{"request":{"method":"PUT","url":"http://localhost:8000/put"},"response":{"status":200}}]}
+{"entries":[{"request":{"method":"PUT","url":"http://localhost:8000/put"},"response":{"status":200,"asserts":[{"query":{"type":"body"},"predicate":{"type":"equal","value":""}}]}}]}
diff --git a/integration/tests_ok/resolve.curl b/integration/tests_ok/resolve.curl
index 21bc52ed5..f3d0c889d 100644
--- a/integration/tests_ok/resolve.curl
+++ b/integration/tests_ok/resolve.curl
@@ -1,3 +1,3 @@
-curl --resolve foo.com:8000:127.0.0.1 --resolve bar.com:8000:127.0.0.1 --resolve baz.com:8000:127.0.0.1 'http://foo.com:8000/hello'
-curl --resolve foo.com:8000:127.0.0.1 --resolve bar.com:8000:127.0.0.1 --resolve baz.com:8000:127.0.0.1 'http://bar.com:8000/hello'
-curl --resolve foo.com:8000:127.0.0.1 --resolve bar.com:8000:127.0.0.1 --resolve baz.com:8000:127.0.0.1 'http://baz.com:8000/hello'
\ No newline at end of file
+curl --resolve foo.com:8000:127.0.0.1 --resolve bar.com:8000:127.0.0.1 --resolve baz.com:8000:127.0.0.1 'http://foo.com:8000/resolve'
+curl --resolve foo.com:8000:127.0.0.1 --resolve bar.com:8000:127.0.0.1 --resolve baz.com:8000:127.0.0.1 'http://bar.com:8000/resolve'
+curl --resolve foo.com:8000:127.0.0.1 --resolve bar.com:8000:127.0.0.1 --resolve baz.com:8000:127.0.0.1 'http://baz.com:8000/resolve'
\ No newline at end of file
diff --git a/integration/tests_ok/resolve.hurl b/integration/tests_ok/resolve.hurl
index 4bd4a8f4b..4253e259f 100644
--- a/integration/tests_ok/resolve.hurl
+++ b/integration/tests_ok/resolve.hurl
@@ -1,13 +1,13 @@
-GET http://foo.com:8000/hello
+GET http://foo.com:8000/resolve
HTTP 200
`Hello World!`
-GET http://bar.com:8000/hello
+GET http://bar.com:8000/resolve
HTTP 200
`Hello World!`
-GET http://baz.com:8000/hello
+GET http://baz.com:8000/resolve
HTTP 200
`Hello World!`
diff --git a/integration/tests_ok/resolve.py b/integration/tests_ok/resolve.py
new file mode 100644
index 000000000..53d866aa7
--- /dev/null
+++ b/integration/tests_ok/resolve.py
@@ -0,0 +1,6 @@
+from app import app
+
+
+@app.route("/resolve")
+def resolve():
+ return "Hello World!"
diff --git a/packages/hurl/src/http/tests/libcurl.rs b/packages/hurl/src/http/tests/libcurl.rs
deleted file mode 100644
index 785a1f667..000000000
--- a/packages/hurl/src/http/tests/libcurl.rs
+++ /dev/null
@@ -1,1211 +0,0 @@
-/*
- * 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 std::default::Default;
-use std::time::Duration;
-
-use regex::Regex;
-
-use crate::http::*;
-use crate::util::logger::{Logger, LoggerOptionsBuilder};
-use crate::util::path::ContextDir;
-
-fn default_get_request(url: &str) -> RequestSpec {
- RequestSpec {
- url: url.to_string(),
- ..Default::default()
- }
-}
-
-fn redirect_count(calls: &[Call]) -> usize {
- calls
- .iter()
- .filter(|call| call.response.status >= 300 && call.response.status < 399)
- .count()
-}
-
-#[test]
-fn test_hello() {
- let options = ClientOptions::default();
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("http://localhost:8000/hello");
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl 'http://localhost:8000/hello'".to_string()
- );
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.method, "GET".to_string());
- assert_eq!(request.url, "http://localhost:8000/hello".to_string());
- assert_eq!(request.headers.len(), 3);
- assert!(request.headers.contains(&Header {
- name: "Host".to_string(),
- value: "localhost:8000".to_string(),
- }));
- assert!(request.headers.contains(&Header {
- name: "Accept".to_string(),
- value: "*/*".to_string(),
- }));
-
- assert_eq!(response.version, Version::Http11);
- assert_eq!(response.status, 200);
- assert_eq!(response.body, b"Hello World!".to_vec());
-
- assert_eq!(response.headers.len(), 6);
- assert!(response.headers.contains(&Header {
- name: "Content-Length".to_string(),
- value: "12".to_string(),
- }));
- assert!(response.headers.contains(&Header {
- name: "Content-Type".to_string(),
- value: "text/html; charset=utf-8".to_string(),
- }));
- assert_eq!(response.get_header_values("Date").len(), 1);
-}
-
-#[test]
-fn test_put() {
- let options = ClientOptions::default();
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = RequestSpec {
- method: Method::Put,
- url: "http://localhost:8000/put".to_string(),
- ..Default::default()
- };
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --request PUT 'http://localhost:8000/put'".to_string()
- );
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.method, "PUT".to_string());
- assert_eq!(request.url, "http://localhost:8000/put".to_string());
- assert!(request.headers.contains(&Header {
- name: "Host".to_string(),
- value: "localhost:8000".to_string(),
- }));
- assert!(request.headers.contains(&Header {
- name: "Accept".to_string(),
- value: "*/*".to_string(),
- }));
-
- assert_eq!(response.status, 200);
- assert!(response.body.is_empty());
-}
-
-#[test]
-fn test_patch() {
- let options = ClientOptions::default();
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
- let request_spec = RequestSpec {
- method: Method::Patch,
- url: "http://localhost:8000/patch/file.txt".to_string(),
- headers: vec![
- Header {
- name: "Host".to_string(),
- value: "www.example.com".to_string(),
- },
- Header {
- name: "Content-Type".to_string(),
- value: "application/example".to_string(),
- },
- Header {
- name: "If-Match".to_string(),
- value: "\"e0023aa4e\"".to_string(),
- },
- ],
- ..Default::default()
- };
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --request PATCH --header 'Host: www.example.com' --header 'Content-Type: application/example' --header 'If-Match: \"e0023aa4e\"' 'http://localhost:8000/patch/file.txt'".to_string()
- );
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.method, "PATCH".to_string());
- assert_eq!(
- request.url,
- "http://localhost:8000/patch/file.txt".to_string()
- );
- assert!(request.headers.contains(&Header {
- name: "Host".to_string(),
- value: "www.example.com".to_string(),
- }));
- assert!(request.headers.contains(&Header {
- name: "Content-Type".to_string(),
- value: "application/example".to_string(),
- }));
-
- assert_eq!(response.status, 204);
- assert!(response.body.is_empty());
-}
-
-#[test]
-fn test_custom_headers() {
- let options = ClientOptions::default();
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = RequestSpec {
- method: Method::Get,
- url: "http://localhost:8000/custom-headers".to_string(),
- headers: vec![
- Header::new("Fruit", "Raspberry"),
- Header::new("Fruit", "Apple"),
- Header::new("Fruit", "Banana"),
- Header::new("Fruit", "Grape"),
- Header::new("Color", "Green"),
- ],
- ..Default::default()
- };
- assert!(options.curl_args().is_empty());
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --header 'Fruit: Raspberry' --header 'Fruit: Apple' --header 'Fruit: Banana' --header 'Fruit: Grape' --header 'Color: Green' 'http://localhost:8000/custom-headers'".to_string()
- );
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.method, "GET".to_string());
- assert_eq!(
- request.url,
- "http://localhost:8000/custom-headers".to_string()
- );
- assert!(request.headers.contains(&Header {
- name: "Fruit".to_string(),
- value: "Raspberry".to_string(),
- }));
- assert_eq!(response.status, 200);
- assert!(response.body.is_empty());
-}
-
-#[test]
-fn test_querystring_params() {
- let options = ClientOptions::default();
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = RequestSpec {
- method: Method::Get,
- url: "http://localhost:8000/querystring-params".to_string(),
- querystring: vec![
- Param {
- name: "param1".to_string(),
- value: "value1".to_string(),
- },
- Param {
- name: "param2".to_string(),
- value: "".to_string(),
- },
- Param {
- name: "param3".to_string(),
- value: "a=b".to_string(),
- },
- Param {
- name: "param4".to_string(),
- value: "1,2,3".to_string(),
- },
- Param {
- name: "$top".to_string(),
- value: "5".to_string(),
- },
- ],
- ..Default::default()
- };
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl 'http://localhost:8000/querystring-params?param1=value1¶m2=¶m3=a%3Db¶m4=1%2C2%2C3&$top=5'".to_string()
- );
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.method, "GET".to_string());
- assert_eq!(request.url, "http://localhost:8000/querystring-params?param1=value1¶m2=¶m3=a%3Db¶m4=1%2C2%2C3&$top=5".to_string());
- assert_eq!(request.headers.len(), 3);
-
- assert_eq!(response.status, 200);
- assert!(response.body.is_empty());
-}
-
-#[test]
-fn test_form_params() {
- let options = ClientOptions::default();
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = RequestSpec {
- method: Method::Post,
- url: "http://localhost:8000/form-params".to_string(),
- form: vec![
- Param {
- name: "param1".to_string(),
- value: "value1".to_string(),
- },
- Param {
- name: "param2".to_string(),
- value: "".to_string(),
- },
- Param {
- name: "param3".to_string(),
- value: "a=b".to_string(),
- },
- Param {
- name: "param4".to_string(),
- value: "a%3db".to_string(),
- },
- Param {
- name: "values[0]".to_string(),
- value: "0".to_string(),
- },
- Param {
- name: "values[1]".to_string(),
- value: "1".to_string(),
- },
- ],
- content_type: Some("application/x-www-form-urlencoded".to_string()),
- ..Default::default()
- };
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --data 'param1=value1' --data 'param2=' --data 'param3=a%3Db' --data 'param4=a%253db' --data 'values[0]=0' --data 'values[1]=1' 'http://localhost:8000/form-params'".to_string()
- );
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.method, "POST".to_string());
- assert_eq!(request.url, "http://localhost:8000/form-params".to_string());
- assert!(request.headers.contains(&Header {
- name: "Content-Type".to_string(),
- value: "application/x-www-form-urlencoded".to_string(),
- }));
-
- assert_eq!(response.status, 200);
- assert!(response.body.is_empty());
-
- // make sure you can reuse client for other request
- let request = default_get_request("http://localhost:8000/hello");
- let call = client.execute(&request, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.method, "GET".to_string());
- assert_eq!(request.url, "http://localhost:8000/hello".to_string());
- assert_eq!(request.headers.len(), 3);
- assert_eq!(response.status, 200);
- assert_eq!(response.body, b"Hello World!".to_vec());
-}
-
-#[test]
-fn test_redirect() {
- let request_spec = default_get_request("http://localhost:8000/redirect-absolute");
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let options = ClientOptions::default();
- let mut client = Client::new(None);
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.method, "GET".to_string());
- assert_eq!(
- request.url,
- "http://localhost:8000/redirect-absolute".to_string()
- );
- assert_eq!(request.headers.len(), 3);
-
- assert_eq!(response.status, 302);
- assert_eq!(
- response.get_header_values("Location").get(0).unwrap(),
- "http://localhost:8000/redirected"
- );
- assert_eq!(
- response.url,
- "http://localhost:8000/redirect-absolute".to_string()
- );
-}
-
-#[test]
-fn test_follow_location() {
- let request_spec = default_get_request("http://localhost:8000/redirect-absolute");
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let options = ClientOptions {
- follow_location: true,
- ..Default::default()
- };
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- assert_eq!(options.curl_args(), vec!["--location".to_string()]);
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --location 'http://localhost:8000/redirect-absolute'".to_string()
- );
-
- let calls = client
- .execute_with_redirect(&request_spec, &options, &logger)
- .unwrap();
- assert_eq!(calls.len(), 2);
-
- let call1 = calls.get(0).unwrap();
- let request1 = &call1.request;
- let response1 = &call1.response;
- assert_eq!(request1.method, "GET".to_string());
- assert_eq!(
- request1.url,
- "http://localhost:8000/redirect-absolute".to_string()
- );
- assert_eq!(request1.headers.len(), 3);
- assert_eq!(response1.status, 302);
- assert!(response1.headers.contains(&Header {
- name: "Location".to_string(),
- value: "http://localhost:8000/redirected".to_string(),
- }));
- assert_eq!(
- response1.url,
- "http://localhost:8000/redirect-absolute".to_string()
- );
-
- let call2 = calls.get(1).unwrap();
- let request2 = &call2.request;
- let response2 = &call2.response;
- assert_eq!(request2.method, "GET".to_string());
- assert_eq!(request2.url, "http://localhost:8000/redirected".to_string());
- assert_eq!(request2.headers.len(), 3);
- assert_eq!(response2.status, 200);
- assert_eq!(
- response2.url,
- "http://localhost:8000/redirected".to_string()
- );
-
- let request = default_get_request("http://localhost:8000/hello");
- let calls = client
- .execute_with_redirect(&request, &options, &logger)
- .unwrap();
- assert_eq!(calls.len(), 1);
- let Call { response, .. } = calls.get(0).unwrap();
- assert_eq!(response.status, 200);
- assert_eq!(response.body, b"Hello World!".to_vec());
-}
-
-#[test]
-fn test_max_redirect() {
- let options = ClientOptions {
- follow_location: true,
- max_redirect: Some(10),
- ..Default::default()
- };
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("http://localhost:8000/redirect/15");
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --location --max-redirs 10 'http://localhost:8000/redirect/15'".to_string()
- );
- let error = client
- .execute_with_redirect(&request_spec, &options, &logger)
- .err()
- .unwrap();
- assert_eq!(error, HttpError::TooManyRedirect);
-
- let request_spec = default_get_request("http://localhost:8000/redirect/8");
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --location --max-redirs 10 'http://localhost:8000/redirect/8'".to_string()
- );
- let calls = client
- .execute_with_redirect(&request_spec, &options, &logger)
- .unwrap();
- let call = calls.last().unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.url, "http://localhost:8000/redirect/0".to_string());
- assert_eq!(response.status, 200);
- assert_eq!(redirect_count(&calls), 8);
-}
-
-#[test]
-fn test_multipart_form_data() {
- let options = ClientOptions::default();
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = RequestSpec {
- method: Method::Post,
- url: "http://localhost:8000/multipart-form-data".to_string(),
- multipart: vec![
- MultipartParam::Param(Param {
- name: "key1".to_string(),
- value: "value1".to_string(),
- }),
- MultipartParam::FileParam(FileParam {
- name: "upload1".to_string(),
- filename: "data.txt".to_string(),
- data: b"Hello World!".to_vec(),
- content_type: "text/plain".to_string(),
- }),
- MultipartParam::FileParam(FileParam {
- name: "upload2".to_string(),
- filename: "data.html".to_string(),
- data: b"Hello World!".to_vec(),
- content_type: "text/html".to_string(),
- }),
- MultipartParam::FileParam(FileParam {
- name: "upload3".to_string(),
- filename: "data.txt".to_string(),
- data: b"Hello World!".to_vec(),
- content_type: "text/html".to_string(),
- }),
- ],
- content_type: Some("multipart/form-data".to_string()),
- ..Default::default()
- };
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --form 'key1=value1' --form 'upload1=@data.txt;type=text/plain' --form 'upload2=@data.html;type=text/html' --form 'upload3=@data.txt;type=text/html' 'http://localhost:8000/multipart-form-data'".to_string()
- );
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert!(request.headers.contains(&Header {
- name: "Content-Length".to_string(),
- value: "627".to_string(),
- }));
- assert_eq!(response.status, 200);
- assert!(response.body.is_empty());
-
- // make sure you can reuse client for other request
- let request_spec = default_get_request("http://localhost:8000/hello");
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.method, "GET".to_string());
- assert_eq!(response.status, 200);
- assert_eq!(response.body, b"Hello World!".to_vec());
-}
-
-#[test]
-fn test_post_bytes() {
- let options = ClientOptions::default();
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = RequestSpec {
- method: Method::Post,
- url: "http://localhost:8000/post-base64".to_string(),
- headers: vec![],
- querystring: vec![],
- form: vec![],
- multipart: vec![],
- cookies: vec![],
- body: Body::Binary(b"Hello World!".to_vec()),
- content_type: None,
- };
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --header 'Content-Type: application/octet-stream' --data $'\\x48\\x65\\x6c\\x6c\\x6f\\x20\\x57\\x6f\\x72\\x6c\\x64\\x21' 'http://localhost:8000/post-base64'".to_string()
- );
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert!(request.headers.contains(&Header {
- name: "Content-Length".to_string(),
- value: "12".to_string(),
- }));
-
- assert_eq!(response.status, 200);
- assert!(response.body.is_empty());
-}
-
-#[test]
-fn test_expect() {
- let options = ClientOptions::default();
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = RequestSpec {
- method: Method::Post,
- url: "http://localhost:8000/expect".to_string(),
- headers: vec![Header {
- name: "Expect".to_string(),
- value: "100-continue".to_string(),
- }],
- querystring: vec![],
- form: vec![],
- multipart: vec![],
- cookies: vec![],
- body: Body::Text("data".to_string()),
- content_type: None,
- };
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --header 'Expect: 100-continue' --header 'Content-Type:' --data 'data' 'http://localhost:8000/expect'".to_string()
- );
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert!(request.headers.contains(&Header {
- name: "Expect".to_string(),
- value: "100-continue".to_string(),
- }));
- assert_eq!(response.status, 200);
- assert_eq!(response.version, Version::Http11);
- assert!(response.body.is_empty());
-}
-
-#[test]
-fn test_basic_authentication() {
- let options = ClientOptions {
- user: Some("bob@email.com:secret".to_string()),
- ..Default::default()
- };
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("http://localhost:8000/basic-authentication");
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --user 'bob@email.com:secret' 'http://localhost:8000/basic-authentication'"
- .to_string()
- );
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert!(request.headers.contains(&Header {
- name: "Authorization".to_string(),
- value: "Basic Ym9iQGVtYWlsLmNvbTpzZWNyZXQ=".to_string(),
- }));
- assert_eq!(response.status, 200);
- assert_eq!(response.version, Version::Http11);
- assert_eq!(response.body, b"You are authenticated".to_vec());
-
- let options = ClientOptions::default();
- let mut client = Client::new(None);
- let request_spec =
- default_get_request("http://bob%40email.com:secret@localhost:8000/basic-authentication");
- assert_eq!(
- request_spec.curl_args(&ContextDir::default()),
- vec!["'http://bob%40email.com:secret@localhost:8000/basic-authentication'".to_string()]
- );
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert!(request.headers.contains(&Header {
- name: "Authorization".to_string(),
- value: "Basic Ym9iQGVtYWlsLmNvbTpzZWNyZXQ=".to_string(),
- }));
- assert_eq!(response.status, 200);
- assert_eq!(response.version, Version::Http11);
- assert_eq!(response.body, b"You are authenticated".to_vec());
-}
-
-#[test]
-fn test_cacert() {
- let options = ClientOptions {
- cacert_file: Some("tests/server_cert_selfsigned.pem".to_string()),
- ..Default::default()
- };
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("https://localhost:8001/hello");
- let Call { response, .. } = client.execute(&request_spec, &options, &logger).unwrap();
- assert_eq!(response.status, 200);
-
- let certificate = response.certificate.unwrap();
-
- assert_eq!(
- certificate.issuer.replace(" = ", "=").replace(';', " "),
- "C=US, ST=Denial, L=Springfield, O=Dis, CN=localhost".to_string()
- );
- assert_eq!(
- certificate.subject.replace(" = ", "=").replace(';', " "),
- "C=US, ST=Denial, L=Springfield, O=Dis, CN=localhost".to_string()
- );
- assert_eq!(
- certificate.start_date,
- chrono::DateTime::parse_from_rfc2822("Tue, 10 Jan 2023 08:29:52 GMT")
- .unwrap()
- .with_timezone(&chrono::Utc)
- );
- assert_eq!(
- certificate.expire_date,
- chrono::DateTime::parse_from_rfc2822("Thu, 30 Oct 2025 08:29:52 GMT")
- .unwrap()
- .with_timezone(&chrono::Utc)
- );
- assert_eq!(
- certificate.serial_number,
- "1e:e8:b1:7f:1b:64:d8:d6:b3:de:87:01:03:d2:a4:f5:33:53:5a:b0".to_string()
- );
-}
-
-#[test]
-fn test_error_could_not_resolve_host() {
- let options = ClientOptions::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("http://unknown");
- let error = client
- .execute(&request_spec, &options, &logger)
- .err()
- .unwrap();
- assert!(matches!(error, HttpError::Libcurl { .. }));
- if let HttpError::Libcurl {
- code,
- description,
- url,
- } = error
- {
- assert_eq!(code, 6);
- assert_eq!(description, "Could not resolve host: unknown");
- assert_eq!(url, "http://unknown");
- }
-}
-
-#[test]
-fn test_error_fail_to_connect() {
- let options = ClientOptions::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("http://localhost:9999");
- let error = client
- .execute(&request_spec, &options, &logger)
- .err()
- .unwrap();
- assert!(matches!(error, HttpError::Libcurl { .. }));
- if let HttpError::Libcurl {
- code,
- description,
- url,
- } = error
- {
- assert_eq!(code, 7);
- assert!(description.starts_with("Failed to connect to localhost port 9999"));
- assert_eq!(url, "http://localhost:9999");
- }
-
- let options = ClientOptions {
- proxy: Some("localhost:9999".to_string()),
- ..Default::default()
- };
- let mut client = Client::new(None);
- let request = default_get_request("http://localhost:8000/hello");
- let error = client.execute(&request, &options, &logger).err().unwrap();
- assert!(matches!(error, HttpError::Libcurl { .. }));
- if let HttpError::Libcurl {
- code,
- description,
- url,
- } = error
- {
- assert_eq!(code, 7);
- eprintln!("description={description}");
- assert!(description.starts_with("Failed to connect to localhost port 9999"));
- assert_eq!(url, "http://localhost:8000/hello");
- }
-}
-
-#[test]
-fn test_error_could_not_resolve_proxy_name() {
- let options = ClientOptions {
- proxy: Some("unknown".to_string()),
- ..Default::default()
- };
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("http://localhost:8000/hello");
- let error = client
- .execute(&request_spec, &options, &logger)
- .err()
- .unwrap();
- assert!(matches!(error, HttpError::Libcurl { .. }));
- if let HttpError::Libcurl {
- code,
- description,
- url,
- } = error
- {
- assert_eq!(code, 5);
- assert_eq!(description, "Could not resolve proxy: unknown");
- assert_eq!(url, "http://localhost:8000/hello");
- }
-}
-
-#[test]
-fn test_error_ssl() {
- let options = ClientOptions::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("https://localhost:8001/hello");
- let error = client
- .execute(&request_spec, &options, &logger)
- .err()
- .unwrap();
- if let HttpError::Libcurl {
- code,
- description,
- url,
- } = error
- {
- // libcurl on linux and mac exists with 60
- // libcurl with openssl3 feature built by vcpkg on x64-windows exists with 35
- assert_eq!(code, 60);
- let descriptions = [
-
- // Windows 2000 github runner messages:
- "schannel: SEC_E_UNTRUSTED_ROOT (0x80090325) - The certificate chain was issued by an authority that is not trusted.".to_string(),
- // Windows 10 Enterprise 2009 10.0.19041.1806
- "schannel: SEC_E_UNTRUSTED_ROOT (0x80090325)".to_string(),
- // Unix-like, before OpenSSL 3.0.0
- "SSL certificate problem: self signed certificate in certificate chain".to_string(),
- // Unix-like, after OpenSSL 3.0.0
- "SSL certificate problem: self-signed certificate".to_string(),
- "SSL certificate problem: self signed certificate".to_string(),
- ];
- assert!(
- descriptions.contains(&description),
- "actual description is {description}"
- );
- assert_eq!(url, "https://localhost:8001/hello");
- }
-}
-
-#[test]
-fn test_timeout() {
- let options = ClientOptions {
- timeout: Duration::from_millis(100),
- ..Default::default()
- };
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("http://localhost:8000/timeout");
- let error = client
- .execute(&request_spec, &options, &logger)
- .err()
- .unwrap();
- assert!(matches!(error, HttpError::Libcurl { .. }));
- if let HttpError::Libcurl {
- code,
- description,
- url,
- } = error
- {
- assert_eq!(code, 28);
- assert!(description.starts_with("Operation timed out after "));
- assert_eq!(url, "http://localhost:8000/timeout");
- }
-}
-
-#[test]
-fn test_accept_encoding() {
- let options = ClientOptions {
- compressed: true,
- ..Default::default()
- };
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("http://localhost:8000/compressed/gzip");
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert!(request.headers.contains(&Header {
- name: "Accept-Encoding".to_string(),
- value: "gzip, deflate, br".to_string(),
- }));
- assert_eq!(response.status, 200);
- assert!(response.headers.contains(&Header {
- name: "Content-Length".to_string(),
- value: "32".to_string(),
- }));
-}
-
-#[test]
-fn test_connect_timeout() {
- let options = ClientOptions {
- connect_timeout: Duration::from_secs(1),
- ..Default::default()
- };
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("http://10.0.0.0");
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --connect-timeout 1 'http://10.0.0.0'".to_string()
- );
- let error = client
- .execute(&request_spec, &options, &logger)
- .err()
- .unwrap();
- assert!(matches!(error, HttpError::Libcurl { .. }));
- if let HttpError::Libcurl {
- code,
- description,
- url,
- } = error
- {
- eprintln!("description={description}");
- // TODO: remove the 7 / "Couldn't connect to server" case
- // On Linux/Windows libcurl version, the correct error message is:
- // `CURLE_OPERATION_TIMEDOUT` (28) / "Connection timeout" | "Connection timed out"
- // On macOS <= 11.6.4, the built-in libcurl is:
- // `CURLE_COULDNT_CONNECT` (7) / "Couldn't connect to server" errors.
- // On the GitHub CI, macOS images are 11.6.4.
- // So we keep this code until a newer macOS image is used in the GitHub actions.
- assert!(code == 7 || code == 28);
- let re = Regex::new(r"^Failed to connect to.*: Timeout was reached$").unwrap();
- assert!(
- re.is_match(&description)
- || description.starts_with("Couldn't connect to server")
- || description.starts_with("Connection timed out")
- || description.starts_with("Connection timeout")
- );
- assert_eq!(url, "http://10.0.0.0");
- }
-}
-
-#[test]
-fn test_cookie() {
- let options = ClientOptions::default();
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = RequestSpec {
- method: Method::Get,
- url: "http://localhost:8000/cookies/set-request-cookie1-valueA".to_string(),
- cookies: vec![RequestCookie {
- name: "cookie1".to_string(),
- value: "valueA".to_string(),
- }],
- ..Default::default()
- };
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --cookie 'cookie1=valueA' 'http://localhost:8000/cookies/set-request-cookie1-valueA'"
- .to_string()
- );
-
- //assert_eq!(request.cookies(), vec!["cookie1=valueA".to_string(),]);
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert!(request.headers.contains(&Header {
- name: "Cookie".to_string(),
- value: "cookie1=valueA".to_string(),
- }));
- assert_eq!(response.status, 200);
- assert!(response.body.is_empty());
-
- let request_spec =
- default_get_request("http://localhost:8000/cookies/assert-that-cookie1-is-not-in-session");
- let Call { response, .. } = client.execute(&request_spec, &options, &logger).unwrap();
- assert_eq!(response.status, 200);
-}
-
-#[test]
-fn test_multiple_request_cookies() {
- let options = ClientOptions::default();
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = RequestSpec {
- method: Method::Get,
- url: "http://localhost:8000/cookies/set-multiple-request-cookies".to_string(),
- cookies: vec![
- RequestCookie {
- name: "user1".to_string(),
- value: "Bob".to_string(),
- },
- RequestCookie {
- name: "user2".to_string(),
- value: "Bill".to_string(),
- },
- RequestCookie {
- name: "user3".to_string(),
- value: "Bruce".to_string(),
- },
- ],
- ..Default::default()
- };
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --cookie 'user1=Bob; user2=Bill; user3=Bruce' 'http://localhost:8000/cookies/set-multiple-request-cookies'".to_string()
- );
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert!(request.headers.contains(&Header {
- name: "Cookie".to_string(),
- value: "user1=Bob; user2=Bill; user3=Bruce".to_string(),
- }));
- assert_eq!(response.status, 200);
- assert!(response.body.is_empty());
-}
-
-#[test]
-fn test_cookie_storage() {
- let options = ClientOptions::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec =
- default_get_request("http://localhost:8000/cookies/set-session-cookie2-valueA");
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(
- request.url,
- "http://localhost:8000/cookies/set-session-cookie2-valueA".to_string()
- );
- assert_eq!(response.status, 200);
- assert!(response.body.is_empty());
-
- let cookie_store = client.get_cookie_storage();
- assert_eq!(
- cookie_store.get(0).unwrap().clone(),
- Cookie {
- domain: "localhost".to_string(),
- include_subdomain: "FALSE".to_string(),
- path: "/".to_string(),
- https: "FALSE".to_string(),
- expires: "0".to_string(),
- name: "cookie2".to_string(),
- value: "valueA".to_string(),
- http_only: false,
- }
- );
-
- let request_spec =
- default_get_request("http://localhost:8000/cookies/assert-that-cookie2-is-valueA");
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert!(request.headers.contains(&Header {
- name: "Cookie".to_string(),
- value: "cookie2=valueA".to_string(),
- }));
- assert_eq!(response.status, 200);
- assert!(response.body.is_empty());
-}
-
-#[test]
-fn test_cookie_file() {
- let options = ClientOptions {
- cookie_input_file: Some("tests/cookies.txt".to_string()),
- ..Default::default()
- };
- let context_dir = ContextDir::default();
- let mut client = Client::new(Some("tests/cookies.txt".to_string()));
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec =
- default_get_request("http://localhost:8000/cookies/assert-that-cookie2-is-valueA");
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --cookie tests/cookies.txt 'http://localhost:8000/cookies/assert-that-cookie2-is-valueA'".to_string()
- );
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(
- request.url,
- "http://localhost:8000/cookies/assert-that-cookie2-is-valueA"
- );
- assert!(request.headers.contains(&Header {
- name: "Cookie".to_string(),
- value: "cookie2=valueA".to_string(),
- }));
-
- assert_eq!(response.status, 200);
- assert!(response.body.is_empty());
-}
-
-#[test]
-fn test_proxy() {
- // roxy listening on port 3128
- let options = ClientOptions {
- proxy: Some("localhost:3128".to_string()),
- ..Default::default()
- };
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = default_get_request("http://127.0.0.1:8000/proxy");
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --proxy 'localhost:3128' 'http://127.0.0.1:8000/proxy'".to_string()
- );
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.url, "http://127.0.0.1:8000/proxy");
- assert_eq!(response.status, 200);
-}
-
-#[test]
-fn test_insecure() {
- let options = ClientOptions {
- insecure: true,
- ..Default::default()
- };
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- assert_eq!(options.curl_args(), vec!["--insecure".to_string()]);
- let request_spec = default_get_request("https://localhost:8001/hello");
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --insecure 'https://localhost:8001/hello'".to_string()
- );
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.url, "https://localhost:8001/hello");
- assert_eq!(response.status, 200);
-}
-
-#[test]
-fn test_head() {
- let options = ClientOptions {
- ..Default::default()
- };
- let context_dir = ContextDir::default();
- let mut client = Client::new(None);
- let logger_opts = LoggerOptionsBuilder::new().build();
- let logger = Logger::from(&logger_opts);
-
- let request_spec = RequestSpec {
- method: Method::Head,
- url: "http://localhost:8000/head".to_string(),
- ..Default::default()
- };
- assert_eq!(
- client.curl_command_line(&request_spec, &context_dir, &options),
- "curl --head 'http://localhost:8000/head'".to_string()
- );
-
- let call = client.execute(&request_spec, &options, &logger).unwrap();
- let request = &call.request;
- let response = &call.response;
- assert_eq!(request.url, "http://localhost:8000/head");
- assert_eq!(response.status, 200);
- assert!(response.headers.contains(&Header {
- name: "Content-Length".to_string(),
- value: "10".to_string(),
- }));
-}
-
-#[test]
-fn test_version() {
- // This test if only informative for the time-being
-
- let output = std::process::Command::new("curl")
- .args(["--version"])
- .output()
- .expect("failed to execute process");
- let curl_version = std::str::from_utf8(&output.stdout).unwrap();
- let index = curl_version.find("libcurl").expect("libcurl substring");
- let expected_version = &curl_version[index..];
- eprintln!("{expected_version:?}");
- let versions = libcurl_version_info();
- eprintln!("{versions:?}");
-}
-
-// This test function can be used to reproduce bug
-#[test]
-fn test_libcurl_directly() {
- use std::io::{stdout, Write};
-
- use curl;
-
- let mut easy = curl::easy::Easy::new();
- easy.url("http://localhost:8000/hello").unwrap();
- easy.write_function(|data| {
- stdout().write_all(data).unwrap();
- Ok(data.len())
- })
- .unwrap();
- easy.perform().unwrap();
-}
diff --git a/packages/hurl/src/http/tests/mod.rs b/packages/hurl/src/http/tests/mod.rs
index f5bef0c68..58a1469b5 100644
--- a/packages/hurl/src/http/tests/mod.rs
+++ b/packages/hurl/src/http/tests/mod.rs
@@ -17,9 +17,6 @@
*/
use crate::http::{Header, Method, Param, RequestCookie, RequestSpec, Response};
-mod libcurl;
-mod runner;
-
/// Some Request Response to be used by tests
pub fn hello_http_request() -> RequestSpec {
diff --git a/packages/hurl/src/http/tests/runner.rs b/packages/hurl/src/http/tests/runner.rs
deleted file mode 100644
index 0df2ee839..000000000
--- a/packages/hurl/src/http/tests/runner.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * 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 std::collections::HashMap;
-
-use crate::runner;
-use crate::runner::RunnerOptions;
-use crate::util::logger::LoggerOptionsBuilder;
-
-#[test]
-fn test_hello() {
- let content = "GET http://localhost;8000/hello";
- let logger_opts = LoggerOptionsBuilder::new().build();
- let variables = HashMap::new();
- let runner_opts = RunnerOptions::default();
- runner::run(content, &runner_opts, &variables, &logger_opts).unwrap();
-}