Skip to content

Make testcase#78

Merged
weibaohui merged 15 commits intomainfrom
make-testcase
Feb 6, 2026
Merged

Make testcase#78
weibaohui merged 15 commits intomainfrom
make-testcase

Conversation

@weibaohui
Copy link
Copy Markdown
Owner

No description provided.

将 Client 和 DynamicClient 字段类型从具体实现改为 kubernetes.Interface 和 dynamic.Interface
修改 pod 链式方法为不可变实现,避免副作用
添加 mock_k8s_test.go 提供完整的 fake client 测试支持
在 Namespace 方法中,当生成的 SQL 条件不为空时,错误地将条件应用到了 `k.Where` 而非返回的 `tx.Where`,导致条件未正确传递给事务查询对象。现在改为正确应用到 `tx.Where` 以返回带有条件的事务对象。
- 新增回调注册测试验证自定义回调逻辑
- 添加 Pod、Deployment、Service、Namespace 等核心资源的 CRUD 测试
- 实现 SQL 查询构建器和语句构建器测试
- 完善工具类测试,包括资源类型检测和对象转换
- 添加应用器测试验证 YAML 创建、更新和删除
- 扩展控制台功能测试,涵盖 rollout、scale、label 等操作
- 修复 fake client 的 patch 类型问题,将 StrategicMergePatchType 改为 MergePatchType
- 增强模拟 Kubernetes 环境,支持更多 API 资源类型
- 添加覆盖率报告显示当前测试覆盖率为 15.3%
添加 ConfigMap、PVC、Service、Node、CronJob、DaemonSet、Ingress、Secret、StatefulSet 和 Deployment 的控制器测试文件,全面覆盖核心 Kubernetes 资源的 CRUD 操作及控制器功能。

修复模拟 Kubernetes 客户端在处理 StrategicMergePatchType 时可能因缺少模式信息而失败的问题,将其转换为 MergePatchType 作为临时解决方案。
添加多个测试文件,覆盖StorageClass、Status、CRD、ReplicaSet、Label/Annotate等资源操作方法,以及Cluster、Struct、Tools、Callback、Kubectl内部逻辑的单元测试。同时优化status.go中的客户端获取逻辑,移除冗余的discovery包导入,并改进mock_k8s_test.go以支持更全面的测试场景。
添加describe_test.go测试文件,包含Describe功能的正向、异常及参数验证测试用例。
扩展mock_k8s_test.go中的fake discovery资源列表,增加更多资源类型以支持测试场景。
在mock回调中注册fakeDescribe处理器,模拟describe操作的执行流程。
初始化集群的describerMap字段,避免测试中的空指针异常。
添加对 parseID、InitTrees 等核心函数的单元测试,覆盖 OpenAPI v2 文档解析和树结构构建的正确性。测试包括:
- 验证 ID 解析能正确提取组、版本和类型信息
- 确保 InitTrees 能正确构建文档树并处理引用展开
- 检查 FetchByRef 和 ListNames 等辅助方法的功能
- 修复 ctl_status_test.go 中的测试逻辑,改为注入 CRD 以验证 GatewayAPI 支持
- 增强 cluster_test.go 中的默认集群、移除集群及版本获取测试
- 新增 aws_test.go 以覆盖 AWS EKS 认证提供者的完整功能测试
- 在mock_k8s_test.go中注册autoscaling/v2 API资源以支持HorizontalPodAutoscaler测试
- 扩展ctl_status_test.go测试Status方法,包括Docs、OpenAPISchema、DescriberMap和APIResources
- 新增cluster_aws_test.go测试AWS集群注册功能
- 扩展ctl_crd_test.go测试ManagedResources相关方法,包括ManagedPods和HPAList
添加 HorizontalPodAutoscaler (autoscaling/v2) 和自定义资源 MyApp (example.com/v1) 到模拟的 Kubernetes 集群资源列表中,以确保相关测试可以正确发现和操作这些资源类型。
添加panic恢复机制,防止因单个资源查询失败导致整个状态汇总goroutine崩溃
- 新增 cluster_register_test.go 文件,包含 RegisterByConfigWithID 扩展功能和异常情况测试
- 新增 ctl_status_count_test.go 文件,包含 GetResourceCountSummary 的资源计数测试
- 扩展 cluster_test.go 中的 RegisterOptions 测试,验证注册选项的正确应用
- 测试覆盖缓存配置、身份模拟、代理设置、CA证书等注册选项功能
- 新增 cluster_manage_test.go 包含集群注册、查询、删除等功能的测试
- 扩展 tools_test.go 使用 testify 断言,覆盖 CRD 查询、GVR 转换等工具方法
- 在 callback_test.go 中添加 Watch 和对象链式调用测试
- 在 ctl_pod_test.go 中补充 StreamExecute 和 PortForward 测试
- 更新 mock_k8s_test.go 模拟 stream-exec 和 port-forward 回调处理器
- 改进 cluster_register_test.go 的证书生成和测试选项
- 添加 github.com/stretchr/testify 依赖以支持断言库
新增 DaemonSet 控制器的 Restart、Stop、Restore、ManagedPods 和 ManagedPod 方法。
为 Deployment 控制器添加 HPAList、ReplaceImageTag 和 ManagedPod 方法。
添加 cluster_kubeconfig_test.go 以测试集群注册功能。
引入 OpenSpec 相关技能文档,包括新建、归档、快速推进、同步规范、应用、继续、验证、批量归档、探索和入门指南。
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 6, 2026

📝 Walkthrough

Summary by CodeRabbit

发布说明

  • 新功能

    • 新增 OpenSpec 变更管理工作流,包括创建、应用、归档和验证变更的完整功能。
  • 文档

    • 新增 OpenSpec 完整入门指南和详细的技能文档,涵盖探索、应用、归档、验证和规范同步等工作流程。
  • 测试

    • 添加大量测试覆盖,确保系统可靠性。
  • 其他

    • 新增 OpenSpec 项目配置支持。

Walkthrough

这个拉取请求引入了十个 OpenSpec 技能文档文件、kom Kubernetes 客户端库的广泛测试覆盖、一个模拟 Kubernetes 集群的测试工具、接口类型的演进以及配置文件和依赖更新。

Changes

Cohort / File(s) Summary
OpenSpec 技能文档
.trae/skills/openspec-apply-change/SKILL.md, .trae/skills/openspec-archive-change/SKILL.md, .trae/skills/openspec-bulk-archive-change/SKILL.md, .trae/skills/openspec-continue-change/SKILL.md, .trae/skills/openspec-explore/SKILL.md, .trae/skills/openspec-ff-change/SKILL.md, .trae/skills/openspec-new-change/SKILL.md, .trae/skills/openspec-onboard/SKILL.md, .trae/skills/openspec-sync-specs/SKILL.md, .trae/skills/openspec-verify-change/SKILL.md
为 OpenSpec 工作流新增十个技能文档,定义了从探索、创建、继续、应用、归档到同步和验证等完整的变更管理生命周期。包含详细的工作流步骤、用户提示、输出格式和护栏机制。
kom 集群基础和 Kubectl 接口
kom/cluster_base.go, kom/kubectl.go
将 Client 从 *kubernetes.Clientset 改为 kubernetes.Interface,DynamicClient 从 *dynamic.DynamicClient 改为 dynamic.Interface,增强代码的可测试性和灵活性。
kom 模拟测试基础设施
kom/mock_k8s_test.go
实现 RegisterFakeCluster 及其配套的十二个假操作处理器(Get、List、Create、Update、Patch、Delete、Exec、Logs、Describe、StreamExec、PortForward 等),为测试提供完整的模拟 Kubernetes 集群能力。
kom 集群管理测试
kom/cluster_aws_test.go, kom/cluster_base_test.go, kom/cluster_kubeconfig_test.go, kom/cluster_manage_test.go, kom/cluster_register_test.go, kom/cluster_test.go
覆盖集群注册、AWS/EKS 认证、kubeconfig 解析、集群管理和配置选项等完整的集群生命周期。
kom 资源操作测试
kom/ctl_*.../ctl_*_test.go(包含 Pod、Deployment、Service、ConfigMap 等二十余个资源类型)
对 Kubernetes 各类资源的 CRUD 操作、扩缩容、重启、标签、注解等常见操作进行详尽的集成测试。
kom 高级功能测试
kom/applier_test.go, kom/callback_test.go, kom/describe_test.go, kom/kubectl_extended_test.go, kom/kubectl_test.go, kom/statement_test.go, kom/sql_test.go, kom/status.go
测试 Applier 多资源应用、回调链执行、资源描述、SQL 查询构建、状态统计等高级功能,以及 sql.go 中的命名空间过滤逻辑优化。
kom 工具和文档测试
kom/tools_test.go, kom/tools_extended_test.go, kom/doc/doc_test.go
验证 GVK/GVR 映射、CRD 解析、资源表名查询、OpenAPI 文档解析等工具函数和 API 文档处理。
覆盖率报告和配置
coverage_report.txt, openspec/config.yaml
新增代码覆盖率统计报告(总覆盖率 15.3%)和 OpenSpec 规格驱动配置文件。
依赖更新
go.mod
添加 github.com/stretchr/testify v1.10.0 依赖以支持断言功能。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Eks #58 — 实现了 kom/aws EKS 认证和令牌刷新功能,与本 PR 新增的 AWS 集群测试(cluster_aws_test.go、aws_test.go)直接相关。

