harness

package module
v0.0.0-...-867d8f5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 7, 2023 License: Apache-2.0 Imports: 27 Imported by: 2

README

Go Report Card Build Status API Reference

Kubernetes Test Harness

This package implements a test harness for running integration or end to end tests in a Kubernetes cluster.

Features:

  • Integrate with the native Go testing package.
  • Create Kubernetes objects such as Deployments, Services, Secrets, ConfigMaps from either manifest file or the client-go API.
  • Full access to the client-go API to manipulate Kubernetes objects.
  • Wait for various readiness conditions.
  • Each test runs in its own namespace, allowing them to run in parallel.
  • Display a detailed error state to help the developer debug failure cases with pod status, events and logs of failing pods.
  • Automatic error checking, no need to check err at every line!

Writing a Test

example/simple has a self-contained example that shows how to write a test with kube-test-harness:

// TestDeployNginx deploys nginx on a kubernetes cluster and tests it's running
// correctly by checking the response of an HTTP GET request on /.
func TestDeployNginx(t *testing.T) {
    // Create a new test from the harness object. A test runs in one namespace, can
    // create Kubernetes objects and perform various checking operations.
    //
    // Always call Close when finished running the test. It will cleanup the
    // resources created in that test and take care of displaying the error state
    // if the test has failed.
    test := kube.NewTest(t).Setup()
    defer test.Close()

    // Create a Deployment from a manifest file.
    //
    // test.Namespace holds the namespace automatically created by the test harness
    // for this test to run in.
    d := test.CreateDeploymentFromFile(test.Namespace, "nginx-deployment.yaml")

    // Wait until the deployment is up and running, timeout of 30s.
    test.WaitForDeploymentReady(d, 30*time.Second)

    // For each pod of the Deployment, check we receive a sensible response to a
    // GET request on /.
    for _, pod := range test.ListPodsFromDeployment(d).Items {
        data, err := test.PodProxyGet(&pod, "80", "/").DoRaw()
        assert.NoError(t, err)
        assert.Equal(t, index, string(data))
    }
}

To run kube-test-harness tests a Kubernetes cluster is needed. It's then a go test invocation away:

$ go test -v ./examples/simple/
=== RUN   TestDeployNginx
--- PASS: TestDeployNginx (3.08s)
    test.go:63: using API server https://192.168.99.116:8443
    namespace.go:12: creating namespace deploy-nginx-1529445457-ns-1
    deployment.go:16: creating deployment nginx
    deployment.go:75: waiting for deployment nginx to be ready
    namespace.go:42: deleting namespace deploy-nginx-1529445457-ns-1
PASS
ok      github.com/dlespiau/kube-test-harness/examples/simple    3.090s

Error State

When a test fails, kube-test-harness will display the state of the cluster to help the developer debug the problem. As an example, I changed the Nginx manifest in example/simple to have an invalid image name. Running the test displayed clues about what the problem was:

$ go test -v ./examples/simple/
=== RUN   TestDeployNginx

=== pods, namespace=kube-system

NAME                         READY   STATUS
kube-addon-manager-kubecon   1/1     Ready
kube-dns-86f6f55dd5-t8kcd    1/1     Ready
kubernetes-dashboard-5k2mn   1/1     Ready
storage-provisioner          1/1     Ready

=== pods, namespace=deploy-nginx-1529447347-ns-1

NAME                     READY   STATUS
nginx-75f7677558-n8rtr   0/1     ImagePullBackOff
nginx-75f7677558-x4wdv   0/1     ImagePullBackOff

=== logs, pod=nginx-75f7677558-n8rtr, container=nginx

container "nginx" in pod "nginx-75f7677558-n8rtr" is waiting to start: trying and failing to pull image

=== logs, pod=nginx-75f7677558-x4wdv, container=nginx

container "nginx" in pod "nginx-75f7677558-x4wdv" is waiting to start: trying and failing to pull image

--- FAIL: TestDeployNginx (30.11s)
    test.go:63: using API server https://192.168.99.116:8443
    namespace.go:12: creating namespace deploy-nginx-1529447347-ns-1
    deployment.go:16: creating deployment nginx
    deployment.go:75: waiting for deployment nginx to be ready
    test.go:191: timed out waiting for the condition
FAIL
FAIL    github.com/dlespiau/kube-test-harness/examples/simple    30.121s

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Harness

