このチャプターの目次

テスト失敗時のデバッグ手法

EnvTestを利用したテストに失敗したときに、その原因を調べたいが、すでにkube-apiserverが終了していて調査ができないという経験はないでしょうか。
そこで、ここではテストに失敗したときにEnvTestを停止せず、デバッグできるように設定をしてみます。

実際のコードは以下をご覧ください。

まずAfterEachでは、テストが失敗し、かつGinkgoの--fail-fastオプションが有効だったときにsuiteFailedフラグを立てるようにします。
--fail-fastは、テストが失敗したときに次のテストケースを実行せずに即終了するためのオプションです。

package controllers

import (
	"context"
	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
)

var _ = Describe("Debug mode", func() {
	ctx := context.TODO()

	AfterEach(func() {
		suiteConfig, _ := GinkgoConfiguration()
		
		// テストが失敗し、かつ`--fail-fast`オプションが有効だったらフラグを立てる
		if CurrentSpecReport().Failed() && suiteConfig.FailFast  {
			suiteFailed = true
		}
	})

	It("should create deployment", func() {
		dep := createDeployment("nginx:latest")

		err := k8sClient.Create(ctx, dep)
		
		// わざとテストを失敗させる
		Expect(err).Should(HaveOccurred())
	})
})

そしてAfterSuiteでは、環境変数DEBUGtrueが設定されていて、かつsuiteFailedフラグが立っているときには、EnvTestを止めないようにします。
また、kube-apiserverに接続するためのファイルのパスを標準出力に表示しておきます。

package controllers

// 中略

var suiteFailed = false

var _ = AfterSuite(func() {
	By("tearing down the test environment")

	if os.Getenv("DEBUG") == "true" && suiteFailed {
		fmt.Printf(`

You can use the following command to investigate the failure:
$ kubectl %s

When you have finished investigation, clean up with the following commands:
$ pkill kube-apiserver
$ pkill etcd
$ rm -rf %s
`, strings.Join(testEnv.ControlPlane.KubeCtl().Opts, " "), testEnv.ControlPlane.APIServer.CertDir)

		return
	}

	err := testEnv.Stop()
	Expect(err).NotTo(HaveOccurred())
})

テストの実行時には、DEBUG環境変数の設定と、--fail-fastオプションの指定をおこないます。

.PHONY: test-debug
test-debug: envtest ginkgo
	KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" DEBUG=true $(GINKGO) -r --fail-fast -v --progress

テストを失敗させてみましょう。
すると、以下のようなメッセージが表示されます。

You can use the following command to investigate the failure:
$ kubectl --kubeconfig=/tmp/k8s_test_framework_4014053130/3019522165.kubecfg

When you have finished investigation, clean up with the following commands:
$ pkill kube-apiserver
$ pkill etcd
$ rm -rf /tmp/k8s_test_framework_4014053130

この表示に従ってkubectlコマンドを実行すると、kube-apiserverに接続することができます。

$ kubectl --kubeconfig=/tmp/k8s_test_framework_4014053130/3019522165.kubecfg get pod
NAME     READY   STATUS    RESTARTS   AGE
sample   0/1     Pending   0          39s

調査が終わったら、以下のコマンドを実行して必ず後片付けをしましょう。

$ pkill kube-apiserver
$ pkill etcd
$ rm -rf /tmp/k8s_test_framework_4014053130