# OCDP 第二次测试报告 **测试日期:** 2026-05-11 **测试环境:** http://10.6.80.114:18080 --- ## 测试1: 资源配额限额 ### 测试方法 使用 test-user-b(quota: cpu=2, mem=4Gi, gpu=0, gpumem=0)在 k3s 集群部署 nginx chart ### 测试结果 | 测试 | 操作 | 预期 | 实际 | 结论 | |------|------|------|------|------| | Test A | 部署 nginx(默认值,在配额内) | 成功 | 部署完成,状态 deployed | ✅ | | Test B | 部署 nginx(requests.cpu=2, mem=4Gi, replica=5,超配额) | 被配额阻止 | Helm release 创建成功,所有 Pod 被 ResourceQuota 阻塞,状态永远 stuck 在 pending-install | ⚠️ 部分通过 | | Test C | 部署 vllm-serve(gpuLimit=1,gpu配额=0) | 被配额阻止 | Helm release 创建成功,Pod 被 ResourceQuota 阻塞,状态 pending-install | ⚠️ 部分通过 | ### 关键发现 **1. 没有 API 层的预检查配额验证** - 后端 API 无条件接受所有部署请求,不检查是否超配额 - 所有超配额请求返回 HTTP 200 + status: pending-install - 后端日志中**没有任何配额相关的条目** **2. K8s ResourceQuota 在 Pod 级别执行** - `tenant-quota` ResourceQuota 对象确实存在并执行限制 - 当 Pod 超配额时,K8s 明确拒绝创建并给出错误消息 - 但 Helm release、Service、Deployment、ReplicaSet **仍然被创建** **3. 实例永远 stuck 在 "pending-install"** - 超配额的实例永远不会转换到 deployed/failed/error - OCDP 平台不检测 ResourceQuota 拒绝事件 - 唯一知道失败的方式是直接查 K8s events **4. GPU 配额绕过** - gpu=0 的用户可以提交需要 GPU 的 chart 部署 - K8s ResourceQuota 最终会阻止,但 Helm release 等资源已被创建 **5. 有效的 ResourceQuota 配置** ```yaml apiVersion: v1 kind: ResourceQuota metadata: name: tenant-quota namespace: ocdp-u-test-b spec: hard: requests.cpu: "2" requests.memory: 4Gi requests.nvidia.com/gpu: "0" requests.nvidia.com/gpumem: "0" ``` ### 建议 1. **添加 API 层预检查配额验证** — 在接受部署前检查请求资源是否超过用户配额 2. **处理 pending-install 超时** — 监控 Helm release 创建后 Pod 是否 stuck,更新状态为 failed 3. **GPU 配额预检查** — 如果 chart 需要 GPU 而用户 gpu=0,在 API 层拒绝 4. **UI 配额指示器** — 在部署表单上显示剩余配额 --- ## 测试2: values.yaml 覆盖优先级 ### 测试方法 使用 test-user-c(quota: cpu=4, mem=8Gi, gpu=1, gpumem=5000)部署 vllm-serve:0.6.0 chart ### 测试结果 | 方法 | 提交方式 | 是否部署成功 | 存储的值 | 结论 | |------|----------|-------------|---------|------| | 方法1 | `values` JSON 字段 | ✅ | cpuRequest=2, gpuMem=10000 | JSON 值被准确接受和存储 | | 方法2 | `valuesYaml` 字符串 | ✅ | cpuRequest=4, gpuMem=10000 | YAML 被正确解析为结构化 values | | 方法3 | 同时提供 `values` + `valuesYaml`(冲突) | ✅ 无任何错误/警告 | **values JSON 全胜** | `values` JSON 静默覆盖 `valuesYaml` | | 方法4 | 不提供任何 values(使用 chart 默认) | ✅ | 仅 namespace | chart 默认值不存储在 API 响应中 | ### 优先级最终结论 | 优先级 | 来源 | 说明 | |--------|------|------| | **最高** | `values` JSON 字段 | 请求体中的结构化 JSON | | **中** | `valuesYaml` 字符串 | 请求体中的 YAML 字符串 | | **最低** | Chart 内置 values.yaml | Helm chart 打包的默认值 | ### 冲突测试详细结果 当同时提供 `values` 和 `valuesYaml` 且值冲突时: - `values` JSON 字段**完全覆盖** `valuesYaml` - **没有任何错误或警告**返回给用户 - 两者被合并到统一的 DB `values` 字段 ### gpuMem=10000 行为 - 整数值 `10000` 在 `values` JSON 和 `valuesYaml` 中都被**正确接受** - 无单位转换(作为整数 MB 标量存储) - 符合项目规范 ### 建议 1. **记录优先级顺序** — 用户需知道同时提供两者时 values JSON 优先 2. **添加冲突警告** — 当两个字段存在冲突值时应返回警告 3. **考虑废弃一个字段** — values 和 valuesYaml 语义重复易混淆 --- ## 测试3: 前端 UI 溢出/滚动/刷新 ### 测试方法 Playwright + 源码分析,测试 1920/768/375 三个视口 ### 测试结果 **总体结论: PASS** — 没有导致功能问题的关键溢出问题 | 测试项 | 结果 | 详情 | |--------|------|------| | 水平溢出 | ✅ 无问题 | 所有视口均无水平溢出 | | 文本截断 | ⚠️ 1 个低风险 | InstanceCard h3 标题 truncate 无 title tooltip | | 响应式设计 | ✅ 正确 | sm/md/lg/xl 断点覆盖完整 | | 滚动行为 | ✅ 流畅 | Sidebar 和内容区独立滚动,overscroll-contain 防滚动穿透 | | 模态框布局 | ✅ 正确 | body scroll lock + 内容独立滚动 | | 页面刷新 | ✅ 正常 | 受保护路由正确重定向到登录页 | | 颜色对比度 | ⚠️ 1 个中风险 | 登录页错误文本 red-400 在白色背景上仅 2.5:1 (WCAG AA 要求 4.5:1) | ### 通过的细分项 - Chart Browser 全高 + overflow-y-auto 布局 ✅ - InstanceCard 操作按钮网格 grid-cols-2/3/5 响应正确 ✅ - Tabs 支持 overflow-x-auto 水平滚动 ✅ - 用户管理表格 overflow-x-auto ✅ - iOS 触摸滚动 (`-webkit-overflow-scrolling: touch`) 已配置 ✅ ### 建议 1. 将登录页错误文本从 text-red-400 改为 text-red-600/700 2. InstanceCard h3 标题添加 title 属性 --- ## 综合建议 1. 添加 API 层配额预检查 2. 处理 pending-install 超时 + 状态更新 3. 记录 values 覆盖优先级并添加冲突警告 4. 统一 values JSON/YAML 的 API 设计