type Harness struct {
	// contains filtered or unexported fields
}

Harness is a test harness for running integration tests on a kubernetes cluster.

func New

func New(options Options) *Harness

New creates a new test harness.

func (*Harness) Close

func (h *Harness) Close() error

Close terminates a test harness and frees its resources.

func (*Harness) KubeClient

func (h *Harness) KubeClient() kubernetes.Interface

KubeClient returns the underlying Kubernetes client hat be used to access the Kubernetes API directly.

func (*Harness) NewTest

func (h *Harness) NewTest(t testing.T) *Test

NewTest creates a new test. Call Close() to free kubernetes resources allocated during the test.

func (*Harness) Run

func (h *Harness) Run(m *testing.M) int

Run setup the test harness and run the tests with m.Run.

func (*Harness) SetKubeconfig

func (h *Harness) SetKubeconfig(kubeconfigPath string) error

SetKubeconfig reconfigures harness with the given kubeconfig file. Using "" as the new path makes harness fallback to the default kubeconfig location on your system.

func (*Harness) Setup

func (h *Harness) Setup() error

Setup initializes the test harness.

type Options

type Options struct {
	// Kubeconfig is the path to a kubeconfig file. If not given, Harness will
	// honour the KUBECONFIG environment variable and try to use
	// $HOME/.kube/config.
	Kubeconfig string
	// ManifestDirectory is the root directory where the test Kubernetes manifests
	// are located. It can be an absolute path a or path relative to the directory
	// where the test is. If not given, defaults to the current working directory.
	ManifestDirectory string
	// NoCleanup controls if tests should cleanup after them.
	NoCleanup bool
	// Logger is the Logger used to dispay test logs. If not given, Harness will
	// use logger.TestLogger which uses the logging built in the testing package.
	// This logger will only display logs on error or when -v is given to go test.
	// Additionally it will only dump the logs once the test has finished running.
	//
	// For writing and debugging long running tests, it is useful to have logs
	// being printed on stdout as it happens. logger.PrintfLogger can be used when
	// such behavior is needed.
	Logger logger.Logger
	// LogLevel controls how verbose the test logs are. Currently only Debug and
	// Info are available. If not given, defaults to Info.
	LogLevel logger.LogLevel
}

Options are configuration options for the test harness.

type Test

type Test struct {
	// ID is a unique identifier for the test, defined from the test function name.
	ID string
	// Namespace is name of the namespace automatically crafted by Setup for the
	// test to run in.
	Namespace string
	// contains filtered or unexported fields
}

Test is a single test running in a kubernetes cluster.

func (*Test) Close

func (t *Test) Close()

Close frees all kubernetes resources allocated during the test.

func (*Test) CreateClusterRole

func (test *Test) CreateClusterRole(cr *rbacv1.ClusterRole)

CreateClusterRole creates a cluster role.

func (*Test) CreateClusterRoleBinding

func (test *Test) CreateClusterRoleBinding(crb *rbacv1.ClusterRoleBinding)

CreateClusterRoleBinding creates a cluster role binding.

func (*Test) CreateClusterRoleBindingFromFile

func (test *Test) CreateClusterRoleBindingFromFile(manifestPath string) *rbacv1.ClusterRoleBinding

CreateClusterRoleBindingFromFile creates a cluster role binding from a manifest file.

func (*Test) CreateClusterRoleFromFile

func (test *Test) CreateClusterRoleFromFile(manifestPath string) *rbacv1.ClusterRole

CreateClusterRoleFromFile creates a cluster role from a manifest file.

func (*Test) CreateConfigMap

func (test *Test) CreateConfigMap(namespace string, cm *v1.ConfigMap)

CreateConfigMap creates a ConfigMap in the given namespace.

func (*Test) CreateConfigMapFromFile

func (test *Test) CreateConfigMapFromFile(namespace string, manifestPath string) *v1.ConfigMap

CreateConfigMapFromFile creates a ConfigMap from a manifest file in the given namespace.

func (*Test) CreateDaemonSet

func (test *Test) CreateDaemonSet(namespace string, d *appsv1.DaemonSet)

CreateDaemonSet creates a daemonset in the given namespace.

func (*Test) CreateDaemonSetFromFile

func (test *Test) CreateDaemonSetFromFile(namespace string, manifestPath string) *appsv1.DaemonSet

