Skip to content

Commit

Permalink
Modify the model representing secrets.
Browse files Browse the repository at this point in the history
  • Loading branch information
jcamiel authored and hurl-bot committed Jan 15, 2025
1 parent f40e815 commit 9522750
Show file tree
Hide file tree
Showing 18 changed files with 193 additions and 85 deletions.
4 changes: 2 additions & 2 deletions integration/hurl/tests_ok/secret.err.pattern
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@
** upload completely sent off: 24 bytes
** Added cookie value="***" for domain localhost, path /, expire 0
** Closing connection
* Response: (received 20 bytes in <<<\d+>>> ms)
* Response: (received 21 bytes in <<<\d+>>> ms)
*
< HTTP/1.1 200 OK
< Server: Werkzeug/<<<.*?>>> Python/<<<.*?>>>
< Date: <<<.*?>>>
< Content-Type: application/json
< Content-Length: 20
< Content-Length: 21
< Set-Cookie: value=***; Path=/
< Server: Flask Server
< Connection: close
Expand Down
2 changes: 1 addition & 1 deletion integration/hurl/tests_ok/secret.hurl
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ HTTP 200
[Captures]
value: jsonpath "$.value"
[Asserts]
jsonpath "$.value" == "secret3"
jsonpath "$.value" == "12345678"
4 changes: 2 additions & 2 deletions integration/hurl/tests_ok/secret.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ $ErrorActionPreference = 'Stop'
hurl --very-verbose `
--secret a=secret1 `
--secret b=secret2 `
--secret c=secret3 `
--secret c=12345678 `
--report-html build/secret `
tests_ok/secret.hurl

$secrets = @("secret1", "secret2", "secret3")
$secrets = @("secret1", "secret2", "12345678")

$files = Get-ChildItem -Filter *.html -Recurse build/secret

Expand Down
2 changes: 1 addition & 1 deletion integration/hurl/tests_ok/secret.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
@app.route("/secret")
def secret():
assert request.json == {"query": "secret1"}
resp = jsonify(value="secret3")
resp = jsonify(value="12345678")
resp.set_cookie("value", "secret2")
return resp
4 changes: 2 additions & 2 deletions integration/hurl/tests_ok/secret.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ set -Eeuo pipefail
hurl --very-verbose \
--secret a=secret1 \
--secret b=secret2 \
--secret c=secret3 \
--secret c=12345678 \
--report-html build/secret \
tests_ok/secret.hurl

secrets=("secret1" "secret2" "secret3")
secrets=("secret1" "secret2" "12345678")

files=$(find build/secret/*.html build/secret/**/*.html)

Expand Down
4 changes: 2 additions & 2 deletions integration/hurl/tests_ok/secret_test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ hurl --test \
--very-verbose \
--secret a=secret1 \
--secret b=secret2 \
--secret c=secret3 \
--secret c=12345678 \
tests_ok/secret.hurl 2>build/secret_test.err

$secrets = @("secret1", "secret2", "secret3")
$secrets = @("secret1", "secret2", "12345678")

$file = "build/secret_test.err"

Expand Down
4 changes: 2 additions & 2 deletions integration/hurl/tests_ok/secret_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ hurl --test \
--very-verbose \
--secret a=secret1 \
--secret b=secret2 \
--secret c=secret3 \
--secret c=12345678 \
tests_ok/secret.hurl 2>build/secret_test.err

secrets=("secret1" "secret2" "secret3")
secrets=("secret1" "secret2" "12345678")

file="build/secret_test.err"

