Skip to content

Commit 4c3f3ca

Browse files
tmccombspront
andauthored
enhancement(unit tests): Allow objects and arrays in log_fields test input (#22406)
* enhancement(unit tests): Allow objects and arrays in log_fields By making vrl Value a configurable type Fixes: #9386 * doc: Add doc comment to vrl::value::Value::to_value Co-authored-by: Pavlos Rontidis <[email protected]> --------- Co-authored-by: Pavlos Rontidis <[email protected]>
1 parent 2b63353 commit 4c3f3ca

File tree

5 files changed

+53
-33
lines changed

5 files changed

+53
-33
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Allow additional types to be used in `tests.inputs.log_fields` values, including
2+
nested objects and arrays.
3+
4+
authors: tmccombs

lib/vector-config/src/external/vrl.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::cell::RefCell;
22

33
use serde_json::Value;
4-
use vrl::{compiler::VrlRuntime, datadog_search_syntax::QueryNode};
4+
use vrl::{compiler::VrlRuntime, datadog_search_syntax::QueryNode, value::Value as VrlValue};
55

66
use crate::{
77
schema::{generate_string_schema, SchemaGenerator, SchemaObject},
@@ -36,3 +36,33 @@ impl Configurable for QueryNode {
3636
Ok(generate_string_schema())
3737
}
3838
}
39+
40+
impl Configurable for VrlValue {
41+
fn is_optional() -> bool {
42+
true
43+
}
44+
45+
fn metadata() -> Metadata {
46+
Metadata::with_transparent(true)
47+
}
48+
49+
fn generate_schema(_: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
50+
// We don't have any constraints on the inputs
51+
Ok(SchemaObject::default())
52+
}
53+
}
54+
55+
impl ToValue for VrlValue {
56+
/// Converts a `VrlValue` into a `serde_json::Value`.
57+
///
58+
/// This conversion should always succeed, though it may result in a loss
59+
/// of type information for some value types.
60+
///
61+
/// # Panics
62+
///
63+
/// This function will panic if serialization fails, which is not expected
64+
/// under normal circumstances.
65+
fn to_value(&self) -> Value {
66+
serde_json::to_value(self).expect("Unable to serialize VRL value")
67+
}
68+
}

src/config/mod.rs

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,13 @@ use std::{
88
time::Duration,
99
};
1010

11-
use crate::{conditions, event::Metric, secrets::SecretBackends, serde::OneOrMany};
11+
use crate::{
12+
conditions,
13+
event::{Metric, Value},
14+
secrets::SecretBackends,
15+
serde::OneOrMany,
16+
};
17+
1218
use indexmap::IndexMap;
1319
use serde::Serialize;
1420

@@ -473,24 +479,6 @@ impl TestDefinition<OutputId> {
473479
}
474480
}
475481

476-
/// Value for a log field.
477-
#[configurable_component]
478-
#[derive(Clone, Debug)]
479-
#[serde(untagged)]
480-
pub enum TestInputValue {
481-
/// A string.
482-
String(String),
483-
484-
/// An integer.
485-
Integer(i64),
486-
487-
/// A floating-point number.
488-
Float(f64),
489-
490-
/// A boolean.
491-
Boolean(bool),
492-
}
493-
494482
/// A unit test input.
495483
///
496484
/// An input describes not only the type of event to insert, but also which transform within the
@@ -522,7 +510,7 @@ pub struct TestInput {
522510
/// The set of log fields to use when creating a log input event.
523511
///
524512
/// Only relevant when `type` is `log`.
525-
pub log_fields: Option<IndexMap<String, TestInputValue>>,
513+
pub log_fields: Option<IndexMap<String, Value>>,
526514

527515
/// The metric to use as an input event.
528516
///

src/config/unit_test/mod.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use std::{
1818

1919
use futures_util::{stream::FuturesUnordered, StreamExt};
2020
use indexmap::IndexMap;
21-
use ordered_float::NotNan;
2221
use tokio::sync::{
2322
oneshot::{self, Receiver},
2423
Mutex,
@@ -39,9 +38,9 @@ use crate::{
3938
conditions::Condition,
4039
config::{
4140
self, loading, ComponentKey, Config, ConfigBuilder, ConfigPath, SinkOuter, SourceOuter,
42-
TestDefinition, TestInput, TestInputValue, TestOutput,
41+
TestDefinition, TestInput, TestOutput,
4342
},
44-
event::{Event, EventMetadata, LogEvent, Value},
43+
event::{Event, EventMetadata, LogEvent},
4544
signal,
4645
topology::{builder::TopologyPieces, RunningTopology},
4746
};
@@ -622,16 +621,8 @@ fn build_input_event(input: &TestInput) -> Result<Event, String> {
622621
if let Some(log_fields) = &input.log_fields {
623622
let mut event = LogEvent::from_str_legacy("");
624623
for (path, value) in log_fields {
625-
let value: Value = match value {
626-
TestInputValue::String(s) => Value::from(s.to_owned()),
627-
TestInputValue::Boolean(b) => Value::from(*b),
628-
TestInputValue::Integer(i) => Value::from(*i),
629-
TestInputValue::Float(f) => Value::from(
630-
NotNan::new(*f).map_err(|_| "NaN value not supported".to_string())?,
631-
),
632-
};
633624
event
634-
.parse_path_and_insert(path, value)
625+
.parse_path_and_insert(path, value.clone())
635626
.map_err(|e| e.to_string())?;
636627
}
637628
Ok(event.into())

src/config/unit_test/tests.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,9 @@ async fn test_log_input() {
805805
message = "this is the message"
806806
int_val = 5
807807
bool_val = true
808+
arr_val = [1, 2, "hi", false]
809+
obj_val = { a = true, b = "b", c = 5 }
810+
808811
809812
[[tests.outputs]]
810813
extract_from = "foo"
@@ -816,6 +819,10 @@ async fn test_log_input() {
816819
assert_eq!(.message, "this is the message")
817820
assert!(.bool_val)
818821
assert_eq!(.int_val, 5)
822+
assert_eq!(.arr_val, [1, 2, "hi", false])
823+
assert!(.obj_val.a)
824+
assert_eq!(.obj_val.b, "b")
825+
assert_eq!(.obj_val.c, 5)
819826
"""
820827
"#})
821828
.unwrap();

0 commit comments

Comments
 (0)