OpenCloud decomposed 存储的验收测试预期失败清单:expected-failures-decomposed-storage.md 机制深度解析 OpenCloud decomposed 存储的验收测试预期失败清单expected-failures-decomposed-storage.md 机制深度解析【免费下载链接】opencloud️ OpenCloud is the open source platform for file management, sharing and collaboration. Simple and sovereign.项目地址: https://gitcode.com/GitHub_Trending/op/opencloud本文基于 OpenCloud 仓库中的 expected-failures-decomposed-storage.md 展开系统讲解这份预期失败清单在验收测试流水线中的定位、被 CI 脚本消费与校验的完整链路以及当某个上游缺陷被修复后如何将对应条目从清单中移除。读完本文你可以准确理解 OpenCloud 如何在 decomposed 存储驱动下运行 BDD 验收测试、如何区分预期失败与真实回归并掌握修复预期失败项的完整工作流。文件定位它是一份已知缺陷场景清单不是缺陷报告expected-failures-decomposed-storage.md的核心作用是列出在 decomposed 存储驱动下运行验收测试时已知会失败的 Behat 场景。每个条目由三部分组成一条上游问题描述标题中附带的 upstream ownCloud/OCIS 或 opencloud issue 编号如 issue #4637、issue #1755一组精确定位到tests/acceptance/features/下某个 feature 文件某一行场景起始行的场景引用按功能域分组的章节结构OpenCloud API 测试、核心 API 测试的 File/Sync/Share/Other 分区以及 Wont fix 分区。它与同目录下的另外两份清单是三兄弟关系分别对应不同的测试运行条件这在 CI 脚本 check-deleted-suites-in-expected-failure.sh 中被显式声明EXPECTED_FAILURE_FILES(expected-failures-decomposed-storage.md expected-failures-posix-storage.md expected-failures-without-remotephp.md)即decomposed元数据与文件内容分离的存储也是本地默认驱动、posix单一 POSIX 文件系统存储、以及不带remote.php的三种运行条件各自维护一份预期失败清单。按 tests/README.md 的说明STORAGE_DRIVER可用值为decomposed默认、owncloudsql和decomposeds3而 CI 中则通过posix/decomposed两种驱动选择对应清单。CI 中如何消费这份清单1. 按存储驱动选择清单文件Docker 化测试入口 run-tests.sh 根据STORAGE_DRIVER环境变量决定使用哪份清单并同时追加对应的 tag 过滤if [ $STORAGE_DRIVER posix ]; then BEHAT_FILTER_TAGS~skipOnOpencloud-posix-Storage EXPECTED_FAILURES_FILE${OC_ROOT}/tests/acceptance/expected-failures-posix-storage.md elif [ $STORAGE_DRIVER decomposed ]; then BEHAT_FILTER_TAGS~skipOnOpencloud-decomposed-Storage EXPECTED_FAILURES_FILE${OC_ROOT}/tests/acceptance/expected-failures-decomposed-storage.md fi export BEHAT_FILTER_TAGS export EXPECTED_FAILURES_FILE注意两个细节~skipOnOpencloud-decomposed-Storage表示在 decomposed 驱动下会跳过带有该 tag 的场景被显式排除的场景与预期失败机制是互补的两种豁免手段如果显式指定了BEHAT_FEATURE只跑单个 feature脚本会unset EXPECTED_FAILURES_FILErun-tests.sh也就是说单场景调试时不做预期失败比对失败就是失败便于直接观察行为。2. 双向比对意外失败与意外通过都会让 CI 变红真正的比对逻辑在 run.sh。它对 Behat 输出的失败场景做双向校验正方向遍历所有实际失败的场景路径从 Behat 日志中提取feature:line逐一grep清单中是否存在[suite/feature.feature:line]grep \[${SUITE_SCENARIO}\] ${EXPECTED_FAILURES_FILE} /dev/null if [ $? -ne 0 ] then log_error Scenario ${SUITE_SCENARIO} failed but was not expected to fail. UNEXPECTED_FAILED_SCENARIOS(${SUITE_SCENARIO}) fi反方向遍历清单中的每一个条目检查它是否真的出现在本次失败列表中如果清单里的场景这次没有失败说明缺陷可能已修复或行为变化同样报 expected to fail but did not fail 并计入UNEXPECTED_PASSED_SCENARIOS。当只运行单个 suiteBEHAT_SUITE时脚本会先用^${BEHAT_SUITE_TO_RUN}/前缀过滤清单只校验本次实际运行的 suite避免把未运行 suite 的条目误判为意外通过。这种失败必须被预期、预期必须真的失败的强约束使得这份 Markdown 清单实质上是 CI 契约的一部分清单漂移新增未登记缺陷、或已修复缺陷未从清单移除都会导致流水线失败迫使贡献者维护它。3. 格式 Lint清单本身也要通过静态检查lint-expected-failures.sh 在每次运行前对清单做静态校验由 run.sh 调用规则包括文件必须以换行符结尾。这正对应清单文件末尾那条 Note: always have an empty line at the end of this file 的注释——lint 脚本第 46 行用tail -c1 ... | wc -l检测末字符缺少换行会直接失败条目行格式必须严格- [suite/feature.feature:line](https://github.com/opencloud-eu/opencloud/blob/main/tests/acceptance/features/...)即方括号内为suite/feature文件:行号圆括号内为与行号严格对应的 GitHub 源码链接。lint 脚本会用正则重算出期望链接并与实际链接逐行比对lint-expected-failures.sh禁止重复条目同一suite/feature:line出现两次会报 Scenario line ... is duplicated以- suite.feature:n或裸[suite/feature.feature:n]形式出现的非标准行会被判定为 Not in the correct format。4. 场景删除检查防止清单悬挂当维护者从tests/acceptance/features/删除某个 suite 或 feature 文件后check-deleted-suites-in-expected-failure.sh 会用正则\[([a-zA-Z0-9]/[a-zA-Z0-9]\.feature:[0-9])\]提取三份清单里引用的全部场景与实际存在的 suite/feature 文件比对把指向已不存在测试的场景逐条列出并返回非零退出码。它输出的提示很直接The following test scenarios do not exist anymore: They can be deleted from the xxx.md。这保证了清单不会随 feature 目录的演化而腐化。清单内容全貌哪些功能域在 decomposed 存储下存在已知缺陷以下按原清单的章节结构完整梳理。issue 编号指向上游 ownCloud/OCIS 项目或 opencloud 项目的缺陷单feature 文件均位于 tests/acceptance/features/ 下行号为场景起始行。OpenCloud API 测试api 前缀的本地测试套件档案下载与 TUS 上传已知缺陷issue 编号受影响场景位置使用资源路径下载文件/文件夹档案不可用#4637apiArchiver/downloadByPath.feature 第 25、26、43、44、47、73、171、172 行TUS 上传携带错误 checksum 的 PATCH 请求返回错误响应#1755apiSpacesShares/shareUploadTUS.feature 第 283、303、384 行Graph API 权限边界已知缺陷issue 编号受影响场景位置Settings 服务用户可以列出他人的角色分配#5032apiGraph/getAssignedRole.feature 第 31–33 行用户可通过 Graph API 获取其他用户的信息#5125apiGraphUserGroup/getUser.feature 第 84–86、628–630、645–647 行普通用户可获取群组展开成员信息#5604apiGraphUserGroup/getGroup.feature 第 399–401、460–462、508–510 行同一用户可被多次加入同一群组#5702apiGraphUserGroup/addUserToGroup.feature 第 294 行用户被加入群组时 host 部分错误#5871apiGraphUserGroup/addUserToGroup.feature 第 378、392 行文件锁定Locks——这是清单中场景密度最高的功能域已知缺陷issue 编号受影响场景位置无法通过不同路径对共享文件加锁#7599apiLocks/lockFiles.feature 第 185–187、309–311、364–369、399–404 行apiLocks/unlockFiles.feature 第 62–64、171–176、199–204、227–232 行文件夹可被加锁且加锁行为部分生效#7641apiLocks/lockFiles.feature 第 417–422、443–448 行匿名用户拿到 lock token 后可解锁其通过公共链接共享的文件#7761apiLocks/unlockFiles.feature 第 42–47 行用共享者的 lock token 解锁共享文件返回 500#7767apiLocks/unlockFiles.feature 第 115–120、143–148 行匿名用户对公共链接共享文件加锁返回 405#7790apiLocks/lockFiles.feature 第 532–535、554–557 行移动操作MOVE已知缺陷issue 编号受影响场景位置shareeeditor 角色按 file-id 将文件 MOVE 到共享子文件夹返回 502#7617apiSpacesDavOperation/moveByFileId.feature 第 368、591 行MOVE 文件到同名同目录返回 404 而非 403#1976apiSpacesShares/moveSpaces.feature 第 69、70、416 行apiSpacesDavOperation/moveByFileId.feature 第 61、174–176、393 行OCM 联邦共享已知缺陷issue 编号受影响场景位置管理员在没有任何联邦连接时无法获取联邦用户#9829apiOcm/searchFederationUsers.feature 第 429、601 行一方删除连接后联邦连接未被彻底删除#10216apiOcm/deleteFederatedConnections.feature 第 21、67 行删除 OCM 用户的共享后服务崩溃#10213apiOcm/deleteFederatedConnections.feature 第 102 行其他单项缺陷已知缺陷issue 编号受影响场景位置Shares Jail 下 PROPFIND 对同一项返回不同 File ID#9933apiSharingNg1/propfindShares.feature 第 149 行部分服务的 Readiness 检查返回 500#10661apiServiceAvailability/serviceAvailabilityCheck.feature 第 123 行REPORT 响应缺少属性 /d:getetag为空#9780、#9783apiSearch1/search.feature 第 437–439、465–467 行核心 API 测试coreApi 前缀从上游迁移而来的套件原清单在此部分进一步按功能分区各区含义如下File基础文件管理上传下载、移动、复制、属性、回收站、版本、分块Sync同步特性etag 传播、mtime 设置、文件锁定Share共享相关OtherAPI、搜索、收藏、配置、capabilities、不存在的路由、CORS 等File 区带命名空间自定义 DAV 属性渲染错误#2140——coreApiWebdavProperties/setFileProperties.feature 第 128–130 行原清单附带备注 ocdav: double-check the webdav property parsing when custom namespaces are used指明排查方向在 ocdav 层的属性解析。Sync 区旧式分块上传带 checksum 应失败但经新 DAV 路径上传的行为异常#2323——coreApiMain/checksums.feature 第 233–235 行。Share 区PROPFIND 的d:quota-available-bytesdprop 返回值错误#8197——coreApiWebdavProperties/getQuota.feature 第 57–59、73–75 行在接收的共享文件夹内删除文件会被移入共享者而非接收者的回收站#1124——coreApiTrashbin/trashbinSharingToShares.feature 第 54–56、83–85、142–144、202–203 行。Other 区场景最多已知缺陷issue 编号受影响场景位置普通用户向他人或不存在用户的 WebDAV 端点发送 MKCOL 应返回 404#5049备注 ocdav: api compatibility, return correct status codecoreApiAuth/webDavMKCOLAuth.feature 第 42、53 行尝试锁定他人文件返回 HTTP 500#2176coreApiAuth/webDavLOCKAuth.feature 第 46、58 行未认证请求的WWW-Authenticate头不够明确#2285coreApiWebdavOperations/refuseAccess.feature 第 21、22 行TUS 上传错误 checksum 的 PATCH 响应错误#1755与 OpenCloud API 区同缺陷coreApiWebdavUploadTUS/checksums.feature 第 74–79、147–149、192–197、240–245 行coreApiWebdavUploadTUS/uploadToShare.feature 第 255–256、279–280、376–377 行删除他人回收站项对 spaces 路径返回 409 而非 404#9791coreApiTrashbin/trashbinDelete.feature 第 92 行MOVE 到同名同目录返回 404 而非 403#1976与 OpenCloud API 区同缺陷coreApiWebdavMove/moveFile.feature 第 100–102 行coreApiWebdavMove/moveFolder.feature 第 217–219 行coreApiWebdavMove/moveShareOnOpencloud.feature 第 334、337、340 行COPY 到同名是允许的folder 在 spaces 路径下报 500#8711coreApiSharePublicLink2/copyFromPublicLink.feature 第 198 行coreApiWebdavCopyCreate/copyFile.feature 第 1094–1096 行恢复个人文件到接收共享文件夹内的文件返回 403 但共享文件已被删除#10356coreApiTrashbin/trashbinSharingToShares.feature 第 277 行预览中 UTF 字符不显示opencloud 项目 issue #1451coreApiWebdavPreviews/previews.feature 第 249–251 行文本文件预览被截断opencloud 项目 issue #1452coreApiWebdavPreviews/previews.feature 第 263–265 行notification 分区issue #323apiNotification/emailNotification.feature 第 280、298 行与 apiNotification/spaceNotification.feature 第 463 行。Wont fix 区明确不修的条目清单末尾的 Wont fix 区记录了有意不实现的行为差异这是预期失败清单的另一类合法形态——不是待修复而是设计如此黑名单忽略文件blacklisted ignored files不再被要求支持因为 OpenCloud 不需要像 Apache 那样处理用户提供的.htaccess文件所带来的安全问题。该区还有一条维护性注释文件末尾必须保留一个空行因为处理该文件的 bash 脚本要求最后一行以换行符结尾——这与上文 lint-expected-failures.sh 的换行检测逻辑一一对应。实战工作流修复一个预期失败项tests/README.md 的 Use Existing Tests for BDD 一节给出了标准流程本质是把这份清单当作待办事项驱动开发第 1 步本地复现。以清单中的 issue #4637 为例先在 decomposed 驱动下逐个运行对应场景make test-acceptance-api \ TEST_SERVER_URLhttps://localhost:9200 \ STORAGE_DRIVERdecomposed \ BEHAT_FEATUREtests/acceptance/features/apiArchiver/downloadByPath.feature:25feature:行号语法即清单条目中引用的那个行号README 特别提醒行号不一定总是指向场景起始行运行前请核对。本地运行 OpenCloud 需先构建二进制并以PROXY_ENABLE_BASIC_AUTHtrue启动允许测试通过 provisioning API 使用 basic auth。第 2 步定位失败原因理解场景为什么失败——对 decomposed 存储而言多数问题与元数据lookup/节点属性与数据blob分离的存储模型相关。仓库甚至提供了专门的离线检查工具 decomposedfs.go 下的opencloud decomposedfs check-treesize --root 存储根 --node spaceId与opencloud decomposedfs metadata dump/get/set命令可用来直接检查与修补 Space 的 treesize 元数据和节点属性--repair模式要求 OpenCloud 未运行。第 3 步修复代码循环验证直到场景通过。第 4 步更新清单并提 PR。将已修复场景对应的行从expected-failures-decomposed-storage.md中删除把代码修复与清单删减放进同一个 PR。若忘记删除CI 的反方向校验expected to fail but did not fail会立刻暴露若场景引用的 feature 被整体删除check-deleted-suites-in-expected-failure.sh 会列出悬挂条目。替代的 CI 路径也可以直接在 Docker 流水线里跑STORAGE_DRIVERdecomposed会自动挂上本清单并启用~skipOnOpencloud-decomposed-Storagetag 过滤STORAGE_DRIVERdecomposed \ BEHAT_SUITEapiLocks \ make -C tests/acceptance/docker run-api-tests小结expected-failures-decomposed-storage.md是 OpenCloud 验收测试体系中已知缺陷登记处其设计要点可以归纳为清单即契约CI 通过 run.sh 做双向比对未登记的失败与已修复未登记的意外通过都会使流水线失败格式强校验lint-expected-failures.sh 强制suite/feature.feature:line格式、链接与行号一致、无重复、文件以换行结尾反腐化检查check-deleted-suites-in-expected-failure.sh 保证清单中不存在指向已删除 feature 的悬挂条目驱动隔离与 posix、without-remotephp 两份清单并列由 run-tests.sh 按STORAGE_DRIVER选择驱动开发闭环按 tests/README.md 的流程逐个复现、修复、删行、合入 PR使清单随版本推进不断收敛。对使用者而言这份文件也是decomposed 存储当前已知行为差异的权威索引——例如在 decomposed 驱动下使用文件锁、按 file-id 移动共享文件、OCM 联邦连接管理等能力时应先核对其中的已知缺陷判断所依赖的行为是否落在当前预期失败范围内。【免费下载链接】opencloud️ OpenCloud is the open source platform for file management, sharing and collaboration. Simple and sovereign.项目地址: https://gitcode.com/GitHub_Trending/op/opencloud创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考