diff --git a/apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs b/apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs index 3b3837176..80014ff44 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs @@ -485,6 +485,33 @@ fn project_write_lock_reports_acl_denial_without_an_existing_target() { ); } +/// 分类判据本身与平台无关,两个平台都要盯住:目标存在才是争用,目标不存在却创建失败 +/// 是权限拒绝。这条用例不依赖 ACL 环境,因此在 CI 容器以 root 运行时仍然有效。 +#[test] +fn project_write_lock_classifies_by_whether_the_target_exists() { + assert_eq!( + project_write_lock_classify_open_error( + &std::io::Error::from(std::io::ErrorKind::AlreadyExists), + true + ), + ProjectWriteLockOpenFailure::Contention + ); + assert_eq!( + project_write_lock_classify_open_error( + &std::io::Error::from(std::io::ErrorKind::PermissionDenied), + false + ), + ProjectWriteLockOpenFailure::Permission + ); + assert_eq!( + project_write_lock_classify_open_error( + &std::io::Error::from(std::io::ErrorKind::NotFound), + false + ), + ProjectWriteLockOpenFailure::Other + ); +} + #[cfg(all(test, windows))] #[test] fn project_write_lock_hardens_space_containing_path_in_process() { diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/project_lock_recovery.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/project_lock_recovery.rs index ef40e1a95..f7de9d54e 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/project_lock_recovery.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/project_lock_recovery.rs @@ -426,10 +426,15 @@ fn project_write_lock_does_not_project_permission_denial_as_contention() { fs::set_permissions(&agent_directory, fs::Permissions::from_mode(0o500)) .expect("去掉控制目录写权限"); - let error = - acquire_project_write_lock(&root, "file.write").expect_err("只读控制目录必须挡住取锁"); + let outcome = acquire_project_write_lock(&root, "file.write"); fs::set_permissions(&agent_directory, original).expect("恢复控制目录权限"); + // CI 容器以 root 运行,0o500 目录照样可以创建文件;此时本用例的前提不成立, + // 直接跳过。分类判据本身另有不依赖 ACL 环境的纯函数用例覆盖。 + let Err(error) = outcome else { + return; + }; + assert!( !error.starts_with("项目正在被其他写操作占用:"), "权限拒绝不得投影成写锁争用:{error}"