Before saving a connection, you want to know whether it works. QoreDB's "Test Connection" button answers that question without leaving anything behind: no open session, no allocated pool, no credential written to disk. It is a deliberately separate operation from actually establishing a connection, and that separation shows up right in the Rust interface every driver implements.
Two methods, two intentions
The DataEngine trait, which defines the surface common to every engine, exposes two neighboring methods with opposite effects. test_connection returns EngineResult<()>: either it succeeds or it fails, producing nothing. connect, by contrast, returns a SessionId, the identifier that will drive every subsequent operation on that connection. The doc comment is unambiguous: testing happens "without establishing a persistent session," to validate credentials before saving them.
async fn test_connection(&self, config: &ConnectionConfig) -> EngineResult<()>;
async fn connect(&self, config: &ConnectionConfig) -> EngineResult<SessionId>;Everything follows from those two return types. One yields nothing but a verdict; the other yields a resource that must be tracked, kept alive, then closed. The rest of the path flows from that difference.
Validate before touching the network
Before a single packet leaves, the service layer normalizes the configuration. It first unifies driver aliases — postgresql becomes postgres, sqlite3 becomes sqlite —, trims every field, then applies rules specific to each engine. A classic SQL client requires a username, but MongoDB, Redis, file-based databases like SQLite and DuckDB, or SQL Server integrated authentication go without one: forcing that field on them would make no sense. The port must be strictly positive, except for file-based databases that have none.
The same pass sets the pool defaults — ten connections maximum, two minimum, fifteen seconds to acquire one — and rejects inconsistent combinations, such as a minimum greater than the maximum. The payoff is very concrete: a good share of connection failures come from a badly filled-out form, not a real network problem. Better to catch them immediately, with a clear message, than after several seconds spent waiting on a server that could never have answered anyway.
The SessionManager orchestrates tunnels and timeout
Once the configuration is validated, the SessionManager takes over and first applies a security rule: in a production environment, an SSH tunnel configured to skip host-key verification is flatly refused. You do not test a production connection with server-spoofing protection turned off.
It then fetches the right driver, sets up any tunnels — proxy first, then SSH — rewriting the target host to 127.0.0.1 on a local port, and wraps the whole thing in a ten-second timeout. Past that threshold the operation is abandoned with an explicit timeout error, rather than leaving the interface frozen on an unreachable server. A test must never be able to hang indefinitely.
Each driver tests in its own way
The trait lets each driver decide what "testing" means for its engine, but the pattern stays constant: establish, probe, discard. The PostgreSQL driver opens a connection from the computed string; Redis and MongoDB open a connection and send a ping. In every case, the result is dropped right away.
// Redis: open, PING, discard.
async fn test_connection(&self, config: &ConnectionConfig) -> EngineResult<()> {
let _ = Self::create_connection_and_ping(config).await?;
Ok(())
}The let _ = prefixing the call says it all: the connection exists only long enough to prove it is possible, then it is destroyed. The comparison with connect is telling — it is often the same internal method that opens the connection, but this time its result is filed into the session table with a freshly generated SessionId. Same probe, different fate: the test validates and forgets, the connection validates and keeps.
The error that surfaces is scrubbed
A failed test produces an error message, and that message may contain things you never want to display: a connection string with a password, an absolute file path that reveals the machine's directory tree. So the command never returns the raw error. It runs it through a sanitizing function that masks credentials in URLs like postgres://user:pass@host, replaces password= parameters, and erases absolute paths, before the text crosses the process boundary on its way to the interface.
The result finally surfaces in a deliberately thin form: a status, an optional message, and a session-identifier field left empty — since there is nothing to keep. The variant that tests an already-saved connection adds one last guardrail: if the encrypted vault is locked, it refuses to test rather than reach for credentials it has no access to anyway.
A test that costs nothing
Testing a connection in QoreDB means validating locally, opening just enough, proving the server responds, then closing everything back down. No session, no pool, no tunnel survives the operation; failure is fast and bounded to ten seconds; and the message that comes back has been purged of any secret. It is the same principle that guides the rest of the product: commit the minimum of resources only once the user has actually decided to connect.
Stay updated on new releases
Subscribe to get product releases, new drivers notifications, and technical tutorials.

