Add portable project metadata diff coverage.

This commit is contained in:
2026-07-21 23:54:37 +02:00
parent 1410b97aeb
commit 2fc683d513
17 changed files with 994 additions and 82 deletions

View File

@@ -352,6 +352,15 @@ impl ApplicationSession {
format!("project '{}' data is unavailable", value.name),
));
}
bds_core::engine::meta::startup_sync(&data_dir)
.and_then(|()| {
bds_core::engine::meta::initialize_metadata_snapshots(
db.conn(),
&data_dir,
&value.id,
)
})
.map_err(ProtocolError::engine)?;
self.selected_project = Some(SelectedProject {
id: value.id.clone(),
data_dir,
@@ -437,8 +446,8 @@ mod tests {
let root = tempfile::tempdir().unwrap();
let database_path = root.path().join("bds.db");
let data_root = root.path().join("data");
let host = ApplicationHost::start(database_path.clone(), data_root.clone()).unwrap();
let db = Database::open(&database_path).unwrap();
db.migrate().unwrap();
let project_dir = root.path().join("blog");
let value = project::create_project(
db.conn(),
@@ -447,6 +456,8 @@ mod tests {
)
.unwrap();
settings::set(db.conn(), settings::UI_LANGUAGE_KEY, "de").unwrap();
drop(db);
let host = ApplicationHost::start(database_path, data_root).unwrap();
Self {
_root: root,
host,
@@ -479,6 +490,12 @@ mod tests {
#[test]
fn session_negotiates_server_locale_and_selects_a_project() {
let fixture = Fixture::new();
let db = fixture.host.database().unwrap();
bds_core::db::queries::setting::delete_settings_by_prefix(
db.conn(),
&format!("project:{}:", fixture.project_id),
)
.unwrap();
let mut session = fixture.host.session().unwrap();
assert_eq!(session.locale(), "de");
assert!(matches!(
@@ -495,6 +512,11 @@ mod tests {
},
));
assert!(matches!(opened, ServerMessage::Response { .. }));
assert!(
bds_core::engine::meta::read_categories_snapshot(db.conn(), &fixture.project_id)
.unwrap()
.is_some()
);
}
#[test]

View File

@@ -377,6 +377,10 @@ impl TuiApp {
let data_dir = project
.as_ref()
.map(|project| host.project_data_dir(project));
if let (Some(project), Some(data_dir)) = (&project, &data_dir) {
engine::meta::startup_sync(data_dir)?;
engine::meta::initialize_metadata_snapshots(db.conn(), data_dir, &project.id)?;
}
let started_task_ids = host
.tasks()
.snapshots()
@@ -2218,8 +2222,12 @@ impl TuiApp {
.parse()
.map_err(|_| anyhow!(self.tr("tui.imageImportConcurrencyInvalid")))?;
metadata.validate().map_err(|error| anyhow!(error))?;
bds_core::db::queries::project::update_project(db.conn(), &project)?;
engine::meta::write_project_json(self.data_dir()?, &metadata)?;
engine::meta::update_project_metadata(
db.conn(),
self.data_dir()?,
&project,
&metadata,
)?;
self.project = Some(project);
if let Some(value) = self.setting_field(engine::settings::UI_LANGUAGE_KEY) {
engine::settings::set(db.conn(), value.key, &value.value)?;
@@ -2235,7 +2243,16 @@ impl TuiApp {
metadata.semantic_similarity_enabled = self
.setting_value("meta.semantic_similarity_enabled")
.eq_ignore_ascii_case("true");
engine::meta::write_project_json(self.data_dir()?, &metadata)?;
let project = self
.project
.as_ref()
.ok_or_else(|| anyhow!(self.tr("tui.noActiveProject")))?;
engine::meta::update_project_metadata(
db.conn(),
self.data_dir()?,
project,
&metadata,
)?;
}
SettingSection::Publishing => {
let preferences = PublishingPreferences {
@@ -2250,7 +2267,12 @@ impl TuiApp {
SshMode::Scp
},
};
engine::meta::write_publishing_json(self.data_dir()?, &preferences)?;
engine::meta::set_publishing_preferences(
db.conn(),
self.data_dir()?,
self.project_id()?,
&preferences,
)?;
}
SettingSection::Mcp => {
engine::settings::set(
@@ -3942,6 +3964,25 @@ mod tests {
}
}
#[test]
fn startup_initializes_legacy_project_metadata_snapshots() {
let fixture = Fixture::new();
let db = fixture.db();
bds_core::db::queries::setting::delete_settings_by_prefix(
db.conn(),
&format!("project:{}:", fixture.project.id),
)
.unwrap();
let _app = fixture.app(false);
assert!(
engine::meta::read_categories_snapshot(db.conn(), &fixture.project.id)
.unwrap()
.is_some()
);
}
fn wait_for(app: &mut TuiApp, predicate: impl Fn(&TuiApp) -> bool) {
let started = Instant::now();
while !predicate(app) && started.elapsed() < Duration::from_secs(2) {