Skip to content

Commit

Permalink
Merge branch 'master' into riccardo/feat/cross-stacks-spooling
Browse files Browse the repository at this point in the history
  • Loading branch information
iambriccardo committed Oct 8, 2024
2 parents 4cf1a95 + d1e950f commit 29eb0cf
Show file tree
Hide file tree
Showing 23 changed files with 911 additions and 318 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ strip = true

[workspace.lints.clippy]
dbg_macro = "warn"
print_stdout = "warn"
print_stderr = "warn"

[workspace.dependencies]
relay-auth = { path = "relay-auth" }
Expand Down
1 change: 1 addition & 0 deletions relay-auth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,7 @@ mod tests {
/// exchanged authentication structures.
/// It follows test_registration but instead of asserting it prints the strings
#[test]
#[allow(clippy::print_stdout, reason = "helper test to generate output")]
fn test_generate_strings_for_test_auth_py() {
let max_age = Duration::minutes(15);
println!("Generating test data for test_auth.py...");
Expand Down
7 changes: 0 additions & 7 deletions relay-filter/src/error_messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,6 @@ mod tests {

for config in &configs[..] {
for &case in &cases[..] {
// Useful output to debug which testcase fails. Hidden if the test passes.
println!(
"------------------------------------------------------------------------"
);
println!("Config: {config:?}");
println!("Case: {case:?}");

let (exc_type, exc_value, logentry_formatted, should_ingest) = case;
let event = Event {
exceptions: Annotated::new(Values::new(vec![Annotated::new(Exception {
Expand Down
4 changes: 4 additions & 0 deletions relay-filter/src/transaction_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ mod tests {
"*/health",
"*/healthz",
"*/ping",
"*/up",
]
.map(|val| val.to_string())
.to_vec();
Expand Down Expand Up @@ -88,6 +89,8 @@ mod tests {
"123/health",
"123/healthz",
"123/ping",
"/up",
"123/up",
];

for name in transaction_names {
Expand Down Expand Up @@ -119,6 +122,7 @@ mod tests {
"delivery",
"notready",
"already",
"/upload",
];
let config = _get_config();

Expand Down
1 change: 1 addition & 0 deletions relay-log/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub fn backtrace_enabled() -> bool {
/// Prefer to use [`relay_log::error`](crate::error) over this function whenever possible. This
/// function is intended to be used during startup, where initializing the logger may fail or when
/// errors need to be logged before the logger has been initialized.
#[allow(clippy::print_stderr, reason = "necessary for early logging")]
pub fn ensure_error<E: AsRef<dyn Error>>(error: E) {
if tracing::event_enabled!(Level::ERROR) {
crate::error!(error = error.as_ref());
Expand Down
202 changes: 193 additions & 9 deletions relay-pattern/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,7 @@ impl Pattern {

/// Returns `true` if the pattern matches the passed string.
pub fn is_match(&self, haystack: &str) -> bool {
match &self.strategy {
MatchStrategy::Literal(literal) => match_literal(literal, haystack, self.options),
MatchStrategy::Prefix(prefix) => match_prefix(prefix, haystack, self.options),
MatchStrategy::Suffix(suffix) => match_suffix(suffix, haystack, self.options),
MatchStrategy::Contains(contains) => match_contains(contains, haystack, self.options),
MatchStrategy::Static(matches) => *matches,
MatchStrategy::Wildmatch(tokens) => wildmatch::is_match(haystack, tokens, self.options),
}
self.strategy.is_match(haystack, self.options)
}
}

Expand All @@ -137,6 +130,45 @@ impl fmt::Display for Pattern {
}
}

/// A collection of [`Pattern`]s sharing the same configuration.
#[derive(Debug, Clone)]
pub struct Patterns {
strategies: Vec<MatchStrategy>,
options: Options,
}

impl Patterns {
/// Creates an empty [`Patterns`] instance which never matches anything.
///
/// ```
/// # use relay_pattern::Patterns;
/// let patterns = Patterns::empty();
///
/// assert!(!patterns.is_match(""));
/// assert!(!patterns.is_match("foobar"));
/// ```
pub fn empty() -> Self {
Self {
strategies: Vec::new(),
options: Options::default(),
}
}

/// Returns a [`PatternsBuilder`].
pub fn builder() -> PatternsBuilder {
PatternsBuilder {
options: Options::default(),
}
}

/// Returns `true` if any of the contained patterns matches the passed string.
pub fn is_match(&self, haystack: &str) -> bool {
self.strategies
.iter()
.any(|s| s.is_match(haystack, self.options))
}
}

/// A builder for a [`Pattern`].
#[derive(Debug)]
pub struct PatternBuilder<'a> {
Expand Down Expand Up @@ -165,7 +197,7 @@ impl<'a> PatternBuilder<'a> {
self
}

/// build a new [`Pattern`] from the passed pattern and configured options.
/// Build a new [`Pattern`] from the passed pattern and configured options.
pub fn build(&self) -> Result<Pattern, Error> {
let mut parser = Parser::new(self.pattern, self.options);
parser.parse().map_err(|kind| Error {
Expand Down Expand Up @@ -197,6 +229,88 @@ impl<'a> PatternBuilder<'a> {
}
}

/// A builder for a collection of [`Patterns`].
#[derive(Debug)]
pub struct PatternsBuilder {
options: Options,
}

impl PatternsBuilder {
/// If enabled matches the pattern case insensitive.
///
/// This is disabled by default.
pub fn case_insensitive(&mut self, enabled: bool) -> &mut Self {
self.options.case_insensitive = enabled;
self
}

/// Returns a [`PatternsBuilderConfigured`] builder which allows adding patterns.
pub fn patterns(&mut self) -> PatternsBuilderConfigured {
PatternsBuilderConfigured {
strategies: Vec::new(),
options: self.options,
}
}

/// Adds a pattern to the builder and returns the resulting [`PatternsBuilderConfigured`].
pub fn add(&mut self, pattern: &str) -> Result<PatternsBuilderConfigured, Error> {
let mut builder = PatternsBuilderConfigured {
strategies: Vec::with_capacity(1),
options: self.options,
};
builder.add(pattern)?;
Ok(builder)
}
}

/// A [`PatternsBuilder`] with all options configured.
///
/// The second step after [`PatternsBuilder`].
#[derive(Debug)]
pub struct PatternsBuilderConfigured {
strategies: Vec<MatchStrategy>,
options: Options,
}

impl PatternsBuilderConfigured {
/// Adds a pattern to the builder.
pub fn add(&mut self, pattern: &str) -> Result<&mut Self, Error> {
let mut parser = Parser::new(pattern, self.options);
parser.parse().map_err(|kind| Error {
pattern: pattern.to_owned(),
kind,
})?;

let strategy =
MatchStrategy::from_tokens(parser.tokens, self.options).map_err(|kind| Error {
pattern: pattern.to_owned(),
kind,
})?;

self.strategies.push(strategy);

Ok(self)
}

/// Builds a [`Patterns`] from the contained patterns.
pub fn build(self) -> Patterns {
Patterns {
strategies: self.strategies,
options: self.options,
}
}

/// Returns [`Patterns`] containing all added patterns and removes them from the builder.
///
/// The builder can still be used afterwards, it keeps the configuration.
pub fn take(&mut self) -> Patterns {
Patterns {
strategies: std::mem::take(&mut self.strategies),
options: self.options,
}
}
}

/// Options to influence [`Pattern`] matching behaviour.
#[derive(Debug, Clone, Copy, Default)]
struct Options {
Expand Down Expand Up @@ -263,6 +377,18 @@ impl MatchStrategy {

Ok(s)
}

/// Returns `true` if the pattern matches the passed string.
pub fn is_match(&self, haystack: &str, options: Options) -> bool {
match &self {
MatchStrategy::Literal(literal) => match_literal(literal, haystack, options),
MatchStrategy::Prefix(prefix) => match_prefix(prefix, haystack, options),
MatchStrategy::Suffix(suffix) => match_suffix(suffix, haystack, options),
MatchStrategy::Contains(contains) => match_contains(contains, haystack, options),
MatchStrategy::Static(matches) => *matches,
MatchStrategy::Wildmatch(tokens) => wildmatch::is_match(haystack, tokens, options),
}
}
}

#[inline(always)]
Expand Down Expand Up @@ -1661,4 +1787,62 @@ mod tests {
.build()
.is_ok());
}

#[test]
fn test_patterns() {
let patterns = Patterns::builder()
.add("foobaR")
.unwrap()
.add("a*")
.unwrap()
.add("*a")
.unwrap()
.add("[0-9]*baz")
.unwrap()
.take();

assert!(patterns.is_match("foobaR"));
assert!(patterns.is_match("abc"));
assert!(patterns.is_match("cba"));
assert!(patterns.is_match("3baz"));
assert!(patterns.is_match("123456789baz"));
assert!(!patterns.is_match("foobar"));
assert!(!patterns.is_match("FOOBAR"));
}

#[test]
fn test_patterns_case_insensitive() {
let patterns = Patterns::builder()
.case_insensitive(true)
.add("fOObar")
.unwrap()
.add("a*")
.unwrap()
.add("*a")
.unwrap()
.add("[0-9]*baz")
.unwrap()
.take();

assert!(patterns.is_match("FooBar"));
assert!(patterns.is_match("abC"));
assert!(patterns.is_match("cbA"));
assert!(patterns.is_match("3BAZ"));
assert!(patterns.is_match("123456789baz"));
assert!(!patterns.is_match("b"));
}

#[test]
fn test_patterns_take_clears_builder() {
let mut builder = Patterns::builder().add("foo").unwrap();

let patterns = builder.take();
assert!(patterns.is_match("foo"));
assert!(!patterns.is_match("bar"));

builder.add("bar").unwrap();
let patterns = builder.build();
assert!(!patterns.is_match("foo"));
assert!(patterns.is_match("bar"));
}
}
Loading

0 comments on commit 29eb0cf

Please sign in to comment.