From 025dc88c25be1ce063d248ca8d1c1a1a2f29bff4 Mon Sep 17 00:00:00 2001 From: Mike Solar Date: Sun, 16 Aug 2026 10:39:31 +0800 Subject: [PATCH] feat(storage,app): PostgreSQL backend (D3) + project manager window (D4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit D3: oakdb+pg:// fully wired (shared sea-orm entities, BIGSERIAL DDL, connect-probe instead of pool retry on dead servers); Storage/Backend=pg + Storage/PgUrl config; 13 OAK_TEST_PG_URL-gated PG tests (verified against a Docker postgres:16), always-on clean-error tests otherwise. D4: DaVinci-style project manager — list with derived stats, create/ rename/duplicate/delete (confirm)/import/export (native dialogs, ove/otio/fcpxml), shown at startup and from the file menu; facade oakengine_library_* exports (list/create/delete/rename/duplicate/ import/export + project_load_library that binds write-through); save/save-as menu becomes 'export project file', open splits into from-library/from-file; status bar shows library write state; storage activates on app start and flushes on exit; spawn_modal reentrancy fixed (window-callback path) with a doc note. Also: the P1 audio test's environment probe was lost in the ffi purge; restored on cpal (the output device is cpal now). --- Cargo.lock | 1 + Cargo.toml | 3 + crates/oakaudio/src/manager.rs | 37 +- crates/oakengine/src/lib.rs | 1 + crates/oakengine/src/library.rs | 368 +++++++ crates/oakengine/src/storage.rs | 111 +- .../oakengine/src/test_support/it_library.rs | 426 ++++++++ crates/oakengine/src/test_support/mod.rs | 1 + .../src/backends/database/entities/mod.rs | 8 +- .../src/backends/database/migration.rs | 55 +- .../oakstorage/src/backends/database/mod.rs | 237 +++-- crates/oakstorage/tests/common/mod.rs | 525 +++++++++ crates/oakstorage/tests/database_pg_test.rs | 996 ++++++++++++++++++ crates/oakstorage/tests/database_test.rs | 526 +-------- docs/project-storage.md | 31 +- docs/screenshot-manager-en.png | Bin 0 -> 467030 bytes docs/screenshot-manager.png | Bin 0 -> 450690 bytes docs/screenshot-window-en.png | Bin 460774 -> 458364 bytes docs/screenshot-window.png | Bin 451733 -> 448044 bytes docs/zh/plans/riir/M13-storage-live.md | 42 + docs/zh/project-storage.md | 28 +- examples/screenshot.rs | 69 +- src/app.rs | 682 +++++++++++- src/i18n.rs | 77 +- src/lib.rs | 3 + src/manager.rs | 538 ++++++++++ src/oakui/engine.rs | 91 ++ src/oakui/ffi.rs | 61 ++ src/oakui/mock.rs | 187 +++- src/oakui/mod.rs | 4 +- src/oakui/real.rs | 225 +++- src/panels/status_bar.rs | 35 +- 32 files changed, 4711 insertions(+), 657 deletions(-) create mode 100644 crates/oakengine/src/library.rs create mode 100644 crates/oakengine/src/test_support/it_library.rs create mode 100644 crates/oakstorage/tests/common/mod.rs create mode 100644 crates/oakstorage/tests/database_pg_test.rs create mode 100644 docs/screenshot-manager-en.png create mode 100644 docs/screenshot-manager.png create mode 100644 src/manager.rs diff --git a/Cargo.lock b/Cargo.lock index 53701141e..227b704e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4744,6 +4744,7 @@ dependencies = [ "gpui_widgets", "image", "oakengine", + "serde_json", "smallvec", ] diff --git a/Cargo.toml b/Cargo.toml index 54c1d60ab..f94c2a1b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,6 +82,9 @@ smallvec = "1" # Editable-text widget (used by the file / export dialogs' path fields, the # same gpui-elements crate gpui_widgets builds on). gpui_elements = { path = "gpui/crates/gpui_elements" } +# The library list crosses the facade C ABI as JSON +# (`oakengine_library_list`, M13 D4); Value-only parsing, no derive. +serde_json = "1" [build-dependencies] # The real engine is NOT linked as an rlib: the app binds only the frozen diff --git a/crates/oakaudio/src/manager.rs b/crates/oakaudio/src/manager.rs index 8c7088fa5..68d9d1ee1 100644 --- a/crates/oakaudio/src/manager.rs +++ b/crates/oakaudio/src/manager.rs @@ -454,10 +454,43 @@ mod tests { fn output_callback_consumes_pushed_samples() { // Skip when the audio system cannot actually run a stream: open a // silent stream and require at least one callback within 2 s. A - // device existing is not enough — headless sessions report - // is_active=true while delivering zero callbacks. + // device existing is not enough — headless sessions report the + // stream running while delivering zero callbacks. use std::sync::atomic::AtomicI64 as A; + use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; static PROBE: A = A::new(0); + PROBE.store(0, Ordering::Relaxed); + let can_play = (|| { + let host = cpal::default_host(); + let device = host.default_output_device()?; + let config = device.default_output_config().ok()?; + let cb = move |data: &mut [f32], _: &cpal::OutputCallbackInfo| { + PROBE.fetch_add(data.len() as i64, Ordering::Relaxed); + for s in data.iter_mut() { + *s = 0.0; + } + }; + let stream = device + .build_output_stream( + config.config(), + cb, + |_| {}, + None, + ) + .ok()?; + stream.play().ok()?; + let deadline = std::time::Instant::now() + std::time::Duration::from_secs(2); + while std::time::Instant::now() < deadline && PROBE.load(Ordering::Relaxed) == 0 { + std::thread::sleep(std::time::Duration::from_millis(50)); + } + let got = PROBE.load(Ordering::Relaxed) > 0; + drop(stream); + Some(got) + })(); + if can_play != Some(true) { + eprintln!("audio session cannot deliver callbacks; skipping"); + return; + } DESTROYED.store(false, Ordering::SeqCst); let manager = MANAGER.get_or_init(|| Mutex::new(ManagerInner::default())); diff --git a/crates/oakengine/src/lib.rs b/crates/oakengine/src/lib.rs index 5fdedd46c..0278d7109 100644 --- a/crates/oakengine/src/lib.rs +++ b/crates/oakengine/src/lib.rs @@ -74,6 +74,7 @@ pub mod handle; pub mod ipc; #[cfg(not(test))] pub mod linkage; +pub mod library; pub mod node; pub mod plugin; pub mod pods; diff --git a/crates/oakengine/src/library.rs b/crates/oakengine/src/library.rs new file mode 100644 index 000000000..e134ef4e1 --- /dev/null +++ b/crates/oakengine/src/library.rs @@ -0,0 +1,368 @@ +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! The project-library manager C ABI (plan M13 §4): list / create / open / +//! rename / duplicate / delete / import / export over the oakstorage +//! database backend the write-through binds to ([`crate::storage`]). +//! +//! These exports are additive (D4): the app talks to the engine dylib only +//! through the frozen `oakengine_*` surface, so the manager's data source +//! crosses the boundary here instead of linking oakstorage directly (which +//! would give the app a second copy of the handle/serializer types). +//! +//! All operations address the configured default library (the same +//! `Storage/Backend` + `Storage/SqlitePath` configuration the write-through +//! uses); with storage disabled every call fails with `OAKENGINE_E_STATE` +//! except [`oakengine_library_list`], which reports an empty library +//! (`"[]"`) so the manager window can still open. + +use std::ffi::{c_char, c_int}; + +use oakstorage::backend::StorageBackend; +use oakstorage::uri::StorageUri; + +use crate::error::{Error, Result}; +use crate::handle::{guard, guard_int, read_cstr, write_string, OakEngineProject}; +use crate::stubs::node as n; + +/// One library row as the project manager shows it: the project metadata +/// plus the stats derived from the head state (plan §4). +#[derive(serde::Serialize)] +struct LibraryRow { + /// Library row uuid (the open/duplicate/export selector). + uuid: String, + /// Display name. + name: String, + /// Row creation time (unix seconds, UTC). + created_at: i64, + /// Last-write time (unix seconds, UTC; the manager sort key). + modified_at: i64, + /// Longest sequence duration, milliseconds. + duration_ms: i64, + /// Total tracks across all sequences. + track_count: i32, + /// Total clip blocks. + clip_count: i32, + /// Total footage nodes. + footage_count: i32, +} + +/// Map an oakstorage error onto the facade error space (the context string +/// is log-only per the error contract). +fn map_err(e: oakstorage::error::Error) -> Error { + use oakstorage::error::Error as E; + match e { + E::Invalid => Error::Invalid, + E::State => Error::State, + E::NotFound => Error::NotFound, + E::NoMem => Error::NoMem, + other => Error::Failed(other.to_string()), + } +} + +/// The configured default library as a parsed URI; [`Error::State`] when +/// the write-through backend is disabled or the path does not resolve. +fn library() -> Result { + if !crate::storage::storage_enabled() { + return Err(Error::State); + } + let uri = crate::storage::library_uri().ok_or(Error::State)?; + StorageUri::parse(&uri).map_err(map_err) +} + +/// The library URI selecting one row (`…?project=`). +fn project_uri(uuid: &str) -> Result { + let uri = library()?; + StorageUri::parse(&format!("{}?project={uuid}", uri.to_uri_string())).map_err(map_err) +} + +/// Load one library row as an owned project handle (refcount 1). +fn load_handle(uuid: &str) -> Result { + let uri = project_uri(uuid)?; + let result = crate::storage::backend().load(&uri).map_err(map_err)?; + if result.project.is_null() { + return Err(Error::Failed(format!( + "library load of {uuid} returned no project (info code {})", + result.version_info + ))); + } + Ok(result.project) +} + +/// Release an owned handle (refcount 1). +fn release(h: crate::handle::CHandle) { + if let Some(release) = h.release { + unsafe { release(h.ctx) }; + } +} + +/// `oakengine_library_list` — the library rows as a JSON array (buf/size +/// convention), most recently modified first. Each row carries the manager +/// stats derived from the head state; a row whose stats fail to replay +/// degrades to zeros instead of failing the whole list. With storage +/// disabled the result is the empty array (`"[]"`), not an error. +#[no_mangle] +pub unsafe extern "C" fn oakengine_library_list(buf: *mut c_char, buf_size: c_int) -> c_int { + guard_int(|| unsafe { + if !crate::storage::storage_enabled() { + return Ok(write_string("[]", buf, buf_size)); + } + let uri = library()?; + let infos = crate::storage::backend() + .list_projects(&uri) + .map_err(map_err)?; + let mut rows = Vec::with_capacity(infos.len()); + for info in infos { + let stats = crate::storage::backend() + .project_stats(&uri, &info.uuid) + .unwrap_or_default(); + rows.push(LibraryRow { + uuid: info.uuid, + name: info.name, + created_at: info.created_at.and_utc().timestamp(), + modified_at: info.modified_at.and_utc().timestamp(), + duration_ms: stats.duration_ms, + track_count: stats.track_count, + clip_count: stats.clip_count, + footage_count: stats.footage_count, + }); + } + let json = serde_json::to_string(&rows) + .map_err(|e| Error::Failed(format!("library list encode: {e}")))?; + Ok(write_string(&json, buf, buf_size)) + }) +} + +/// `oakengine_library_create` — create a blank project named `name` as a +/// new library row and report its uuid (buf/size convention on +/// `out_uuid`; the return value is the uuid length, negative on error). +/// The row lands immediately (one `kind='import'` command), so the +/// manager list shows it before the first edit. +#[no_mangle] +pub unsafe extern "C" fn oakengine_library_create( + name: *const c_char, + out_uuid: *mut c_char, + out_size: c_int, +) -> c_int { + guard_int(|| unsafe { + if name.is_null() { + return Err(Error::Invalid); + } + let name = read_cstr(name); + if name.trim().is_empty() { + return Err(Error::Invalid); + } + let uri = library()?; + + let mut h = n::oaknode_project_init(); + if h.is_null() { + return Err(Error::NoMem); + } + let outcome = (|| -> Result { + Error::from_module(n::oaknode_project_initialize(h))?; + let uuid = { + let arc = crate::handle::domain::project_of(&h).ok_or(Error::Invalid)?; + let mut guard = arc.lock().unwrap_or_else(|e| e.into_inner()); + guard.settings.insert("projectname".to_string(), name); + guard.uuid.clone() + }; + crate::storage::backend().save(h, &uri, 0).map_err(map_err)?; + Ok(uuid) + })(); + n::oaknode_project_free(&mut h); + let uuid = outcome?; + Ok(write_string(&uuid, out_uuid, out_size)) + }) +} + +/// `oakengine_library_delete` — delete the library row `uuid` (cascades +/// settings / snapshots / journal; `OAKENGINE_E_NOT_FOUND` when absent). +/// The manager confirms with the user before calling. +#[no_mangle] +pub unsafe extern "C" fn oakengine_library_delete(uuid: *const c_char) -> c_int { + guard(|| unsafe { + if uuid.is_null() { + return Err(Error::Invalid); + } + let uuid = read_cstr(uuid); + if uuid.is_empty() { + return Err(Error::Invalid); + } + crate::storage::backend() + .delete_project(&library()?, &uuid) + .map_err(map_err) + }) +} + +/// `oakengine_library_rename` — rename the library row `uuid` (the +/// manager's list name; the in-project `projectname` setting is +/// untouched). +#[no_mangle] +pub unsafe extern "C" fn oakengine_library_rename( + uuid: *const c_char, + name: *const c_char, +) -> c_int { + guard(|| unsafe { + if uuid.is_null() || name.is_null() { + return Err(Error::Invalid); + } + let (uuid, name) = (read_cstr(uuid), read_cstr(name)); + if uuid.is_empty() || name.trim().is_empty() { + return Err(Error::Invalid); + } + crate::storage::backend() + .rename_project(&library()?, &uuid, name.trim()) + .map_err(map_err) + }) +} + +/// `oakengine_library_duplicate` — copy the library row `uuid` (settings, +/// snapshots and the full journal history included) under a fresh uuid, +/// reporting the new row's uuid (buf/size convention on `out_uuid`; the +/// return value is the uuid length, negative on error). +/// `name` is the copy's display name; NULL/empty defaults to +/// ` (copy)`. +#[no_mangle] +pub unsafe extern "C" fn oakengine_library_duplicate( + uuid: *const c_char, + name: *const c_char, + out_uuid: *mut c_char, + out_size: c_int, +) -> c_int { + guard_int(|| unsafe { + if uuid.is_null() { + return Err(Error::Invalid); + } + let uuid = read_cstr(uuid); + if uuid.is_empty() { + return Err(Error::Invalid); + } + let name = read_cstr(name); + let name = match name.trim() { + "" => None, + trimmed => Some(trimmed), + }; + let info = crate::storage::backend() + .duplicate_project(&library()?, &uuid, name) + .map_err(map_err)?; + Ok(write_string(&info.uuid, out_uuid, out_size)) + }) +} + +/// `oakengine_library_import` — import a `.ove` / `.otio` / `.fcpxml` +/// project file as a new library row (the file backend parses it, a fresh +/// uuid is assigned, and the first save journals the whole project as one +/// `kind='import'` command). Reports the new row's uuid (buf/size +/// convention on `out_uuid`; the return value is the uuid length, +/// negative on error). +#[no_mangle] +pub unsafe extern "C" fn oakengine_library_import( + path: *const c_char, + out_uuid: *mut c_char, + out_size: c_int, +) -> c_int { + guard_int(|| unsafe { + if path.is_null() { + return Err(Error::Invalid); + } + let path = read_cstr(path); + if path.is_empty() { + return Err(Error::Invalid); + } + let file_uri = StorageUri::parse(&path).map_err(map_err)?; + let uuid = crate::storage::backend() + .import_from_file(&library()?, &file_uri) + .map_err(map_err)?; + Ok(write_string(&uuid, out_uuid, out_size)) + }) +} + +/// `oakengine_library_export` — export the library row `uuid` to the file +/// `path`; the format is dispatched by extension through the oakstorage +/// registry (`.ove` / `.ovexml` → ove-xml, `.otio` / `.fcpxml` → the +/// interchange backend). Nothing is written back to the library. +#[no_mangle] +pub unsafe extern "C" fn oakengine_library_export( + uuid: *const c_char, + path: *const c_char, +) -> c_int { + guard(|| unsafe { + if uuid.is_null() || path.is_null() { + return Err(Error::Invalid); + } + let (uuid, path) = (read_cstr(uuid), read_cstr(path)); + if uuid.is_empty() || path.is_empty() { + return Err(Error::Invalid); + } + let file_uri = StorageUri::parse(&path).map_err(map_err)?; + if file_uri.scheme != "file" { + return Err(Error::Invalid); + } + let handle = load_handle(&uuid)?; + let backend = oakstorage::registry::Registry::global() + .resolve(&file_uri) + .map_err(map_err)?; + let result = backend.save(handle, &file_uri, 0).map_err(map_err); + release(handle); + result + }) +} + +/// `oakengine_project_load_library` — load the library row `uuid` into a +/// fresh project shell (same contract as `oakengine_project_load`: the +/// shell must carry no content). On success the undo stack is cleared, the +/// modified flag is reset, and the project is bound to the library session +/// (the write-through continues the row's journal from its head seq). +#[no_mangle] +pub unsafe extern "C" fn oakengine_project_load_library( + self_: *mut OakEngineProject, + uuid: *const c_char, + err: *mut c_char, + err_size: c_int, +) -> c_int { + guard(|| unsafe { + if self_.is_null() || uuid.is_null() { + return Err(Error::Invalid); + } + let h = crate::handle::unbox(self_)?; + if !n::oaknode_project_root(h).is_null() { + return Err(Error::State); + } + let uuid = read_cstr(uuid); + if uuid.is_empty() { + return Err(Error::Invalid); + } + let loaded = match load_handle(&uuid) { + Ok(handle) => handle, + Err(e) => { + write_string(&e.to_string(), err, err_size); + return Err(e); + } + }; + // Swap the loaded content into the caller's shell box, releasing + // the empty shell handle the box was created with. + let mut old = (*self_).handle; + (*self_).handle = loaded; + n::oaknode_project_free(&mut old); + crate::undo::oakengine_undo_clear(); + Error::from_module(n::oaknode_project_set_modified(loaded, 0))?; + crate::storage::bind_project(loaded); + if !err.is_null() && err_size > 0 { + *err = 0; + } + Ok(()) + }) +} diff --git a/crates/oakengine/src/storage.rs b/crates/oakengine/src/storage.rs index be5c8b45a..720d35dcc 100644 --- a/crates/oakengine/src/storage.rs +++ b/crates/oakengine/src/storage.rs @@ -41,9 +41,9 @@ //! The library is selected from the `Storage` config group (all defaults //! are config-driven, plan §5): //! -//! - `Storage/Backend` — `"sqlite"` (the documented default value) or -//! `"database"` enable the write-through; any other value (e.g. -//! `"off"`) disables it. When the key is absent, no library is +//! - `Storage/Backend` — `"sqlite"` (the documented default value), +//! `"database"` or `"pg"` enable the write-through; any other value +//! (e.g. `"off"`) disables it. When the key is absent, no library is //! configured: projects stay unbound and the undo path runs without //! touching a database (graceful degradation — this is what keeps //! headless consumers and the test suite from writing to the user's @@ -52,6 +52,12 @@ //! storage is enabled) `/library.db` (the same //! location `FileFunctions::get_configuration_location` derives, //! honoring `OAK_CONFIG_DIR` and portable mode). +//! - `Storage/PgUrl` — the PostgreSQL connection string (plan D3), used +//! when `Storage/Backend` is `"pg"`: `user:pass@host:5432/dbname` +//! (libpq URL form; an optional `postgres://`/`postgresql://` scheme is +//! accepted and stripped). The resolved library URI is +//! `oakdb+pg://`. When `Backend = "pg"` but `PgUrl` is absent +//! or empty, no library is configured (same graceful degradation). //! //! ## Snapshot thread and exit flush //! @@ -101,9 +107,9 @@ struct Binding { } /// The process-wide oakstorage backend (shared by the UI thread's -/// write-throughs and the snapshot thread; the backend serializes its own -/// operations). -fn backend() -> &'static DatabaseBackend { +/// write-throughs, the snapshot thread and the library manager exports in +/// [`crate::library`]; the backend serializes its own operations). +pub(crate) fn backend() -> &'static DatabaseBackend { static BACKEND: OnceLock = OnceLock::new(); BACKEND.get_or_init(DatabaseBackend::new) } @@ -291,18 +297,18 @@ fn record_error(key: usize, message: &str) { // --------------------------------------------------------------------------- /// Whether the write-through backend is enabled (config-driven, plan §5): -/// `Storage/Backend` set to `"sqlite"` or `"database"` enables it; any -/// other explicit value (e.g. `"off"`) disables it. When NO `Storage` -/// configuration is present the backend is NOT enabled — "no library -/// configured" degrades gracefully to plain unbound projects, which keeps -/// headless consumers (the CLI) and the test suite from ever writing to -/// the user's default library. The documented default *values* are -/// `Backend = "sqlite"` and `SqlitePath = /library.db` +/// `Storage/Backend` set to `"sqlite"`, `"database"` or `"pg"` enables +/// it; any other explicit value (e.g. `"off"`) disables it. When NO +/// `Storage` configuration is present the backend is NOT enabled — "no +/// library configured" degrades gracefully to plain unbound projects, +/// which keeps headless consumers (the CLI) and the test suite from ever +/// writing to the user's default library. The documented default *values* +/// are `Backend = "sqlite"` and `SqlitePath = /library.db` /// (used once storage is enabled without an explicit path). pub(crate) fn storage_enabled() -> bool { let store = oakcommon::configstore::ConfigStore::instance(); match store.get(Some("Storage"), "Backend") { - Ok(b) => b == "sqlite" || b == "database", + Ok(b) => b == "sqlite" || b == "database" || b == "pg", Err(_) => false, } } @@ -316,6 +322,29 @@ fn configured_sqlite_path() -> Option { } } +/// The configured PostgreSQL connection string (`Storage/PgUrl`; empty +/// value = not configured). +fn configured_pg_url() -> Option { + let store = oakcommon::configstore::ConfigStore::instance(); + match store.get(Some("Storage"), "PgUrl") { + Ok(u) if !u.trim().is_empty() => Some(u.trim().to_string()), + _ => None, + } +} + +/// The `oakdb+pg://…` uri of the configured PostgreSQL library (None +/// when `Storage/PgUrl` is absent). A `postgres://`/`postgresql://` +/// scheme on the config value is stripped — the oakdb uri body is the +/// bare connection string (`user:pass@host:5432/dbname`). +fn pg_library_uri() -> Option { + let url = configured_pg_url()?; + let body = url + .strip_prefix("postgres://") + .or_else(|| url.strip_prefix("postgresql://")) + .unwrap_or(&url); + Some(format!("oakdb+pg://{body}")) +} + /// The default library file: `/library.db`, where /// the data directory is the standard per-user location /// (`FileFunctions::get_configuration_location`: macOS Application @@ -327,9 +356,14 @@ pub(crate) fn default_library_path() -> String { format!("{}/library.db", dir) } -/// The `oakdb+sqlite://…` uri of the configured library (None when the -/// path cannot be made absolute). -fn library_uri() -> Option { +/// The `oakdb+…` uri of the configured library (None when the path +/// cannot be made absolute, or the PG url is missing). Shared with the +/// library manager exports in [`crate::library`]. +pub(crate) fn library_uri() -> Option { + let store = oakcommon::configstore::ConfigStore::instance(); + if store.get(Some("Storage"), "Backend").ok().as_deref() == Some("pg") { + return pg_library_uri(); + } let path = match configured_sqlite_path() { Some(p) => p, None => default_library_path(), @@ -580,4 +614,47 @@ mod tests { assert!(!storage_enabled()); let _ = std::fs::remove_dir_all(&dir); } + + #[test] + fn library_uri_resolves_pg_config() { + use oakcommon::configstore::ConfigStore; + let store = ConfigStore::instance(); + let _g = crate::tests::common::STORAGE_CONFIG_LOCK + .lock() + .unwrap_or_else(|e| e.into_inner()); + + // Backend = "pg" yields an oakdb+pg uri from Storage/PgUrl; a + // postgres:// scheme on the config value is stripped. + store.set(Some("Storage"), "Backend", "pg"); + store.set( + Some("Storage"), + "PgUrl", + "postgres://user:pass@host:5432/oak", + ); + assert!(storage_enabled()); + assert_eq!( + library_uri().as_deref(), + Some("oakdb+pg://user:pass@host:5432/oak") + ); + + // postgresql:// is accepted too. + store.set( + Some("Storage"), + "PgUrl", + "postgresql://u@h/db?sslmode=disable", + ); + assert_eq!( + library_uri().as_deref(), + Some("oakdb+pg://u@h/db?sslmode=disable") + ); + + // Backend = "pg" with no PgUrl = no library (graceful + // degradation, same as an absent sqlite path). + store.set(Some("Storage"), "PgUrl", ""); + assert_eq!(library_uri(), None); + + // Leave the store in a safe state. + store.set(Some("Storage"), "Backend", "off"); + assert!(!storage_enabled()); + } } diff --git a/crates/oakengine/src/test_support/it_library.rs b/crates/oakengine/src/test_support/it_library.rs new file mode 100644 index 000000000..b5985ae1c --- /dev/null +++ b/crates/oakengine/src/test_support/it_library.rs @@ -0,0 +1,426 @@ +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! D4 integration tests: the project-library manager C ABI +//! (`src/library.rs`, plan M13 §4). +//! +//! End-to-end against real SQLite library files in temp directories, +//! driving the facade exactly like the app's project manager: create lands +//! a row immediately, list reports it with the derived stats, open +//! (`oakengine_project_load_library`) binds the loaded project to the +//! library session (the next undoable edit write-throughs onto the row's +//! journal), rename / duplicate / delete / import / export round-trip, and +//! the disabled-backend configuration degrades to an empty list + error +//! codes. +//! +//! Every test holds the shared undo-stack lock (the facade's stack is +//! process-wide, same as the it_undo / it_storage families) and the +//! storage-config lock, so the suite never races on either singleton. + +use std::ffi::CString; +use std::path::{Path, PathBuf}; + +use super::common; +use super::it_undo::GLOBAL_STACK_LOCK; + +use crate::error::{OAKENGINE_OK, OAKENGINE_E_INVALID, OAKENGINE_E_NOT_FOUND, OAKENGINE_E_STATE}; +use crate::handle::OakEngineProject; + +/// The math node type id (a factory type the tests add as an undoable +/// edit; footage is not factory-creatable, so the write-through is +/// verified on the journal rows directly). +const MATH: &str = "org.olivevideoeditor.Olive.math"; + +/// The journal row count of a library row (direct sea-orm read, the same +/// pattern as the it_storage tests). +fn journal_rows(db: &Path, uuid: &str) -> usize { + use sea_orm::entity::prelude::*; + use oakstorage::backends::database::entities::{journal, project}; + + let runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + runtime.block_on(async { + let conn = sea_orm::Database::connect(format!("sqlite://{}?mode=ro", db.display())) + .await + .unwrap(); + let model = project::Entity::find() + .filter(project::Column::Uuid.eq(uuid)) + .one(&conn) + .await + .unwrap() + .expect("the row exists"); + journal::Entity::find() + .filter(journal::Column::ProjectId.eq(model.id)) + .all(&conn) + .await + .unwrap() + .len() + }) +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/// Serialize a library test: hold the process-global undo-stack lock AND +/// the storage-config lock for the whole body, then point the library at a +/// temp SQLite file. +fn with_library(db: &Path, f: impl FnOnce() -> R) -> R { + let _stack = GLOBAL_STACK_LOCK.lock().unwrap_or_else(|e| e.into_inner()); + let _config = common::STORAGE_CONFIG_LOCK + .lock() + .unwrap_or_else(|e| e.into_inner()); + let store = oakcommon::configstore::ConfigStore::instance(); + store.set(Some("Storage"), "Backend", "sqlite"); + store.set(Some("Storage"), "SqlitePath", &db.to_string_lossy()); + f() +} + +/// A fresh, unique temp directory for one test. +fn temp_dir(tag: &str) -> PathBuf { + let dir = + std::env::temp_dir().join(format!("oakengine_library_{}_{}", std::process::id(), tag)); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + dir +} + +/// Two-stage string read over a facade `(buf, size)` getter. +fn read_string(f: impl Fn(*mut std::ffi::c_char, i32) -> i32) -> String { + let needed = f(std::ptr::null_mut(), 0); + if needed <= 0 { + return String::new(); + } + let mut buf = vec![0 as std::ffi::c_char; needed as usize + 1]; + f(buf.as_mut_ptr(), needed + 1); + let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len()); + String::from_utf8_lossy(unsafe { std::slice::from_raw_parts(buf.as_ptr() as *const u8, len) }) + .into_owned() +} + +/// The library list JSON. +fn list_json() -> String { + read_string(|buf, size| unsafe { crate::library::oakengine_library_list(buf, size) }) +} + +/// Create a library row; returns its uuid. The create export has a side +/// effect, so it is called ONCE with a stack buffer (never two-stage). +fn create(name: &str) -> String { + let name = CString::new(name).unwrap(); + let mut buf = [0 as std::ffi::c_char; 256]; + let rc = unsafe { crate::library::oakengine_library_create(name.as_ptr(), buf.as_mut_ptr(), 256) }; + assert!(rc > 0, "create {name:?} rc={rc}"); + let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len()); + String::from_utf8_lossy(unsafe { std::slice::from_raw_parts(buf.as_ptr() as *const u8, len) }) + .into_owned() +} + +/// Duplicate a library row (single call with a stack buffer, see +/// [`create`]). +fn duplicate(uuid: &str) -> String { + let uuid = CString::new(uuid).unwrap(); + let mut buf = [0 as std::ffi::c_char; 256]; + let rc = unsafe { + crate::library::oakengine_library_duplicate( + uuid.as_ptr(), + std::ptr::null(), + buf.as_mut_ptr(), + 256, + ) + }; + assert!(rc > 0, "duplicate rc={rc}"); + let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len()); + String::from_utf8_lossy(unsafe { std::slice::from_raw_parts(buf.as_ptr() as *const u8, len) }) + .into_owned() +} + +/// The uuids in the library list JSON (order preserved). +fn list_uuids(json: &str) -> Vec { + serde_json::from_str::(json) + .expect("list is JSON") + .as_array() + .expect("list is an array") + .iter() + .map(|row| { + row.get("uuid") + .and_then(|v| v.as_str()) + .expect("row uuid") + .to_string() + }) + .collect() +} + +/// One row of the library list JSON by uuid. +fn list_row<'a>(json: &'a str, uuid: &str) -> Option { + serde_json::from_str::(json) + .expect("list is JSON") + .as_array() + .expect("list is an array") + .iter() + .find(|row| row.get("uuid").and_then(|v| v.as_str()) == Some(uuid)) + .cloned() +} + +/// Open a library row into a fresh facade project shell. +fn open(uuid: &str) -> *mut OakEngineProject { + let project = unsafe { crate::node::oakengine_project_create() }; + assert!(!project.is_null()); + let uuid_c = CString::new(uuid).unwrap(); + let mut err = [0 as std::ffi::c_char; 4096]; + let rc = unsafe { + crate::library::oakengine_project_load_library( + project, + uuid_c.as_ptr(), + err.as_mut_ptr(), + err.len() as i32, + ) + }; + assert_eq!(rc, OAKENGINE_OK, "open {uuid}"); + project +} + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +/// Create lands a row immediately; list reports it with the metadata and +/// the (zero) stats. +#[test] +fn create_then_list_shows_the_row() { + let dir = temp_dir("create"); + with_library(&dir.join("lib.db"), || { + let uuid = create("Demo Reel"); + assert!(!uuid.is_empty(), "create reports the new uuid"); + + let json = list_json(); + let row = list_row(&json, &uuid).expect("the created row is listed"); + assert_eq!(row.get("name").and_then(|v| v.as_str()), Some("Demo Reel")); + assert!(row.get("modified_at").and_then(|v| v.as_i64()).unwrap() > 0); + assert_eq!(row.get("track_count").and_then(|v| v.as_i64()), Some(0)); + assert_eq!(row.get("footage_count").and_then(|v| v.as_i64()), Some(0)); + + // A second create adds a second row. + let other = create("Second"); + assert_ne!(uuid, other); + assert_eq!(list_uuids(&list_json()).len(), 2); + }); + let _ = std::fs::remove_dir_all(&dir); +} + +/// Opening a library row binds the project to the library session: the +/// next undoable edit write-throughs onto the row's journal. +#[test] +fn open_binds_and_write_through_advances_the_row() { + let dir = temp_dir("open"); + let db = dir.join("lib.db"); + with_library(&db, || { + let uuid = create("Editable"); + let before = journal_rows(&db, &uuid); + let project = open(&uuid); + assert_eq!( + unsafe { crate::storage::oakengine_storage_is_bound(project) }, + 1, + "the library-opened project is bound" + ); + + // An undoable edit write-throughs. + let node = unsafe { + crate::node::oakengine_project_add_node(project, CString::new(MATH).unwrap().as_ptr()) + }; + assert!(!node.is_null()); + unsafe { crate::node::oakengine_node_free(node) }; + + let after = journal_rows(&db, &uuid); + assert!( + after > before, + "the edit journaled new rows ({before} -> {after})" + ); + + // The row name comes from the projectname setting (the facade's + // project name is filename-derived, so a library project displays + // "(untitled)"; the app overrides it with the row name). + let row = list_row(&list_json(), &uuid).expect("row after the edit"); + assert_eq!(row.get("name").and_then(|v| v.as_str()), Some("Editable")); + + unsafe { crate::node::oakengine_project_free(project) }; + }); + let _ = std::fs::remove_dir_all(&dir); +} + +/// Rename and duplicate keep the list coherent; delete removes the row and +/// opening it afterwards fails. +#[test] +fn rename_duplicate_delete() { + let dir = temp_dir("rdd"); + with_library(&dir.join("lib.db"), || { + let uuid = create("Original"); + + // Rename. + let rc = unsafe { + crate::library::oakengine_library_rename( + CString::new(uuid.clone()).unwrap().as_ptr(), + CString::new("Renamed").unwrap().as_ptr(), + ) + }; + assert_eq!(rc, OAKENGINE_OK); + let row = list_row(&list_json(), &uuid).expect("renamed row"); + assert_eq!(row.get("name").and_then(|v| v.as_str()), Some("Renamed")); + + // Duplicate (default " (copy)" name). + let copy = duplicate(&uuid); + assert_ne!(copy, uuid); + let row = list_row(&list_json(), ©).expect("the copy is listed"); + assert_eq!( + row.get("name").and_then(|v| v.as_str()), + Some("Renamed (copy)") + ); + + // The copy opens (its journal history came along). + let project = open(©); + unsafe { crate::node::oakengine_project_free(project) }; + + // Delete the copy; opening it afterwards fails. + let rc = unsafe { + crate::library::oakengine_library_delete(CString::new(copy.clone()).unwrap().as_ptr()) + }; + assert_eq!(rc, OAKENGINE_OK); + assert!(!list_uuids(&list_json()).contains(©)); + let shell = unsafe { crate::node::oakengine_project_create() }; + let rc = unsafe { + crate::library::oakengine_project_load_library( + shell, + CString::new(copy).unwrap().as_ptr(), + std::ptr::null_mut(), + 0, + ) + }; + assert_eq!(rc, OAKENGINE_E_NOT_FOUND, "a deleted row does not open"); + unsafe { crate::node::oakengine_project_free(shell) }; + + // Unknown uuids are E_NOT_FOUND; empty arguments E_INVALID. + let rc = unsafe { + crate::library::oakengine_library_delete(CString::new("{no-such}").unwrap().as_ptr()) + }; + assert_eq!(rc, OAKENGINE_E_NOT_FOUND); + let rc = unsafe { crate::library::oakengine_library_delete(c"".as_ptr()) }; + assert_eq!(rc, OAKENGINE_E_INVALID); + }); + let _ = std::fs::remove_dir_all(&dir); +} + +/// Export writes the row's head state to a file (dispatched by extension), +/// and import brings a file back as a new library row that opens. +#[test] +fn export_then_import_round_trip() { + let dir = temp_dir("xport"); + with_library(&dir.join("lib.db"), || { + // A row with one node, so the exported file has content. + let uuid = create("Exchange"); + let project = open(&uuid); + let node = unsafe { + crate::node::oakengine_project_add_node(project, CString::new(MATH).unwrap().as_ptr()) + }; + assert!(!node.is_null()); + unsafe { crate::node::oakengine_node_free(node) }; + unsafe { crate::node::oakengine_project_free(project) }; + + // Export as .ove and as .otio. + let ove = dir.join("out.ove"); + let otio = dir.join("out.otio"); + for path in [&ove, &otio] { + let rc = unsafe { + crate::library::oakengine_library_export( + CString::new(uuid.clone()).unwrap().as_ptr(), + CString::new(path.to_string_lossy().into_owned()).unwrap().as_ptr(), + ) + }; + assert_eq!(rc, OAKENGINE_OK, "export {}", path.display()); + assert!(path.exists(), "{} exists", path.display()); + } + let xml = std::fs::read_to_string(&ove).unwrap(); + assert!(xml.contains(" 0, "import rc={rc}"); + let len = buf.iter().position(|&c| c == 0).unwrap_or(buf.len()); + let imported = + String::from_utf8_lossy(unsafe { std::slice::from_raw_parts(buf.as_ptr() as *const u8, len) }) + .into_owned(); + assert!(!imported.is_empty(), "import reports the new uuid"); + assert_ne!(imported, uuid, "import assigns a fresh uuid"); + let project = open(&imported); + // The projectname setting round-trips into the imported row's name. + let row = list_row(&list_json(), &imported).expect("the imported row is listed"); + assert_eq!(row.get("name").and_then(|v| v.as_str()), Some("Exchange")); + unsafe { crate::node::oakengine_project_free(project) }; + + // Importing a missing file fails. + let rc = unsafe { + crate::library::oakengine_library_import( + CString::new(dir.join("nope.ove").to_string_lossy().into_owned()) + .unwrap() + .as_ptr(), + std::ptr::null_mut(), + 0, + ) + }; + assert!(rc < 0, "a missing file does not import"); + }); + let _ = std::fs::remove_dir_all(&dir); +} + +/// With the backend disabled the list is empty (not an error) and every +/// mutating call fails with E_STATE. +#[test] +fn disabled_backend_degrades_gracefully() { + let _stack = GLOBAL_STACK_LOCK.lock().unwrap_or_else(|e| e.into_inner()); + let _off = common::storage_off_guard(); + + assert_eq!(list_json(), "[]", "no library configured reads as empty"); + + let rc = unsafe { + crate::library::oakengine_library_create( + c"Nope".as_ptr(), + std::ptr::null_mut(), + 0, + ) + }; + assert_eq!(rc, OAKENGINE_E_STATE); + let rc = unsafe { crate::library::oakengine_library_delete(c"{x}".as_ptr()) }; + assert_eq!(rc, OAKENGINE_E_STATE); + let rc = unsafe { crate::library::oakengine_library_export(c"{x}".as_ptr(), c"/tmp/x.ove".as_ptr()) }; + assert_eq!(rc, OAKENGINE_E_STATE); + + let shell = unsafe { crate::node::oakengine_project_create() }; + let rc = unsafe { + crate::library::oakengine_project_load_library( + shell, + c"{x}".as_ptr(), + std::ptr::null_mut(), + 0, + ) + }; + assert_eq!(rc, OAKENGINE_E_STATE); + unsafe { crate::node::oakengine_project_free(shell) }; +} diff --git a/crates/oakengine/src/test_support/mod.rs b/crates/oakengine/src/test_support/mod.rs index da26b2297..da42b101e 100644 --- a/crates/oakengine/src/test_support/mod.rs +++ b/crates/oakengine/src/test_support/mod.rs @@ -41,6 +41,7 @@ mod it_audio; mod it_codec; mod it_common; mod it_export; +mod it_library; mod it_plugin; mod it_storage; mod it_task; diff --git a/crates/oakstorage/src/backends/database/entities/mod.rs b/crates/oakstorage/src/backends/database/entities/mod.rs index 7dee44324..562b5e8b2 100644 --- a/crates/oakstorage/src/backends/database/entities/mod.rs +++ b/crates/oakstorage/src/backends/database/entities/mod.rs @@ -18,10 +18,10 @@ //! //! One module per entity: the `DeriveEntityModel` macro generates //! `Entity`/`Column`/`Model`/`ActiveModel` in the defining module, so -//! each table gets its own scope. The same definitions serve SQLite -//! today and PostgreSQL (D3) — the column types (`i64`, `String`, -//! `Option`, `NaiveDateTime`) map to BIGINT/TEXT/TIMESTAMP on -//! both. +//! each table gets its own scope. The same definitions serve SQLite and +//! PostgreSQL — the column types (`i64`, `String`, `Option`, +//! `NaiveDateTime`) map to BIGINT/TEXT/TIMESTAMP on both, so the shared +//! save/replay logic never branches on the dialect. pub mod journal; pub mod project; diff --git a/crates/oakstorage/src/backends/database/migration.rs b/crates/oakstorage/src/backends/database/migration.rs index 7d27bd09b..3e3bcf1f8 100644 --- a/crates/oakstorage/src/backends/database/migration.rs +++ b/crates/oakstorage/src/backends/database/migration.rs @@ -60,22 +60,53 @@ const SQLITE_DDL: &[&str] = &[ )", ]; -/// Apply the schema (idempotent; safe to run on every connection open). -/// -/// PostgreSQL (D3) gets its own `BIGSERIAL` DDL — same shape, currently -/// unreachable because the backend rejects `oakdb+pg://` before any -/// connection is opened. +/// PostgreSQL DDL for the four tables — the same shape with the PG +/// dialect differences (plan D3: BIGSERIAL for the surrogate key, +/// BIGINT for the FKs; `TEXT` everywhere, matching the SQLite TEXT +/// decision — no BYTEA). `CREATE TABLE IF NOT EXISTS` makes it +/// idempotent, exactly like the SQLite side. +const POSTGRES_DDL: &[&str] = &[ + "CREATE TABLE IF NOT EXISTS projects ( + id BIGSERIAL PRIMARY KEY, + uuid TEXT NOT NULL UNIQUE, + name TEXT NOT NULL, + schema_ver INTEGER NOT NULL, + created_at TIMESTAMP NOT NULL, + modified_at TIMESTAMP NOT NULL, + command_seq BIGINT NOT NULL DEFAULT 0 + )", + "CREATE TABLE IF NOT EXISTS settings ( + project_id BIGINT NOT NULL REFERENCES projects(id) ON DELETE CASCADE, + key TEXT NOT NULL, + value TEXT NOT NULL, + PRIMARY KEY (project_id, key) + )", + "CREATE TABLE IF NOT EXISTS snapshots ( + project_id BIGINT NOT NULL REFERENCES projects(id) ON DELETE CASCADE, + command_seq BIGINT NOT NULL, + payload TEXT NOT NULL, + written_at TIMESTAMP NOT NULL, + PRIMARY KEY (project_id, command_seq) + )", + "CREATE TABLE IF NOT EXISTS journal ( + project_id BIGINT NOT NULL REFERENCES projects(id) ON DELETE CASCADE, + seq BIGINT NOT NULL, + node_identity BIGINT NOT NULL, + kind TEXT NOT NULL, + old_xml TEXT, + new_xml TEXT, + at TIMESTAMP NOT NULL, + PRIMARY KEY (project_id, seq, node_identity) + )", +]; + +/// Apply the schema for the connection's dialect (idempotent; safe to +/// run on every connection open). pub async fn migrate(db: &impl ConnectionTrait) -> crate::error::Result<()> { let backend = db.get_database_backend(); let statements: &[&str] = match backend { DatabaseBackend::Sqlite => SQLITE_DDL, - // D3: `BIGSERIAL PRIMARY KEY` for projects.id, `BIGINT` for the - // FKs — the rest of the column set is identical. - DatabaseBackend::Postgres => { - return Err(crate::error::Error::Failed( - "oakdb+pg is a D3 milestone; the PostgreSQL schema is not wired yet".to_string(), - )); - } + DatabaseBackend::Postgres => POSTGRES_DDL, other => { return Err(crate::error::Error::Failed(format!( "unsupported database backend {other:?}" diff --git a/crates/oakstorage/src/backends/database/mod.rs b/crates/oakstorage/src/backends/database/mod.rs index ca023dc62..f02ec3a45 100644 --- a/crates/oakstorage/src/backends/database/mod.rs +++ b/crates/oakstorage/src/backends/database/mod.rs @@ -14,16 +14,20 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! The database backend (plan M13 §1/§2), SQLite first. +//! The database backend (plan M13 §1/§2): SQLite and PostgreSQL share +//! one code path — the same sea-orm entities, diff/save/replay logic and +//! migrations, with the dialect differences (BIGSERIAL vs AUTOINCREMENT, +//! `IF NOT EXISTS` DDL) converged in the connection and migration layer. //! //! URI forms: //! - `oakdb+sqlite:///absolute/path.db[?project=]` — local file //! database; the optional `project` query selects the library row to //! load (default: the most recently modified project). -//! - `oakdb+pg://user:pass@host:5432/db[?project=]` — PostgreSQL -//! (D3). The target is parsed into [`DbTarget::Pg`] today, but every -//! operation rejects it with [`crate::error::Error::NoBackend`] until -//! the D3 client lands. +//! - `oakdb+pg://user:pass@host:5432/db[?project=]` — PostgreSQL; +//! the body is the libpq connection string without a scheme. A `?…` +//! part is the `?project=` selector only when it carries a `project=` +//! key — a bare query (e.g. `?sslmode=disable`) belongs to the +//! connection string and is passed through untouched. //! //! The async sea-orm API is driven by a private current-thread tokio //! runtime so the public surface stays synchronous (plan §6: "后端内嵌 @@ -104,9 +108,11 @@ pub(crate) enum DbTarget { /// `?project=` uuid; `None` = most recently modified row. project: Option, }, - /// PostgreSQL (parsed for D3; rejected until then). + /// PostgreSQL server. Pg { - /// Connection string (`user:pass@host:port/db`). + /// Connection string body (`user:pass@host:port/db`, without a + /// scheme; may carry its own `?param=…` query when it does not + /// contain a `project=` key). conn: String, /// `?project=` uuid; `None` = most recently modified row. project: Option, @@ -114,20 +120,6 @@ pub(crate) enum DbTarget { } impl DbTarget { - /// True for the PostgreSQL variant (all ops return E_NO_BACKEND - /// until D3). - fn is_pg(&self) -> bool { - matches!(self, DbTarget::Pg { .. }) - } - - /// The SQLite path (`None` for PG). - fn sqlite_path(&self) -> Option<&str> { - match self { - DbTarget::Sqlite { path, .. } => Some(path), - DbTarget::Pg { .. } => None, - } - } - /// The `?project=` selector. fn project(&self) -> Option<&str> { match self { @@ -138,12 +130,23 @@ impl DbTarget { } } +/// The connection-cache key of a parsed target (the database location — +/// an absolute SQLite path or a PostgreSQL connection string body). +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +enum DbKey { + /// SQLite file database at an absolute path. + Sqlite(String), + /// PostgreSQL server (connection string body, see [`DbTarget::Pg`]). + Pg(String), +} + /// Parse a storage URI into a [`DbTarget`]. /// /// `oakdb+sqlite://` requires an absolute path (E_INVALID otherwise); /// the body may carry `?project=` (no percent-decoding — uuid -/// values contain only hex/braces/hyphens). Unknown `oakdb` variants -/// are E_NO_BACKEND. +/// values contain only hex/braces/hyphens). `oakdb+pg://` requires a +/// non-empty, parseable connection string (E_INVALID otherwise). Unknown +/// `oakdb` variants are E_NO_BACKEND. pub(crate) fn parse_target(uri: &StorageUri) -> Result { match uri.scheme.as_str() { "oakdb+sqlite" => { @@ -157,16 +160,37 @@ pub(crate) fn parse_target(uri: &StorageUri) -> Result { }) } "oakdb+pg" => { - let (conn, query) = split_query(&uri.body); - Ok(DbTarget::Pg { - conn: conn.to_string(), - project: query_param(query, "project"), - }) + let (base, query) = split_query(&uri.body); + // A `?…` part is the `?project=` selector only when it carries + // a `project=` key; otherwise (e.g. `?sslmode=disable`) it + // belongs to the connection string and the whole body passes + // through. + let project = match query { + Some(q) if query_param(Some(q), "project").is_some() => { + query_param(Some(q), "project") + } + _ => None, + }; + let conn = match &project { + Some(_) => base.to_string(), + None => uri.body.clone(), + }; + if conn.is_empty() || !valid_pg_conn(&conn) { + return Err(Error::Invalid); + } + Ok(DbTarget::Pg { conn, project }) } _ => Err(Error::NoBackend), } } +/// Whether `conn` parses as a PostgreSQL connection string (the libpq +/// URL form, `user:pass@host:port/db[?params]`, with a scheme prepended). +fn valid_pg_conn(conn: &str) -> bool { + use std::str::FromStr; + sea_orm::sqlx::postgres::PgConnectOptions::from_str(&format!("postgres://{conn}")).is_ok() +} + /// Split `body` at the first `?` (the query part, if any). fn split_query(body: &str) -> (&str, Option<&str>) { match body.split_once('?') { @@ -310,8 +334,8 @@ pub struct DatabaseBackend { runtime: OnceLock, /// Serializes all database operations of this backend. op_lock: Mutex<()>, - /// Open connections by database path. - connections: Mutex>, + /// Open connections by database location (path or PG conn string). + connections: Mutex>, } impl DatabaseBackend { @@ -332,10 +356,11 @@ impl DatabaseBackend { .expect("tokio current_thread runtime") } - /// Run `f` against the database at `key` (an absolute SQLite path). - /// The op lock is held for the whole call; the connection is opened - /// and migrated on first use, then cached. - fn run(&self, key: &str, f: F) -> Result + /// Run `f` against the database at `key` (an absolute SQLite path or a + /// PostgreSQL connection string). The op lock is held for the whole + /// call; the connection is opened and migrated on first use, then + /// cached. + fn run(&self, key: DbKey, f: F) -> Result where F: FnOnce(DatabaseConnection) -> Fut, Fut: Future>, @@ -343,33 +368,36 @@ impl DatabaseBackend { let _guard = self.op_lock.lock().unwrap_or_else(|e| e.into_inner()); let runtime = self.runtime.get_or_init(Self::build_runtime); runtime.block_on(async { - let conn = self.connect_cached(key).await?; + let conn = self.connect_cached(&key).await?; f(conn).await }) } - /// Open (and migrate) the SQLite database at `path`, caching the - /// connection. + /// Open (and migrate) the database at `key`, caching the connection. /// - /// Two writers racing on a fresh file surface SQLite's `database is + /// Two writers racing on a fresh SQLite file surface `database is /// locked` (SQLITE_BUSY) — most often when a fresh connection's WAL /// mode switch collides with the other's, which `busy_timeout` cannot - /// wait out — so connect+ migrate are retried a few times (plan §6: - /// single-writer is the contract; a clean error beats a silent - /// failure). - async fn connect_cached(&self, path: &str) -> Result { + /// wait out — so the SQLite connect + migrate are retried a few times + /// (plan §6: single-writer is the contract; a clean error beats a + /// silent failure). PostgreSQL connections are never retried (their + /// errors are not retryable by [`retryable`]). + async fn connect_cached(&self, key: &DbKey) -> Result { if let Some(conn) = self .connections .lock() .unwrap_or_else(|e| e.into_inner()) - .get(path) + .get(key) { return Ok(conn.clone()); } let mut attempt = 0; let conn = loop { let result = async { - let conn = connect_sqlite(path).await?; + let conn = match key { + DbKey::Sqlite(path) => connect_sqlite(path).await?, + DbKey::Pg(conn) => connect_pg(conn).await?, + }; migration::migrate(&conn).await?; Ok::<_, Error>(conn) } @@ -386,7 +414,7 @@ impl DatabaseBackend { self.connections .lock() .unwrap_or_else(|e| e.into_inner()) - .insert(path.to_string(), conn.clone()); + .insert(key.clone(), conn.clone()); Ok(conn) } @@ -396,8 +424,8 @@ impl DatabaseBackend { /// node graph). pub fn list_projects(&self, uri: &StorageUri) -> Result> { let target = parse_target(uri)?; - let path = sqlite_path_of(&target)?; - self.run(path, |conn| async move { + let key = db_key_of(&target); + self.run(key, |conn| async move { let models = project::Entity::find() .order_by_desc(project::Column::ModifiedAt) .all(&conn) @@ -422,9 +450,9 @@ impl DatabaseBackend { /// the project's data is gone — the manager confirms before calling). pub fn delete_project(&self, uri: &StorageUri, uuid: &str) -> Result<()> { let target = parse_target(uri)?; - let path = sqlite_path_of(&target)?; + let key = db_key_of(&target); let uuid = uuid.to_string(); - self.run(path, move |conn| async move { + self.run(key, move |conn| async move { let tx = conn.begin().await.map_err(db_err)?; let res = project::Entity::delete_many() .filter(project::Column::Uuid.eq(&uuid)) @@ -449,10 +477,10 @@ impl DatabaseBackend { new_name: Option<&str>, ) -> Result { let target = parse_target(uri)?; - let path = sqlite_path_of(&target)?; + let key = db_key_of(&target); let uuid = uuid.to_string(); let new_name = new_name.map(str::to_string); - self.run(path, move |conn| async move { + self.run(key, move |conn| async move { let tx = conn.begin().await.map_err(db_err)?; let src = project::Entity::find() .filter(project::Column::Uuid.eq(&uuid)) @@ -556,10 +584,10 @@ impl DatabaseBackend { /// in-app project name (`settings["projectname"]`) is untouched. pub fn rename_project(&self, uri: &StorageUri, uuid: &str, new_name: &str) -> Result<()> { let target = parse_target(uri)?; - let path = sqlite_path_of(&target)?; + let key = db_key_of(&target); let uuid = uuid.to_string(); let new_name = new_name.to_string(); - self.run(path, move |conn| async move { + self.run(key, move |conn| async move { let now = chrono::Utc::now().naive_utc(); let tx = conn.begin().await.map_err(db_err)?; let res = project::Entity::update_many() @@ -633,9 +661,9 @@ impl DatabaseBackend { /// the head seq. pub fn snapshot(&self, uri: &StorageUri, uuid: &str) -> Result<()> { let target = parse_target(uri)?; - let path = sqlite_path_of(&target)?; + let key = db_key_of(&target); let uuid = uuid.to_string(); - self.run(path, move |conn| async move { + self.run(key, move |conn| async move { let model = project::Entity::find() .filter(project::Column::Uuid.eq(&uuid)) .one(&conn) @@ -657,9 +685,9 @@ impl DatabaseBackend { /// the empty project. E_INVALID when `seq` is out of range. pub fn load_at(&self, uri: &StorageUri, uuid: &str, seq: i64) -> Result { let target = parse_target(uri)?; - let path = sqlite_path_of(&target)?; + let key = db_key_of(&target); let uuid = uuid.to_string(); - self.run(path, move |conn| async move { + self.run(key, move |conn| async move { let model = project::Entity::find() .filter(project::Column::Uuid.eq(&uuid)) .one(&conn) @@ -695,9 +723,9 @@ impl DatabaseBackend { /// handle (the head state). fn load_handle_by_uuid(&self, uri: &StorageUri, uuid: &str) -> Result { let target = parse_target(uri)?; - let path = sqlite_path_of(&target)?; + let key = db_key_of(&target); let uuid = uuid.to_string(); - self.run(path, move |conn| async move { + self.run(key, move |conn| async move { let model = project::Entity::find() .filter(project::Column::Uuid.eq(&uuid)) .one(&conn) @@ -736,9 +764,9 @@ impl StorageBackend for DatabaseBackend { fn load(&self, uri: &StorageUri) -> Result { let target = parse_target(uri)?; - let path = sqlite_path_of(&target)?; + let key = db_key_of(&target); let project = target.project().map(str::to_string); - self.run(path, move |conn| async move { + self.run(key, move |conn| async move { let model = pick_project(&conn, project.as_deref()).await?; let xml = assemble_at(&conn, model.id, &model.uuid, model.command_seq).await?; let handle = @@ -749,7 +777,7 @@ impl StorageBackend for DatabaseBackend { fn save(&self, project: CHandle, uri: &StorageUri, _options: u32) -> Result<()> { let target = parse_target(uri)?; - let path = sqlite_path_of(&target)?; + let key = db_key_of(&target); // Serialize under the project lock (the same per-node writer the // `.ove` backend uses — one serialization truth). let arc = unsafe { crate::nodeutil::project_arc(&project)? }; @@ -760,21 +788,19 @@ impl StorageBackend for DatabaseBackend { let (nodes, settings_xml, settings_map) = serialize_project_state(&guard)?; (uuid, name, nodes, settings_xml, settings_map) }; - self.run(path, move |conn| async move { + self.run(key, move |conn| async move { save_tx(&conn, &uuid, &name, &nodes, &settings_xml, &settings_map).await })?; Ok(()) } } -/// The SQLite path of a target, rejecting PG with E_NO_BACKEND (D3). -fn sqlite_path_of(target: &DbTarget) -> Result<&str> { - if target.is_pg() { - // D3: `oakdb+pg://` is parsed (see parse_target) but every - // operation refuses it until the PostgreSQL client is wired. - return Err(Error::NoBackend); +/// The connection-cache key of a target (SQLite path or PG conn string). +fn db_key_of(target: &DbTarget) -> DbKey { + match target { + DbTarget::Sqlite { path, .. } => DbKey::Sqlite(path.clone()), + DbTarget::Pg { conn, .. } => DbKey::Pg(conn.clone()), } - Ok(target.sqlite_path().expect("pg rejected above")) } /// Display name for a project on first entry: the `projectname` setting @@ -804,6 +830,34 @@ async fn connect_sqlite(path: &str) -> Result { Ok(DatabaseConnection::from(pool)) } +/// Open the PostgreSQL database at `conn` (a connection string body, +/// e.g. `user:pass@host:5432/db`; a scheme is prepended for sqlx). +/// +/// The server is first probed with a single, non-retrying connection +/// attempt: the pool retries refused connections with backoff for the +/// whole acquire timeout, which would hold a dead server for seconds. +/// A single `connect()` surfaces the refusal immediately, so a dead / +/// unreachable host fails fast with a clean E_IO. +async fn connect_pg(conn: &str) -> Result { + use std::str::FromStr; + use sea_orm::sqlx::postgres::{PgConnectOptions, PgPoolOptions}; + use sea_orm::sqlx::ConnectOptions; + let url = format!("postgres://{conn}"); + let options = PgConnectOptions::from_str(&url) + .map_err(|e| Error::Io(format!("invalid postgres connection string: {e}")))?; + options + .connect() + .await + .map_err(|e| Error::Io(format!("cannot connect to postgres database: {e}")))?; + let pool = PgPoolOptions::new() + .max_connections(1) + .acquire_timeout(Duration::from_secs(10)) + .connect_with(options) + .await + .map_err(|e| Error::Io(format!("cannot connect to postgres database: {e}")))?; + Ok(DatabaseConnection::from(pool)) +} + /// Whether an error is worth retrying (SQLite BUSY — plan §6 note in /// [`DatabaseBackend::run`]). fn retryable(e: &Error) -> bool { @@ -1450,7 +1504,7 @@ mod tests { } #[test] - fn parse_target_pg_kept_for_d3() { + fn parse_target_pg_conn_string() { let t = parse_target(&uri("oakdb+pg://user:pass@host:5432/db")).unwrap(); assert_eq!( t, @@ -1459,6 +1513,47 @@ mod tests { project: None } ); + // A `?project=` query is the row selector, not a conn param. + let t = parse_target(&uri("oakdb+pg://user@host/db?project={abc-123}")).unwrap(); + assert_eq!( + t, + DbTarget::Pg { + conn: "user@host/db".to_string(), + project: Some("{abc-123}".to_string()) + } + ); + // A query without a `project=` key belongs to the conn string + // (e.g. `?sslmode=disable` passes through untouched). + let t = parse_target(&uri("oakdb+pg://user@host/db?sslmode=disable")).unwrap(); + assert_eq!( + t, + DbTarget::Pg { + conn: "user@host/db?sslmode=disable".to_string(), + project: None + } + ); + } + + #[test] + fn parse_target_pg_invalid_rejected() { + // Empty / unparseable connection strings are E_INVALID (clean, no + // network touched), matching the sqlite relative-path rule. + assert!(matches!( + parse_target(&uri("oakdb+pg://")), + Err(Error::Invalid) + )); + assert!(matches!( + parse_target(&uri("oakdb+pg://?project={x}")), + Err(Error::Invalid) + )); + assert!(matches!( + parse_target(&uri("oakdb+pg://user@")), + Err(Error::Invalid) + )); + assert!(matches!( + parse_target(&uri("oakdb+pg://not a url")), + Err(Error::Invalid) + )); } #[test] diff --git a/crates/oakstorage/tests/common/mod.rs b/crates/oakstorage/tests/common/mod.rs new file mode 100644 index 000000000..b7d24385f --- /dev/null +++ b/crates/oakstorage/tests/common/mod.rs @@ -0,0 +1,525 @@ +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Shared fixtures and helpers for the database-backend integration +//! tests (plan M13 D1/D3). +//! +//! Everything here is dialect-agnostic: the test bodies run against a +//! `oakdb+sqlite://…` or `oakdb+pg://…` uri string, and the helpers that +//! inspect rows behind the backend's back open a raw sea-orm connection +//! ([`inspect_sqlite`] / [`inspect_pg`]). `tests/database_test.rs` runs +//! the SQLite suite; `tests/database_pg_test.rs` runs the same behaviors +//! against a real PostgreSQL server gated on `OAK_TEST_PG_URL`. + +// The module is compiled into two test binaries, each of which uses only +// the helpers for its own dialect, so the other dialect's helpers look +// dead to one binary while the other uses them. +#![allow(dead_code)] + +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; + +use sea_orm::entity::prelude::*; +use oakcore_rs::Rational; +use oaknode::block::ClipBlockBehavior; +use oaknode::footage::FootageBehavior; +use oaknode::id::NodeId; +use oaknode::keyframe::{Interpolation, Keyframe}; +use oaknode::node::NodeCore; +use oaknode::project::Project; +use oaknode::sequence::SequenceBehavior; +use oaknode::track::{TrackBehavior, TrackListBehavior, TrackType}; +use oaknode::value::NodeValue; +use oakstorage::backend::StorageBackend; +use oakstorage::backends::database::entities::settings; +use oakstorage::backends::database::DatabaseBackend; +use oakstorage::error::OAKSTORAGE_OK; +use oakstorage::handle::CHandle; +use oakstorage::nodeutil::{make_project_owned, project_arc}; +use oakstorage::uri::StorageUri; + +// --------------------------------------------------------------------------- +// URIs and paths +// --------------------------------------------------------------------------- + +/// A fresh, unique temp directory for one test. +pub(crate) fn temp_dir(tag: &str) -> PathBuf { + let dir = std::env::temp_dir().join(format!("oakstorage_db_{}_{}", std::process::id(), tag)); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + dir +} + +/// `oakdb+sqlite:///…` URI for a database file. +pub(crate) fn db_uri(path: &Path) -> String { + format!("oakdb+sqlite://{}", path.display()) +} + +/// `oakdb+sqlite:///…?project=` URI selecting one library row. +pub(crate) fn project_uri(db: &str, uuid: &str) -> String { + format!("{db}?project={uuid}") +} + +/// `file://…` URI for a plain file. +pub(crate) fn file_uri(path: &Path) -> String { + format!("file://{}", path.display()) +} + +// --------------------------------------------------------------------------- +// Save / load through the backend +// --------------------------------------------------------------------------- + +/// Release an owned handle (refcount 1). +pub(crate) fn release(h: CHandle) { + if let Some(release) = h.release { + unsafe { release(h.ctx) }; + } +} + +/// Save an `Arc>` through the database backend. +pub(crate) fn save_project( + backend: &DatabaseBackend, + project: &Arc>, + uri: &str, +) -> oakstorage::error::Result<()> { + let parsed = StorageUri::parse(uri).unwrap(); + let handle = make_project_owned(project.clone()); + let result = backend.save(handle, &parsed, 0); + release(handle); + result +} + +/// Load a project through a *new* database backend session (a fresh +/// connection pool = a fresh session), returning `(uuid, loaded)`. +pub(crate) fn load_project(backend: &DatabaseBackend, uri: &str) -> (String, Arc>) { + let parsed = StorageUri::parse(uri).unwrap(); + let result = backend.load(&parsed).unwrap(); + assert_eq!(result.version_info, OAKSTORAGE_OK); + let handle = result.project; + let loaded = unsafe { project_arc(&handle) }.unwrap(); + let uuid = loaded.lock().unwrap().uuid.clone(); + release(handle); + (uuid, loaded) +} + +/// Load the state at `seq` (undo to any point). +pub(crate) fn load_at(backend: &DatabaseBackend, uri: &str, uuid: &str, seq: i64) -> Arc> { + let parsed = StorageUri::parse(uri).unwrap(); + let handle = backend.load_at(&parsed, uuid, seq).unwrap(); + let loaded = unsafe { project_arc(&handle) }.unwrap(); + release(handle); + loaded +} + +pub(crate) fn r_to_f(r: Rational) -> f64 { + r.numerator() as f64 / r.denominator() as f64 +} + +pub(crate) fn assert_close(a: f64, b: f64) { + assert!((a - b).abs() < 1e-6, "expected {a} close to {b}"); +} + +// --------------------------------------------------------------------------- +// Row inspection (raw sea-orm connections behind the backend's back) +// --------------------------------------------------------------------------- + +/// Open a raw sea-orm SQLite connection to `path` and drive one future +/// against it on a private current-thread runtime. +pub(crate) fn inspect_sqlite(path: &Path, f: impl FnOnce(sea_orm::DatabaseConnection) -> Fut) -> R +where + Fut: std::future::Future, +{ + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + rt.block_on(async { + let options = sea_orm::sqlx::sqlite::SqliteConnectOptions::new() + .filename(path) + .create_if_missing(true) + .journal_mode(sea_orm::sqlx::sqlite::SqliteJournalMode::Wal) + .busy_timeout(Duration::from_secs(5)) + .foreign_keys(true); + let pool = sea_orm::sqlx::sqlite::SqlitePoolOptions::new() + .max_connections(1) + .connect_with(options) + .await + .unwrap(); + f(sea_orm::DatabaseConnection::from(pool)).await + }) +} + +/// Open a raw sea-orm PostgreSQL connection to `url` and drive one +/// future against it on a private current-thread runtime. +pub(crate) fn inspect_pg(url: &str, f: impl FnOnce(sea_orm::DatabaseConnection) -> Fut) -> R +where + Fut: std::future::Future, +{ + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + rt.block_on(async { + let pool = sea_orm::sqlx::postgres::PgPoolOptions::new() + .max_connections(1) + .connect(url) + .await + .unwrap(); + f(sea_orm::DatabaseConnection::from(pool)).await + }) +} + +/// The settings mirror rows of a project (SQLite). +pub(crate) fn settings_rows(path: &Path, project_id: i64) -> Vec<(String, String)> { + inspect_sqlite(path, |conn| async move { + settings::Entity::find() + .filter(settings::Column::ProjectId.eq(project_id)) + .all(&conn) + .await + .unwrap() + .into_iter() + .map(|s| (s.key, s.value)) + .collect() + }) +} + +/// The settings mirror rows of a project (PostgreSQL). +pub(crate) fn settings_rows_pg(url: &str, project_id: i64) -> Vec<(String, String)> { + inspect_pg(url, |conn| async move { + settings::Entity::find() + .filter(settings::Column::ProjectId.eq(project_id)) + .all(&conn) + .await + .unwrap() + .into_iter() + .map(|s| (s.key, s.value)) + .collect() + }) +} + +/// The project uuid. +pub(crate) fn uuid_of(project: &Arc>) -> String { + project.lock().unwrap().uuid.clone() +} + +/// Read a config value for the duration of a test (the config store is +/// process-global, so restore it afterwards). +pub(crate) fn with_config(group: &str, key: &str, value: i32, f: impl FnOnce()) { + let store = oakcommon::configstore::ConfigStore::instance(); + let before = store.get_int(Some(group), key, 0); + store.set_int(Some(group), key, value); + f(); + store.set_int(Some(group), key, before); +} + +// --------------------------------------------------------------------------- +// Full-feature fixture (footage / sequence / track / clip / effect / +// keyframes) — the union of the ove round-trip and timeline fixtures. +// --------------------------------------------------------------------------- + +pub(crate) const MATH: &str = "org.olivevideoeditor.Olive.math"; + +/// Build the round-trip fixture: root folder + two math nodes with +/// values/keyframes/label/color/link/connection + a sequence "My Seq" +/// with one video track carrying two clips (footage /a/b.mp4, /a/c.mp4). +pub(crate) fn build_full_project() -> Arc> { + let project = Project::new(); + let mut p = project.lock().unwrap(); + p.initialize().unwrap(); + + let (core, behavior) = (oaknode::factory::Factory::global().find(MATH).unwrap().create)(); + let a = p.graph.add_node(core, behavior); + { + let e = p.graph.get_mut(a).unwrap(); + e.core.label = "Math A".to_string(); + e.core.override_color = 2; + e.core.set_standard_value("param_a_in", -1, NodeValue::Float(2.5)); + e.core + .keyframe_track_mut("param_a_in", -1) + .set_key(Keyframe { + time: Rational::new(0, 1), + value: NodeValue::Float(1.0), + interpolation: Interpolation::Linear, + bezier_in: (0.0, 0.0), + bezier_out: (0.0, 0.0), + }); + e.core + .keyframe_track_mut("param_a_in", -1) + .set_key(Keyframe { + time: Rational::new(1, 1), + value: NodeValue::Float(3.0), + interpolation: Interpolation::Bezier, + bezier_in: (0.1, 0.2), + bezier_out: (0.3, 0.4), + }); + } + let (core, behavior) = (oaknode::factory::Factory::global().find(MATH).unwrap().create)(); + let b = p.graph.add_node(core, behavior); + p.graph + .get_mut(b) + .unwrap() + .core + .set_standard_value("param_a_in", -1, NodeValue::Float(4.0)); + p.graph.connect(a, b, "param_b_in", -1).unwrap(); + p.graph.link(a, b); + + // Timeline: sequence + video track + two clips with footage. + let (seq_id, lists) = oakstorage::nodeutil::create_sequence(&mut p.graph); + p.graph.get_mut(seq_id).unwrap().core.label = "My Seq".to_string(); + + let mut tb = TrackBehavior::new(TrackType::Video); + tb.track_list = Some(lists[0]); + let track_id = p.graph.add_node(NodeCore::new(), Box::new(tb)); + + let foot1 = p + .graph + .add_node(NodeCore::new(), Box::new(FootageBehavior::new("/a/b.mp4"))); + let clip1 = { + let (core, mut behavior) = oaknode::block::clip_create(); + let clip = behavior + .as_any_mut() + .and_then(|a| a.downcast_mut::()) + .unwrap(); + clip.core.range = oakcore_rs::TimeRange::new(Rational::new(0, 1), Rational::new(100, 25)); + clip.core.media_in = Rational::new(0, 1); + clip.core.track = Some(track_id); + clip.footage = Some(foot1); + p.graph.add_node(core, behavior) + }; + + let foot2 = p + .graph + .add_node(NodeCore::new(), Box::new(FootageBehavior::new("/a/c.mp4"))); + let clip2 = { + let (core, mut behavior) = oaknode::block::clip_create(); + let clip = behavior + .as_any_mut() + .and_then(|a| a.downcast_mut::()) + .unwrap(); + clip.core.range = + oakcore_rs::TimeRange::new(Rational::new(100, 25), Rational::new(150, 25)); + clip.core.media_in = Rational::new(10, 25); + clip.core.track = Some(track_id); + clip.footage = Some(foot2); + p.graph.add_node(core, behavior) + }; + + if let Some(entry) = p.graph.get_mut(track_id) { + entry + .behavior + .as_any_mut() + .and_then(|a| a.downcast_mut::()) + .unwrap() + .blocks = vec![clip1, clip2]; + } + if let Some(entry) = p.graph.get_mut(lists[0]) { + entry + .behavior + .as_any_mut() + .and_then(|a| a.downcast_mut::()) + .unwrap() + .tracks = vec![track_id]; + } + + p.settings + .insert("projectname".to_string(), "full-fixture".to_string()); + drop(p); + project +} + +/// Field-by-field comparison of the full fixture after a round-trip +/// (uuid included). +pub(crate) fn assert_full_fields(orig: &Project, loaded: &Project) { + assert_eq!(loaded.uuid, orig.uuid, "uuid"); + assert_full_state(orig, loaded); +} + +/// Field-by-field comparison that ignores the uuid (a duplicated row +/// carries a fresh uuid by design). +pub(crate) fn assert_full_state(orig: &Project, loaded: &Project) { + assert_eq!(loaded.settings, orig.settings, "settings"); + + // Node set: count, type order (slot order preserved by the writer). + let o_ids = orig.graph.node_ids(); + let l_ids = loaded.graph.node_ids(); + assert_eq!(l_ids.len(), o_ids.len(), "node count"); + let o_types: Vec<&str> = o_ids + .iter() + .map(|id| orig.graph.get(*id).unwrap().behavior.type_id()) + .collect(); + let l_types: Vec<&str> = l_ids + .iter() + .map(|id| loaded.graph.get(*id).unwrap().behavior.type_id()) + .collect(); + assert_eq!(l_types, o_types, "node types"); + + // Math A: label, color, value, keyframes. + let (a_o, a_l) = (o_ids[1], l_ids[1]); + assert_eq!( + loaded.graph.get(a_l).unwrap().core.label, + orig.graph.get(a_o).unwrap().core.label, + "label" + ); + assert_eq!( + loaded.graph.get(a_l).unwrap().core.override_color, + orig.graph.get(a_o).unwrap().core.override_color, + "color" + ); + assert_eq!( + loaded + .graph + .get(a_l) + .unwrap() + .core + .standard_value("param_a_in", -1), + orig.graph + .get(a_o) + .unwrap() + .core + .standard_value("param_a_in", -1), + "value a" + ); + let keys_o = orig + .graph + .get(a_o) + .unwrap() + .core + .keyframe_track("param_a_in", -1) + .unwrap() + .keys() + .to_vec(); + let keys_l = loaded + .graph + .get(a_l) + .unwrap() + .core + .keyframe_track("param_a_in", -1) + .unwrap() + .keys() + .to_vec(); + assert_eq!(keys_l.len(), keys_o.len(), "keyframe count"); + for (ko, kl) in keys_o.iter().zip(&keys_l) { + assert_eq!(kl.time, ko.time, "key time"); + assert_eq!(kl.value.to_double(), ko.value.to_double(), "key value"); + assert_eq!(kl.interpolation, ko.interpolation, "key interpolation"); + assert_eq!(kl.bezier_in, ko.bezier_in, "key bezier in"); + assert_eq!(kl.bezier_out, ko.bezier_out, "key bezier out"); + } + + // Connection a -> b.param_b_in and the link. + assert_eq!( + loaded.graph.connected_output(l_ids[2], "param_b_in", -1), + Some(a_l), + "connection" + ); + assert!(loaded.graph.are_linked(a_l, l_ids[2]), "link"); + + // Timeline: sequence, track lists, track, clips, footage. + let mut seq: Option<(NodeId, Vec)> = None; + for id in loaded.graph.node_ids() { + let entry = loaded.graph.get(id).unwrap(); + if entry.behavior.type_id() == "org.olivevideoeditor.Olive.sequence" { + let s = entry + .behavior + .as_any() + .and_then(|a| a.downcast_ref::()) + .unwrap(); + seq = Some((id, s.track_lists.clone())); + break; + } + } + let (_seq_id, lists) = seq.expect("sequence present"); + assert_eq!(lists.len(), 3, "video/audio/subtitle lists"); + let list = loaded + .graph + .get(lists[0]) + .unwrap() + .behavior + .as_any() + .and_then(|a| a.downcast_ref::()) + .unwrap(); + assert_eq!(list.kind, TrackType::Video); + assert_eq!(list.array_base, 0); + assert_eq!(list.tracks.len(), 1); + let track = loaded + .graph + .get(list.tracks[0]) + .unwrap() + .behavior + .as_any() + .and_then(|a| a.downcast_ref::()) + .unwrap(); + assert_eq!(track.kind, TrackType::Video); + assert_eq!(track.blocks.len(), 2); + let c1 = loaded + .graph + .get(track.blocks[0]) + .unwrap() + .behavior + .as_any() + .and_then(|a| a.downcast_ref::()) + .unwrap(); + assert_close(r_to_f(c1.core.length()), 4.0); + assert_close(r_to_f(c1.core.media_in), 0.0); + let f1 = loaded + .graph + .get(c1.footage.unwrap()) + .unwrap() + .behavior + .as_any() + .and_then(|a| a.downcast_ref::()) + .unwrap(); + assert_eq!(f1.filename, "/a/b.mp4"); + let c2 = loaded + .graph + .get(track.blocks[1]) + .unwrap() + .behavior + .as_any() + .and_then(|a| a.downcast_ref::()) + .unwrap(); + assert_close(r_to_f(c2.core.length()), 2.0); + assert_close(r_to_f(c2.core.media_in), 0.4); + let f2 = loaded + .graph + .get(c2.footage.unwrap()) + .unwrap() + .behavior + .as_any() + .and_then(|a| a.downcast_ref::()) + .unwrap(); + assert_eq!(f2.filename, "/a/c.mp4"); +} + +/// Build a small project with a `projectname` setting (fast saves). +pub(crate) fn build_named_project(name: &str) -> Arc> { + let project = Project::new(); + { + let mut p = project.lock().unwrap(); + p.initialize().unwrap(); + p.settings.insert("projectname".to_string(), name.to_string()); + } + project +} + +/// Save a fresh named project, returning its uuid. +pub(crate) fn save_named_project(backend: &DatabaseBackend, uri: &str, name: &str) -> String { + let project = build_named_project(name); + let uuid = uuid_of(&project); + save_project(backend, &project, uri).unwrap(); + uuid +} diff --git a/crates/oakstorage/tests/database_pg_test.rs b/crates/oakstorage/tests/database_pg_test.rs new file mode 100644 index 000000000..38437e51a --- /dev/null +++ b/crates/oakstorage/tests/database_pg_test.rs @@ -0,0 +1,996 @@ +// Oak Video Editor - Non-Linear Video Editor +// Copyright (C) 2026 Oak Team +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! PostgreSQL variants of the database-backend integration tests (plan +//! M13 D3): the same behaviors `database_test.rs` runs against SQLite, +//! driven by the shared fixtures in `tests/common/mod.rs`, against a +//! real PostgreSQL server. +//! +//! Gating: when `OAK_TEST_PG_URL` (a libpq URL such as +//! `postgres://user:pass@host:5432/db`) is set, every test connects to +//! that server and runs for real; when it is absent the tests skip with +//! a note on stderr, so `cargo test -p oakstorage` is green without a +//! PostgreSQL server (CI included). The URL should point at a dedicated +//! test database: each test resets the four schema tables (DROP + the +//! migration recreates them on connect), and the tests run serialized +//! against the shared database. + +mod common; + +use std::sync::Mutex; + +use sea_orm::entity::prelude::*; +use sea_orm::{ConnectionTrait, QueryOrder}; +use oaknode::id::NodeId; +use oaknode::value::NodeValue; +use oakstorage::backend::StorageBackend; +use oakstorage::backends::database::entities::{journal, project, snapshot}; +use oakstorage::backends::database::{ + derive_stats, DatabaseBackend, KIND_IMPORT, KIND_REDO, ProjectStats, SNAPSHOT_KEEP, +}; +use oakstorage::error::{ + OAKSTORAGE_E_FORMAT, OAKSTORAGE_E_INVALID, OAKSTORAGE_E_NOT_FOUND, OAKSTORAGE_OK, +}; +use oakstorage::nodeutil::project_arc; +use oakstorage::registry::Registry; +use oakstorage::uri::StorageUri; + +use common::*; + +// --------------------------------------------------------------------------- +// Gating and isolation +// --------------------------------------------------------------------------- + +/// The `OAK_TEST_PG_URL` connection string (None when not configured). +fn pg_url() -> Option { + std::env::var("OAK_TEST_PG_URL") + .ok() + .filter(|s| !s.trim().is_empty()) +} + +/// Strip the `postgres://` / `postgresql://` scheme from a connection +/// URL to get the `oakdb+pg://` uri body. +fn pg_body(url: &str) -> &str { + url.strip_prefix("postgres://") + .or_else(|| url.strip_prefix("postgresql://")) + .unwrap_or(url) +} + +/// Reset the four schema tables (the migration recreates them on the +/// next connection). Serialized with the other PG tests. +fn reset_tables(url: &str) { + inspect_pg(url, |conn| async move { + for table in ["journal", "snapshots", "settings", "projects"] { + conn.execute_raw(sea_orm::Statement::from_string( + sea_orm::DatabaseBackend::Postgres, + format!("DROP TABLE IF EXISTS {table} CASCADE"), + )) + .await + .unwrap(); + } + }); +} + +/// Run `f` with `(pg_url, oakdb+pg uri)` for an isolated test session. +/// Skips (with a note) when `OAK_TEST_PG_URL` is absent; otherwise the +/// tables are reset and the test runs against the shared database (the +/// tests share one server and one schema, so they run one at a time). +fn with_pg_uri(tag: &str, f: impl FnOnce(&str, &str)) { + let Some(url) = pg_url() else { + eprintln!("OAK_TEST_PG_URL is not set — skipping the PostgreSQL variant of '{tag}'"); + return; + }; + static PG_LOCK: Mutex<()> = Mutex::new(()); + let _g = PG_LOCK.lock().unwrap_or_else(|e| e.into_inner()); + reset_tables(&url); + let uri = format!("oakdb+pg://{}", pg_body(&url)); + f(&url, &uri); +} + +// --------------------------------------------------------------------------- +// Round-trip through a fresh session +// --------------------------------------------------------------------------- + +#[test] +fn pg_roundtrip_field_by_field() { + with_pg_uri("roundtrip_field_by_field", |url, uri| { + let backend = DatabaseBackend::new(); + + let project = build_full_project(); + let uuid = uuid_of(&project); + save_project(&backend, &project, uri).unwrap(); + + // A new backend instance = a new session; the library row is + // selected explicitly by uuid. + let session = DatabaseBackend::new(); + let (loaded_uuid, loaded) = load_project(&session, &project_uri(uri, &uuid)); + assert_eq!(loaded_uuid, uuid); + { + let o = project.lock().unwrap(); + let l = loaded.lock().unwrap(); + assert_full_fields(&o, &l); + } + + // The default (no ?project=) pick returns the same single row. + let session = DatabaseBackend::new(); + let (loaded_uuid, _) = load_project(&session, uri); + assert_eq!(loaded_uuid, uuid); + + // The settings mirror carries the current keys. + let uuid_c = uuid.clone(); + let row = inspect_pg(url, move |conn| async move { + project::Entity::find() + .filter(project::Column::Uuid.eq(&uuid_c)) + .one(&conn) + .await + .unwrap() + .unwrap() + .id + }); + let mirrored = settings_rows_pg(url, row); + assert!( + mirrored.contains(&("projectname".to_string(), "full-fixture".to_string())), + "{mirrored:?}" + ); + }); +} + +// --------------------------------------------------------------------------- +// Journal semantics: import, diff, no-op save +// --------------------------------------------------------------------------- + +/// First save is one `kind='import'` command carrying every node plus +/// the settings pseudo-node (plan §2); the project row advances to seq 1. +#[test] +fn pg_first_save_is_an_import_command() { + with_pg_uri("first_save_is_an_import_command", |url, uri| { + let backend = DatabaseBackend::new(); + + let project = build_full_project(); + let uuid = uuid_of(&project); + let node_count = project.lock().unwrap().graph.node_count(); + save_project(&backend, &project, uri).unwrap(); + + let uuid_c = uuid.clone(); + let rows = inspect_pg(url, move |conn| async move { + let proj = project::Entity::find() + .filter(project::Column::Uuid.eq(&uuid_c)) + .one(&conn) + .await + .unwrap() + .unwrap(); + let rows = journal::Entity::find() + .filter(journal::Column::ProjectId.eq(proj.id)) + .order_by_asc(journal::Column::Seq) + .order_by_asc(journal::Column::NodeIdentity) + .all(&conn) + .await + .unwrap(); + (proj.id, proj.command_seq, rows) + }); + let (pid, command_seq, rows) = rows; + assert_eq!(command_seq, 1); + assert_eq!( + rows.len(), + node_count + 1, + "every node + the settings pseudo-node" + ); + assert!(rows.iter().all(|r| r.seq == 1 && r.kind == KIND_IMPORT), "one import command"); + assert!(rows.iter().all(|r| r.old_xml.is_none()), "import has no before images"); + assert!(rows.iter().all(|r| r.new_xml.is_some()), "import has after images"); + // The settings pseudo-node (identity 0) is present. + assert!(rows.iter().any(|r| r.node_identity == 0), "settings row present"); + assert_eq!( + rows.iter().filter(|r| r.node_identity == 0).count(), + 1, + "exactly one settings row" + ); + // The real-node rows use the +1 offset (settings 0 reserved). + assert!(rows.iter().all(|r| r.node_identity >= 1 || r.node_identity == 0)); + // The node fragments round-trip: the settings row holds the settings + // element. + let settings_row = rows.iter().find(|r| r.node_identity == 0).unwrap(); + assert!(settings_row.new_xml.as_deref().unwrap().starts_with("")); + let _ = pid; + }); +} + +/// A later save is a diff: only the changed nodes land as `kind='redo'` +/// rows with both before and after images (plan §0). +#[test] +fn pg_later_saves_are_diffs() { + with_pg_uri("later_saves_are_diffs", |url, uri| { + let backend = DatabaseBackend::new(); + + let project = build_full_project(); + let uuid = uuid_of(&project); + save_project(&backend, &project, uri).unwrap(); + + // Change one math node's value and one setting key. + { + let mut p = project.lock().unwrap(); + let math_ids: Vec = p + .graph + .node_ids() + .into_iter() + .filter(|id| p.graph.get(*id).unwrap().behavior.type_id() == MATH) + .collect(); + let a = math_ids[0]; + p.graph + .get_mut(a) + .unwrap() + .core + .set_standard_value("param_a_in", -1, NodeValue::Float(9.5)); + p.settings.insert("projectname".to_string(), "diffed".to_string()); + } + save_project(&backend, &project, uri).unwrap(); + + let uuid_c = uuid.clone(); + let rows = inspect_pg(url, move |conn| async move { + let proj = project::Entity::find() + .filter(project::Column::Uuid.eq(&uuid_c)) + .one(&conn) + .await + .unwrap() + .unwrap(); + let rows = journal::Entity::find() + .filter(journal::Column::ProjectId.eq(proj.id)) + .all(&conn) + .await + .unwrap(); + (proj.id, proj.command_seq, rows) + }); + let (pid, command_seq, rows) = rows; + assert_eq!(command_seq, 2); + let seq2: Vec<&journal::Model> = rows.iter().filter(|r| r.seq == 2).collect(); + assert_eq!(seq2.len(), 2, "one changed node + the settings row, nothing else"); + assert!(seq2.iter().all(|r| r.kind == KIND_REDO)); + assert!( + seq2.iter().all(|r| r.old_xml.is_some() && r.new_xml.is_some()), + "diff carries both images" + ); + let settings_row = seq2.iter().find(|r| r.node_identity == 0).unwrap(); + assert!(settings_row.new_xml.as_deref().unwrap().contains(">diffed<")); + let _ = pid; + + // Head state after the diff reflects both changes. + let session = DatabaseBackend::new(); + let (_, loaded) = load_project(&session, &project_uri(uri, &uuid)); + { + let l = loaded.lock().unwrap(); + let math_ids: Vec = l + .graph + .node_ids() + .into_iter() + .filter(|id| l.graph.get(*id).unwrap().behavior.type_id() == MATH) + .collect(); + assert_eq!( + l.graph.get(math_ids[0]).unwrap().core.standard_value("param_a_in", -1), + NodeValue::Float(9.5) + ); + assert_eq!( + l.settings.get("projectname").cloned(), + Some("diffed".to_string()) + ); + } + }); +} + +/// A save that changes nothing bumps no command seq and writes no rows. +#[test] +fn pg_no_op_save_is_a_touch_only() { + with_pg_uri("no_op_save_is_a_touch_only", |url, uri| { + let backend = DatabaseBackend::new(); + + let project = build_full_project(); + let uuid = uuid_of(&project); + save_project(&backend, &project, uri).unwrap(); + save_project(&backend, &project, uri).unwrap(); + + let uuid_c = uuid.clone(); + let (head, count) = inspect_pg(url, move |conn| async move { + let proj = project::Entity::find() + .filter(project::Column::Uuid.eq(&uuid_c)) + .one(&conn) + .await + .unwrap() + .unwrap(); + let n = journal::Entity::find() + .filter(journal::Column::ProjectId.eq(proj.id)) + .count(&conn) + .await + .unwrap(); + (proj.command_seq, n) + }); + assert_eq!(head, 1, "no-op save keeps the head seq"); + // The import wrote 12 nodes + 1 settings row; the no-op added none. + assert_eq!(count, 13, "only the import rows remain"); + }); +} + +// --------------------------------------------------------------------------- +// Snapshot + journal replay and undo to any point +// --------------------------------------------------------------------------- + +/// With `Storage/SnapshotIntervalSec` ≤ 0 every dirty save writes a +/// snapshot; the newest snapshot is the replay base and the journal rows +/// after it are applied on top. Deleting every snapshot still recovers +/// the same state from an empty base plus the full journal (plan §0). +#[test] +fn pg_snapshot_and_journal_replay() { + with_pg_uri("snapshot_and_journal_replay", |url, uri| { + let backend = DatabaseBackend::new(); + + with_config("Storage", "SnapshotIntervalSec", 0, || { + let project = build_full_project(); + let uuid = uuid_of(&project); + save_project(&backend, &project, uri).unwrap(); + // Second command: one value change. + { + let mut p = project.lock().unwrap(); + let math_ids: Vec = p + .graph + .node_ids() + .into_iter() + .filter(|id| p.graph.get(*id).unwrap().behavior.type_id() == MATH) + .collect(); + p.graph + .get_mut(math_ids[0]) + .unwrap() + .core + .set_standard_value("param_a_in", -1, NodeValue::Float(7.25)); + } + save_project(&backend, &project, uri).unwrap(); + + // Both saves produced snapshots (head seq 2). + let uuid_c = uuid.clone(); + let snaps = inspect_pg(url, move |conn| async move { + let proj = project::Entity::find() + .filter(project::Column::Uuid.eq(&uuid_c)) + .one(&conn) + .await + .unwrap() + .unwrap(); + snapshot::Entity::find() + .filter(snapshot::Column::ProjectId.eq(proj.id)) + .all(&conn) + .await + .unwrap() + }); + assert_eq!(snaps.len(), 2, "one snapshot per dirty save"); + + // Load (head): snapshot seq 2 is the base, nothing after it. + let session = DatabaseBackend::new(); + let (_, loaded) = load_project(&session, &project_uri(uri, &uuid)); + { + let o = project.lock().unwrap(); + let l = loaded.lock().unwrap(); + assert_full_fields(&o, &l); + } + + // Destroy the snapshots: replay degrades to empty base + full + // journal and still reconstructs the head. + let uuid_c = uuid.clone(); + inspect_pg(url, move |conn| async move { + let proj = project::Entity::find() + .filter(project::Column::Uuid.eq(&uuid_c)) + .one(&conn) + .await + .unwrap() + .unwrap(); + snapshot::Entity::delete_many() + .filter(snapshot::Column::ProjectId.eq(proj.id)) + .exec(&conn) + .await + .unwrap(); + }); + let session = DatabaseBackend::new(); + let (_, loaded) = load_project(&session, &project_uri(uri, &uuid)); + { + let o = project.lock().unwrap(); + let l = loaded.lock().unwrap(); + assert_full_fields(&o, &l); + } + }); + }); +} + +/// The journal is the persistent undo history: `load_at(seq)` replays to +/// any point (plan §0 "撤销到任意点"). +#[test] +fn pg_undo_to_any_point() { + with_pg_uri("undo_to_any_point", |_url, uri| { + let backend = DatabaseBackend::new(); + + let project = build_full_project(); + let uuid = uuid_of(&project); + let math_a = { + let p = project.lock().unwrap(); + p.graph + .node_ids() + .into_iter() + .find(|id| p.graph.get(*id).unwrap().behavior.type_id() == MATH) + .unwrap() + }; + // Command 1: value 2.5 (fixture default). + save_project(&backend, &project, uri).unwrap(); + // Command 2: value 6.0. + { + let mut p = project.lock().unwrap(); + p.graph + .get_mut(math_a) + .unwrap() + .core + .set_standard_value("param_a_in", -1, NodeValue::Float(6.0)); + } + save_project(&backend, &project, uri).unwrap(); + // Command 3: add a node. + let (new_id, value) = { + let mut p = project.lock().unwrap(); + let (core, behavior) = (oaknode::factory::Factory::global().find(MATH).unwrap().create)(); + let id = p.graph.add_node(core, behavior); + p.graph + .get_mut(id) + .unwrap() + .core + .set_standard_value("param_a_in", -1, NodeValue::Float(11.0)); + let v = p + .graph + .get(id) + .unwrap() + .core + .standard_value("param_a_in", -1); + (id, v) + }; + save_project(&backend, &project, uri).unwrap(); + + // Head (seq 3): the extra node exists. + let session = DatabaseBackend::new(); + let (_, head) = load_project(&session, &project_uri(uri, &uuid)); + { + let h = head.lock().unwrap(); + assert!(h.graph.is_valid(new_id), "node added in command 3 is live"); + assert_eq!( + h.graph.get(new_id).unwrap().core.standard_value("param_a_in", -1), + value + ); + } + + // Undo to seq 2: the node is gone, the value is 6.0. + let session = DatabaseBackend::new(); + let at2 = load_at(&session, uri, &uuid, 2); + { + let l = at2.lock().unwrap(); + assert!(!l.graph.is_valid(new_id), "command 3 rolled back"); + let id = l + .graph + .node_ids() + .into_iter() + .find(|id| l.graph.get(*id).unwrap().behavior.type_id() == MATH) + .unwrap(); + assert_eq!( + l.graph.get(id).unwrap().core.standard_value("param_a_in", -1), + NodeValue::Float(6.0) + ); + } + + // Undo to seq 1: the value is back to the fixture default. + let session = DatabaseBackend::new(); + let at1 = load_at(&session, uri, &uuid, 1); + { + let l = at1.lock().unwrap(); + assert_eq!(l.graph.node_count(), 12, "fixture node count"); + let id = l + .graph + .node_ids() + .into_iter() + .find(|id| l.graph.get(*id).unwrap().behavior.type_id() == MATH) + .unwrap(); + assert_eq!( + l.graph.get(id).unwrap().core.standard_value("param_a_in", -1), + NodeValue::Float(2.5) + ); + } + + // Undo to seq 0: an empty project. + let session = DatabaseBackend::new(); + let at0 = load_at(&session, uri, &uuid, 0); + { + let l = at0.lock().unwrap(); + assert_eq!(l.graph.node_count(), 0, "empty project at seq 0"); + } + + // Out of range -> E_INVALID. + let session = DatabaseBackend::new(); + assert_eq!( + session + .load_at(&StorageUri::parse(uri).unwrap(), &uuid, 99) + .err() + .unwrap() + .code(), + OAKSTORAGE_E_INVALID + ); + }); +} + +/// Snapshot pruning keeps the newest [`SNAPSHOT_KEEP`] copies. +#[test] +fn pg_snapshot_pruning_keeps_three() { + with_pg_uri("snapshot_pruning_keeps_three", |url, uri| { + let backend = DatabaseBackend::new(); + + with_config("Storage", "SnapshotIntervalSec", 0, || { + let project = build_full_project(); + let uuid = uuid_of(&project); + // 6 commands, each dirty-snapshotted. + for i in 0..6i64 { + { + let mut p = project.lock().unwrap(); + let id = p.graph.node_ids()[0]; + p.graph.get_mut(id).unwrap().core.label = format!("step {i}"); + } + save_project(&backend, &project, uri).unwrap(); + } + let uuid_c = uuid.clone(); + let seqs = inspect_pg(url, move |conn| async move { + let proj = project::Entity::find() + .filter(project::Column::Uuid.eq(&uuid_c)) + .one(&conn) + .await + .unwrap() + .unwrap(); + snapshot::Entity::find() + .filter(snapshot::Column::ProjectId.eq(proj.id)) + .order_by_desc(snapshot::Column::CommandSeq) + .all(&conn) + .await + .unwrap() + .into_iter() + .map(|s| s.command_seq) + .collect::>() + }); + assert_eq!(seqs.len() as u64, SNAPSHOT_KEEP, "only the newest {SNAPSHOT_KEEP}"); + assert_eq!(seqs[0], 6, "the newest survives"); + }); + }); +} + +/// Journal retention (`Storage/JournalRetentionDays`): rows older than +/// the window and covered by the newest snapshot are dropped; the head +/// stays reconstructible (snapshot + remaining rows). +#[test] +fn pg_journal_retention_truncation() { + with_pg_uri("journal_retention_truncation", |url, uri| { + let backend = DatabaseBackend::new(); + + let project = build_full_project(); + let uuid = uuid_of(&project); + // Command 1 (import) + command 2 (a value change). + save_project(&backend, &project, uri).unwrap(); + { + let mut p = project.lock().unwrap(); + let math_ids: Vec = p + .graph + .node_ids() + .into_iter() + .filter(|id| p.graph.get(*id).unwrap().behavior.type_id() == MATH) + .collect(); + p.graph + .get_mut(math_ids[0]) + .unwrap() + .core + .set_standard_value("param_a_in", -1, NodeValue::Float(3.25)); + } + save_project(&backend, &project, uri).unwrap(); + // Snapshot at the head so rows ≤ 2 are covered. + backend + .snapshot(&StorageUri::parse(uri).unwrap(), &uuid) + .unwrap(); + + // Backdate every journal row two days, then save a third command + // with a 1-day retention window. + inspect_pg(url, |conn| async move { + let old = chrono::Utc::now().naive_utc() - chrono::Duration::days(2); + journal::Entity::update_many() + .col_expr(journal::Column::At, sea_orm::sea_query::Expr::value(old)) + .exec(&conn) + .await + .unwrap(); + }); + with_config("Storage", "JournalRetentionDays", 1, || { + { + let mut p = project.lock().unwrap(); + let math_ids: Vec = p + .graph + .node_ids() + .into_iter() + .filter(|id| p.graph.get(*id).unwrap().behavior.type_id() == MATH) + .collect(); + p.graph + .get_mut(math_ids[0]) + .unwrap() + .core + .set_standard_value("param_a_in", -1, NodeValue::Float(4.5)); + } + save_project(&backend, &project, uri).unwrap(); + }); + + // Only the third command's rows survive. + let uuid_c = uuid.clone(); + let (pid, rows) = inspect_pg(url, move |conn| async move { + let proj = project::Entity::find() + .filter(project::Column::Uuid.eq(&uuid_c)) + .one(&conn) + .await + .unwrap() + .unwrap(); + let rows = journal::Entity::find() + .filter(journal::Column::ProjectId.eq(proj.id)) + .all(&conn) + .await + .unwrap(); + (proj.id, rows) + }); + let seqs: Vec = rows.iter().map(|r| r.seq).collect(); + assert!(!seqs.contains(&1) && !seqs.contains(&2), "old commands pruned: {seqs:?}"); + assert_eq!(seqs, vec![3], "only the fresh command remains"); + let _ = pid; + + // The head state is still correct (snapshot at seq 2 + command 3). + let session = DatabaseBackend::new(); + let (_, loaded) = load_project(&session, &project_uri(uri, &uuid)); + { + let l = loaded.lock().unwrap(); + let math_ids: Vec = l + .graph + .node_ids() + .into_iter() + .filter(|id| l.graph.get(*id).unwrap().behavior.type_id() == MATH) + .collect(); + assert_eq!( + l.graph.get(math_ids[0]).unwrap().core.standard_value("param_a_in", -1), + NodeValue::Float(4.5) + ); + assert_eq!(l.graph.node_count(), 12); + } + }); +} + +// --------------------------------------------------------------------------- +// Project-manager API surface +// --------------------------------------------------------------------------- + +#[test] +fn pg_list_delete_duplicate_rename() { + with_pg_uri("list_delete_duplicate_rename", |_url, uri| { + let backend = DatabaseBackend::new(); + + // Empty library lists nothing. + assert!(backend.list_projects(&StorageUri::parse(uri).unwrap()).unwrap().is_empty()); + + let alpha = save_named_project(&backend, uri, "Alpha"); + let beta = save_named_project(&backend, uri, "Beta"); + + let list = backend.list_projects(&StorageUri::parse(uri).unwrap()).unwrap(); + assert_eq!(list.len(), 2, "two rows"); + // Most recently modified first. + assert_eq!(list[0].name, "Beta"); + assert_eq!(list[1].name, "Alpha"); + assert_eq!(list[0].command_seq, 1); + assert_eq!(list[0].schema_ver, oaknode::serializer::CURRENT_VERSION.0 as i32); + + // Rename (library metadata). + backend + .rename_project(&StorageUri::parse(uri).unwrap(), &alpha, "Alpha Renamed") + .unwrap(); + let list = backend.list_projects(&StorageUri::parse(uri).unwrap()).unwrap(); + assert!(list.iter().any(|p| p.name == "Alpha Renamed"), "{list:?}"); + assert_eq!( + backend + .rename_project(&StorageUri::parse(uri).unwrap(), "{missing}", "X") + .err() + .unwrap() + .code(), + OAKSTORAGE_E_NOT_FOUND + ); + + // Duplicate: fresh uuid, default "(copy)" name, history copied. + let copy = backend + .duplicate_project(&StorageUri::parse(uri).unwrap(), &beta, None) + .unwrap(); + assert_ne!(copy.uuid, beta, "fresh uuid"); + assert_eq!(copy.name, "Beta (copy)"); + assert_eq!(copy.command_seq, 1); + let list = backend.list_projects(&StorageUri::parse(uri).unwrap()).unwrap(); + assert_eq!(list.len(), 3); + let renamed_copy = backend + .duplicate_project(&StorageUri::parse(uri).unwrap(), &beta, Some("Beta Clone")) + .unwrap(); + assert_eq!(renamed_copy.name, "Beta Clone"); + assert_eq!( + backend + .duplicate_project(&StorageUri::parse(uri).unwrap(), "{missing}", None) + .err() + .unwrap() + .code(), + OAKSTORAGE_E_NOT_FOUND + ); + + // Delete. + for uuid in [&alpha, &beta, ©.uuid, &renamed_copy.uuid] { + backend + .delete_project(&StorageUri::parse(uri).unwrap(), uuid) + .unwrap(); + } + assert!(backend.list_projects(&StorageUri::parse(uri).unwrap()).unwrap().is_empty()); + assert_eq!( + backend + .delete_project(&StorageUri::parse(uri).unwrap(), "{missing}") + .err() + .unwrap() + .code(), + OAKSTORAGE_E_NOT_FOUND + ); + }); +} + +/// Duplicating a full-feature project copies the whole history: the copy +/// loads identically under its own uuid and keeps the undo history. +#[test] +fn pg_duplicate_preserves_history() { + with_pg_uri("duplicate_preserves_history", |_url, uri| { + let backend = DatabaseBackend::new(); + + let project = build_full_project(); + let uuid = uuid_of(&project); + save_project(&backend, &project, uri).unwrap(); + { + let mut p = project.lock().unwrap(); + let math_ids: Vec = p + .graph + .node_ids() + .into_iter() + .filter(|id| p.graph.get(*id).unwrap().behavior.type_id() == MATH) + .collect(); + p.graph + .get_mut(math_ids[0]) + .unwrap() + .core + .set_standard_value("param_a_in", -1, NodeValue::Float(6.0)); + } + save_project(&backend, &project, uri).unwrap(); + + let copy = backend + .duplicate_project(&StorageUri::parse(uri).unwrap(), &uuid, None) + .unwrap(); + assert_eq!(copy.command_seq, 2); + + // The copy loads through a fresh session, field-for-field (uuid is + // fresh by design). + let session = DatabaseBackend::new(); + let (loaded_uuid, loaded) = load_project(&session, &project_uri(uri, ©.uuid)); + assert_eq!(loaded_uuid, copy.uuid); + { + let o = project.lock().unwrap(); + let l = loaded.lock().unwrap(); + assert_full_state(&o, &l); + } + + // Undo history travels with the copy: load_at(1) on the copy gives + // the pre-change state. + let session = DatabaseBackend::new(); + let at1 = load_at(&session, uri, ©.uuid, 1); + { + let l = at1.lock().unwrap(); + let math_ids: Vec = l + .graph + .node_ids() + .into_iter() + .filter(|id| l.graph.get(*id).unwrap().behavior.type_id() == MATH) + .collect(); + assert_eq!( + l.graph.get(math_ids[0]).unwrap().core.standard_value("param_a_in", -1), + NodeValue::Float(2.5) + ); + } + }); +} + +/// Manager stats are derived from the node graph, not stored (plan §4). +#[test] +fn pg_project_stats_derived_from_graph() { + with_pg_uri("project_stats_derived_from_graph", |_url, uri| { + let backend = DatabaseBackend::new(); + + let project = build_full_project(); + let uuid = uuid_of(&project); + save_project(&backend, &project, uri).unwrap(); + + let stats = backend + .project_stats(&StorageUri::parse(uri).unwrap(), &uuid) + .unwrap(); + assert_eq!( + stats, + ProjectStats { + duration_ms: 6000, + track_count: 1, + clip_count: 2, + footage_count: 2, + } + ); + // Same numbers derive_stats yields directly on the live project. + let guard = project.lock().unwrap(); + assert_eq!(derive_stats(&guard), stats); + assert_eq!( + backend + .project_stats(&StorageUri::parse(uri).unwrap(), "{missing}") + .err() + .unwrap() + .code(), + OAKSTORAGE_E_NOT_FOUND + ); + }); +} + +#[test] +fn pg_export_and_import_round_trip() { + with_pg_uri("export_and_import_round_trip", |_url, uri| { + let dir = temp_dir("pg_xi"); + let backend = DatabaseBackend::new(); + + let project = build_full_project(); + let uuid = uuid_of(&project); + save_project(&backend, &project, uri).unwrap(); + + // Export: .ove written from an in-memory assembly; the file backend + // re-imports it byte-for-byte. + let out = dir.join("exported.ove"); + let file = file_uri(&out); + backend + .export_to_file( + &StorageUri::parse(uri).unwrap(), + &uuid, + &StorageUri::parse(&file).unwrap(), + ) + .unwrap(); + assert!(out.exists(), ".ove written"); + let text = std::fs::read_to_string(&out).unwrap(); + assert!(text.starts_with(""), "{text}"); + let file_backend = Registry::global() + .resolve(&StorageUri::parse(&file).unwrap()) + .unwrap(); + let result = file_backend + .load(&StorageUri::parse(&file).unwrap()) + .unwrap(); + assert_eq!(result.version_info, OAKSTORAGE_OK); + let loaded = unsafe { project_arc(&result.project) }.unwrap(); + release(result.project); + { + let o = project.lock().unwrap(); + let l = loaded.lock().unwrap(); + assert_full_fields(&o, &l); + } + + // Import: the .ove lands as a new library row under a fresh uuid; + // importing it again yields a distinct row. + let imported = backend + .import_from_file( + &StorageUri::parse(uri).unwrap(), + &StorageUri::parse(&file).unwrap(), + ) + .unwrap(); + assert_ne!(imported, uuid, "import gets a fresh uuid"); + let imported2 = backend + .import_from_file( + &StorageUri::parse(uri).unwrap(), + &StorageUri::parse(&file).unwrap(), + ) + .unwrap(); + assert_ne!(imported2, imported, "repeat imports are new rows"); + let list = backend.list_projects(&StorageUri::parse(uri).unwrap()).unwrap(); + assert_eq!(list.len(), 3, "original + two imports"); + let session = DatabaseBackend::new(); + let (imported_uuid, imported_proj) = load_project(&session, &project_uri(uri, &imported)); + assert_eq!(imported_uuid, imported); + { + let l = imported_proj.lock().unwrap(); + assert_eq!(l.graph.node_count(), 12); + assert_eq!( + l.settings.get("projectname").cloned(), + Some("full-fixture".to_string()) + ); + } + + // Error paths: unknown project on export; non-file target; corrupt + // file on import. + assert_eq!( + backend + .export_to_file( + &StorageUri::parse(uri).unwrap(), + "{missing}", + &StorageUri::parse(&file).unwrap(), + ) + .err() + .unwrap() + .code(), + OAKSTORAGE_E_NOT_FOUND + ); + assert_eq!( + backend + .export_to_file( + &StorageUri::parse(uri).unwrap(), + &uuid, + &StorageUri::parse("oakdb+sqlite:///tmp/x.db").unwrap(), + ) + .err() + .unwrap() + .code(), + OAKSTORAGE_E_INVALID + ); + let corrupt = dir.join("corrupt.ove"); + std::fs::write(&corrupt, "").unwrap(); + assert_eq!( + backend + .import_from_file( + &StorageUri::parse(uri).unwrap(), + &StorageUri::parse(&file_uri(&corrupt)).unwrap(), + ) + .err() + .unwrap() + .code(), + OAKSTORAGE_E_FORMAT + ); + }); +} + +// --------------------------------------------------------------------------- +// Project selection (`?project=` vs default) +// --------------------------------------------------------------------------- + +#[test] +fn pg_project_selection_via_query() { + with_pg_uri("project_selection_via_query", |_url, uri| { + let backend = DatabaseBackend::new(); + + let a = save_named_project(&backend, uri, "A"); + let b = save_named_project(&backend, uri, "B"); + + // Explicit uuid picks the right row regardless of recency. + let session = DatabaseBackend::new(); + let (loaded_uuid, _) = load_project(&session, &project_uri(uri, &a)); + assert_eq!(loaded_uuid, a); + + // Default pick = most recently modified (B was written last). + let session = DatabaseBackend::new(); + let (loaded_uuid, loaded) = load_project(&session, uri); + assert_eq!(loaded_uuid, b); + assert_eq!( + loaded.lock().unwrap().settings.get("projectname").cloned(), + Some("B".to_string()) + ); + + // Unknown uuid -> E_NOT_FOUND; empty library -> E_NOT_FOUND. + let session = DatabaseBackend::new(); + assert_eq!( + session + .load(&StorageUri::parse(&project_uri(uri, "{missing}")).unwrap()) + .err() + .unwrap() + .code(), + OAKSTORAGE_E_NOT_FOUND + ); + }); +} diff --git a/crates/oakstorage/tests/database_test.rs b/crates/oakstorage/tests/database_test.rs index 04cabe0f4..7861316ef 100644 --- a/crates/oakstorage/tests/database_test.rs +++ b/crates/oakstorage/tests/database_test.rs @@ -22,459 +22,33 @@ //! journal (import + diff), snapshot + journal replay, undo to any //! point, snapshot pruning and journal retention, the project-manager //! API surface (list/delete/duplicate/rename/import/export) and the -//! error/URI matrices. Nothing touches a real library. +//! error/URI matrices. Nothing touches a real library. The same +//! behaviors run against real PostgreSQL in `database_pg_test.rs` +//! (gated on `OAK_TEST_PG_URL`); both suites share the fixtures and +//! helpers in `tests/common/mod.rs`. -use std::path::{Path, PathBuf}; -use std::sync::{Arc, Mutex}; -use std::time::Duration; +mod common; + +use std::path::PathBuf; use sea_orm::entity::prelude::*; use sea_orm::QueryOrder; -use oakcore_rs::Rational; -use oaknode::block::ClipBlockBehavior; -use oaknode::footage::FootageBehavior; use oaknode::id::NodeId; -use oaknode::keyframe::{Interpolation, Keyframe}; -use oaknode::node::NodeCore; -use oaknode::project::Project; -use oaknode::sequence::SequenceBehavior; -use oaknode::track::{TrackBehavior, TrackListBehavior, TrackType}; use oaknode::value::NodeValue; use oakstorage::backend::StorageBackend; -use oakstorage::backends::database::entities::{journal, project, settings, snapshot}; -use oakstorage::backends::database::{derive_stats, DatabaseBackend, KIND_IMPORT, KIND_REDO, ProjectStats, SNAPSHOT_KEEP}; +use oakstorage::backends::database::entities::{journal, project, snapshot}; +use oakstorage::backends::database::{ + derive_stats, DatabaseBackend, KIND_IMPORT, KIND_REDO, ProjectStats, SNAPSHOT_KEEP, +}; use oakstorage::error::{ OAKSTORAGE_E_FORMAT, OAKSTORAGE_E_INVALID, OAKSTORAGE_E_IO, OAKSTORAGE_E_NO_BACKEND, OAKSTORAGE_E_NOT_FOUND, OAKSTORAGE_OK, }; -use oakstorage::handle::CHandle; -use oakstorage::nodeutil::{make_project_owned, project_arc}; +use oakstorage::nodeutil::project_arc; use oakstorage::registry::Registry; use oakstorage::uri::StorageUri; -// --------------------------------------------------------------------------- -// Helpers -// --------------------------------------------------------------------------- - -/// A fresh, unique temp directory for one test. -fn temp_dir(tag: &str) -> PathBuf { - let dir = std::env::temp_dir().join(format!("oakstorage_db_{}_{}", std::process::id(), tag)); - let _ = std::fs::remove_dir_all(&dir); - std::fs::create_dir_all(&dir).unwrap(); - dir -} - -/// `oakdb+sqlite:///…` URI for a database file. -fn db_uri(path: &Path) -> String { - format!("oakdb+sqlite://{}", path.display()) -} - -/// `oakdb+sqlite:///…?project=` URI selecting one library row. -fn project_uri(db: &str, uuid: &str) -> String { - format!("{db}?project={uuid}") -} - -/// `file://…` URI for a plain file. -fn file_uri(path: &Path) -> String { - format!("file://{}", path.display()) -} - -/// Release an owned handle (refcount 1). -fn release(h: CHandle) { - if let Some(release) = h.release { - unsafe { release(h.ctx) }; - } -} - -/// Save an `Arc>` through the database backend. -fn save_project( - backend: &DatabaseBackend, - project: &Arc>, - uri: &str, -) -> oakstorage::error::Result<()> { - let parsed = StorageUri::parse(uri).unwrap(); - let handle = make_project_owned(project.clone()); - let result = backend.save(handle, &parsed, 0); - release(handle); - result -} - -/// Load a project through a *new* database backend session (a fresh -/// connection pool = a fresh session), returning `(uuid, loaded)`. -fn load_project(backend: &DatabaseBackend, uri: &str) -> (String, Arc>) { - let parsed = StorageUri::parse(uri).unwrap(); - let result = backend.load(&parsed).unwrap(); - assert_eq!(result.version_info, OAKSTORAGE_OK); - let handle = result.project; - let loaded = unsafe { project_arc(&handle) }.unwrap(); - let uuid = loaded.lock().unwrap().uuid.clone(); - release(handle); - (uuid, loaded) -} - -/// Load the state at `seq` (undo to any point). -fn load_at(backend: &DatabaseBackend, uri: &str, uuid: &str, seq: i64) -> Arc> { - let parsed = StorageUri::parse(uri).unwrap(); - let handle = backend.load_at(&parsed, uuid, seq).unwrap(); - let loaded = unsafe { project_arc(&handle) }.unwrap(); - release(handle); - loaded -} - -fn r_to_f(r: Rational) -> f64 { - r.numerator() as f64 / r.denominator() as f64 -} - -fn assert_close(a: f64, b: f64) { - assert!((a - b).abs() < 1e-6, "expected {a} close to {b}"); -} - -/// Open a raw sea-orm connection to the database file (for inspecting -/// and injecting rows behind the backend's back) and drive one future -/// against it on a private current-thread runtime. The connection is -/// handed to `f` by value (a clone of the pool). -fn inspect_db(path: &Path, f: impl FnOnce(sea_orm::DatabaseConnection) -> Fut) -> R -where - Fut: std::future::Future, -{ - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .unwrap(); - rt.block_on(async { - let options = sea_orm::sqlx::sqlite::SqliteConnectOptions::new() - .filename(path) - .create_if_missing(true) - .journal_mode(sea_orm::sqlx::sqlite::SqliteJournalMode::Wal) - .busy_timeout(Duration::from_secs(5)) - .foreign_keys(true); - let pool = sea_orm::sqlx::sqlite::SqlitePoolOptions::new() - .max_connections(1) - .connect_with(options) - .await - .unwrap(); - f(sea_orm::DatabaseConnection::from(pool)).await - }) -} - -/// The settings mirror rows of a project. -fn settings_rows(path: &Path, project_id: i64) -> Vec<(String, String)> { - inspect_db(path, |conn| async move { - settings::Entity::find() - .filter(settings::Column::ProjectId.eq(project_id)) - .all(&conn) - .await - .unwrap() - .into_iter() - .map(|s| (s.key, s.value)) - .collect() - }) -} - -/// The project uuid. -fn uuid_of(project: &Arc>) -> String { - project.lock().unwrap().uuid.clone() -} - -/// Read a config value for the duration of a test (the config store is -/// process-global, so restore it afterwards). -fn with_config(group: &str, key: &str, value: i32, f: impl FnOnce()) { - let store = oakcommon::configstore::ConfigStore::instance(); - let before = store.get_int(Some(group), key, 0); - store.set_int(Some(group), key, value); - f(); - store.set_int(Some(group), key, before); -} - -// --------------------------------------------------------------------------- -// Full-feature fixture (footage / sequence / track / clip / effect / -// keyframes) — the union of the ove round-trip and timeline fixtures. -// --------------------------------------------------------------------------- - -const MATH: &str = "org.olivevideoeditor.Olive.math"; - -/// Build the round-trip fixture: root folder + two math nodes with -/// values/keyframes/label/color/link/connection + a sequence "My Seq" -/// with one video track carrying two clips (footage /a/b.mp4, /a/c.mp4). -fn build_full_project() -> Arc> { - let project = Project::new(); - let mut p = project.lock().unwrap(); - p.initialize().unwrap(); - - let (core, behavior) = (oaknode::factory::Factory::global().find(MATH).unwrap().create)(); - let a = p.graph.add_node(core, behavior); - { - let e = p.graph.get_mut(a).unwrap(); - e.core.label = "Math A".to_string(); - e.core.override_color = 2; - e.core.set_standard_value("param_a_in", -1, NodeValue::Float(2.5)); - e.core - .keyframe_track_mut("param_a_in", -1) - .set_key(Keyframe { - time: Rational::new(0, 1), - value: NodeValue::Float(1.0), - interpolation: Interpolation::Linear, - bezier_in: (0.0, 0.0), - bezier_out: (0.0, 0.0), - }); - e.core - .keyframe_track_mut("param_a_in", -1) - .set_key(Keyframe { - time: Rational::new(1, 1), - value: NodeValue::Float(3.0), - interpolation: Interpolation::Bezier, - bezier_in: (0.1, 0.2), - bezier_out: (0.3, 0.4), - }); - } - let (core, behavior) = (oaknode::factory::Factory::global().find(MATH).unwrap().create)(); - let b = p.graph.add_node(core, behavior); - p.graph - .get_mut(b) - .unwrap() - .core - .set_standard_value("param_a_in", -1, NodeValue::Float(4.0)); - p.graph.connect(a, b, "param_b_in", -1).unwrap(); - p.graph.link(a, b); - - // Timeline: sequence + video track + two clips with footage. - let (seq_id, lists) = oakstorage::nodeutil::create_sequence(&mut p.graph); - p.graph.get_mut(seq_id).unwrap().core.label = "My Seq".to_string(); - - let mut tb = TrackBehavior::new(TrackType::Video); - tb.track_list = Some(lists[0]); - let track_id = p.graph.add_node(NodeCore::new(), Box::new(tb)); - - let foot1 = p - .graph - .add_node(NodeCore::new(), Box::new(FootageBehavior::new("/a/b.mp4"))); - let clip1 = { - let (core, mut behavior) = oaknode::block::clip_create(); - let clip = behavior - .as_any_mut() - .and_then(|a| a.downcast_mut::()) - .unwrap(); - clip.core.range = oakcore_rs::TimeRange::new(Rational::new(0, 1), Rational::new(100, 25)); - clip.core.media_in = Rational::new(0, 1); - clip.core.track = Some(track_id); - clip.footage = Some(foot1); - p.graph.add_node(core, behavior) - }; - - let foot2 = p - .graph - .add_node(NodeCore::new(), Box::new(FootageBehavior::new("/a/c.mp4"))); - let clip2 = { - let (core, mut behavior) = oaknode::block::clip_create(); - let clip = behavior - .as_any_mut() - .and_then(|a| a.downcast_mut::()) - .unwrap(); - clip.core.range = - oakcore_rs::TimeRange::new(Rational::new(100, 25), Rational::new(150, 25)); - clip.core.media_in = Rational::new(10, 25); - clip.core.track = Some(track_id); - clip.footage = Some(foot2); - p.graph.add_node(core, behavior) - }; - - if let Some(entry) = p.graph.get_mut(track_id) { - entry - .behavior - .as_any_mut() - .and_then(|a| a.downcast_mut::()) - .unwrap() - .blocks = vec![clip1, clip2]; - } - if let Some(entry) = p.graph.get_mut(lists[0]) { - entry - .behavior - .as_any_mut() - .and_then(|a| a.downcast_mut::()) - .unwrap() - .tracks = vec![track_id]; - } - - p.settings - .insert("projectname".to_string(), "full-fixture".to_string()); - drop(p); - project -} - -/// Field-by-field comparison of the full fixture after a round-trip -/// (uuid included). -fn assert_full_fields(orig: &Project, loaded: &Project) { - assert_eq!(loaded.uuid, orig.uuid, "uuid"); - assert_full_state(orig, loaded); -} - -/// Field-by-field comparison that ignores the uuid (a duplicated row -/// carries a fresh uuid by design). -fn assert_full_state(orig: &Project, loaded: &Project) { - assert_eq!(loaded.settings, orig.settings, "settings"); - - // Node set: count, type order (slot order preserved by the writer). - let o_ids = orig.graph.node_ids(); - let l_ids = loaded.graph.node_ids(); - assert_eq!(l_ids.len(), o_ids.len(), "node count"); - let o_types: Vec<&str> = o_ids - .iter() - .map(|id| orig.graph.get(*id).unwrap().behavior.type_id()) - .collect(); - let l_types: Vec<&str> = l_ids - .iter() - .map(|id| loaded.graph.get(*id).unwrap().behavior.type_id()) - .collect(); - assert_eq!(l_types, o_types, "node types"); - - // Math A: label, color, value, keyframes. - let (a_o, a_l) = (o_ids[1], l_ids[1]); - assert_eq!( - loaded.graph.get(a_l).unwrap().core.label, - orig.graph.get(a_o).unwrap().core.label, - "label" - ); - assert_eq!( - loaded.graph.get(a_l).unwrap().core.override_color, - orig.graph.get(a_o).unwrap().core.override_color, - "color" - ); - assert_eq!( - loaded - .graph - .get(a_l) - .unwrap() - .core - .standard_value("param_a_in", -1), - orig.graph - .get(a_o) - .unwrap() - .core - .standard_value("param_a_in", -1), - "value a" - ); - let keys_o = orig - .graph - .get(a_o) - .unwrap() - .core - .keyframe_track("param_a_in", -1) - .unwrap() - .keys() - .to_vec(); - let keys_l = loaded - .graph - .get(a_l) - .unwrap() - .core - .keyframe_track("param_a_in", -1) - .unwrap() - .keys() - .to_vec(); - assert_eq!(keys_l.len(), keys_o.len(), "keyframe count"); - for (ko, kl) in keys_o.iter().zip(&keys_l) { - assert_eq!(kl.time, ko.time, "key time"); - assert_eq!(kl.value.to_double(), ko.value.to_double(), "key value"); - assert_eq!(kl.interpolation, ko.interpolation, "key interpolation"); - assert_eq!(kl.bezier_in, ko.bezier_in, "key bezier in"); - assert_eq!(kl.bezier_out, ko.bezier_out, "key bezier out"); - } - - // Connection a -> b.param_b_in and the link. - assert_eq!( - loaded.graph.connected_output(l_ids[2], "param_b_in", -1), - Some(a_l), - "connection" - ); - assert!(loaded.graph.are_linked(a_l, l_ids[2]), "link"); - - // Timeline: sequence, track lists, track, clips, footage. - let mut seq: Option<(NodeId, Vec)> = None; - for id in loaded.graph.node_ids() { - let entry = loaded.graph.get(id).unwrap(); - if entry.behavior.type_id() == "org.olivevideoeditor.Olive.sequence" { - let s = entry - .behavior - .as_any() - .and_then(|a| a.downcast_ref::()) - .unwrap(); - seq = Some((id, s.track_lists.clone())); - break; - } - } - let (_seq_id, lists) = seq.expect("sequence present"); - assert_eq!(lists.len(), 3, "video/audio/subtitle lists"); - let list = loaded - .graph - .get(lists[0]) - .unwrap() - .behavior - .as_any() - .and_then(|a| a.downcast_ref::()) - .unwrap(); - assert_eq!(list.kind, TrackType::Video); - assert_eq!(list.array_base, 0); - assert_eq!(list.tracks.len(), 1); - let track = loaded - .graph - .get(list.tracks[0]) - .unwrap() - .behavior - .as_any() - .and_then(|a| a.downcast_ref::()) - .unwrap(); - assert_eq!(track.kind, TrackType::Video); - assert_eq!(track.blocks.len(), 2); - let c1 = loaded - .graph - .get(track.blocks[0]) - .unwrap() - .behavior - .as_any() - .and_then(|a| a.downcast_ref::()) - .unwrap(); - assert_close(r_to_f(c1.core.length()), 4.0); - assert_close(r_to_f(c1.core.media_in), 0.0); - let f1 = loaded - .graph - .get(c1.footage.unwrap()) - .unwrap() - .behavior - .as_any() - .and_then(|a| a.downcast_ref::()) - .unwrap(); - assert_eq!(f1.filename, "/a/b.mp4"); - let c2 = loaded - .graph - .get(track.blocks[1]) - .unwrap() - .behavior - .as_any() - .and_then(|a| a.downcast_ref::()) - .unwrap(); - assert_close(r_to_f(c2.core.length()), 2.0); - assert_close(r_to_f(c2.core.media_in), 0.4); - let f2 = loaded - .graph - .get(c2.footage.unwrap()) - .unwrap() - .behavior - .as_any() - .and_then(|a| a.downcast_ref::()) - .unwrap(); - assert_eq!(f2.filename, "/a/c.mp4"); -} - -/// Build a small project with a `projectname` setting (fast saves). -fn build_named_project(name: &str) -> Arc> { - let project = Project::new(); - { - let mut p = project.lock().unwrap(); - p.initialize().unwrap(); - p.settings.insert("projectname".to_string(), name.to_string()); - } - project -} +use common::*; // --------------------------------------------------------------------------- // Round-trip through a fresh session @@ -508,7 +82,7 @@ fn roundtrip_field_by_field() { assert_eq!(loaded_uuid, uuid); // The settings mirror carries the current keys. - let row = inspect_db(&db, |conn| async move { + let row = inspect_sqlite(&db, |conn| async move { project::Entity::find() .filter(project::Column::Uuid.eq(&uuid)) .one(&conn) @@ -566,7 +140,7 @@ fn first_save_is_an_import_command() { let node_count = project.lock().unwrap().graph.node_count(); save_project(&backend, &project, &uri).unwrap(); - let rows = inspect_db(&db, |conn| async move { + let rows = inspect_sqlite(&db, |conn| async move { let proj = project::Entity::find() .filter(project::Column::Uuid.eq(&uuid)) .one(&conn) @@ -637,7 +211,7 @@ fn later_saves_are_diffs() { save_project(&backend, &project, &uri).unwrap(); let uuid_q = uuid.clone(); - let rows = inspect_db(&db, move |conn| async move { + let rows = inspect_sqlite(&db, move |conn| async move { let proj = project::Entity::find() .filter(project::Column::Uuid.eq(&uuid_q)) .one(&conn) @@ -693,7 +267,7 @@ fn no_op_save_is_a_touch_only() { save_project(&backend, &project, &uri).unwrap(); save_project(&backend, &project, &uri).unwrap(); - let (head, count) = inspect_db(&db, |conn| async move { + let (head, count) = inspect_sqlite(&db, |conn| async move { let proj = project::Entity::find() .filter(project::Column::Uuid.eq(&uuid)) .one(&conn) @@ -751,7 +325,7 @@ fn snapshot_and_journal_replay() { // Both saves produced snapshots (head seq 2). let uuid_q = uuid.clone(); - let snaps = inspect_db(&db, move |conn| async move { + let snaps = inspect_sqlite(&db, move |conn| async move { let proj = project::Entity::find() .filter(project::Column::Uuid.eq(&uuid_q)) .one(&conn) @@ -778,7 +352,7 @@ fn snapshot_and_journal_replay() { // Destroy the snapshots: replay degrades to empty base + full // journal and still reconstructs the head. let uuid_q = uuid.clone(); - inspect_db(&db, move |conn| async move { + inspect_sqlite(&db, move |conn| async move { let proj = project::Entity::find() .filter(project::Column::Uuid.eq(&uuid_q)) .one(&conn) @@ -944,7 +518,7 @@ fn snapshot_pruning_keeps_three() { } save_project(&backend, &project, &uri).unwrap(); } - let seqs = inspect_db(&db, |conn| async move { + let seqs = inspect_sqlite(&db, |conn| async move { let proj = project::Entity::find() .filter(project::Column::Uuid.eq(&uuid)) .one(&conn) @@ -1000,7 +574,7 @@ fn journal_retention_truncation() { // Backdate every journal row two days, then save a third command // with a 1-day retention window. - inspect_db(&db, |conn| async move { + inspect_sqlite(&db, |conn| async move { let old = chrono::Utc::now().naive_utc() - chrono::Duration::days(2); journal::Entity::update_many() .col_expr(journal::Column::At, sea_orm::sea_query::Expr::value(old)) @@ -1028,7 +602,7 @@ fn journal_retention_truncation() { // Only the third command's rows survive. let uuid_q = uuid.clone(); - let (pid, rows) = inspect_db(&db, move |conn| async move { + let (pid, rows) = inspect_sqlite(&db, move |conn| async move { let proj = project::Entity::find() .filter(project::Column::Uuid.eq(&uuid_q)) .one(&conn) @@ -1070,13 +644,6 @@ fn journal_retention_truncation() { // Project-manager API surface // --------------------------------------------------------------------------- -fn save_named_project(backend: &DatabaseBackend, uri: &str, name: &str) -> String { - let project = build_named_project(name); - let uuid = uuid_of(&project); - save_project(backend, &project, uri).unwrap(); - uuid -} - #[test] fn list_delete_duplicate_rename() { let dir = temp_dir("mgr"); @@ -1404,8 +971,13 @@ fn project_selection_via_query() { // Error paths, locking, URI matrix // --------------------------------------------------------------------------- +/// PG targets are now live: malformed connection strings fail cleanly at +/// parse time (E_INVALID, no network touched) and an unreachable server +/// fails cleanly at connect (E_IO, no panic). Both run without a real +/// PostgreSQL server — the connection-refused case uses port 1 on +/// loopback, which nothing listens on. #[test] -fn pg_target_rejected_until_d3() { +fn pg_invalid_and_unreachable_targets_error_cleanly() { let dir = temp_dir("pg"); let db = dir.join("lib.db"); let uri = db_uri(&db); @@ -1414,27 +986,45 @@ fn pg_target_rejected_until_d3() { save_project(&backend, &project, &uri).unwrap(); let uuid = uuid_of(&project); - let pg = "oakdb+pg://user:pass@host:5432/db"; + // Invalid connection strings -> E_INVALID at parse (no connection). + for bad in ["oakdb+pg://", "oakdb+pg://?project={x}", "oakdb+pg://user@"] { + let err = backend + .list_projects(&StorageUri::parse(bad).unwrap()) + .err() + .unwrap(); + assert_eq!(err.code(), OAKSTORAGE_E_INVALID, "{bad}"); + } + + // Unreachable server (port 1 on loopback) -> E_IO at connect, and the + // error is clean (no panic) across every operation. The connect probe + // fails on the refused TCP connection without waiting out the pool's + // acquire timeout. + let dead = "oakdb+pg://user@127.0.0.1:1/db"; for call in [ - backend.load(&StorageUri::parse(pg).unwrap()).map(|_| ()), - backend.save(CHandle::null(), &StorageUri::parse(pg).unwrap(), 0), - backend.list_projects(&StorageUri::parse(pg).unwrap()).map(|_| ()), - backend.delete_project(&StorageUri::parse(pg).unwrap(), &uuid), - backend.rename_project(&StorageUri::parse(pg).unwrap(), &uuid, "X"), + backend.load(&StorageUri::parse(dead).unwrap()).map(|_| ()), + save_project(&backend, &project, dead), + backend.list_projects(&StorageUri::parse(dead).unwrap()).map(|_| ()), + backend.delete_project(&StorageUri::parse(dead).unwrap(), &uuid), + backend.rename_project(&StorageUri::parse(dead).unwrap(), &uuid, "X"), backend - .duplicate_project(&StorageUri::parse(pg).unwrap(), &uuid, None) + .duplicate_project(&StorageUri::parse(dead).unwrap(), &uuid, None) .map(|_| ()), backend .export_to_file( - &StorageUri::parse(pg).unwrap(), + &StorageUri::parse(dead).unwrap(), &uuid, &StorageUri::parse("file:///tmp/x.ove").unwrap(), ), - backend.snapshot(&StorageUri::parse(pg).unwrap(), &uuid), - backend.load_at(&StorageUri::parse(pg).unwrap(), &uuid, 1).map(|_| ()), + backend.snapshot(&StorageUri::parse(dead).unwrap(), &uuid), + backend.load_at(&StorageUri::parse(dead).unwrap(), &uuid, 1).map(|_| ()), ] { - assert_eq!(call.err().unwrap().code(), OAKSTORAGE_E_NO_BACKEND, "pg target"); + assert_eq!(call.err().unwrap().code(), OAKSTORAGE_E_IO, "dead pg target"); } + + // The sqlite library next to it is untouched by all of the above. + let session = DatabaseBackend::new(); + let (loaded_uuid, _) = load_project(&session, &project_uri(&uri, &uuid)); + assert_eq!(loaded_uuid, uuid); } #[test] @@ -1606,7 +1196,7 @@ fn concurrent_writers_are_serialized() { let session = DatabaseBackend::new(); let (loaded_uuid, _) = load_project(&session, &project_uri(&uri, &same)); assert_eq!(loaded_uuid, same, "library consistent after races"); - let (head, seqs) = inspect_db(&db, |conn| async move { + let (head, seqs) = inspect_sqlite(&db, |conn| async move { let proj = project::Entity::find() .filter(project::Column::Uuid.eq(&same)) .one(&conn) diff --git a/docs/project-storage.md b/docs/project-storage.md index 6eaeeca6a..7578b0ce4 100644 --- a/docs/project-storage.md +++ b/docs/project-storage.md @@ -91,12 +91,39 @@ removed clips. or otio backend; nothing is read from or written to the database beyond the current state. +## Configuration + +Library selection and behavior are driven by the `Storage` config group +(read by `crates/oakengine/src/storage.rs`): + +- `Storage/Backend` — `"sqlite"` (the documented default), `"database"` + or `"pg"` enables write-through; any other value (e.g. `"off"`) + disables it. When the key is absent no library is configured and + projects stay unbound (headless consumers and the test suite never + touch the user's real library). +- `Storage/SqlitePath` — the SQLite library file; default + `/library.db` (honoring `OAK_CONFIG_DIR`). +- `Storage/PgUrl` — the PostgreSQL connection string, used when + `Backend = "pg"`: `user:pass@host:5432/dbname` (libpq URL form; an + optional `postgres://`/`postgresql://` scheme is stripped). The + resolved library URI is `oakdb+pg://`. +- `Storage/SnapshotIntervalSec` (default 600) and + `Storage/JournalRetentionDays` (default 0 = keep forever) — see above. + ## Multi-writer and platforms v1 assumes a single writer per database (SQLite `busy_timeout`, PG row locks). Multi-writer collaboration is future work (M14). The default -database is a single user-level SQLite file; PostgreSQL is selected -with an `oakdb+pg://` URI. +database is a single user-level SQLite file; PostgreSQL is selected with +`Storage/Backend = "pg"` + `Storage/PgUrl`, or directly with an +`oakdb+pg://` URI. + +Database tests: `cargo test -p oakstorage` is green without PostgreSQL — +the SQLite suite always runs; the PG suite (`tests/database_pg_test.rs`) +connects to a real server when `OAK_TEST_PG_URL` is set (e.g. +`postgres://user:pass@host:5432/db`) and skips with a note otherwise. +The URL should point at a dedicated test database: each test resets the +four tables. See also: [M10 oakstorage manual](plans/riir/M10-oakstorage.md), [M13 write-through plan](plans/riir/M13-storage-live.md), diff --git a/docs/screenshot-manager-en.png b/docs/screenshot-manager-en.png new file mode 100644 index 0000000000000000000000000000000000000000..5d0dee27a9b2f7391b7a5050428c8d3df38fbc3e GIT binary patch literal 467030 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