harness

package module
v0.0.0-...-ec3f93e Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2019 License: Apache-2.0 Imports: 26 Imported by: 0

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) 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) 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) 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) 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) 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) 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) GetSecret

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

GetSecret returns a Secret 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) 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.ManifestsDirectory.

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.ManifestsDirectory.

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.ManifestsDirectory.

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.ManifestsDirectory.

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.ManifestsDirectory.

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) 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) 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) 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