Skip to content

Commit 376bc79

Browse files
pmorris-devclaude
andcommitted
fix: reject zero values for max_databases and transaction_timeout
Setting max_databases to 0 prevents any database from loading since the length check always fails. Similarly, a zero transaction_timeout causes every interruptible transaction to expire immediately. Both are obvious misconfigurations that silently break the plugin. Return Error::InvalidConfig from the builder setters so callers get a clear error at configuration time rather than puzzling runtime behavior. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 91a87bc commit 376bc79

1 file changed

Lines changed: 55 additions & 5 deletions

File tree

src/lib.rs

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ pub struct MigrationEvent {
156156
/// .expect("error while running tauri application");
157157
/// # }
158158
/// ```
159-
#[derive(Default)]
159+
#[derive(Debug, Default)]
160160
pub struct Builder {
161161
/// Migrations registered per database path
162162
migrations: HashMap<String, Arc<Migrator>>,
@@ -206,18 +206,32 @@ impl Builder {
206206
///
207207
/// If an interruptible transaction exceeds this duration, it will be automatically
208208
/// rolled back on the next access attempt. Defaults to 5 minutes.
209-
pub fn transaction_timeout(mut self, timeout: std::time::Duration) -> Self {
209+
///
210+
/// Returns `Err(Error::InvalidConfig)` if `timeout` is zero.
211+
pub fn transaction_timeout(mut self, timeout: std::time::Duration) -> Result<Self> {
212+
if timeout.is_zero() {
213+
return Err(Error::InvalidConfig(
214+
"transaction_timeout must be greater than zero".to_string(),
215+
));
216+
}
210217
self.transaction_timeout = Some(timeout);
211-
self
218+
Ok(self)
212219
}
213220

214221
/// Set the maximum number of databases that can be loaded simultaneously.
215222
///
216223
/// Prevents unbounded memory growth from connection pool proliferation.
217224
/// Defaults to 50.
218-
pub fn max_databases(mut self, max: usize) -> Self {
225+
///
226+
/// Returns `Err(Error::InvalidConfig)` if `max` is zero.
227+
pub fn max_databases(mut self, max: usize) -> Result<Self> {
228+
if max == 0 {
229+
return Err(Error::InvalidConfig(
230+
"max_databases must be greater than zero".to_string(),
231+
));
232+
}
219233
self.max_databases = Some(max);
220-
self
234+
Ok(self)
221235
}
222236

223237
/// Build the plugin with command registration and state management.
@@ -541,3 +555,39 @@ fn resolve_migration_path<R: Runtime>(
541555
) -> Result<std::path::PathBuf> {
542556
crate::resolve::resolve_database_path(path, app)
543557
}
558+
559+
#[cfg(test)]
560+
mod tests {
561+
use super::*;
562+
563+
#[test]
564+
fn test_max_databases_rejects_zero() {
565+
let err = Builder::new().max_databases(0).unwrap_err();
566+
assert!(matches!(err, Error::InvalidConfig(_)));
567+
}
568+
569+
#[test]
570+
fn test_max_databases_accepts_positive() {
571+
let builder = Builder::new().max_databases(1).unwrap();
572+
assert_eq!(builder.max_databases, Some(1));
573+
}
574+
575+
#[test]
576+
fn test_transaction_timeout_rejects_zero() {
577+
let err = Builder::new()
578+
.transaction_timeout(std::time::Duration::ZERO)
579+
.unwrap_err();
580+
assert!(matches!(err, Error::InvalidConfig(_)));
581+
}
582+
583+
#[test]
584+
fn test_transaction_timeout_accepts_positive() {
585+
let builder = Builder::new()
586+
.transaction_timeout(std::time::Duration::from_secs(1))
587+
.unwrap();
588+
assert_eq!(
589+
builder.transaction_timeout,
590+
Some(std::time::Duration::from_secs(1))
591+
);
592+
}
593+
}

0 commit comments

Comments
 (0)