Poem

🐰 一只兔子的庆贺

十个技能编织成网,
模拟集群如真一样,
测试覆盖遍地开花,
接口优雅如春风拂面,
OpenSpec 蓝图已成章,
工程更稳,代码更亮!✨

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch make-testcase

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
kom/sql.go (1)

177-177: ⚠️ Potential issue | 🟡 Minor

预存问题:len(opt) >= 0 恒为真,可能导致 panic。

len(opt) >= 0 对任何切片都成立。当 opt 为非 nil 的空切片时,此条件通过后,第 186 行的 opt[0] 会触发索引越界 panic。此处应为 len(opt) > 0

虽然这不是本次 PR 的变更范围,但建议一并修复。

🔧 建议修复
-	if opt != nil && len(opt) >= 0 {
+	if len(opt) > 0 {

注:len(opt) > 0 隐含 opt != nil,因此 nil 检查也可以省略。

kom/ctl_pod.go (1)

52-64: ⚠️ Potential issue | 🟠 Major

GetLogsopt 为 nil 时存在空指针解引用风险。

第 59 行将 opt 赋值给 tx.Statement.PodLogOptions,第 60 行立即对其解引用设置 Container。如果调用方传入 nil,将触发 panic。

🛡️ 建议添加 nil 检查
 func (p *pod) GetLogs(requestPtr interface{}, opt *v1.PodLogOptions) *pod {
 	tx := p.kubectl.getInstance()
+	if opt == nil {
+		opt = &v1.PodLogOptions{}
+	}
 	tx.Statement.PodLogOptions = opt
 	tx.Statement.PodLogOptions.Container = tx.Statement.ContainerName
🤖 Fix all issues with AI agents
In `@kom/cluster_test.go`:
- Around line 71-93: TestDefaultCluster relies on global state in Clusters() and
can be flakey; before registering test clusters, reset or remove any
pre-existing clusters and register cleanup to undo registrations. Modify
TestDefaultCluster to (1) clear relevant IDs from the Clusters() singleton at
the start (or call a provided reset method if available) so previous tests
cannot affect it, (2) use t.Cleanup to unregister or restore the cluster state
after RegisterFakeCluster calls, and (3) tighten the assertion in the Case 2
check on Clusters().DefaultCluster() (referencing TestDefaultCluster,
RegisterFakeCluster, Clusters(), and DefaultCluster) to assert the exact
expected ID ("default") when "InCluster" is not registered, rather than allowing
either value.

In `@kom/ctl_deploy_extended_test.go`:
- Around line 148-151: Remove the developer inner-note comments in the "Test
Restart" block of ctl_deploy_extended_test.go (the comment lines mentioning
"Let's check ctl_rollout.go. Yes, I fixed it..." and other in-progress thoughts)
so that only concise, relevant test comments remain; locate the "Test Restart"
section and delete or replace those internal decision traces with a short
neutral comment describing the test intent.
- Line 39: Several seed Resource(...).Create(...) calls (e.g., the call using
k.Resource(deploy).Create(deploy) and the other Create invocations around the
same area) ignore the returned error; change each bare Create(...) invocation to
capture its result and assert/check result.Error (for example using
t.Fatalf/require.NoError/Assert) so test execution fails immediately with the
real error when seed creation fails; update the Create calls at the same spots
mentioned (the calls at the other Create sites) to use the same pattern and
include a descriptive message referencing the resource being created.
- Around line 116-120: 在多处使用 k.Resource(&d).Namespace(ns).Name(name).Get(&d)
时没有检查返回错误,可能导致使用旧的 d 值误判;修改这些调用(例如在 kom/ctl_deploy_extended_test.go 中对变量 d
appsv1.Deployment 的所有 Get 调用)为接收并检查错误:err :=
k.Resource(&d).Namespace(ns).Name(name).Get(&d) 并在 err != nil 时通过 t.Fatalf 或
t.Fatalf/ t.Fatalf 类似的测试失败处理(带上上下文错误信息),然后再对 *d.Spec.Replicas 等断言进行验证。

In `@kom/statement_test.go`:
- Around line 46-59: The test assertions for WithLabelSelector and
WithFieldSelector incorrectly use "len(...) > 0 && ..." which short-circuits
when ListOptions is empty and hides failures; update tests around
WithLabelSelector, WithFieldSelector and the Statement.ListOptions checks to
first assert ListOptions is non-empty (e.g. if len(kX.Statement.ListOptions) ==
0 { t.Errorf("ListOptions empty for WithLabelSelector/WithFieldSelector") }) and
then check the specific selector value (e.g. if
kX.Statement.ListOptions[0].LabelSelector != "expected" {
t.Errorf("LabelSelector mismatch") }), doing the same pattern for FieldSelector
and for the merged label case in WithLabelSelector.
🟡 Minor comments (20)
.trae/skills/openspec-bulk-archive-change/SKILL.md-55-58 (1)

55-58: ⚠️ Potential issue | 🟡 Minor

为所有围栏代码块补充语言标识以通过 lint。

本文件存在多处未指定语言的 ``` 代码块,markdownlint 已提示 MD040。建议统一补充 text/`bash`/`markdown` 等语言标识。

🛠️ 示例修正(其余代码块同理补充语言标识)
-   ```
+   ```text
    auth -> [change-a, change-b]  <- CONFLICT (2+ changes)
    api  -> [change-c]            <- OK (only 1 change)
-   ```
+   ```

Also applies to: 86-94, 96-99, 143-157

.trae/skills/openspec-onboard/SKILL.md-35-51 (1)

35-51: ⚠️ Potential issue | 🟡 Minor

为所有围栏代码块补充语言标识以通过 lint。

本文件存在多处未指定语言的 ``` 代码块,markdownlint 已提示 MD040。建议统一补充 text/`bash`/`markdown` 等语言标识。

🛠️ 示例修正(其余代码块同理补充语言标识)
-```
+```markdown
 ## Welcome to OpenSpec!
@@
-```
+```

Also applies to: 77-101, 140-152

.trae/skills/openspec-verify-change/SKILL.md-112-123 (1)

112-123: ⚠️ Potential issue | 🟡 Minor

为所有围栏代码块补充语言标识以通过 lint。

本文件存在多处未指定语言的 ``` 代码块,markdownlint 已提示 MD040。建议统一补充 text/`bash`/`markdown` 等语言标识。

🛠️ 示例修正(其余代码块同理补充语言标识)
-   ```
+   ```markdown
    ## Verification Report: <change-name>
@@
-   ```
+   ```

Also applies to: 124-140

.trae/skills/openspec-verify-change/SKILL.md-163-163 (1)

163-163: ⚠️ Potential issue | 🟡 Minor

“markdown”应为“Markdown”。

Line 163 的专有名词建议大写以保持一致性与规范性。

kom/ctl_service_extended_test.go-60-64 (1)

60-64: ⚠️ Potential issue | 🟡 Minor

第 61 行 Get 操作的错误未检查。

Update 后重新 Get 的返回值未检查错误。如果 Get 失败,updated 将是零值结构体,第 62 行的端口断言会在错误数据上通过或给出误导性的失败信息。

🐛 建议检查 Get 错误
 	var updated corev1.Service
-	k.Resource(&updated).Namespace(ns).Name(name).Get(&updated)
+	err = k.Resource(&updated).Namespace(ns).Name(name).Get(&updated).Error
+	if err != nil {
+		t.Fatalf("Get after Update failed: %v", err)
+	}
 	if updated.Spec.Ports[0].Port != 8080 {
kom/ctl_configmap_test.go-57-61 (1)

57-61: ⚠️ Potential issue | 🟡 Minor

Update 后重新 Get 缺少错误检查(与 Ingress 测试同类问题)。

第 58 行 k.Resource(&updated).Namespace(ns).Name(name).Get(&updated) 未检查 .Error,如果 Get 失败,第 59 行断言会产生误导性错误信息。

🔧 建议添加错误检查
 	var updated corev1.ConfigMap
-	k.Resource(&updated).Namespace(ns).Name(name).Get(&updated)
-	if updated.Data["key"] != "newValue" {
+	err = k.Resource(&updated).Namespace(ns).Name(name).Get(&updated).Error
+	if err != nil {
+		t.Fatalf("Get after Update failed: %v", err)
+	}
+	if updated.Data["key"] != "newValue" {
kom/ctl_ingress_test.go-82-86 (1)

82-86: ⚠️ Potential issue | 🟡 Minor

Update 后重新 Get 时缺少错误检查。

第 83 行的 Get(&updated) 调用没有检查 .Error。如果 Get 失败,updated 可能是零值,后续第 84 行的断言会报一个误导性的错误信息,而不是真正的 Get 失败原因。

🔧 建议添加错误检查
-	k.Resource(&updated).Namespace(ns).Name(name).Get(&updated)
-	if updated.Spec.Rules[0].Host != "new.example.com" {
+	err = k.Resource(&updated).Namespace(ns).Name(name).Get(&updated).Error
+	if err != nil {
+		t.Fatalf("Get after Update failed: %v", err)
+	}
+	if updated.Spec.Rules[0].Host != "new.example.com" {
kom/ctl_node_test.go-59-62 (1)

59-62: ⚠️ Potential issue | 🟡 Minor

Cordon 后重新获取节点时未检查 Get 错误。

如果 Get 失败,fetched 可能仍是旧数据,后续断言会给出误导性结果。同样的问题也存在于第 69 行的 UnCordon 验证处。

建议修复
-	k.Resource(&fetched).Name(name).Get(&fetched)
+	err = k.Resource(&fetched).Name(name).Get(&fetched).Error
+	if err != nil {
+		t.Fatalf("Get after Cordon failed: %v", err)
+	}
 	if !fetched.Spec.Unschedulable {
 		t.Errorf("Expected node to be unschedulable after Cordon")
 	}

第 69 行同理:

-	k.Resource(&fetched).Name(name).Get(&fetched)
+	err = k.Resource(&fetched).Name(name).Get(&fetched).Error
+	if err != nil {
+		t.Fatalf("Get after UnCordon failed: %v", err)
+	}
 	if fetched.Spec.Unschedulable {
 		t.Errorf("Expected node to be schedulable after UnCordon")
 	}
kom/ctl_rollout_test.go-53-53 (1)

53-53: ⚠️ Potential issue | 🟡 Minor

Deployment 和 ReplicaSet 的 Create 调用均未检查错误。

第 53、83、112 行的 Create 返回值被丢弃。如果任一创建失败,后续 History/Status/Restart/Undo 测试都会产生级联的、难以排查的错误。建议与其他测试文件保持一致,使用 t.Fatalf 及早终止。

建议修复
-	k.Resource(deploy).Create(deploy)
+	err := k.Resource(deploy).Create(deploy).Error
+	if err != nil {
+		t.Fatalf("Create deploy failed: %v", err)
+	}

第 83 行和第 112 行同理:

-	k.Resource(rs1).Create(rs1)
+	err = k.Resource(rs1).Create(rs1).Error
+	if err != nil {
+		t.Fatalf("Create rs1 failed: %v", err)
+	}
-	k.Resource(rs2).Create(rs2)
+	err = k.Resource(rs2).Create(rs2).Error
+	if err != nil {
+		t.Fatalf("Create rs2 failed: %v", err)
+	}
kom/ctl_pvc_test.go-59-63 (1)

59-63: ⚠️ Potential issue | 🟡 Minor

Update 后重新获取 PVC 时未检查 Get 错误。

如果 Get 失败,updated 为零值,Labels 为 nil,断言会给出误导性的失败信息而非明确的错误提示。

建议修复
 var updated corev1.PersistentVolumeClaim
-k.Resource(&updated).Namespace(ns).Name(name).Get(&updated)
+err = k.Resource(&updated).Namespace(ns).Name(name).Get(&updated).Error
+if err != nil {
+	t.Fatalf("Get after Update failed: %v", err)
+}
 if updated.Labels["updated"] != "true" {
kom/ctl_rs_test.go-66-69 (1)

66-69: ⚠️ Potential issue | 🟡 Minor

Scale/Stop/Restore 后多次 Get 均未检查错误。

第 66、76、85 行的 Get 调用均未检查 .Error。如果操作实际失败,fetched 中残留的旧副本数会使断言静默通过,掩盖真正的问题。

建议修复(以 Scale 为例,Stop/Restore 同理)
-	k.Resource(&fetched).Get(&fetched)
-	if *fetched.Spec.Replicas != 5 {
+	err = k.Resource(&fetched).Get(&fetched).Error
+	if err != nil {
+		t.Fatalf("Get after Scale failed: %v", err)
+	}
+	if *fetched.Spec.Replicas != 5 {
kom/tools_extended_test.go-125-135 (1)

125-135: ⚠️ Potential issue | 🟡 Minor

GetCRD 失败后 gotCRD 可能为 nil,导致后续调用 panic。

Line 127 使用 t.Errorf 而非 t.Fatalf,意味着即使 GetCRD 返回错误,测试仍会继续执行到 Line 131 的 GetGVRFromCRD(gotCRD)。如果 gotCRD 为 nil,这很可能导致 panic。

建议修复
 	gotCRD, err := k.Tools().GetCRD("MyCRD", "example.com")
 	if err != nil {
-		t.Errorf("GetCRD failed: %v", err)
+		t.Fatalf("GetCRD failed: %v", err)
 	}
kom/ctl_secret_test.go-44-51 (1)

44-51: ⚠️ Potential issue | 🟡 Minor

Get 验证实际上没有进行任何断言。

Lines 44-51 的 if/else 分支中没有调用 t.Errort.Fatal。无论 StringDataData 的值是什么,测试都会静默通过。这使得 Get 操作的验证形同虚设。

建议添加实际的错误断言
-	if fetched.StringData["key"] != "value" {
-		// If StringData is empty, check Data
-		if string(fetched.Data["key"]) != "value" {
-			// If both are empty, that's an issue with how we create or fetch.
-			// But for now let's assume one of them works.
-			// Actually, let's just use Data for update test to be safe.
-		}
-	}
+	if fetched.StringData["key"] != "value" && string(fetched.Data["key"]) != "value" {
+		t.Errorf("Expected key='value' in StringData or Data, got StringData=%v, Data=%v",
+			fetched.StringData, fetched.Data)
+	}
kom/ctl_secret_test.go-70-70 (1)

70-70: ⚠️ Potential issue | 🟡 Minor

Get 操作的 error 未检查。

Line 70 调用了 Get(&updated) 但忽略了返回的 error。如果 Get 失败,后续 Line 72 的断言可能基于未初始化的数据产生误导性结果。

建议检查 error
-	k.Resource(&updated).Namespace(ns).Name(name).Get(&updated)
+	err = k.Resource(&updated).Namespace(ns).Name(name).Get(&updated).Error
+	if err != nil {
+		t.Fatalf("Get after update failed: %v", err)
+	}
kom/ctl_extended_test.go-86-101 (1)

86-101: ⚠️ Potential issue | 🟡 Minor

ds.UID 为空值,OwnerReference 匹配将失效。

第96行使用 UID: ds.UID 作为 OwnerReference,但 ds 是本地构造的对象,其 UID 为零值(空字符串)。即使 fake 动态客户端在 Create 时生成了 UID,它也不会回写到本地的 ds 变量中。因此 ManagedPods 通过 OwnerReference 过滤时,UID 将无法匹配。

如果 ManagedPods 实现中依赖 UID 做精确匹配,此测试实际上无法验证正确的行为。建议在 Create 后重新 Get DaemonSet 以获取服务端生成的 UID,或在构造时手动设置一个确定的 UID。

kom/ctl_extended_test.go-37-37 (1)

37-37: ⚠️ Potential issue | 🟡 Minor

三处 Create 调用均未检查错误,导致后续断言可能无效。

第37、72、101行的 k.Resource(...).Create(...) 返回值都被忽略。如果资源创建失败(例如 GVR 匹配问题),后续的 PauseStopManagedPods 等操作将在不存在的资源上运行,测试结果不可信。

建议至少对创建结果做 Fatal 检查
-	k.Resource(cj).Create(cj)
+	if err := k.Resource(cj).Create(cj).Error; err != nil {
+		t.Fatalf("Failed to create CronJob: %v", err)
+	}

同样适用于第72行(DaemonSet)和第101行(Pod)。

Also applies to: 72-72, 101-101

kom/tools_test.go-172-186 (1)

172-186: ⚠️ Potential issue | 🟡 Minor

第185行的类型断言未做安全检查,测试可能 panic 而非报告失败。

result["metadata"].(map[string]interface{})["name"] 如果 metadata 的实际类型不是 map[string]interface{},将触发 panic 而非产生清晰的测试失败信息。

建议使用 comma-ok 模式或嵌套断言
-		assert.Equal(t, "test-pod", result["metadata"].(map[string]interface{})["name"])
+		meta, ok := result["metadata"].(map[string]interface{})
+		assert.True(t, ok, "metadata should be map[string]interface{}")
+		if ok {
+			assert.Equal(t, "test-pod", meta["name"])
+		}
kom/ctl_status_test.go-103-108 (1)

103-108: ⚠️ Potential issue | 🟡 Minor

APIResources 断言始终为真,无法验证 SetAPIResources 的实际效果。

第104行将 apiResources 设置为空切片 []*metav1.APIResource{}(非 nil),然后第106行断言 APIResources() != nil。由于空切片在 Go 中不是 nil,此断言永远通过,无论 SetAPIResources 是否真正生效。

建议改为设置含有元素的切片并验证长度,或验证 APIResources() 返回的切片与设置的切片引用一致:

更有意义的断言
-	cluster.apiResources = []*metav1.APIResource{}
-	k.Status().SetAPIResources(cluster.apiResources)
-	if k.Status().APIResources() == nil {
-		t.Error("APIResources should not be nil after setting")
-	}
+	mockResources := []*metav1.APIResource{{Name: "pods", Kind: "Pod"}}
+	k.Status().SetAPIResources(mockResources)
+	if got := k.Status().APIResources(); len(got) != 1 {
+		t.Errorf("Expected 1 APIResource, got %d", len(got))
+	}
kom/ctl_test.go-127-141 (1)

127-141: ⚠️ Potential issue | 🟡 Minor

Create 调用的错误被忽略,后续操作可能在不存在的资源上运行。

第134行 k.Resource(&pod).Create(&pod) 的错误未检查。如果创建失败,第137、140行的 Label / Annotate 操作将在不存在的 Pod 上执行,测试结果毫无意义。

建议检查 Create 错误
-	k.Resource(&pod).Create(&pod)
+	if err := k.Resource(&pod).Create(&pod).Error; err != nil {
+		t.Fatalf("Failed to create pod: %v", err)
+	}
kom/kubectl_test.go-198-198 (1)

198-198: ⚠️ Potential issue | 🟡 Minor

json.Marshal 的错误被忽略。

如果序列化失败,patchBytesnil,后续 Patch 调用行为不可预测,测试结果将难以排查。

🛡️ 建议的修改
-	patchBytes, _ := json.Marshal(patchData)
+	patchBytes, err := json.Marshal(patchData)
+	if err != nil {
+		t.Fatalf("Failed to marshal patch data: %v", err)
+	}
🧹 Nitpick comments (56)
.trae/skills/openspec-sync-specs/SKILL.md (1)

115-131: 为该围栏代码块补充语言标识
Line 117 的代码块缺少语言标识,触发 MD040。建议标注为 textmarkdown,以避免 lint 警告并提升可读性。

.trae/skills/openspec-explore/SKILL.md (6)

53-69: 为 ASCII 图示代码块补充语言标识
Line 54 的围栏代码块缺少语言标识,建议标注为 text,避免 MD040 警告。


149-171: 为示例对话代码块补充语言标识
Line 150 的围栏代码块缺少语言标识,建议标注为 text


173-201: 为示例对话代码块补充语言标识
Line 173 的围栏代码块缺少语言标识,建议标注为 text


204-218: 为示例对话代码块补充语言标识
Line 204 的围栏代码块缺少语言标识,建议标注为 text


221-247: 为示例对话代码块补充语言标识
Line 221 的围栏代码块缺少语言标识,建议标注为 text


262-275: 为总结模板代码块补充语言标识
Line 262 的围栏代码块缺少语言标识,建议标注为 textmarkdown

.trae/skills/openspec-apply-change/SKILL.md (4)

90-102: 为示例输出代码块补充语言标识
Line 92 的围栏代码块缺少语言标识,建议标注为 textmarkdown


104-119: 为完成输出代码块补充语言标识
Line 106 的围栏代码块缺少语言标识,建议标注为 textmarkdown


121-139: 为暂停输出代码块补充语言标识
Line 123 的围栏代码块缺少语言标识,建议标注为 textmarkdown


151-156: 句子主语不完整,建议补全以避免歧义
Can be invoked anytime …” 这一条缺少明确主语,建议改成 “This skill can be invoked anytime …”。

.trae/skills/openspec-archive-change/SKILL.md (1)

94-105: 为成功输出代码块补充语言标识
Line 96 的围栏代码块缺少语言标识,建议标注为 textmarkdown

kom/ctl_sc_test.go (4)

29-37: Get 失败后继续断言 fetched.Name 可能产生误导性错误信息

第 32-34 行在 Get 失败时使用 t.Errorf(不会终止测试),然后第 35 行继续检查 fetched.Name。如果 Get 确实失败了,fetched 可能是零值,会触发第二个与实际问题无关的错误信息,干扰问题定位。

建议在 Get 失败后使用 t.Fatalf 终止测试,与 Create 的处理方式保持一致;或者在 t.Errorf 后加 return / 将后续断言放入 else 分支。

♻️ 建议修改
 	err = k.Resource(&fetched).Name(name).Get(&fetched).Error
 	if err != nil {
-		t.Errorf("Get failed: %v", err)
+		t.Fatalf("Get failed: %v", err)
 	}

39-47: List 失败后继续检查长度,与 Get 同理

与上面 Get 部分相同的问题:如果 List 失败,scList 可能为 nil(len(nil) 在 Go 中返回 0,不会 panic),但会产生一个额外的 "Expected 1 SC, got 0" 错误,掩盖真正的 List 失败原因。

♻️ 建议修改
 	err = k.Resource(&storagev1.StorageClass{}).List(&scList).Error
 	if err != nil {
-		t.Errorf("List failed: %v", err)
+		t.Fatalf("List failed: %v", err)
 	}

49-53: Delete 后缺少验证,建议增加删除后的确认断言

当前测试仅验证了 Delete 调用无错误返回,但没有验证资源是否真正被删除。建议在 Delete 后再执行一次 List 或 Get,确认资源已不存在,以提高测试的可靠性。

♻️ 建议在 Delete 后增加验证
 	err = k.Resource(&fetched).Delete().Error
 	if err != nil {
 		t.Errorf("Delete failed: %v", err)
 	}
+
+	// 验证删除后资源不再存在
+	var scListAfterDelete []storagev1.StorageClass
+	err = k.Resource(&storagev1.StorageClass{}).List(&scListAfterDelete).Error
+	if err != nil {
+		t.Errorf("List after delete failed: %v", err)
+	}
+	if len(scListAfterDelete) != 0 {
+		t.Errorf("Expected 0 SC after delete, got %d", len(scListAfterDelete))
+	}

10-13: RegisterFakeCluster 没有清理 的提议可以改进,但并非必需

当前代码中 RegisterFakeCluster("sc-cluster") 将集群存储在全局注册表中,且没有在测试结束后清理。不过由于该测试套件中每个测试都使用了唯一的集群 ID,且集群在全局注册表中按 ID 隔离,所以实际上不存在状态污染问题。

虽然可以使用 t.Cleanup 结合 RemoveClusterById() 作为最佳实践(提高代码的防御性和可维护性),但这不是必需的。注意整个测试套件都遵循相同的模式,没有进行显式清理。如果计划改进这一点,应在整个项目中保持一致的做法。

kom/doc/doc_test.go (2)

37-152: 建议将单体测试拆分为子测试(t.Run),提高隔离性和失败定位效率。

当前 TestInitTrees 函数同时测试了 InitTrees、Pod 节点验证、FetchByRefListNames,任一中间步骤失败时,后续断言的上下文不够清晰。使用 t.Run 可以改善:

t.Run("FetchByRef_ObjectMeta", func(t *testing.T) {
    refNode := d.FetchByRef("#/definitions/io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta")
    if refNode == nil {
        t.Fatal("FetchByRef failed for ObjectMeta")
    }
    if refNode.Label != "ObjectMeta" {
        t.Errorf("FetchByRef node label expected ObjectMeta, got %s", refNode.Label)
    }
})

144-147: 清理探究性注释。

第 144 行 // parseID extracts kind as label? 和第 145 行 // buildTree splits name by "."... 是调查阶段的疑问注释,不适合留在最终测试代码中。建议删除或改为确定性的说明注释。

♻️ 建议修改
-		if refNode.Label != "ObjectMeta" { // parseID extracts kind as label? 
-            // buildTree splits name by ".", so io.k8s...ObjectMeta -> ObjectMeta
+		if refNode.Label != "ObjectMeta" {
 			t.Errorf("FetchByRef node label expected ObjectMeta, got %s", refNode.Label)
coverage_report.txt (1)

1-329: 不建议将覆盖率报告文件提交到版本控制中。

coverage_report.txt 是测试生成的产物,每次测试运行都会变化,提交到仓库中会在后续 PR 中造成不必要的 diff 噪音。建议:

  1. 将此文件添加到 .gitignore
  2. 在 CI 流水线中生成覆盖率报告,并发布到覆盖率服务(如 Codecov)或作为 CI artifact 保存
  3. 从仓库中移除此文件
kom/sql_test.go (1)

21-53: 条件查找逻辑重复,可抽取辅助函数。

三处条件搜索循环(lines 22-26, 34-38, 46-50)模式完全相同,可考虑提取为测试辅助函数以减少重复。

♻️ 可选:提取辅助函数
func hasCondition(conditions []*Condition, field, value string) bool {
	for _, c := range conditions {
		if c.Field == field && c.Value == value {
			return true
		}
	}
	return false
}

然后各处简化为:

if !hasCondition(k2.Statement.Filter.Conditions, "metadata.name", "pod1") {
    t.Errorf("Sql condition name mismatch")
}
kom/callback_test.go (2)

78-84: p.Execute(k) 的错误返回值被忽略了。

第 80 行调用 p.Execute(k) 后未检查返回的 error,而在第 52 行和第 64 行对同一方法的调用都做了错误检查。建议保持一致。

♻️ 建议修复
 	executionOrder = nil
-	p.Execute(k)
+	err = p.Execute(k)
+	if err != nil {
+		t.Errorf("Execute failed after replace: %v", err)
+	}
 	// Should be step1-replaced, step3

98-130: TestCallbackWildcard 中 p.Execute(k) 的错误返回值也未检查。

第 119 行 p.Execute(k) 忽略了返回的 error。如果执行过程中出现错误,测试会静默通过,建议加上错误断言。

♻️ 建议修复
-	p.Execute(k)
+	if err := p.Execute(k); err != nil {
+		t.Fatalf("Execute failed: %v", err)
+	}
kom/ctl_sts_test.go (1)

61-88: Scale/Stop/Restore 后的 Get 调用均未检查错误。

第 66、76、85 行的 k.Resource(&fetched).Get(&fetched) 未检查 .Error。如果 Get 静默失败,后续对 fetched.Spec.Replicas 的断言将基于旧数据操作,可能掩盖真实的 Scale/Stop/Restore 问题。

♻️ 以 Scale 部分(第 66-69 行)为例的修复建议
-	k.Resource(&fetched).Get(&fetched)
-	if *fetched.Spec.Replicas != 3 {
+	if err = k.Resource(&fetched).Get(&fetched).Error; err != nil {
+		t.Fatalf("Get after scale failed: %v", err)
+	}
+	if *fetched.Spec.Replicas != 3 {

其余第 76 行和第 85 行的 Get 调用也应做同样处理。

kom/aws/aws_test.go (1)

49-65: 命令校验测试依赖宿主环境的 echo 命令。

TestValidateCommandSuccessTestExecuteCommandEchoTestGetTokenWithRetry 等多个测试函数依赖系统 echo 命令的可用性。在 Windows CI 环境或受限容器中,echo 可能不是独立可执行文件(而是 shell 内置命令),exec.LookPath("echo") 可能会失败。如果需要跨平台兼容,可以考虑在不支持的平台上跳过测试。

kom/ctl_cronjob_test.go (1)

64-74: Update 后的 Get 调用未检查错误。

第 71 行 k.Resource(&updated).Namespace(ns).Name(name).Get(&updated) 的返回值被忽略。如果 Get 失败,第 72 行的 Schedule 断言将基于零值 updated 操作,可能导致误报。

♻️ 建议修复
-	k.Resource(&updated).Namespace(ns).Name(name).Get(&updated)
-	if updated.Spec.Schedule != "*/5 * * * *" {
+	if err = k.Resource(&updated).Namespace(ns).Name(name).Get(&updated).Error; err != nil {
+		t.Fatalf("Get after update failed: %v", err)
+	}
+	if updated.Spec.Schedule != "*/5 * * * *" {
kom/ctl_ds_test.go (2)

60-70: 多处 Get 调用未检查错误返回值。

第 67、90、101 行的 Get 调用均未检查 .Error。如果 Get 失败(例如由于前一步操作未正确生效),后续断言将基于旧数据运行,掩盖真正的缺陷。建议对所有用于验证状态变更的 Get 调用检查错误。

♻️ 以第 67 行为例的修复建议
-	k.Resource(&updated).Namespace(ns).Name(name).Get(&updated)
-	if updated.Labels["updated"] != "true" {
+	if err = k.Resource(&updated).Namespace(ns).Name(name).Get(&updated).Error; err != nil {
+		t.Fatalf("Get after update failed: %v", err)
+	}
+	if updated.Labels["updated"] != "true" {

Also applies to: 89-106


108-130: Pod 创建(第 120 行)的错误未检查,可能导致 ManagedPods 测试误报。

k.Resource(pod).Create(pod).Error 被忽略。如果 Pod 创建失败,后续第 122 行的 ManagedPods() 断言 len(pods) != 1 将以一个令人困惑的错误信息失败,而非直接指出 Pod 创建问题。

♻️ 建议修复
-	k.Resource(pod).Create(pod)
+	if err = k.Resource(pod).Create(pod).Error; err != nil {
+		t.Fatalf("Create owned pod failed: %v", err)
+	}
kom/ctl_pod_test.go (1)

14-25: Execute 和 GetLogs 仅验证了无错误,缺少输出内容断言。

第 16 行 Execute(&res) 和第 22 行 GetLogs(&res, ...) 都没有验证 res 的实际内容(而 StreamExecute 在第 36 行做了内容断言)。建议补充对 res 的内容校验以提高测试置信度。

kom/ctl_deploy_test.go (1)

45-50: Update 后缺少重新 Get 验证更新结果。

与 Ingress 和 ConfigMap 测试不同,Deployment 的 Update 测试(第 45-50 行)仅验证了操作无错误,但未重新获取资源以确认 Replicas 已被更新为 2。建议补充验证以保持测试套件的一致性。

♻️ 建议补充更新验证
 	err = Cluster("deploy-cluster").Resource(&appsv1.Deployment{}).Namespace(ns).Name(name).Update(&res).Error
 	if err != nil {
 		t.Fatalf("Update Deployment failed: %v", err)
 	}
+	var updated appsv1.Deployment
+	err = Cluster("deploy-cluster").Resource(&appsv1.Deployment{}).Namespace(ns).Name(name).Get(&updated).Error
+	if err != nil {
+		t.Fatalf("Get after Update failed: %v", err)
+	}
+	if *updated.Spec.Replicas != 2 {
+		t.Errorf("Expected 2 replicas, got %d", *updated.Spec.Replicas)
+	}
kom/ctl_rollout_test.go (1)

39-45: Deployment 的 PodTemplateSpec 缺少 Containers 定义。

虽然在 fake client 下不会校验,但这使测试与真实 Kubernetes 对象的差异较大,降低了测试的可信度。如果未来换成 envtest 等更真实的测试环境,此测试会失败。建议补充一个最小的 Container 定义以保持一致性。

kom/cluster_kubeconfig_test.go (1)

33-33: 100ms 超时在慢速 CI 环境中可能导致偶发失败。

RegisterTimeout(100*time.Millisecond) 非常短。如果注册流程中涉及连接尝试(即使会立即失败),在网络栈负载较高时仍可能偶发超时。建议适当放宽到 1*time.Second 或更长,以降低 flaky test 的风险。

kom/cluster_register_test.go (2)

42-117: 建议使用 t.Run 子测试来隔离各个测试场景。

当前 5 个测试场景写在同一个函数中,如果前面的场景 t.Fatalf 失败,后续场景不会执行,且共享状态可能导致误报。使用 t.Run 可以提高可读性和隔离性,也方便单独运行某个子测试。

示例结构
 func TestRegisterByConfigWithID_Extended(t *testing.T) {
-	// 1. Test Register with CacheConfig
-	cfg := &rest.Config{Host: "https://test-cache-config"}
-	...
+	t.Run("CacheConfig", func(t *testing.T) {
+		cfg := &rest.Config{Host: "https://test-cache-config"}
+		// ...
+	})
+
+	t.Run("Impersonation", func(t *testing.T) {
+		// ...
+	})
+	// ... 其他场景类似
 }

19-40: generateSelfSignedCertPEM 静默返回 nil 可能掩盖问题。

如果密钥生成或证书创建失败,函数返回 nil 而不提供任何诊断信息。虽然调用方(Line 94)检查了 nil,但在调试时不清楚哪一步失败了。可以考虑接受 *testing.T 参数,直接用 t.Fatal 报错。

建议改进
-func generateSelfSignedCertPEM() []byte {
-	priv, err := rsa.GenerateKey(rand.Reader, 2048)
-	if err != nil {
-		return nil
-	}
+func generateSelfSignedCertPEM(t *testing.T) []byte {
+	t.Helper()
+	priv, err := rsa.GenerateKey(rand.Reader, 2048)
+	if err != nil {
+		t.Fatalf("Failed to generate RSA key: %v", err)
+	}
kom/tools_extended_test.go (1)

12-154: 与前面文件类似,建议拆分为 t.Run 子测试。

这是一个 ~150 行的单一测试函数,包含 8 个以上的测试场景且有顺序依赖(CRD 创建后才能查询)。建议至少将独立的场景(如 IsBuiltinResourceByGVK、GetGVK 等)用 t.Run 包裹,以提高可读性和故障定位效率。

kom/applier_test.go (1)

63-74: 更新路径的断言实际上不会失败。

当前代码只是 t.Logf 记录结果,即使没有任何结果包含 "updated",测试也会通过。虽然注释解释了 fake client 行为的不确定性,但这使得此测试场景形同虚设。如果希望保留此场景的价值,可以至少断言结果数量为 2。

建议至少验证结果数量
 	results2 := k.Applier().Apply(yamlContent)
+	if len(results2) != 2 {
+		t.Errorf("Expected 2 results on re-apply, got %d", len(results2))
+	}
 	for _, res := range results2 {
kom/cluster_manage_test.go (2)

32-58: DefaultCluster 子测试可能受到其他测试注册的集群影响。

由于同一包内的测试函数共享全局的 Clusters() 状态,Line 44 的 assert.Equal(t, defaultID, def.ID) 假设注册 "default" ID 后 DefaultCluster() 必然返回它。如果 DefaultCluster() 的实现存在对 "InCluster" 的优先级判断,而之前的测试(如 TestRegisterByConfigWithID_ExtendedTestRegisterAWSClusterWithID)注册了 "InCluster" 集群但未清理,则此断言可能意外失败。

建议在此子测试开始时确保全局状态的可预测性,或者使用更宽松的断言。


11-16: 此文件使用了 testify/assert,而 PR 中其他测试文件使用标准 testing 包断言。

两种风格都可以,但混用会降低一致性。可以考虑在后续统一风格。

kom/ctl_test.go (2)

9-91: TestCtlResourcesTestCtlEntryPoints 高度重复。

TestCtlResources(第56-91行)是 TestCtlEntryPoints(第9-53行)的严格子集——它检查的每个 wrapper 在 TestCtlEntryPoints 中都已覆盖。建议合并为一个测试,或为 TestCtlResources 增加差异化的断言逻辑,否则只是在维护冗余代码。


93-125: wrapper 方法的返回错误均被丢弃,削弱了测试的有效性。

TestCtlWrapperMethods 中所有调用(RestartScaleCordonUndo 等)的错误返回值都用 _ = 忽略了。即使在 fake 环境中某些操作可能报错,至少应使用 t.Log 记录,或对预期能成功的调用做 t.Error 断言,否则这些调用仅验证"不 panic"而非"功能正确"。

示例:对关键调用添加错误检查
 	// Deployment wrappers
 	deploy := k.Name("dep1").Namespace("default").Ctl().Deployment()
-	_ = deploy.Restart()
-	_ = deploy.Scale(2)
+	if err := deploy.Restart(); err != nil {
+		t.Logf("Deployment Restart: %v", err)
+	}
+	if err := deploy.Scale(2); err != nil {
+		t.Logf("Deployment Scale: %v", err)
+	}
kom/ctl_status_count_test.go (1)

10-60: 测试逻辑清晰,建议清理残留的调试注释。

第54-57行的注释(Let's debug if neededIn mock_k8s_test.go, we populate v1/podsBut let's check if summary is empty)属于开发过程中的思考痕迹,不应保留在最终代码中。简化为一句即可。

kom/ctl_extended_test.go (1)

118-135: checkCronJobSuspend 是未被调用的死代码。

该辅助函数在文件内及其他测试文件中均未被引用。如果是为将来使用而预留的,建议添加 TODO 注释说明;否则应移除以保持代码整洁。

kom/ctl_status_test.go (1)

47-70: 残留大量开发过程中的思考注释,建议清理。

第47-70行包含多处内心独白式的注释(如 "Wait, GetResourceCountSummary counts actual resources by listing them?""No, it usually lists them.""Let's add a pod to verify count.")。这些是开发探索过程的痕迹,不属于测试文档。建议精简为一到两行说明预期行为即可。

kom/tools_test.go (2)

80-99: DebugCRD 子测试是纯调试输出,无任何断言。

该子测试仅使用 fmt.Printf 打印内部状态,没有任何 assertt.Error 调用。它在每次 go test 时都会产生输出(即使不传 -v),且不验证任何行为。建议删除,或将关键检查转为正式断言。

若需保留诊断信息,至少使用 t.Log 并添加断言
 	t.Run("DebugCRD", func(t *testing.T) {
-		fmt.Printf("k.ID: %s\n", k.ID)
-		clusterFromMgr := Clusters().GetClusterById(id)
-		fmt.Printf("Cluster from Mgr: %p, CRDList len: %d\n", clusterFromMgr, len(clusterFromMgr.crdList))
-
-		parentCluster := k.ParentCluster()
-		fmt.Printf("Parent Cluster: %p, CRDList len: %d\n", parentCluster, len(parentCluster.crdList))
-
-		crdList := k.Status().CRDList()
-		fmt.Printf("CRDList from Status: len: %d\n", len(crdList))
-		if len(crdList) > 0 {
-			c := crdList[0]
-			spec, found, err := unstructured.NestedMap(c.Object, "spec")
-			fmt.Printf("Spec found: %v, err: %v\n", found, err)
-			if found {
-				kind, found, err := unstructured.NestedString(spec, "names", "kind")
-				fmt.Printf("Kind: %s, found: %v, err: %v\n", kind, found, err)
-			}
-		}
+		crdList := k.Status().CRDList()
+		assert.Equal(t, 1, len(crdList), "Expected 1 CRD in list")
 	})

74-76: 多处使用 time.Sleep 等待异步缓存操作,测试存在竞态风险。

第76、207、215行通过固定 time.Sleep(10 * time.Millisecond) 等待缓存写入完成。在 CI 环境或高负载下,10ms 可能不够,导致间歇性测试失败(flaky test)。如果 ristrettoWait() 方法能保证写入完成,那么 Sleep 是多余的;否则建议使用重试轮询(polling)机制替代硬编码的 sleep。

Also applies to: 206-207, 214-215

kom/kubectl_extended_test.go (2)

62-85: TestKubectlGetters 后半部分为未完成的思考注释,没有对 ClusterCache 做断言。

第75-84行是对 ClusterCache 是否为 nil 的推理过程,但最终没有添加任何断言或 t.Skip。建议补全测试或显式跳过:

建议方案
 	if k.DynamicClient() == nil {
 		t.Error("DynamicClient should not be nil")
 	}
-	// ClusterCache might be nil if not initialized or mocked properly?
-	// RegisterFakeCluster initializes it?
-	// RegisterFakeCluster calls RegisterFakeCluster -> initKubectl.
-	// But ClusterInst creation in RegisterFakeCluster doesn't explicitly create Cache?
-	// Let's check RegisterFakeCluster in mock_k8s_test.go.
-	// It doesn't seem to create Cache.
-	// So k.ClusterCache() might return nil or panic.
-	// Let's check ClusterCache method:
-	// func (k *Kubectl) ClusterCache() *ristretto.Cache[string, any] { return Clusters().GetClusterById(k.ID).Cache }
-	// If Cache is nil, it returns nil.
+	// ClusterCache 在 RegisterFakeCluster 中未初始化,此处跳过
+	t.Log("Skipping ClusterCache check: not initialized in fake cluster")

109-129: TestInitializeCRDList 是空壳测试,没有任何断言。

整个函数体都是关于 cache 模拟复杂度的注释和一个 _ = cluster。它既不测试成功路径也不测试失败路径。建议要么补全测试逻辑,要么移除以避免给出虚假的覆盖率。

若暂不实现,至少标记为跳过
 func TestInitializeCRDList(t *testing.T) {
+	t.Skip("TODO: requires ristretto cache mock in RegisterFakeCluster")
 	RegisterFakeCluster("crd-list-test")
-	_ = Cluster("crd-list-test")
-
-	// Mock cache if necessary, but RegisterFakeCluster doesn't set Cache.
-	// ...
-	_ = cluster
+	// ...
 }
kom/cluster_test.go (1)

157-168: TestAllClusters 的断言 len(all) < 2 过于宽松,无法精确验证预期。

由于全局状态中可能已存在其他测试注册的集群,len(all) 可能远大于 2。此断言仅能证明"至少有 2 个",无法发现重复注册或泄漏的集群。如果能在测试前后做差量检查会更可靠,但当前全局架构下这很难实现,记录为已知限制即可。

kom/kubectl_test.go (3)

157-183: pod 对象在创建后被就地修改,可能导致测试脆弱。

第 160 行 pod 被传入 RegisterFakeCluster 作为种子数据,第 164 行又直接修改了 pod.Labels。由于 fake client 内部可能持有对该对象的引用,就地修改可能在某些场景下导致种子数据与预期不一致。建议在 Update 前使用 pod.DeepCopy() 创建副本,在副本上修改后传入 Update。

♻️ 建议的修改
 	pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: podName, Namespace: ns}}
 	RegisterFakeCluster("update-cluster", pod)

-	// Modify pod
-	pod.Labels = map[string]string{"updated": "true"}
+	// Modify a copy of pod
+	updatedPod := pod.DeepCopy()
+	updatedPod.Labels = map[string]string{"updated": "true"}

 	var res v1.Pod
-	err := Cluster("update-cluster").Resource(&v1.Pod{}).Namespace(ns).Name(podName).Update(pod).Error
+	err := Cluster("update-cluster").Resource(&v1.Pod{}).Namespace(ns).Name(podName).Update(updatedPod).Error

79-107: 侧效应测试逻辑清晰,但测试断言依赖内部未导出字段。

c1.kubectl.Statement.ContainerName 直接访问了未导出字段。虽然同包内可以访问,但这使测试与内部实现强耦合。当前作为白盒回归测试可以接受,建议在注释中注明这一设计意图(第 91-93 行的注释已部分说明)。


225-278: 方法链测试覆盖全面,但各子测试间共享同一个 k 实例。

如果 Cluster("kubectl-cluster") 返回的 Kubectl 在链式调用中产生了意外副作用(例如某个方法修改了原始 k 的 Statement),后续断言可能受到前面调用的影响。当前实现如果每次链式调用都返回新实例(newInstance),则没有问题。建议确认链式调用不会污染 k 本身。

kom/ctl_deploy_extended_test.go (1)

12-234: 考虑将单体测试拆分为子测试。

当前所有 9 个测试场景在单个函数中顺序执行,前面步骤失败会导致后续所有步骤无法运行。可使用 t.Run 拆分为子测试,或至少将种子数据创建逻辑提取为 helper,使各场景的失败信息更精确。这不影响当前功能,可以后续优化。

kom/mock_k8s_test.go (5)

166-177: fakePortForward 中的 goroutine 可能泄漏。

第 171-175 行启动了一个 goroutine 等待 PortForwardStopCh 关闭。如果调用方未关闭该 channel,goroutine 将永远阻塞。在测试代码中虽然影响有限(进程退出即回收),但如果有大量端口转发测试运行,可能在测试期间积累泄漏的 goroutine。

建议添加超时或使用 context 作为取消机制。

♻️ 建议的修改
 func fakePortForward(k *Kubectl) error {
 	if k.Statement.PortForwardLocalPort == "" || k.Statement.PortForwardPodPort == "" {
 		return fmt.Errorf("ports not set")
 	}
-	// Simulate port forward started
-	go func() {
-		if k.Statement.PortForwardStopCh != nil {
-			<-k.Statement.PortForwardStopCh
-		}
-	}()
 	return nil
 }

如果不需要真正模拟阻塞行为,直接移除 goroutine 即可。


22-139: RegisterFakeCluster 注册到全局 map 后没有清理机制。

每次调用 RegisterFakeCluster 都会向全局 Clusters().clusters 写入条目(第 136 行),但没有提供 t.Cleanup 回调来在测试结束后移除。虽然每个测试使用唯一 ID 可以避免直接冲突,但在长期运行或大规模测试套件中,陈旧条目可能累积。

建议接受 *testing.T 参数并注册清理回调:

♻️ 建议的修改方向
-func RegisterFakeCluster(id string, objects ...runtime.Object) *Kubectl {
+func RegisterFakeCluster(id string, objects ...runtime.Object) *Kubectl {
 	// ... existing code ...
 	Clusters().clusters.Store(id, cluster)
+	// 如果后续改为接受 *testing.T,可添加:
+	// t.Cleanup(func() { Clusters().clusters.Delete(id) })
 	return k
 }

255-288: StrategicMergePatchTypeMergePatchType 的静默转换已有注释说明,但可能隐藏真实 bug。

第 267-269 行将 StrategicMergePatchType 自动降级为 MergePatchType。这对 fake client 的兼容性是合理的,但如果生产代码中 Patch 类型设置有误,测试不会捕获到。建议在转换时添加日志或计数器,便于调试时发现意外的 patch 类型降级。


400-457: fakeDescribe 中的错误信息语言不一致。

第 408 行和第 416 行使用中文错误信息,而其他 fake handler 使用英文。建议统一语言风格,或至少在同一文件中保持一致。


73-74: 避免直接修改全局 scheme.Scheme,为每个测试创建独立的 scheme 实例。

第 73-74 行 s := scheme.Schemeapiextensionsv1.AddToScheme(s) 修改了 client-go 的全局 scheme 对象。由于 RegisterFakeCluster 被大量测试文件调用,这个副作用会在整个测试套件运行期间持续存在。虽然添加 apiextensionsv1 不太可能直接导致测试失败,但这违反了测试隔离原则,可能在特殊情况下引发问题。

建议使用 runtime.NewScheme() 创建独立的 scheme 实例,如注释中的代码示例所示,确保测试之间不会因为 scheme 状态产生隐含依赖。

♻️ 建议的修改方向
-	s := scheme.Scheme
-	_ = apiextensionsv1.AddToScheme(s)
+	s := runtime.NewScheme()
+	_ = scheme.AddToScheme(s)  // 添加标准 Kubernetes 类型
+	_ = apiextensionsv1.AddToScheme(s)

注意:确保新 scheme 包含 fake.NewSimpleDynamicClient 所需的所有类型。

Comment thread kom/cluster_test.go
Comment on lines +71 to +93
func TestDefaultCluster(t *testing.T) {
// Case 1: Random/First available
RegisterFakeCluster("random-cluster")
if DefaultCluster() == nil {
t.Error("DefaultCluster should return a cluster when one is registered")
}

// Case 2: "default" ID priority
RegisterFakeCluster("default")

dc := Clusters().DefaultCluster()
if dc.ID != "default" && dc.ID != "InCluster" {
// If "InCluster" is not there, it should be "default"
t.Errorf("DefaultCluster should prefer 'default', got %s", dc.ID)
}

// Case 3: "InCluster" ID priority
RegisterFakeCluster("InCluster")
dc = Clusters().DefaultCluster()
if dc.ID != "InCluster" {
t.Errorf("DefaultCluster should prefer 'InCluster', got %s", dc.ID)
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

TestDefaultCluster 受全局状态影响,断言容易被其他测试干扰。

第82行 dc.ID != "default" && dc.ID != "InCluster" 实际上是在说"只要不是这两个之外的都行",这掩盖了测试意图。如果其他测试(甚至当前文件的 TestClusterRegistration)先注册了 "InCluster" 集群,Case 2 的断言就无法验证 "default" 优先级。

根本原因是所有测试共享 Clusters() 全局单例且无清理。建议在每个测试中通过 t.Cleanup 注销已注册的集群,或者至少在此测试开头清理相关 ID:

添加清理逻辑示例
 func TestDefaultCluster(t *testing.T) {
+	// 清理可能干扰优先级判断的预注册集群
+	Clusters().RemoveClusterById("default")
+	Clusters().RemoveClusterById("InCluster")
+
 	// Case 1: Random/First available
 	RegisterFakeCluster("random-cluster")
+	t.Cleanup(func() { Clusters().RemoveClusterById("random-cluster") })
🤖 Prompt for AI Agents
In `@kom/cluster_test.go` around lines 71 - 93, TestDefaultCluster relies on
global state in Clusters() and can be flakey; before registering test clusters,
reset or remove any pre-existing clusters and register cleanup to undo
registrations. Modify TestDefaultCluster to (1) clear relevant IDs from the
Clusters() singleton at the start (or call a provided reset method if available)
so previous tests cannot affect it, (2) use t.Cleanup to unregister or restore
the cluster state after RegisterFakeCluster calls, and (3) tighten the assertion
in the Case 2 check on Clusters().DefaultCluster() (referencing
TestDefaultCluster, RegisterFakeCluster, Clusters(), and DefaultCluster) to
assert the exact expected ID ("default") when "InCluster" is not registered,
rather than allowing either value.

},
},
}
k.Resource(deploy).Create(deploy)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

多处 Create 调用未检查错误,可能导致后续断言产生误导性失败。

第 39、55、71、94、187 行的 Create 调用均未检查 .Error。如果种子数据创建失败,后续所有操作和断言都会失败,但错误信息将指向错误的位置,增加排查难度。

🛡️ 建议对所有 Create 调用检查错误(示例)
-	k.Resource(deploy).Create(deploy)
+	if err := k.Resource(deploy).Create(deploy).Error; err != nil {
+		t.Fatalf("Create deployment failed: %v", err)
+	}

同样应用于第 55、71、94、187 行的 Create 调用。

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
k.Resource(deploy).Create(deploy)
if err := k.Resource(deploy).Create(deploy).Error; err != nil {
t.Fatalf("Create deployment failed: %v", err)
}
🤖 Prompt for AI Agents
In `@kom/ctl_deploy_extended_test.go` at line 39, Several seed
Resource(...).Create(...) calls (e.g., the call using
k.Resource(deploy).Create(deploy) and the other Create invocations around the
same area) ignore the returned error; change each bare Create(...) invocation to
capture its result and assert/check result.Error (for example using
t.Fatalf/require.NoError/Assert) so test execution fails immediately with the
real error when seed creation fails; update the Create calls at the same spots
mentioned (the calls at the other Create sites) to use the same pattern and
include a descriptive message referencing the resource being created.

Comment on lines +116 to +120
var d appsv1.Deployment
k.Resource(&d).Namespace(ns).Name(name).Get(&d)
if *d.Spec.Replicas != 5 {
t.Errorf("Expected 5 replicas, got %d", *d.Spec.Replicas)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

多处 Get 调用未检查错误。

第 117、127、140、160、208、219 行的 Get 调用均未检查错误。如果 Get 失败,d 可能保留上一次调用的旧值,导致断言通过但实际验证的是陈旧数据。

🛡️ 建议示例
-	k.Resource(&d).Namespace(ns).Name(name).Get(&d)
-	if *d.Spec.Replicas != 5 {
+	if err := k.Resource(&d).Namespace(ns).Name(name).Get(&d).Error; err != nil {
+		t.Fatalf("Get after Scale failed: %v", err)
+	}
+	if *d.Spec.Replicas != 5 {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var d appsv1.Deployment
k.Resource(&d).Namespace(ns).Name(name).Get(&d)
if *d.Spec.Replicas != 5 {
t.Errorf("Expected 5 replicas, got %d", *d.Spec.Replicas)
}
var d appsv1.Deployment
if err := k.Resource(&d).Namespace(ns).Name(name).Get(&d).Error; err != nil {
t.Fatalf("Get after Scale failed: %v", err)
}
if *d.Spec.Replicas != 5 {
t.Errorf("Expected 5 replicas, got %d", *d.Spec.Replicas)
}
🤖 Prompt for AI Agents
In `@kom/ctl_deploy_extended_test.go` around lines 116 - 120, 在多处使用
k.Resource(&d).Namespace(ns).Name(name).Get(&d) 时没有检查返回错误,可能导致使用旧的 d
值误判;修改这些调用(例如在 kom/ctl_deploy_extended_test.go 中对变量 d appsv1.Deployment 的所有 Get
调用)为接收并检查错误:err := k.Resource(&d).Namespace(ns).Name(name).Get(&d) 并在 err != nil
时通过 t.Fatalf 或 t.Fatalf/ t.Fatalf 类似的测试失败处理(带上上下文错误信息),然后再对 *d.Spec.Replicas
等断言进行验证。

Comment on lines +148 to +151
// 6. Test Restart
// Restart uses Patch with MergePatchType (since we fixed ctl_rollout.go earlier for restart?)
// Let's check ctl_rollout.go. Yes, I fixed it in ctl_rollout.go (Restart uses MergePatchType).
// But wait, ctl_deploy.go Restart calls ctl_rollout.go Restart.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

删除开发过程中的内部备注。

第 148-151 行包含开发者在编写测试时的思考过程和内部决策注释(如 "Let's check ctl_rollout.go. Yes, I fixed it...")。这些不属于提交到代码库的内容,建议清理。

♻️ 建议的修改
 	// 6. Test Restart
-	// Restart uses Patch with MergePatchType (since we fixed ctl_rollout.go earlier for restart?)
-	// Let's check ctl_rollout.go. Yes, I fixed it in ctl_rollout.go (Restart uses MergePatchType).
-	// But wait, ctl_deploy.go Restart calls ctl_rollout.go Restart.
 	err = k.Resource(deploy).Ctl().Deployment().Restart()
🤖 Prompt for AI Agents
In `@kom/ctl_deploy_extended_test.go` around lines 148 - 151, Remove the developer
inner-note comments in the "Test Restart" block of ctl_deploy_extended_test.go
(the comment lines mentioning "Let's check ctl_rollout.go. Yes, I fixed it..."
and other in-progress thoughts) so that only concise, relevant test comments
remain; locate the "Test Restart" section and delete or replace those internal
decision traces with a short neutral comment describing the test intent.

Comment thread kom/statement_test.go
@weibaohui weibaohui merged commit 9ec623c into main Feb 6, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant