Skip to content

Commit

Permalink
Added fixes for declare returning stringified json
Browse files Browse the repository at this point in the history
- Added fix for collect always returning stringified json if it is returning an array of objects
- Added fix for declare expressions that were escaping json in the declare
- Added example yaml that shows json in vars, declare, and collect objects
  • Loading branch information
tkmcmaster committed Oct 30, 2023
1 parent 4b151c9 commit a34bf2d
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 2 deletions.
75 changes: 75 additions & 0 deletions examples/declare.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
load_pattern:
- !linear
to: 100%
over: 15s
loggers:
l:
to: !stdout
vars:
var_string: "foo"
var_array: ["foo", "foo", "foo"]
port: "${e:PORT}"
# a var that is an an object as a string.
# Putting this in directly will escape out all the quotes. You must wrap it as ${x:(${v:var_string_json})} to avoid escaping
var_string_json: '{"d":234,"e":"pqr","f":2.34}'
# a var that is a an object as an object
var_object: {"d":890,"e":"xyz","f":7.89}
providers:
provider_range:
!range
provider_list_objects: # List of objects
!list
values:
- a: 123
b: 'abc'
c: 1.23
- a: 456
b: 'def'
c: 4.56
- a: 789
b: 'ghi'
c: 7.89
- a: 101112
b: 'jkl'
c: 10.1112
repeat: true
endpoints:
- method: POST
declare:
# Collects the string into an array
collect_strings: !c
collects:
- take: 3
from: '${v:var_string}'
as: _b
then: ${p:_b}
# Collects the objects into an array
collect_objects: !c
collects:
- take: 2
from: '${p:provider_list_objects}'
as: _c
then: ${p:_c}
declare_string_json: !x '[{"provider_range": ${p:provider_range}, "var_string": "${v:var_string}","provider_list_objects": ${p:provider_list_objects}, "h": "tuv" }]'
url: http://localhost:${v:port}/
body: !str >-
{
"provider_range": ${p:provider_range},
"var_string": "${v:var_string}",
"provider_list_objects": ${p:provider_list_objects},
"collect_objects": ${p:collect_objects},
"collect_strings": ${p:collect_strings},
"var_array": ${v:var_array},
"var_string_json": ${x:(${v:var_string_json})},
"var_object": ${v:var_object},
"declare_string_json": ${p:declare_string_json},
"const_string": "test"
}
peak_load: 1.1hps
headers:
Content-Type: application/json
logs:
l:
select:
status: response.status
body: response.body
48 changes: 46 additions & 2 deletions lib/config/src/configv2/templating.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use ether::{Either, Either3};
use futures::{Stream, TryStreamExt};
pub use helpers::*;
use itertools::Itertools;
use log::debug;
use serde::Deserialize;
use std::{
borrow::Cow,
Expand Down Expand Up @@ -205,6 +206,11 @@ impl<T: TemplateType<ProvAllowed = True>> Template<String, T, True, True> {
Ar: Clone + Send + Unpin + 'static,
E: StdError + Send + Clone + Unpin + 'static + From<EvalExprError>,
{
debug!(
"Template into_stream template={:?}, providers={:?}",
self,
providers.keys()
);
self.into_stream_with(move |p| providers.get(p).map(|p| p.as_stream()))
}

Expand Down Expand Up @@ -234,9 +240,18 @@ impl<T: TemplateType<ProvAllowed = True>> Template<String, T, True, True> {
use futures::stream::repeat;
Ok(match self {
Self::Literal { value } => {
debug!(
"Template::Literal into_stream_with value='{}', json='{}'",
value,
serde_json::Value::String(value.clone())
);
Either::A(repeat(Ok((serde_json::Value::String(value), vec![]))))
}
Self::NeedsProviders { script, .. } => {
debug!(
"Template::NeedsProviders into_stream_with script={:?}",
script
);
let streams = script
.into_iter()
.map(|s| match s {
Expand All @@ -254,13 +269,42 @@ impl<T: TemplateType<ProvAllowed = True>> Template<String, T, True, True> {
.collect::<Result<Vec<_>, _>>()?;
Either::B(zip_all::zip_all(streams).map_ok(|js| {
js.into_iter()
.map(|(j, ar)| (j.to_string().trim_matches('"').to_owned(), ar))
.map(|(j, ar)| {
match j {
serde_json::Value::String(s) => {
// We don't want to stringify the json::Value::String or it will escape out quotes, etc.
// Get the internal string and use it.
debug!("Template into_stream_with zip_all json::string s={}, to_string={}", s, s.to_string());
(s.trim_matches('"').to_owned(), ar)
},
other => {
debug!("Template into_stream_with zip_all json::other j={}, to_string={}", other, other.to_string());
(other.to_string().trim_matches('"').to_owned(), ar)
},
}
})
.reduce(|mut acc, e| {
acc.0.push_str(&e.0);
acc.1.extend(e.1);
acc
})
.map(|(s, ar)| (serde_json::Value::String(s), ar))
.map(|(s, ar)| {
// If it's an object we're turning it into a string here
(
match serde_json::from_str(&s) {
Ok(serde_json::Value::String(s)) => {
log::debug!("Using literal string {s:?} as the json value");
serde_json::Value::String(s)
}
Ok(v) => v,
Err(e) => {
log::debug!("String {s:?} is not valid JSON ({e}); reusing same string value");
serde_json::Value::String(s)
}
},
ar,
)
})
.unwrap_or_default()
}))
}
Expand Down

0 comments on commit a34bf2d

Please sign in to comment.