CreateDaemonSetFromFile creates a daemonset from a manifest file in the given namespace.

func (*Test) CreateDeployment

func (test *Test) CreateDeployment(namespace string, d *appsv1.Deployment)

CreateDeployment creates a deployment in the given namespace.

func (*Test) CreateDeploymentFromFile

func (test *Test) CreateDeploymentFromFile(namespace string, manifestPath string) *appsv1.Deployment

CreateDeploymentFromFile creates a deployment from a manifest file in the given namespace.

func (*Test) CreateNamespace

func (test *Test) CreateNamespace(name string)

CreateNamespace creates a new namespace.

func (*Test) CreateSecret

func (test *Test) CreateSecret(namespace string, secret *v1.Secret)

CreateSecret creates a secret in the given namespace.

func (*Test) CreateSecretFromFile

func (test *Test) CreateSecretFromFile(namespace string, manifestPath string) *v1.Secret

CreateSecretFromFile creates a secret from a manifest file in the given namespace.

func (*Test) CreateService

func (test *Test) CreateService(namespace string, service *v1.Service)

CreateService creates a service in the given namespace.

func (*Test) CreateServiceAccount

func (test *Test) CreateServiceAccount(namespace string, serviceAccount *v1.ServiceAccount)

CreateServiceAccount creates a service account in the given namespace.

func (*Test) CreateServiceAccountFromFile

func (test *Test) CreateServiceAccountFromFile(namespace string, manifestPath string) *v1.ServiceAccount

CreateServiceAccountFromFile creates a service account from a manifest file in the given namespace.

func (*Test) CreateServiceFromFile

func (test *Test) CreateServiceFromFile(namespace string, manifestPath string) *v1.Service

CreateServiceFromFile creates a service from a manifest file in the given namespace.

func (*Test) Debug

func (t *Test) Debug(msg string)

Debug prints a debug message.

func (*Test) Debugf

func (t *Test) Debugf(f string, args ...interface{})

Debugf prints a debug message with a format string.

func (*Test) DeleteClusterRole

func (test *Test) DeleteClusterRole(cr *rbacv1.ClusterRole)

DeleteClusterRole deletes a cluster role.

func (*Test) DeleteClusterRoleBinding

func (test *Test) DeleteClusterRoleBinding(crb *rbacv1.ClusterRoleBinding)

DeleteClusterRoleBinding deletes a cluster role binding.

func (*Test) DeleteConfigMap

func (test *Test) DeleteConfigMap(ConfigMap *v1.ConfigMap)

DeleteConfigMap deletes a ConfigMap.

func (*Test) DeleteDaemonSet

func (test *Test) DeleteDaemonSet(d *appsv1.DaemonSet)

DeleteDaemonSet deletes a daemonset in the given namespace.

func (*Test) DeleteDeployment

func (test *Test) DeleteDeployment(d *appsv1.Deployment)

DeleteDeployment deletes a deployment in the given namespace.

func (*Test) DeleteNamespace

func (test *Test) DeleteNamespace(name string)

DeleteNamespace deletes a Namespace.

func (*Test) DeletePod

func (test *Test) DeletePod(pod *v1.Pod)

DeletePod deletes a pod in the given namespace.

func (*Test) DeleteSecret

func (test *Test) DeleteSecret(secret *v1.Secret)

DeleteSecret deletes a secret.

func (*Test) DeleteService

func (test *Test) DeleteService(service *v1.Service)

DeleteService deletes a service.

func (*Test) DeleteServiceAccount

func (test *Test) DeleteServiceAccount(serviceAccount *v1.ServiceAccount)

DeleteServiceAccount deletes a ServiceAccount.

func (*Test) DumpNamespace

func (t *Test) DumpNamespace(w io.Writer, ns string)

DumpNamespace writes to w information about the pods in a namespace.

func (*Test) DumpTestState

func (t *Test) DumpTestState(w io.Writer)

DumpTestState writes to w information about the objects created by the test.

func (*Test) GetClusterRole

func (test *Test) GetClusterRole(name string) (*rbacv1.ClusterRole, error)

GetClusterRole returns a ClusterRole object if it exists or error.

func (*Test) GetClusterRoleBinding

func (test *Test) GetClusterRoleBinding(name string) (*rbacv1.ClusterRoleBinding, error)

