vector_vrl_tests/
main.rs

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