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