envTestを使って、kubernetesのAPIを使うテストを行う
KubernetesのAPIを呼び出すコードを書いていてそこにロジックが含まれる時、テストを行いたい。こういう時、envTestを使うと手軽にetcdとapiserverを起動してテストできる。
ドキュメントは https://book.kubebuilder.io/reference/envtest.html
まずはシンプルに動かしてみる。testEnv.Start() でetcdとapiserverを起動し、そのapiserverに繋がるrest.Configを得る。rest.Configを使ってkubernetes.Clientsetを作成し、ConfigMapを作成したり取得するというもの。テストの最後にはtestEnv.Stop()でetcdとapiserverを停止している。
package main
import (
"fmt"
"github.com/k0kubun/pp"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"testing"
)
func Test_envtest(t *testing.T) {
testEnv := &envtest.Environment{}
restConfig, err := testEnv.Start()
if err != nil {
t.Error(err)
}
clientset, err := kubernetes.NewForConfig(restConfig)
if err != nil {
t.Error(err)
}
cm := &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "test-configmap",
Namespace: "default",
},
Data: map[string]string{
"foo": "bar",
},
}
fmt.Printf("cm: %s\n", pp.Sprint(cm))
_, err = clientset.CoreV1().ConfigMaps("default").Create(cm)
if err != nil {
t.Error(err)
}
got, err := clientset.CoreV1().ConfigMaps("default").Get("test-configmap", metav1.GetOptions{})
if err != nil {
t.Error(err)
}
fmt.Printf("got: %s\n", pp.Sprint(got))
if got.Name != cm.Name {
t.Errorf("missmatch: got = %v, want = %v", got.Name, cm.Name)
}
err = testEnv.Stop()
if err != nil {
t.Error(err)
}
}
実行するとこのようになる。作成元のConfigMapと取得したConfigMapをそれぞれ出力しているが、UIDなどが付与されておりリソースとして登録されていることが確認できる。
$ go test ./testenv_test.go -v
=== RUN Test_envtest
cm: &v1.ConfigMap{
TypeMeta: v1.TypeMeta{
Kind: "",
APIVersion: "",
},
ObjectMeta: v1.ObjectMeta{
Name: "test-configmap",
GenerateName: "",
Namespace: "default",
SelfLink: "",
UID: "",
ResourceVersion: "",
Generation: 0,
CreationTimestamp: v1.Time{
Time: 1-01-01 00:00:00 UTC,
},
DeletionTimestamp: (*v1.Time)(nil),
DeletionGracePeriodSeconds: (*int64)(nil),
Labels: map[string]string{},
Annotations: map[string]string{},
OwnerReferences: []v1.OwnerReference{},
Initializers: (*v1.Initializers)(nil),
Finalizers: []string{},
ClusterName: "",
ManagedFields: []v1.ManagedFieldsEntry{},
},
Data: map[string]string{
"foo": "bar",
},
BinaryData: map[string][]uint8{},
}
got: &v1.ConfigMap{
TypeMeta: v1.TypeMeta{
Kind: "",
APIVersion: "",
},
ObjectMeta: v1.ObjectMeta{
Name: "test-configmap",
GenerateName: "",
Namespace: "default",
SelfLink: "/api/v1/namespaces/default/configmaps/test-configmap",
UID: "478835ca-73df-11ea-b65a-acde48001122",
ResourceVersion: "43",
Generation: 0,
CreationTimestamp: v1.Time{
Time: 2020-04-01 15:09:00 Local,
},
DeletionTimestamp: (*v1.Time)(nil),
DeletionGracePeriodSeconds: (*int64)(nil),
Labels: map[string]string{},
Annotations: map[string]string{},
OwnerReferences: []v1.OwnerReference{},
Initializers: (*v1.Initializers)(nil),
Finalizers: []string{},
ClusterName: "",
ManagedFields: []v1.ManagedFieldsEntry{},
},
Data: map[string]string{
"foo": "bar",
},
BinaryData: map[string][]uint8{},
}
--- PASS: Test_envtest (6.17s)
PASS
ok command-line-arguments 8.066s
client-goのパッケージはモッキングするのも大変だろうから、envtestを使っていくと良さそう。