repl.info

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を使っていくと良さそう。