use criterion::{Criterion, criterion_group, criterion_main};
use dbnexus::{sql_parser::{SqlOperationType, SqlParser}, DbConfig};
use std::hint::black_box;
use std::time::Duration;
fn bench_db_config_building(c: &mut Criterion) {
c.bench_function("db_config_build_basic", |b| {
b.iter(|| {
let _ = DbConfig {
url: "sqlite::memory:".to_string(),
max_connections: 10,
min_connections: 1,
..Default::default()
};
})
});
c.bench_function("db_config_build_full", |b| {
b.iter(|| {
let _ = DbConfig {
url: "postgresql://user:pass@localhost:5432/db".to_string(),
max_connections: 100,
min_connections: 5,
idle_timeout: 300,
acquire_timeout: 5000,
permissions_path: Some("./permissions.yaml".to_string()),
migrations_dir: Some("./migrations".to_string()),
auto_migrate: true,
..Default::default()
};
})
});
}
fn bench_sql_parsing(c: &mut Criterion) {
let parser = SqlParser::new();
c.bench_function("sql_parse_select_simple", |b| {
b.iter(|| {
let _ = black_box(parser.parse_single("SELECT * FROM users WHERE id = 1"));
})
});
c.bench_function("sql_parse_insert", |b| {
b.iter(|| {
let _ =
black_box(parser.parse_single("INSERT INTO users (name, email) VALUES ('test', 'test@example.com')"));
})
});
c.bench_function("sql_parse_update", |b| {
b.iter(|| {
let _ = black_box(parser.parse_single("UPDATE users SET name = 'new_name' WHERE id = 1"));
})
});
c.bench_function("sql_parse_delete", |b| {
b.iter(|| {
let _ = black_box(parser.parse_single("DELETE FROM users WHERE id = 1"));
})
});
c.bench_function("sql_parse_complex_select", |b| {
b.iter(|| {
let _ = black_box(parser.parse_single(
"SELECT u.id, u.name, o.total
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active'
AND o.created_at > '2024-01-01'
ORDER BY o.total DESC
LIMIT 100",
));
})
});
c.bench_function("sql_validate_operation_select", |b| {
b.iter(|| {
let result = parser.parse_single("SELECT * FROM users");
let _ = black_box(matches!(result, Ok(r) if r.operation_type == SqlOperationType::Select));
})
});
c.bench_function("sql_validate_operation_insert", |b| {
b.iter(|| {
let result = parser.parse_single("INSERT INTO users VALUES (1)");
let _ = black_box(matches!(result, Ok(r) if r.operation_type == SqlOperationType::Insert));
})
});
c.bench_function("sql_validate_operation_update", |b| {
b.iter(|| {
let result = parser.parse_single("UPDATE users SET id = 1");
let _ = black_box(matches!(result, Ok(r) if r.operation_type == SqlOperationType::Update));
})
});
c.bench_function("sql_validate_operation_delete", |b| {
b.iter(|| {
let result = parser.parse_single("DELETE FROM users");
let _ = black_box(matches!(result, Ok(r) if r.operation_type == SqlOperationType::Delete));
})
});
}
fn bench_string_operations(c: &mut Criterion) {
c.bench_function("string_format_simple", |b| {
b.iter(|| {
let _ = format!("{}:{}:{}", "admin", "users", "SELECT");
})
});
c.bench_function("string_format_long", |b| {
b.iter(|| {
let attrs: Vec<_> = (0..10).map(|i| format!("key_{}={}", i, i)).collect();
let _ = attrs.join(":");
})
});
c.bench_function("string_sanitize_basic", |b| {
b.iter(|| {
let input = "User logged in successfully. Query time: 123ms.";
let sanitized: String = input
.chars()
.filter(|c| c.is_alphanumeric() || c.is_ascii_punctuation() || c.is_whitespace())
.take(256)
.collect();
sanitized
})
});
c.bench_function("string_mask_url", |b| {
b.iter(|| {
let url = "postgresql://user:password123@localhost:5432/db";
let masked: String = url
.chars()
.map(|c| if c == '@' || c == ':' { c } else { '*' })
.collect();
masked
})
});
}
fn bench_config_parsing(c: &mut Criterion) {
c.bench_function("config_parse_yaml", |b| {
b.iter(|| {
let yaml = r#"
roles:
admin:
- subject: admin
resource: "*"
actions: ["SELECT", "INSERT", "UPDATE", "DELETE"]
user:
- subject: user
resource: users
actions: ["SELECT"]
"#;
let _ = serde_yaml::from_str::<serde_yaml::Value>(yaml);
})
});
c.bench_function("config_url_parse_simple", |b| {
b.iter(|| {
let url = "sqlite::memory:";
let _ = url::Url::parse(url);
})
});
c.bench_function("config_url_parse_postgres", |b| {
b.iter(|| {
let url = "postgresql://user:pass@localhost:5432/db";
let _ = url::Url::parse(url);
})
});
}
fn bench_collection_operations(c: &mut Criterion) {
use std::collections::HashSet;
c.bench_function("hashset_insert_100", |b| {
b.iter(|| {
let mut set = HashSet::new();
for i in 0..100 {
set.insert(i);
}
set
})
});
c.bench_function("hashset_contains_100", |b| {
b.iter(|| {
let set: HashSet<_> = (0..100).collect();
let mut found = 0;
for i in 0..100 {
if set.contains(&i) {
found += 1;
}
}
found
})
});
c.bench_function("vec_preallocated_100", |b| {
b.iter(|| {
let mut vec = Vec::with_capacity(100);
for i in 0..100 {
vec.push(i);
}
vec
})
});
c.bench_function("vec_default_100", |b| {
b.iter(|| {
let mut vec = Vec::new();
for i in 0..100 {
vec.push(i);
}
vec
})
});
}
fn bench_regex_operations(c: &mut Criterion) {
use regex::Regex;
static SQL_INJECTION_REGEX: std::sync::LazyLock<Regex> =
std::sync::LazyLock::new(|| Regex::new(r#"(['";]|(--)|(/*)|\bOR\b|\bAND\b|\bUNION\b|\bSELECT\b)"#).unwrap());
static PATH_TRAVERSAL_REGEX: std::sync::LazyLock<Regex> =
std::sync::LazyLock::new(|| Regex::new(r"\.\.|%2e%2e|/").unwrap());
c.bench_function("regex_sql_injection_match", |b| {
b.iter(|| {
let input = "'; DROP TABLE users; --";
let _ = SQL_INJECTION_REGEX.is_match(input);
})
});
c.bench_function("regex_sql_injection_no_match", |b| {
b.iter(|| {
let input = "SELECT * FROM users WHERE id = 1";
let _ = SQL_INJECTION_REGEX.is_match(input);
})
});
c.bench_function("regex_path_traversal_match", |b| {
b.iter(|| {
let input = "../../../etc/passwd";
let _ = PATH_TRAVERSAL_REGEX.is_match(input);
})
});
c.bench_function("regex_path_traversal_no_match", |b| {
b.iter(|| {
let input = "/var/lib/data/file.txt";
let _ = PATH_TRAVERSAL_REGEX.is_match(input);
})
});
}
fn bench_serialization(c: &mut Criterion) {
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
struct TestEvent {
user_id: String,
operation: String,
entity_type: String,
entity_id: String,
timestamp: String,
severity: String,
}
let test_event = TestEvent {
user_id: "admin".to_string(),
operation: "SELECT".to_string(),
entity_type: "users".to_string(),
entity_id: "123".to_string(),
timestamp: "2024-01-01T12:00:00Z".to_string(),
severity: "INFO".to_string(),
};
c.bench_function("json_serialize_event", |b| {
b.iter(|| {
let _ = serde_json::to_string(&test_event);
})
});
c.bench_function("json_deserialize_event", |b| {
b.iter(|| {
let json = r#"{"user_id":"admin","operation":"SELECT","entity_type":"users","entity_id":"123","timestamp":"2024-01-01T12:00:00Z","severity":"INFO"}"#;
let _: TestEvent = serde_json::from_str(json).unwrap();
})
});
}
fn bench_error_handling(c: &mut Criterion) {
use thiserror::Error;
#[derive(Error, Debug)]
pub enum TestError {
#[error("Configuration error: {0}")]
Config(String),
#[error("Connection error: {0}")]
Connection(String),
#[error("Permission denied: {0}")]
Permission(String),
}
c.bench_function("error_creation_config", |b| {
b.iter(|| TestError::Config("Invalid configuration value".to_string()))
});
c.bench_function("error_creation_connection", |b| {
b.iter(|| TestError::Connection("Connection refused".to_string()))
});
c.bench_function("error_display_config", |b| {
b.iter(|| {
let err = TestError::Config("Invalid configuration value".to_string());
let _ = format!("{}", err);
})
});
c.bench_function("error_chain_display", |b| {
b.iter(|| {
let err = TestError::Connection("Database connection failed".to_string());
let _ = format!("Error: {}", err);
})
});
}
fn bench_temp_file_operations(c: &mut Criterion) {
use std::io::Write;
c.bench_function("temp_file_create", |b| {
b.iter(|| {
let mut file = tempfile::NamedTempFile::new().unwrap();
file.write_all(b"test data").unwrap();
file
})
});
c.bench_function("temp_dir_create", |b| {
b.iter(|| {
let _ = tempfile::TempDir::new().unwrap();
})
});
}
criterion_group!(
name = benches;
config = Criterion::default()
.sample_size(100)
.measurement_time(Duration::from_secs(5))
.warm_up_time(Duration::from_secs(1))
.noise_threshold(0.02)
.significance_level(0.01);
targets =
bench_db_config_building,
bench_sql_parsing,
bench_string_operations,
bench_config_parsing,
bench_collection_operations,
bench_regex_operations,
bench_serialization,
bench_error_handling,
bench_temp_file_operations,
);
criterion_main!(benches);