GetClusterRoleBinding returns a ClusterRoleBinding object if it exists or error.

func (*Test) GetConfigMap

func (test *Test) GetConfigMap(ns, name string) (*v1.ConfigMap, error)

GetConfigMap returns a ConfigMap object if it exists or error.

func (*Test) GetDaemonSet

func (test *Test) GetDaemonSet(ns, name string) (*appsv1.DaemonSet, error)

GetDaemonSet returns daemonset if it exists or error if it doesn't.

func (*Test) GetDeployment

func (test *Test) GetDeployment(ns, name string) (*appsv1.Deployment, error)

GetDeployment returns Deployment if it exists or error if it doesn't.

func (*Test) GetNamespace

func (test *Test) GetNamespace(name string) (*v1.Namespace, error)

GetNamespace returns a Namespace object if it exists or error.

func (*Test) GetSecret

func (test *Test) GetSecret(ns, name string) (*v1.Secret, error)

GetSecret returns a Secret object if it exists or error.

func (*Test) GetService

func (test *Test) GetService(namespace, name string) *v1.Service

GetService retrieves a service with a given name and namespace.

func (*Test) GetServiceAccount

func (test *Test) GetServiceAccount(namespace, name string) (*v1.ServiceAccount, error)

GetServiceAccount returns a ServiceAccount object if it exists or error.

func (*Test) Info

func (t *Test) Info(msg string)

Info prints an informational message.

func (*Test) Infof

func (t *Test) Infof(f string, args ...interface{})

Infof prints a informational message with a format string.

func (*Test) ListNodes

func (test *Test) ListNodes(options metav1.ListOptions) *v1.NodeList

ListNodes returns all nodes that are part of the cluster.

func (*Test) ListPods

func (test *Test) ListPods(namespace string, options metav1.ListOptions) *v1.PodList

ListPods returns the list of pods in namespace matching options.

func (*Test) ListPodsFromDeployment

func (test *Test) ListPodsFromDeployment(d *appsv1.Deployment) *v1.PodList

ListPodsFromDeployment returns the list of pods created by a deployment.

func (*Test) LoadClusterRole

func (test *Test) LoadClusterRole(manifestPath string) *rbacv1.ClusterRole

LoadClusterRole loads a cluster role from a YAML manifest. The path to the manifest is relative to Harness.ManifestDirectory.

func (*Test) LoadClusterRoleBinding

func (test *Test) LoadClusterRoleBinding(manifestPath string) *rbacv1.ClusterRoleBinding

LoadClusterRoleBinding loads a cluster role binding from a YAML manifest. The path to the manifest is relative to Harness.ManifestDirectory.

func (*Test) LoadConfigMap

func (test *Test) LoadConfigMap(manifestPath string) *v1.ConfigMap

LoadConfigMap loads a ConfigMap from a YAML manifest. The path to the manifest is relative to Harness.ManifestDirectory.

func (*Test) LoadDaemonSet

func (test *Test) LoadDaemonSet(manifestPath string) *appsv1.DaemonSet

LoadDaemonSet loads a daemonset from a YAML manifest. The path to the manifest is relative to Harness.ManifestDirectory.

func (*Test) LoadDeployment

func (test *Test) LoadDeployment(manifestPath string) *appsv1.Deployment

LoadDeployment loads a deployment from a YAML manifest. The path to the manifest is relative to Harness.ManifestDirectory.

func (*Test) LoadSecret

func (test *Test) LoadSecret(manifestPath string) *v1.Secret

LoadSecret loads a secret from a YAML manifest. The path to the manifest is relative to Harness.ManifestDirectory.

func (*Test) LoadService

func (test *Test) LoadService(manifestPath string) *v1.Service

LoadService loads a service from a YAML manifest. The path to the manifest is relative to Harness.ManifestDirectory.

func (*Test) LoadServiceAccount

func (test *Test) LoadServiceAccount(manifestPath string) *v1.ServiceAccount

LoadServiceAccount loads a service account from a YAML manifest. The path to the manifest is relative to Harness.ManifestDirectory.

func (*Test) NodeReady

func (test *Test) NodeReady(node *v1.Node) bool

NodeReady returns whether a node is ready.

func (*Test) PodLogs

func (test *Test) PodLogs(w io.Writer, pod *v1.Pod, containerName string) error

