vector_vrl_tests/
main.rs

1#![allow(clippy::print_stdout)] // tests
2#![allow(clippy::print_stderr)] // tests
3
4mod docs;
5mod test_enrichment;
6mod test_vrl_metrics;
7
8use std::{collections::HashSet, env, path::PathBuf};
9
10use chrono_tz::Tz;
11use clap::Parser;
12use glob::glob;
13use vrl::{
14    compiler::{CompileConfig, TimeZone, VrlRuntime},
15    test::{Test, TestConfig, get_tests_from_functions, run_tests},
16};
17
18#[cfg(not(target_env = "msvc"))]
19#[global_allocator]
20static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
21
22#[derive(Parser, Debug)]
23#[clap(name = "VRL Tests", about = "Vector Remap Language Tests")]
24pub struct Cmd {
25    #[clap(short, long)]
26    pattern: Option<String>,
27
28    #[clap(short, long)]
29    fail_early: bool,
30
31    #[clap(short, long)]
32    verbose: bool,
33
34    #[clap(short, long)]
35    no_diff: bool,
36
37    /// When enabled, any log output at the INFO or above level is printed
38    /// during the test run.
39    #[clap(short, long)]
40    logging: bool,
41
42    /// When enabled, show run duration for each individual test.
43    #[clap(short, long)]
44    timings: bool,
45
46    #[clap(short = 'z', long)]
47    timezone: Option<String>,
48
49    /// Should we use the VM to evaluate the VRL
50    #[clap(short, long = "runtime", default_value_t)]
51    runtime: VrlRuntime,
52
53    /// Ignore the Cue tests (to speed up run)
54    #[clap(long)]
55    ignore_cue: bool,
56}
57
58impl Cmd {
59    fn timezone(&self) -> TimeZone {
60        if let Some(ref tz) = self.timezone {
61            TimeZone::parse(tz).unwrap_or_else(|| panic!("couldn't parse timezone: {tz}"))
62        } else {
63            TimeZone::Named(Tz::UTC)
64        }
65    }
66}
67
68fn should_run(name: &str, pat: &Option<String>, _runtime: VrlRuntime) -> bool {
69    if name == "tests/example.vrl" {
70        return false;
71    }
72
73    if let Some(pat) = pat
74        && !name.contains(pat)
75    {
76        return false;
77    }
78
79    true
80}
81
82fn main() {
83    let cmd = Cmd::parse();
84
85    if cmd.logging {
86        tracing_subscriber::fmt::init();
87    }
88
89    let tests = get_tests(&cmd);
90
91    let cfg = TestConfig {
92        fail_early: cmd.fail_early,
93        verbose: cmd.verbose,
94        no_diff: cmd.no_diff,
95        timings: cmd.timings,
96        runtime: cmd.runtime,
97        timezone: cmd.timezone(),
98    };
99
100    run_tests(
101        tests,
102        &cfg,
103        &vector_vrl_functions::all(),
104        || {
105            let mut config = CompileConfig::default();
106            let enrichment_table = test_enrichment::test_enrichment_table();
107            config.set_custom(enrichment_table.clone());
108            config.set_custom(test_vrl_metrics::test_vrl_metrics_storage());
109            (config, enrichment_table)
110        },
111        |registry| registry.finish_load(),
112    );
113}
114
115pub fn test_dir() -> PathBuf {
116    PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap())
117}
118
119fn test_glob_pattern() -> String {
120    test_dir().join("**/*.vrl").to_str().unwrap().to_string()
121}
122
123#[allow(clippy::disallowed_methods)]
124fn get_tests(cmd: &Cmd) -> Vec<Test> {
125    // Don't test vrl stdlib functions examples since they are already tested in VRL and some will
126    // fail to compile since they are missing required source files such as proto definitions.
127    let ignore_examples_from_functions: HashSet<String> = vrl::stdlib::all()
128        .into_iter()
129        .map(|f| format!("functions/{}", f.identifier()))
130        .collect();
131
132    let tests_from_functions = get_tests_from_functions(vector_vrl_functions::all());
133    let tests_from_functions = tests_from_functions
134        .into_iter()
135        .filter(|test| !ignore_examples_from_functions.contains(&test.category));
136
137    glob(test_glob_pattern().as_str())
138        .expect("valid pattern")
139        .filter_map(|entry| {
140            let path = entry.ok()?;
141            Some(Test::from_path(&path))
142        })
143        .chain(docs::tests(cmd.ignore_cue))
144        .chain(tests_from_functions)
145        .filter(|test| {
146            should_run(
147                &format!("{}/{}", test.category, test.name),
148                &cmd.pattern,
149                cmd.runtime,
150            )
151        })
152        .collect::<Vec<_>>()
153}