mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-04 19:45:34 +08:00
ac764b4818
Replace the generic provider upsert surface with strict typed create, update, rename, endpoint, and compensation operations. This app-independent prerequisite owns provider writes without depending on Pi runtime or canonical restore. The v17 migration also reserves dormant device-local ledger tables and the Pi skill bit alongside endpoint normalization. Keeping that reservation here prevents a later stacked feature from rewriting a published migration; no Pi runtime behavior is activated by this commit. Old save_provider callsite classification ========================================== Inventory authority: abandoned 5a385fc8 tree. The old definition at src-tauri/src/database/dao/providers.rs:180 is deleted and is not a callsite. Production callsites: - src-tauri/src/commands/provider.rs:253 [create] Claude Desktop import creates one absent aggregate; it now strict-inserts the row and initial endpoints in one transaction. - src-tauri/src/database/dao/providers.rs:638 [create] official seed first proves absence, then strict-creates; a racing insert is a conflict. - src-tauri/src/database/dao/providers.rs:704 [create] on-demand seed first proves absence, then strict-creates; it cannot overwrite an existing row. - src-tauri/src/services/omo.rs:291 [create] OMO import constructs a new aggregate and strict-creates it; OMO is not eligible for rename. - src-tauri/src/services/provider/endpoints.rs:85 [update] endpoint last-used is not a Provider-row save; it now calls the exact touch endpoint operation. - src-tauri/src/services/provider/live.rs:1567 [create/update] default live import is reconciliation: read first, then strict create or strict update. - src-tauri/src/services/provider/live.rs:1743 [update] an existing OpenCode live provider follows the strict row-update branch. - src-tauri/src/services/provider/live.rs:1770 [create] a new OpenCode live provider follows the strict aggregate-create branch. - src-tauri/src/services/provider/live.rs:1825 [update] an existing OpenClaw live provider follows the strict row-update branch. - src-tauri/src/services/provider/live.rs:1858 [create] a new OpenClaw live provider follows the strict aggregate-create branch. - src-tauri/src/services/provider/live.rs:1900 [update] an existing Hermes live provider follows the strict row-update branch. - src-tauri/src/services/provider/live.rs:1926 [create] a new Hermes live provider follows the strict aggregate-create branch. - src-tauri/src/services/provider/mod.rs:2568 [create] ProviderService::add owns strict aggregate creation and all initial endpoints. - src-tauri/src/services/provider/mod.rs:2680 [rename] an additive DB-only key change now uses the dedicated transactional rename after eligibility checks. - src-tauri/src/services/provider/mod.rs:2711 [update] OMO edit updates exactly the existing main row after its live-file coordination. - src-tauri/src/services/provider/mod.rs:2740 [update] additive-provider edit updates exactly the existing main row after resolving live ownership. - src-tauri/src/services/provider/mod.rs:2750 [update] switch-mode edit updates exactly the existing main row and never inserts. - src-tauri/src/services/provider/mod.rs:2948 [update] remove-from-live changes only the existing provider's live-managed marker. - src-tauri/src/services/provider/mod.rs:3120 [update] switch backfill updates only the existing current provider row. - src-tauri/src/services/provider/mod.rs:3174 [update] successful additive switch changes only the existing live-managed marker. - src-tauri/src/services/provider/mod.rs:3315 [update] common-config migration updates only each already-read existing row. - src-tauri/src/services/provider/mod.rs:3895 [update] Gemini credential scrub updates only each already-read existing row. - src-tauri/src/services/provider/mod.rs:4082 [update] sort ordering is routed to the dedicated sort-index state operation, not row replacement. - src-tauri/src/services/provider/mod.rs:4636 [create/update] universal-to- Claude reconciliation reads the target and selects strict create or update. - src-tauri/src/services/provider/mod.rs:4651 [create/update] universal-to- Codex reconciliation reads the target and selects strict create or update. - src-tauri/src/services/provider/mod.rs:4665 [create/update] universal-to- Gemini reconciliation reads the target and selects strict create or update. Required indirect ownership paths: - src-tauri/src/deeplink/provider.rs [create] the old indirect flow called ProviderService::add and then appended endpoints one by one. It now supplies every non-primary endpoint to one strict aggregate create, so hydration is complete atomically and a duplicate is zero-side-effect. - [restore] no old generic-save callsite is reclassified as restore. Exact aggregate replacement exists only as the sealed restore_provider_aggregate_on_tx compensation primitive. Test-only callsites: Every item below is classified [test]. Each is fixture setup, not a production write authority, and is migrated to a real ProviderService entry where the behavior is under test or to the cfg(test)-only typed fixture reconciler where the test merely needs pre-existing rows. - src-tauri/src/codex_history_migration.rs:1442 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:1452 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2174 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2176 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2199 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2219 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2247 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2267 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2288 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2320 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2393 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2449 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2498 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2555 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2604 [test] migration fixture setup. - src-tauri/src/codex_history_migration.rs:2625 [test] migration fixture setup. - src-tauri/src/database/dao/providers.rs:754 [test] DAO fixture setup. - src-tauri/src/proxy/provider_router.rs:351 [test] router fixture setup. - src-tauri/src/proxy/provider_router.rs:352 [test] router fixture setup. - src-tauri/src/proxy/provider_router.rs:377 [test] router fixture setup. - src-tauri/src/proxy/provider_router.rs:378 [test] router fixture setup. - src-tauri/src/proxy/provider_router.rs:410 [test] router fixture setup. - src-tauri/src/proxy/provider_router.rs:411 [test] router fixture setup. - src-tauri/src/proxy/provider_router.rs:447 [test] router fixture setup. - src-tauri/src/proxy/provider_router.rs:448 [test] router fixture setup. - src-tauri/src/proxy/provider_router.rs:488 [test] router fixture setup. - src-tauri/src/services/provider/mod.rs:485 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:586 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:813 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:825 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:1472 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:1607 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:1737 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:1945 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:1952 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:1978 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:2006 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:2056 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:2130 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:2167 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:2207 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:2235 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:2270 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:2320 [test] service fixture setup. - src-tauri/src/services/provider/mod.rs:2362 [test] service fixture setup. - src-tauri/src/services/proxy.rs:3762 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:3948 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:4034 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:4095 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:4114 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:4263 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:4341 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:4421 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:4533 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:4651 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:4787 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5264 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5320 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5385 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5387 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5460 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5462 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5611 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5613 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5615 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5698 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5700 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:5998 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:6000 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:6173 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:6175 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:6417 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:6419 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:6553 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:6555 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:6635 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:6637 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:6919 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:7173 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:7175 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:7240 [test] proxy fixture setup. - src-tauri/src/services/proxy.rs:7242 [test] proxy fixture setup. - src-tauri/tests/profile_roundtrip.rs:112 [test] profile fixture create. - src-tauri/tests/profile_roundtrip.rs:116 [test] profile fixture create. - src-tauri/tests/profile_roundtrip.rs:126 [test] profile fixture create. - src-tauri/tests/profile_roundtrip.rs:133 [test] profile fixture create. - src-tauri/tests/profile_roundtrip.rs:292 [test] profile fixture create. - src-tauri/tests/profile_roundtrip.rs:501 [test] profile fixture create. - src-tauri/tests/profile_roundtrip.rs:505 [test] profile fixture create. - src-tauri/tests/profile_roundtrip.rs:670 [test] profile fixture create. - src-tauri/tests/profile_roundtrip.rs:677 [test] profile fixture create. - src-tauri/tests/profile_roundtrip.rs:762 [test] Linux Desktop fixture create. - src-tauri/tests/profile_roundtrip.rs:769 [test] Linux Desktop fixture create. - src-tauri/tests/provider_commands.rs:69 [test] command fixture create. - src-tauri/tests/provider_service.rs:2927 [test] service fixture create.
110 lines
3.6 KiB
Rust
110 lines
3.6 KiB
Rust
use std::path::{Path, PathBuf};
|
|
use std::sync::{Arc, Mutex, OnceLock};
|
|
|
|
use cc_switch_lib::{
|
|
update_settings, AppSettings, AppState, Database, MultiAppConfig, Provider,
|
|
ProviderMutationInput,
|
|
};
|
|
|
|
/// Build the public write DTO explicitly for integration tests. Keeping this
|
|
/// conversion test-only avoids reintroducing a production `From<Provider>`
|
|
/// path from hydrated read projections to provider mutations.
|
|
#[allow(dead_code)]
|
|
pub fn new_provider_input(provider: Provider) -> ProviderMutationInput {
|
|
ProviderMutationInput {
|
|
id: provider.id,
|
|
name: provider.name,
|
|
settings_config: provider.settings_config,
|
|
website_url: provider.website_url,
|
|
category: provider.category,
|
|
created_at: provider.created_at,
|
|
sort_index: provider.sort_index,
|
|
notes: provider.notes,
|
|
meta: provider.meta,
|
|
icon: provider.icon,
|
|
icon_color: provider.icon_color,
|
|
in_failover_queue: provider.in_failover_queue,
|
|
}
|
|
}
|
|
|
|
/// 为测试设置隔离的 HOME 目录,避免污染真实用户数据。
|
|
pub fn ensure_test_home() -> &'static Path {
|
|
static HOME: OnceLock<PathBuf> = OnceLock::new();
|
|
HOME.get_or_init(|| {
|
|
let base = std::env::temp_dir().join("cc-switch-test-home");
|
|
if base.exists() {
|
|
let _ = std::fs::remove_dir_all(&base);
|
|
}
|
|
std::fs::create_dir_all(&base).expect("create test home");
|
|
// Windows 上 `dirs::home_dir()` 不受 HOME/USERPROFILE 影响(走 Known Folder API),
|
|
// 用 CC_SWITCH_TEST_HOME 显式覆盖,以确保测试不会污染真实用户目录。
|
|
std::env::set_var("CC_SWITCH_TEST_HOME", &base);
|
|
std::env::set_var("HOME", &base);
|
|
#[cfg(windows)]
|
|
std::env::set_var("USERPROFILE", &base);
|
|
base
|
|
})
|
|
.as_path()
|
|
}
|
|
|
|
/// 清理测试目录中生成的配置文件与缓存。
|
|
pub fn reset_test_fs() {
|
|
let home = ensure_test_home();
|
|
for sub in [
|
|
".claude",
|
|
".codex",
|
|
".cc-switch",
|
|
".gemini",
|
|
".grok",
|
|
".config",
|
|
".openclaw",
|
|
"profiles",
|
|
] {
|
|
let path = home.join(sub);
|
|
if path.exists() {
|
|
if let Err(err) = std::fs::remove_dir_all(&path) {
|
|
eprintln!("failed to clean {}: {}", path.display(), err);
|
|
}
|
|
}
|
|
}
|
|
let claude_json = home.join(".claude.json");
|
|
if claude_json.exists() {
|
|
let _ = std::fs::remove_file(&claude_json);
|
|
}
|
|
|
|
// 重置内存中的设置缓存,确保测试环境不受上一次调用影响
|
|
let _ = update_settings(AppSettings::default());
|
|
}
|
|
|
|
#[allow(dead_code)]
|
|
pub fn enable_codex_official_auth_preservation() {
|
|
update_settings(AppSettings {
|
|
preserve_codex_official_auth_on_switch: true,
|
|
..Default::default()
|
|
})
|
|
.expect("enable Codex official auth preservation");
|
|
}
|
|
|
|
/// 全局互斥锁,避免多测试并发写入相同的 HOME 目录。
|
|
pub fn test_mutex() -> &'static Mutex<()> {
|
|
static MUTEX: OnceLock<Mutex<()>> = OnceLock::new();
|
|
MUTEX.get_or_init(|| Mutex::new(()))
|
|
}
|
|
|
|
/// 创建测试用的 AppState,包含一个空的数据库
|
|
#[allow(dead_code)]
|
|
pub fn create_test_state() -> Result<AppState, Box<dyn std::error::Error>> {
|
|
let db = Arc::new(Database::init()?);
|
|
Ok(AppState::new(db))
|
|
}
|
|
|
|
/// 创建测试用的 AppState,并从 MultiAppConfig 迁移数据
|
|
#[allow(dead_code)]
|
|
pub fn create_test_state_with_config(
|
|
config: &MultiAppConfig,
|
|
) -> Result<AppState, Box<dyn std::error::Error>> {
|
|
let db = Arc::new(Database::init()?);
|
|
db.migrate_from_json(config)?;
|
|
Ok(AppState::new(db))
|
|
}
|