PodLogs writes the container logs on w. If the pod has a single container, containerName is optional and can be set to "".

func (*Test) PodProxyGet

func (test *Test) PodProxyGet(pod *v1.Pod, port, path string) *rest.Request

PodProxyGet returns a Request that can used to perform an HTTP GET to a pod through the API server proxy. Port can be a port name or the port number.

If port is "", the first port found in the containers spec will be used.

func (*Test) PodProxyGetJSON

func (test *Test) PodProxyGetJSON(pod *v1.Pod, port, path string, v interface{})

PodProxyGetJSON is a convenience function around PodProxyGet that also unmarshals the response body into v.

func (*Test) PodReady

func (test *Test) PodReady(pod v1.Pod) (bool, error)

PodReady returns whether a pod is running and each container has is in the ready state.

func (*Test) Setup

func (t *Test) Setup() *Test

Setup setups the test to be run in the Test.Namespace temporary namespace.

func (*Test) UpdateService

func (test *Test) UpdateService(service *v1.Service)

UpdateService updates a service.

func (*Test) WaitForClusterRoleBindingReady

func (test *Test) WaitForClusterRoleBindingReady(crb *rbacv1.ClusterRole, timeout time.Duration)

WaitForClusterRoleBindingReady waits until ClusterRoleBinding is created, otherwise times out.

func (*Test) WaitForClusterRoleReady

func (test *Test) WaitForClusterRoleReady(cr *rbacv1.ClusterRole, timeout time.Duration)

WaitForClusterRoleReady waits until ClusterRole is created, otherwise times out.

func (*Test) WaitForConfigMapReady

func (test *Test) WaitForConfigMapReady(cm *v1.ConfigMap, timeout time.Duration)

WaitForConfigMapReady waits until ConfigMap is created, otherwise times out.

func (*Test) WaitForDaemonSetDeleted

func (test *Test) WaitForDaemonSetDeleted(d *appsv1.DaemonSet, timeout time.Duration)

WaitForDaemonSetDeleted waits until a deleted daemonset has disappeared from the cluster.

func (*Test) WaitForDaemonSetReady

func (test *Test) WaitForDaemonSetReady(d *appsv1.DaemonSet, timeout time.Duration)

WaitForDaemonSetReady waits until all replica pods are running and ready.

func (*Test) WaitForDeploymentDeleted

func (test *Test) WaitForDeploymentDeleted(d *appsv1.Deployment, timeout time.Duration)

WaitForDeploymentDeleted waits until a deleted deployment has disappeared from the cluster.

func (*Test) WaitForDeploymentReady

func (test *Test) WaitForDeploymentReady(d *appsv1.Deployment, timeout time.Duration)

WaitForDeploymentReady waits until all replica pods are running and ready.

func (*Test) WaitForNodesReady

func (test *Test) WaitForNodesReady(expectedNodes int, timeout time.Duration)

WaitForNodesReady waits until the specified number of nodes are running and ready. The function waits until the exact number is of expected node is matched.

func (*Test) WaitForNodesReadyMin

func (test *Test) WaitForNodesReadyMin(minExpectedNodes int, timeout time.Duration)

WaitForNodesReadyMin waits until the specified minimum number of nodes are running and ready. The function waits until the exact number is of expected node is matched.

func (*Test) WaitForPodsReady

func (test *Test) WaitForPodsReady(namespace string, opts metav1.ListOptions, expectedReplicas int, timeout time.Duration) error

WaitForPodsReady waits for a selection of Pods to be running and each container to pass its readiness check.

func (*Test) WaitForSecretReady

func (test *Test) WaitForSecretReady(secret *v1.Secret, timeout time.Duration)

WaitForSecretReady waits until Secret is created, otherwise times out.

func (*Test) WaitForServiceAccountReady

func (test *Test) WaitForServiceAccountReady(serviceAccount *v1.ServiceAccount)

WaitForServiceAccountReady waits until ConfigMap is created, otherwise times out.

func (*Test) WaitForServiceDeleted

func (test *Test) WaitForServiceDeleted(service *v1.Service)

WaitForServiceDeleted waits until deleted service has disappeared from the cluster.

func (*Test) WaitForServiceReady

func (test *Test) WaitForServiceReady(service *v1.Service)

WaitForServiceReady will wait until at least one endpoint backing up the service is ready.

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL