98 lines
3.4 KiB
Rust
98 lines
3.4 KiB
Rust
use aster_storage::{Storage, StorageConfig};
|
|
|
|
#[test]
|
|
fn configuration_defaults_precedence_and_errors() {
|
|
assert!(
|
|
matches!(StorageConfig::from_values(None, None).unwrap(), StorageConfig::SqliteFile(p) if p.to_str() == Some("data/aster.db"))
|
|
);
|
|
assert!(matches!(
|
|
StorageConfig::from_values(None, Some(":memory:")).unwrap(),
|
|
StorageConfig::SqliteMemory
|
|
));
|
|
assert!(matches!(
|
|
StorageConfig::from_values(Some("postgresql://localhost/aster"), Some("")).unwrap(),
|
|
StorageConfig::Postgres(_)
|
|
));
|
|
assert!(StorageConfig::from_values(Some(""), None).is_err());
|
|
assert!(StorageConfig::from_values(Some("mysql://localhost/aster"), None).is_err());
|
|
assert!(StorageConfig::from_values(None, Some("")).is_err());
|
|
let config = StorageConfig::Postgres("postgres://user:secret@localhost/db".into());
|
|
assert!(!format!("{config:?}").contains("secret"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn memory_store_is_shared_by_clones_but_isolated_between_stores() {
|
|
let store = Storage::connect(&StorageConfig::SqliteMemory)
|
|
.await
|
|
.unwrap();
|
|
let other = Storage::connect(&StorageConfig::SqliteMemory)
|
|
.await
|
|
.unwrap();
|
|
store.ping().await.unwrap();
|
|
assert_eq!(store.get("missing").await.unwrap(), None);
|
|
store.put("message", "你好 ' ? $1 ;").await.unwrap();
|
|
assert_eq!(
|
|
store.clone().get("message").await.unwrap().as_deref(),
|
|
Some("你好 ' ? $1 ;")
|
|
);
|
|
assert_eq!(other.get("message").await.unwrap(), None);
|
|
store.put("message", "updated").await.unwrap();
|
|
assert_eq!(
|
|
store.get("message").await.unwrap().as_deref(),
|
|
Some("updated")
|
|
);
|
|
store.close().await;
|
|
other.close().await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn sqlite_file_creates_parents_and_survives_reopen() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let path = dir.path().join("nested/data/metadata.db");
|
|
let config = StorageConfig::SqliteFile(path.clone());
|
|
let store = Storage::connect(&config).await.unwrap();
|
|
store.put("project", "Aster VM").await.unwrap();
|
|
store.close().await;
|
|
assert!(path.is_file());
|
|
let reopened = Storage::connect(&config).await.unwrap();
|
|
assert_eq!(
|
|
reopened.get("project").await.unwrap().as_deref(),
|
|
Some("Aster VM")
|
|
);
|
|
reopened.put("project", "v2").await.unwrap();
|
|
assert_eq!(
|
|
reopened.get("project").await.unwrap().as_deref(),
|
|
Some("v2")
|
|
);
|
|
reopened.close().await;
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn invalid_sqlite_directory_reports_error() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let file = dir.path().join("file");
|
|
std::fs::write(&file, "occupied").unwrap();
|
|
assert!(
|
|
Storage::connect(&StorageConfig::SqliteFile(file.join("aster.db")))
|
|
.await
|
|
.is_err()
|
|
);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn postgres_connection_failure_is_an_error() {
|
|
// Hold a TCP port without serving PostgreSQL: deterministic local failure.
|
|
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
|
|
let url = format!(
|
|
"postgres://aster:secret@{}/aster?sslmode=disable",
|
|
listener.local_addr().unwrap()
|
|
);
|
|
let result = Storage::connect(&StorageConfig::Postgres(url)).await;
|
|
let error = match result {
|
|
Ok(_) => panic!("unreachable PostgreSQL must fail"),
|
|
Err(error) => error,
|
|
};
|
|
assert!(!error.to_string().contains("secret"));
|
|
assert!(error.to_string().contains("no fallback"));
|
|
}
|