Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
09c562a
add fix and small refactor
neuronull Jul 11, 2023
1e0e6e7
fix compilation errors
neuronull Jul 11, 2023
63a9581
3 ticks
neuronull Jul 11, 2023
c6af43e
dont compute expected metrics in validator
neuronull Jul 12, 2023
55a3518
cleanup
neuronull Jul 12, 2023
8ec87b3
cleanup
neuronull Jul 12, 2023
4b3b721
clippy
neuronull Jul 12, 2023
f9854bf
feedback tz: sent_eventssssss
neuronull Jul 12, 2023
0577ee6
feedback tz: fix telemetry shutdown finishing logic
neuronull Jul 12, 2023
51e9ab4
3 ticks
neuronull Jul 13, 2023
99a2d20
Merge branch 'master' into neuronull/draft_component_validation_bette…
neuronull Jul 13, 2023
e8cdf11
small reorg to add sinks
neuronull Jul 13, 2023
c460a49
mini refactor of the component spec validators
neuronull Jul 14, 2023
3daced5
attempt to set expected values from the resource
neuronull Jul 14, 2023
b7a7bd3
feedback tz- from not try_from
neuronull Jul 19, 2023
af7e9b2
Merge branch 'neuronull/draft_component_validation_better_validation'…
neuronull Jul 19, 2023
0ce0e25
back to 3 ticks
neuronull Jul 19, 2023
35efd5a
fix incorrect expected values
neuronull Jul 19, 2023
1f4ea02
Even more reduction
neuronull Jul 19, 2023
e8b17af
clippy
neuronull Jul 19, 2023
cdeab8f
add the discarded events total check
neuronull Jul 19, 2023
a0f7a65
Merge branch 'master' into neuronull/draft_component_validation_bette…
neuronull Jul 19, 2023
0a6c056
Merge branch 'neuronull/draft_component_validation_better_validation'…
neuronull Jul 19, 2023
77c110b
Merge branch 'master' into neuronull/component_validation_sink_compon…
neuronull Jul 20, 2023
006db51
workaround the new sync issues
neuronull Jul 20, 2023
4745a2f
Merge branch 'master' into neuronull/component_validation_sink_compon…
neuronull Jan 23, 2024
1a43e8b
check events
neuronull Jan 23, 2024
f54bdac
Merge branch 'master' into neuronull/component_validation_sink_compon…
neuronull Jan 26, 2024
f6aa019
partial feedback
neuronull Feb 2, 2024
a2689fe
thought i removed that
neuronull Feb 2, 2024
3ff66e0
use ref
neuronull Feb 5, 2024
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
21 changes: 21 additions & 0 deletions src/components/validation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ pub use self::runner::*;
pub use self::test_case::{TestCase, TestCaseExpectation};
pub use self::validators::*;

pub mod component_names {
pub const TEST_SOURCE_NAME: &str = "test_source";
pub const TEST_SINK_NAME: &str = "test_sink";
pub const TEST_TRANSFORM_NAME: &str = "test_transform";
pub const TEST_INPUT_SOURCE_NAME: &str = "input_source";
pub const TEST_OUTPUT_SINK_NAME: &str = "output_sink";
}

/// Component types that can be validated.
// TODO: We should centralize this in `vector-common` or something, where both this code and the
// configuration schema stuff (namely the proc macros that use this) can share it.
Expand Down Expand Up @@ -170,6 +178,19 @@ macro_rules! register_validatable_component {
};
}

/// Input and Output runners populate this structure as they send and receive events.
/// The structure is passed into the validator to use as the expected values for the
/// metrics that the components under test actually output.
#[derive(Default, Debug)]
pub struct RunnerMetrics {
pub received_events_total: u64,
pub received_event_bytes_total: u64,
pub received_bytes_total: u64,
pub sent_bytes_total: u64,
pub sent_event_bytes_total: u64,
pub sent_events_total: u64,
}

