feat: accept mariadb as a db_type across validation, test-connection, and db_connect (Task 1)
This commit is contained in:
@@ -2,7 +2,7 @@ use crate::models::{Connection, ConnectionInput};
|
|||||||
use crate::store::Store;
|
use crate::store::Store;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
const VALID_DB_TYPES: [&str; 4] = ["postgresql", "mysql", "sqlite", "redis"];
|
const VALID_DB_TYPES: [&str; 5] = ["postgresql", "mysql", "mariadb", "sqlite", "redis"];
|
||||||
|
|
||||||
fn validate(input: &ConnectionInput) -> Result<(), String> {
|
fn validate(input: &ConnectionInput) -> Result<(), String> {
|
||||||
if input.name.is_empty() || input.name.chars().count() > 100 {
|
if input.name.is_empty() || input.name.chars().count() > 100 {
|
||||||
@@ -360,3 +360,7 @@ mod tests {
|
|||||||
assert_eq!(get_recent_connections_inner(&st, 10).unwrap().len(), 0);
|
assert_eq!(get_recent_connections_inner(&st, 10).unwrap().len(), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "connections.test.rs"]
|
||||||
|
mod connections_tests;
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn mariadb_input() -> ConnectionInput {
|
||||||
|
ConnectionInput {
|
||||||
|
name: "Maria local".into(),
|
||||||
|
db_type: "mariadb".into(),
|
||||||
|
host: "127.0.0.1".into(),
|
||||||
|
port: Some(3306),
|
||||||
|
username: Some("root".into()),
|
||||||
|
folder_id: None,
|
||||||
|
tag_ids: vec![],
|
||||||
|
password: None,
|
||||||
|
database: Some("test".into()),
|
||||||
|
environment: None,
|
||||||
|
ssh_host: None,
|
||||||
|
ssh_port: None,
|
||||||
|
ssh_user: None,
|
||||||
|
ssh_auth_method: None,
|
||||||
|
ssh_private_key_path: None,
|
||||||
|
ssh_password: None,
|
||||||
|
ssh_passphrase: None,
|
||||||
|
ssl_mode: None,
|
||||||
|
ssl_ca_path: None,
|
||||||
|
ssl_cert_path: None,
|
||||||
|
ssl_key_path: None,
|
||||||
|
use_keychain: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_accepts_mariadb_with_port() {
|
||||||
|
assert!(validate(&mariadb_input()).is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_rejects_mariadb_without_port() {
|
||||||
|
let mut input = mariadb_input();
|
||||||
|
input.port = None;
|
||||||
|
assert!(validate(&input).is_err(), "mariadb requires a port like mysql");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_rejects_unknown_db_type() {
|
||||||
|
let mut input = mariadb_input();
|
||||||
|
input.db_type = "oracle".into();
|
||||||
|
assert!(validate(&input).is_err());
|
||||||
|
}
|
||||||
@@ -1198,7 +1198,7 @@ pub async fn db_connect(
|
|||||||
}
|
}
|
||||||
Err(e) => Err(format!("Connection failed: {}", e)),
|
Err(e) => Err(format!("Connection failed: {}", e)),
|
||||||
}
|
}
|
||||||
} else if config.db_type == "mysql" {
|
} else if config.db_type == "mysql" || config.db_type == "mariadb" {
|
||||||
run_mysql_connect(
|
run_mysql_connect(
|
||||||
&connection_id,
|
&connection_id,
|
||||||
&config,
|
&config,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::store::Store;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
const VALID_DB_TYPES: [&str; 4] = ["postgresql", "mysql", "sqlite", "redis"];
|
const VALID_DB_TYPES: [&str; 5] = ["postgresql", "mysql", "mariadb", "sqlite", "redis"];
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub(crate) struct ImportRecord {
|
pub(crate) struct ImportRecord {
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ fn url_scheme_end(msg: &str, i: usize) -> Option<usize> {
|
|||||||
pub fn validate_test_input(config: &DbConfig) -> Option<String> {
|
pub fn validate_test_input(config: &DbConfig) -> Option<String> {
|
||||||
let db_type = config.db_type.to_lowercase();
|
let db_type = config.db_type.to_lowercase();
|
||||||
|
|
||||||
let valid_types = ["postgresql", "mysql", "sqlite", "redis"];
|
let valid_types = ["postgresql", "mysql", "mariadb", "sqlite", "redis"];
|
||||||
if !valid_types.contains(&db_type.as_str()) {
|
if !valid_types.contains(&db_type.as_str()) {
|
||||||
return Some(format!(
|
return Some(format!(
|
||||||
"unsupported database type: {}. Supported types: {}",
|
"unsupported database type: {}. Supported types: {}",
|
||||||
@@ -220,6 +220,7 @@ pub async fn test_database_connection(config: &DbConfig, ssh: &SshManager) -> Te
|
|||||||
let result = match config.db_type.to_lowercase().as_str() {
|
let result = match config.db_type.to_lowercase().as_str() {
|
||||||
"postgresql" => test_pg_connection(config, ssh).await,
|
"postgresql" => test_pg_connection(config, ssh).await,
|
||||||
"mysql" => test_mysql_connection(config, ssh).await,
|
"mysql" => test_mysql_connection(config, ssh).await,
|
||||||
|
"mariadb" => test_mysql_connection(config, ssh).await,
|
||||||
"sqlite" => test_sqlite_connection(config),
|
"sqlite" => test_sqlite_connection(config),
|
||||||
"redis" => test_redis_connection(config, ssh).await,
|
"redis" => test_redis_connection(config, ssh).await,
|
||||||
other => TestConnectionResult {
|
other => TestConnectionResult {
|
||||||
@@ -724,3 +725,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "test_connection.test.rs"]
|
||||||
|
mod test_connection_tests;
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::commands::ssh::{Ssh2Backend, SshTunnelManager};
|
||||||
|
use crate::db::pool::DbConfig;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
fn mariadb_config(port: Option<i64>) -> DbConfig {
|
||||||
|
DbConfig {
|
||||||
|
db_type: "mariadb".into(),
|
||||||
|
host: "127.0.0.1".into(),
|
||||||
|
port,
|
||||||
|
username: Some("root".into()),
|
||||||
|
password: None,
|
||||||
|
database: Some("test".into()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_test_input_accepts_mariadb_with_port() {
|
||||||
|
assert_eq!(validate_test_input(&mariadb_config(Some(3306))), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validate_test_input_rejects_mariadb_without_port() {
|
||||||
|
assert!(validate_test_input(&mariadb_config(None)).is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Live test against a real MariaDB server. Run with:
|
||||||
|
/// `GRIDLINE_TEST_MARIADB_HOST=… GRIDLINE_TEST_MARIADB_PORT=3306 \
|
||||||
|
/// GRIDLINE_TEST_MARIADB_USER=… GRIDLINE_TEST_MARIADB_PASSWORD=… \
|
||||||
|
/// GRIDLINE_TEST_MARIADB_DB=… cargo test -- --ignored mariadb_live`
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn mariadb_live_test_connection_reports_mariadb_version() {
|
||||||
|
let config = DbConfig {
|
||||||
|
host: std::env::var("GRIDLINE_TEST_MARIADB_HOST").expect("GRIDLINE_TEST_MARIADB_HOST"),
|
||||||
|
port: std::env::var("GRIDLINE_TEST_MARIADB_PORT")
|
||||||
|
.ok()
|
||||||
|
.and_then(|p| p.parse::<i64>().ok()),
|
||||||
|
username: std::env::var("GRIDLINE_TEST_MARIADB_USER").ok(),
|
||||||
|
password: std::env::var("GRIDLINE_TEST_MARIADB_PASSWORD").ok(),
|
||||||
|
database: std::env::var("GRIDLINE_TEST_MARIADB_DB").ok(),
|
||||||
|
..mariadb_config(None)
|
||||||
|
};
|
||||||
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
|
let ssh = std::sync::Mutex::new(SshTunnelManager::new(Arc::new(Ssh2Backend)));
|
||||||
|
let result = rt.block_on(async { test_mysql_connection(&config, &ssh).await });
|
||||||
|
assert!(result.ok, "connection failed: {:?}", result.error);
|
||||||
|
let version = result.server_version.unwrap_or_default().to_lowercase();
|
||||||
|
assert!(
|
||||||
|
version.contains("mariadb"),
|
||||||
|
"expected a MariaDB server, got version: {version:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user