v0.5.3-pre.002

This commit is contained in:
2026-08-11 22:22:40 +02:00
parent 01d78b5845
commit 8448ad1079
134 changed files with 4518 additions and 3595 deletions

View File

@@ -1,5 +1,5 @@
// file: ks-pipeline-demo-scenarios/src/environment.rs
// version: 7
// version: 9
//! Environment initialization for opt-in demonstration scenarios.
@@ -83,28 +83,53 @@ pub fn resolve_demo_devnet_profile(
};
}
/// Readiness report for one Devnet profile PostgreSQL store.
/// Backend-agnostic readiness report for one Devnet profile store.
#[derive(Clone, Debug, serde::Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DevnetProfileStoreReadiness {
/// Selected Devnet profile.
pub profile_name: std::string::String,
/// Selected backend code.
pub backend: std::string::String,
/// Whether schema creation was allowed by configuration.
pub auto_initialize_schema: bool,
/// Number of known tables already present before preparation.
pub existing_tables_before: usize,
/// Number of known tables created during preparation.
pub created_tables: usize,
/// Number of known tables present after preparation.
pub existing_tables_after: usize,
/// Total number of known tables expected by the current store.
pub expected_tables: usize,
/// Number of known logical resources already present before preparation.
pub available_resources_before: usize,
/// Number of known logical resources created during preparation.
pub created_resources: usize,
/// Number of known logical resources present after preparation.
pub available_resources_after: usize,
/// Total number of logical resources expected by the current store contract.
pub expected_resources: usize,
}
/// Verifies or initializes the PostgreSQL schema selected by one Devnet profile.
/// Builds backend-agnostic store-open options from one resolved profile.
fn store_open_options_from_profile(
profile: &ks_config::ProfileConfig,
) -> ks_core::Result<ks_store::StoreOpenOptions> {
return ks_store::StoreOpenOptions::new(
profile.database.enabled,
profile.database.backend.clone(),
profile.database.backend_options.clone(),
);
}
/// Opens the backend-agnostic store selected by one resolved profile.
#[cfg(test)]
pub(crate) async fn open_profile_store(
profile: &ks_config::ProfileConfig,
) -> ks_core::Result<ks_store::Store> {
let options = match store_open_options_from_profile(profile) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
return ks_store::Store::open(options).await;
}
/// Verifies or initializes the store selected by one Devnet profile.
pub async fn prepare_demo_devnet_profile_store(
profile: &ks_config::ProfileConfig,
) -> ks_core::Result<DevnetProfileStoreReadiness> {
) -> ks_core::Result<crate::DevnetProfileStoreReadiness> {
if profile.wallet.cluster != "devnet" {
return std::result::Result::Err(ks_core::Error::config(format!(
"profile '{}' is not configured for Devnet",
@@ -117,65 +142,78 @@ pub async fn prepare_demo_devnet_profile_store(
profile.name
)));
}
if profile.database.backend != "postgres" {
let options = match store_open_options_from_profile(profile) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let configuration = match options.configuration_summary() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let store = match ks_store::Store::open(options).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let initialization = store.initialization_summary();
if initialization.status != ks_store::StoreInitializationStatus::Ready {
return std::result::Result::Err(ks_core::Error::config(format!(
"Devnet profile '{}' must use the PostgreSQL backend",
profile.name
"Devnet profile '{}' store model is incomplete and automatic initialization is {}",
profile.name,
if configuration.auto_initialize_schema { "enabled" } else { "disabled" }
)));
}
let options = match ks_store::PostgresStoreOptions::new(
profile.database.postgres.url.clone(),
profile.database.postgres.max_connections,
profile.database.postgres.connect_timeout_ms,
false,
return std::result::Result::Ok(crate::DevnetProfileStoreReadiness {
profile_name: profile.name.clone(),
backend: configuration.backend_code,
auto_initialize_schema: configuration.auto_initialize_schema,
available_resources_before: initialization
.available_resource_count
.saturating_sub(initialization.created_resource_count)
as usize,
created_resources: initialization.created_resource_count as usize,
available_resources_after: initialization.available_resource_count as usize,
expected_resources: initialization.expected_resource_count as usize,
});
}
#[cfg(test)]
pub(crate) fn override_profile_store_url_for_test(
profile: &mut ks_config::ProfileConfig,
database_url: std::string::String,
) -> ks_core::Result<()> {
profile.database.enabled = true;
profile.database.backend = "postgres".to_string();
let backend_options = match profile.database.backend_options.as_object_mut() {
std::option::Option::Some(value) => value,
std::option::Option::None => {
return std::result::Result::Err(ks_core::Error::config(
"test store backend options must be an object",
));
},
};
backend_options.insert("url".to_string(), serde_json::Value::String(database_url));
backend_options.insert("auto_initialize_schema".to_string(), serde_json::Value::Bool(true));
return std::result::Result::Ok(());
}
#[cfg(test)]
pub(crate) async fn open_test_store(
database_url: std::string::String,
) -> ks_core::Result<ks_store::Store> {
let options = match ks_store::StoreOpenOptions::new(
true,
"postgres",
serde_json::json!({
"url": database_url,
"max_connections": 5,
"connect_timeout_ms": 5_000,
"auto_initialize_schema": true
}),
) {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let store = match ks_store::PostgresStore::connect(options).await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let before = match store.known_table_diagnostics().await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let existing_tables_before = before.iter().filter(|table| return table.exists).count();
if profile.database.postgres.auto_initialize_schema
&& let std::result::Result::Err(error) = store.initialize_store_schema().await
{
return std::result::Result::Err(error);
}
let after = match store.known_table_diagnostics().await {
std::result::Result::Ok(value) => value,
std::result::Result::Err(error) => return std::result::Result::Err(error),
};
let existing_tables_after = after.iter().filter(|table| return table.exists).count();
if existing_tables_after != after.len() {
let missing = after
.iter()
.filter(|table| return !table.exists)
.map(|table| return table.table_name.clone())
.collect::<std::vec::Vec<_>>();
return std::result::Result::Err(ks_core::Error::config(format!(
"Devnet profile '{}' PostgreSQL schema is incomplete and auto initialization is {}: missing {}",
profile.name,
if profile.database.postgres.auto_initialize_schema {
"enabled"
} else {
"disabled"
},
missing.join(", ")
)));
}
return std::result::Result::Ok(DevnetProfileStoreReadiness {
profile_name: profile.name.clone(),
auto_initialize_schema: profile.database.postgres.auto_initialize_schema,
existing_tables_before,
created_tables: existing_tables_after.saturating_sub(existing_tables_before),
existing_tables_after,
expected_tables: after.len(),
});
return ks_store::Store::open(options).await;
}
#[cfg(test)]