#[cfg(all(test, feature = "component-validation-tests"))]
mod tests {
use std::{
Expand Down
113 changes: 102 additions & 11 deletions src/components/validation/resources/event.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
use bytes::BytesMut;
use serde::Deserialize;
use snafu::Snafu;
use tokio_util::codec::Encoder as _;

use crate::codecs::Encoder;
use codecs::{
encoding, JsonSerializer, LengthDelimitedEncoder, LogfmtSerializer, MetricTagValues,
NewlineDelimitedEncoder,
};
use vector_core::event::{Event, LogEvent};

/// An event used in a test case.
/// A test case event for deserialization from yaml file.
/// This is an intermediary step to TestEvent.
#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum TestEvent {
pub enum RawTestEvent {
/// The event is used, as-is, without modification.
Passthrough(EventData),

Expand All @@ -20,15 +30,6 @@ pub enum TestEvent {
Modified { modified: bool, event: EventData },
}

impl TestEvent {
pub fn into_event(self) -> Event {
match self {
Self::Passthrough(event) => event.into_event(),
Self::Modified { event, .. } => event.into_event(),
}
}
}

#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum EventData {
Expand All @@ -44,3 +45,93 @@ impl EventData {
}
}
}

/// An event used in a test case.
/// It is important to have created the event with all fields, immediately after deserializing from the
/// test case definition yaml file. This ensures that the event data we are using in the expected/actual
/// metrics collection is based on the same event. Namely, one issue that can arise from creating the event
/// from the event data twice (once for the expected and once for actual), it can result in a timestamp in
/// the event which may or may not have the same millisecond precision as it's counterpart.
#[derive(Clone, Debug, Deserialize)]
#[serde(try_from = "RawTestEvent")]
#[serde(untagged)]
pub enum TestEvent {
/// The event is used, as-is, without modification.
Passthrough(Event),

/// The event is potentially modified by the external resource.
///
/// The modification made is dependent on the external resource, but this mode is made available
/// for when a test case wants to exercise the failure path, but cannot cause a failure simply
/// by constructing the event in a certain way i.e. adding an invalid field, or removing a
/// required field, or using an invalid field value, and so on.
///
/// For transforms and sinks, generally, the only way to cause an error is if the event itself
/// is malformed in some way, which can be achieved without this test event variant.
Modified { modified: bool, event: Event },
}

impl TestEvent {
#[allow(clippy::missing_const_for_fn)] // const cannot run destructor
pub fn into_event(self) -> Event {
match self {
Self::Passthrough(event) => event,
Self::Modified { event, .. } => event,
}
}
}

#[derive(Clone, Debug, Eq, PartialEq, Snafu)]
pub enum RawTestEventParseError {}

impl TryFrom<RawTestEvent> for TestEvent {
type Error = RawTestEventParseError;

fn try_from(other: RawTestEvent) -> Result<Self, Self::Error> {
Ok(match other {
RawTestEvent::Passthrough(event_data) => {
TestEvent::Passthrough(event_data.into_event())
}
RawTestEvent::Modified { modified, event } => TestEvent::Modified {
modified,
event: event.into_event(),
},
})
}
}

pub fn encode_test_event(
encoder: &mut Encoder<encoding::Framer>,
buf: &mut BytesMut,
event: TestEvent,
) {
match event {
TestEvent::Passthrough(event) => {
// Encode the event normally.
encoder
.encode(event, buf)
.expect("should not fail to encode input event");
}
TestEvent::Modified { event, .. } => {
// This is a little fragile, but we check what serializer this encoder uses, and based
// on `Serializer::supports_json`, we choose an opposing codec. For example, if the
// encoder supports JSON, we'll use a serializer that doesn't support JSON, and vise
// versa.
let mut alt_encoder = if encoder.serializer().supports_json() {
Encoder::<encoding::Framer>::new(
LengthDelimitedEncoder::new().into(),
LogfmtSerializer::new().into(),
)
} else {
Encoder::<encoding::Framer>::new(
NewlineDelimitedEncoder::new().into(),
JsonSerializer::new(MetricTagValues::default()).into(),
)
};

alt_encoder
.encode(event, buf)
.expect("should not fail to encode input event");
}
}
}
Loading