Expand Down
12 changes: 8 additions & 4 deletions packages/hurl/src/cli/options/matches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,8 @@ pub fn secret(matches: &ArgMatches) -> Result<HashMap<String, String>, CliOption
let mut secrets = HashMap::new();
if let Some(secret) = get_strings(matches, "secret") {
for s in secret {
let (name, value) = variables::parse(&s)?;
let inferred = false;
let (name, value) = variables::parse(&s, inferred)?;
// We check that there is no existing secrets
if secrets.contains_key(&name) {
return Err(CliOptionsError::Error(format!(
Expand Down Expand Up @@ -469,7 +470,8 @@ pub fn variables(matches: &ArgMatches) -> Result<HashMap<String, Value>, CliOpti
// Use environment variables prefix by HURL_
for (env_name, env_value) in env::vars() {
if let Some(name) = env_name.strip_prefix("HURL_") {
let value = variables::parse_value(env_value.as_str())?;
let inferred = true;
let value = variables::parse_value(env_value.as_str(), inferred)?;
variables.insert(name.to_string(), value);
}
}
Expand Down Expand Up @@ -501,15 +503,17 @@ pub fn variables(matches: &ArgMatches) -> Result<HashMap<String, Value>, CliOpti
if line.starts_with('#') || line.is_empty() {
continue;
}
let (name, value) = variables::parse(line)?;
let inferred = true;
let (name, value) = variables::parse(line, inferred)?;
variables.insert(name.to_string(), value);
}
}
}

if let Some(input) = get_strings(matches, "variable") {
for s in input {
let (name, value) = variables::parse(&s)?;
let inferred = true;
let (name, value) = variables::parse(&s, inferred)?;
variables.insert(name.to_string(), value);
}
}
Expand Down
62 changes: 40 additions & 22 deletions packages/hurl/src/cli/options/variables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use hurl_core::ast::is_variable_reserved;

/// Parses a string "name=value" as a pair of `String` and `Value`.
///
/// Value variant is inferred from the `value`, for instance `true` is parsed as [`Value::Bool(true)`].
pub fn parse(s: &str) -> Result<(String, Value), CliOptionsError> {
/// If `inferred` is `true`, value variant is inferred from the `value`, for instance `true` is parsed as [`Value::Bool(true)`].
pub fn parse(s: &str, inferred: bool) -> Result<(String, Value), CliOptionsError> {
match s.find('=') {
None => Err(CliOptionsError::Error(format!(
"Missing value for variable {s}!"
Expand All @@ -35,17 +35,19 @@ pub fn parse(s: &str) -> Result<(String, Value), CliOptionsError> {
"Variable {name} conflicts with the {name} function, use a different name."
)));
}
let value = parse_value(&value[1..])?;
let value = parse_value(&value[1..], inferred)?;
Ok((name.to_string(), value))
}
}
}

/// Parses a `value` as a pair of String and Value.
///
/// Value variant is inferred from the `value`, for instance true is parsed as [`Value::Bool(true)`].
pub fn parse_value(s: &str) -> Result<Value, CliOptionsError> {
if s == "true" {
/// If `inferred` is `true`, value variant is inferred from the `value`, for instance true is parsed as [`Value::Bool(true)`].
pub fn parse_value(s: &str, inferred: bool) -> Result<Value, CliOptionsError> {
if !inferred {
Ok(Value::String(s.to_string()))
} else if s == "true" {
Ok(Value::Bool(true))
} else if s == "false" {
Ok(Value::Bool(false))
Expand Down Expand Up @@ -75,73 +77,89 @@ mod tests {
#[test]
fn test_parse() {
assert_eq!(
parse("name=Jennifer").unwrap(),
parse("name=Jennifer", true).unwrap(),
("name".to_string(), Value::String("Jennifer".to_string()))
);
assert_eq!(
parse("female=true").unwrap(),
parse("female=true", true).unwrap(),
("female".to_string(), Value::Bool(true))
);
assert_eq!(
parse("age=30").unwrap(),
parse("age=30", true).unwrap(),
("age".to_string(), Value::Number(Number::Integer(30)))
);
assert_eq!(
parse("height=1.7").unwrap(),
parse("height=1.7", true).unwrap(),
("height".to_string(), Value::Number(Number::Float(1.7)))
);
assert_eq!(
parse("id=\"123\"").unwrap(),
parse("id=\"123\"", true).unwrap(),
("id".to_string(), Value::String("123".to_string()))
);
assert_eq!(
parse("a_null=null").unwrap(),
parse("a_null=null", true).unwrap(),
("a_null".to_string(), Value::Null)
);
assert_eq!(
parse("a_null=null", false).unwrap(),
("a_null".to_string(), Value::String("null".to_string()))
);
}

#[test]
fn test_parse_error() {
assert_eq!(
parse("name").err().unwrap(),
parse("name", true).err().unwrap(),
CliOptionsError::Error("Missing value for variable name!".to_string())
);
}

#[test]
fn test_parse_value() {
assert_eq!(
parse_value("Jennifer").unwrap(),
parse_value("Jennifer", true).unwrap(),
Value::String("Jennifer".to_string())
);
assert_eq!(parse_value("true").unwrap(), Value::Bool(true));
assert_eq!(parse_value("true", true).unwrap(), Value::Bool(true));
assert_eq!(
parse_value("30").unwrap(),
parse_value("30", true).unwrap(),
Value::Number(Number::Integer(30))
);
assert_eq!(
parse_value("1.7").unwrap(),
parse_value("30", false).unwrap(),
Value::String("30".to_string())
);
assert_eq!(
parse_value("1.7", true).unwrap(),
Value::Number(Number::Float(1.7))
);
assert_eq!(
parse_value("1.0").unwrap(),
parse_value("1.7", false).unwrap(),
Value::String("1.7".to_string())
);
assert_eq!(
parse_value("1.0", true).unwrap(),
Value::Number(Number::Float(1.0))
);
assert_eq!(
parse_value("-1.0").unwrap(),
parse_value("-1.0", true).unwrap(),
Value::Number(Number::Float(-1.0))
);
assert_eq!(
parse_value("\"123\"").unwrap(),
parse_value("\"123\"", true).unwrap(),
Value::String("123".to_string())
);
assert_eq!(parse_value("null").unwrap(), Value::Null);
assert_eq!(
parse_value("\"123\"", false).unwrap(),
Value::String("\"123\"".to_string())
);
assert_eq!(parse_value("null", true).unwrap(), Value::Null);
}

#[test]
fn test_parse_value_error() {
assert_eq!(
parse_value("\"123").err().unwrap(),
parse_value("\"123", true).err().unwrap(),
CliOptionsError::Error("Value should end with a double quote".to_string())
);
}
Expand Down
1 change: 0 additions & 1 deletion packages/hurl/src/json/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ impl Value {
Value::Bool(v) => serde_json::Value::Bool(*v),
Value::Date(v) => serde_json::Value::String(v.to_string()),
Value::Number(v) => v.to_json(),
Value::Secret(s) => serde_json::Value::String(s.clone()),
Value::String(s) => serde_json::Value::String(s.clone()),
Value::List(values) => {
let values = values.iter().map(|v| v.to_json()).collect();
Expand Down
6 changes: 3 additions & 3 deletions packages/hurl/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use std::path::Path;

use hurl::parallel::job::{Job, JobResult};
use hurl::parallel::runner::ParallelRunner;
use hurl::runner::{HurlResult, Output, Value, VariableSet};
use hurl::runner::{HurlResult, Output, VariableSet};
use hurl::util::term::{Stdout, WriteMode};
use hurl::{output, parallel, runner};
use hurl_core::error::{DisplaySourceError, OutputFormat};
Expand Down Expand Up @@ -62,7 +62,7 @@ pub fn run_seq(
// insert all the secrets in the variable set.
options.secrets.iter().for_each(|(name, value)| {
variables
.insert(name.clone(), Value::Secret(value.clone()))
.insert_secret(name.clone(), value.clone())
.unwrap();
});
let runner_options = options.to_runner_options(&filename, current_dir);
Expand Down Expand Up @@ -187,7 +187,7 @@ pub fn run_par(
// insert all the secrets in the variable set.
options.secrets.iter().for_each(|(name, value)| {
variables
.insert(name.clone(), Value::Secret(value.clone()))
.insert_secret(name.clone(), value.clone())
.unwrap();
});
let output_type = options
Expand Down
4 changes: 2 additions & 2 deletions packages/hurl/src/runner/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ use super::function;
pub fn eval(expr: &Expr, variables: &VariableSet) -> Result<Value, RunnerError> {
match &expr.kind {
ExprKind::Variable(variable) => {
if let Some(value) = variables.get(variable.name.as_str()) {
Ok(value.clone())
if let Some(variable) = variables.get(variable.name.as_str()) {
Ok(variable.value().clone())
} else {
let kind = RunnerErrorKind::TemplateVariableNotDefined {
name: variable.name.clone(),
Expand Down
8 changes: 4 additions & 4 deletions packages/hurl/src/runner/hurl_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use hurl_core::typing::Count;
use crate::http::{Call, Client};
use crate::runner::event::EventListener;
use crate::runner::runner_options::RunnerOptions;
use crate::runner::{entry, options, EntryResult, HurlResult, Value, VariableSet};
use crate::runner::{entry, options, EntryResult, HurlResult, VariableSet};
use crate::util::logger::{ErrorFormat, Logger, LoggerOptions};
use crate::util::term::{Stderr, Stdout, WriteMode};

Expand Down Expand Up @@ -518,12 +518,12 @@ fn log_run_info(

let variables = variables
.iter()
.filter(|(_, value)| !matches!(value, Value::Secret(_)))
.filter(|(_, variable)| !variable.is_secret())
.collect::<Vec<_>>();
if !variables.is_empty() {
logger.debug_important("Variables:");
for (name, value) in variables.iter() {
logger.debug(&format!(" {name}: {value}"));
for (name, variable) in variables.iter() {
logger.debug(&format!(" {name}: {}", variable.value()));
}
}
if let Some(to_entry) = runner_options.to_entry {
Expand Down
2 changes: 1 addition & 1 deletion packages/hurl/src/runner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub use self::output::Output;
pub use self::result::{AssertResult, CaptureResult, EntryResult, HurlResult};
pub use self::runner_options::{RunnerOptions, RunnerOptionsBuilder};
pub use self::value::Value;
pub use self::variable::VariableSet;
pub use self::variable::{Variable, VariableSet, Visibility};

mod assert;
mod body;
Expand Down
1 change: 0 additions & 1 deletion packages/hurl/src/runner/predicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ impl Value {
Value::Number(number) => number.expected(),
Value::Object(values) => format!("list of size {}", values.len()),
Value::Regex(value) => format!("regex <{value}>"),
Value::Secret(value) => format!("string <{value}>"),
Value::String(value) => format!("string <{value}>"),
Value::Unit => "something".to_string(),
}
Expand Down
10 changes: 4 additions & 6 deletions packages/hurl/src/runner/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,12 +290,10 @@ fn eval_query_regex(
/// Evaluates a variable, given a set of `variables`.
fn eval_query_variable(name: &Template, variables: &VariableSet) -> QueryResult {
let name = eval_template(name, variables)?;
let value = variables.get(&name);
// Secrets value becomes "normal" strings so they can be filtered, used in predicates values etc...
match value {
Some(Value::Secret(s)) => Ok(Some(Value::String(s.clone()))),
Some(v) => Ok(Some(v.clone())),
None => Ok(None),
if let Some(variable) = variables.get(&name) {
Ok(Some(variable.value().clone()))
} else {
Ok(None)
}
}

Expand Down
Loading

0 comments on commit 9522750

Please sign in to comment.