7- kubebuilder 進階: 測試

Operator 的測試是一個比較頭疼的問題,在 kubernetes 資源是在不斷變化的,並且想要在測試的時候跑一整套的 kubernetes 環境也不是一件容易的事情,今天我們大概看一下單元測試和集成測試怎麼做。

單元測試

單元測試和 golang 的單元測試沒有什麼太大的區別,一般可以通過單元測試搞定的首先使用單元測試,因爲單元測試寫起來最容易,例如下面這一段對節點標籤更新邏輯進行測試

func TestNodePoolSpec_ApplyNode(t *testing.T) {
 type fields struct {
  Taints  []corev1.Taint
  Labels  map[string]string
  Handler string
 }
 type args struct {
  node v1.Node
 }
 tests := []struct {
  name   string
  fields fields
  args   args
  want   *corev1.Node
 }{
  {
   name: "label",
   fields: fields{
    Labels: map[string]string{
     "node-pool.lailin.xyz/test""",
    },
   },
   args: args{
    node: v1.Node{
     ObjectMeta: metav1.ObjectMeta{
      Name: "worker",
      Labels: map[string]string{
       "kubernetes.io/arch""amd64",
       "a":                  "b",
      },
     },
    },
   },
   want: &v1.Node{
    ObjectMeta: metav1.ObjectMeta{
     Name: "worker",
     Labels: map[string]string{
      "kubernetes.io/arch":        "amd64",
      "node-pool.lailin.xyz/test""",
     },
    },
   },
  },
 }
 for _, tt := range tests {
  t.Run(tt.name, func(t *testing.T) {
   s := &NodePoolSpec{
    Taints:  tt.fields.Taints,
    Labels:  tt.fields.Labels,
    Handler: tt.fields.Handler,
   }
   assert.Equal(t, tt.want, s.ApplyNode(tt.args.node))
  })
 }
}

集成測試

controller-runtime 提供 envtest ,這個包可以幫助你爲你在 etcd 和 Kubernetes API server 中設置並啓動的 controllers 實例來寫集成測試,不需要 kubelet,controller-manager 或者其他組件。

envtest

一個 envtest 的簡單例子如下

import sigs.k8s.io/controller-runtime/pkg/envtest

//指定 testEnv 配置
testEnv = &envtest.Environment{
    CRDDirectoryPaths: []string{filepath.Join("..""config""crd""bases")},
}

//啓動 testEnv
cfg, err = testEnv.Start()

//編寫測試邏輯

//停止 testEnv
err = testEnv.Stop()

envtest 在啓動的時候需要設置一些環境變量來說明我們使用什麼控制平面來進行測試

編寫測試

kubebuilder 在生成代碼的時候已經幫我們生成好了相關的腳手架,已經環境配置,我們只需要寫具體的測試邏輯就行了

下面我們就以創建一個 NodePool 爲例子看看集成測試怎麼寫

controllers/suite_test.go

var _ = Describe("node labels", func() {
 pool := &nodesv1.NodePool{
  ObjectMeta: metav1.ObjectMeta{
   Name: "test",
  },
  Spec: nodesv1.NodePoolSpec{
   Labels: map[string]string{
    "node-pool.lailin.xyz/xxx""",
   },
   Handler: "",
  },
 }

 It("create pool", func() {
  ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  defer cancel()
  err := k8sClient.Create(ctx, pool)
  Expect(err).NotTo(HaveOccurred())
 })
})

使用 make test 執行測試

Using cached envtest tools from blog-code/k8s-operator/07-node-pool-operator/testbin
setting up env vars
?       github.com/mohuishou/blog-code/k8s-operator/node-pool-operator  [no test files]
ok      github.com/mohuishou/blog-code/k8s-operator/node-pool-operator/api/v1   9.403s  coverage: 24.5% of statements
ok      github.com/mohuishou/blog-code/k8s-operator/node-pool-operator/controllers      10.390s coverage: 0.0% of statements

總結

今天這篇文章主要還是希望起一個拋磚引玉的作用,沒有過多的去深入具體改如何寫單元測試和集成測試,只是給了兩個例子,關於集成測試如果感興趣可以看看 https://onsi.github.io/ginkgo 和  envtest 的相關文檔。

對於 Operator 來說建議能寫單元測試的還是寫單元測試,能夠本地寫集成測試的就寫集成測試這樣我們在實際上線的時候就會減少 bug 的概率,因爲相對於業務代碼來說 Operator 的測試實在是比較麻煩,對於測試同學的要求也比較高,一不小心就有可能遺漏一些問題。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/tcLIx3E0LyRkNhPO0U8zmg