Skip to content

Latest commit

 

History

History

e2e

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

Importable End-To-End Test Suite

Virtual Kubelet (VK) provides an importable end-to-end (E2E) test suite containing a set of common integration tests. As a provider, you can import the test suite and use it to validate your VK implementation.

Prerequisite

To run the E2E test suite, three things are required:

  • A local Kubernetes cluster (we have tested with Docker for Mac and Minikube);
  • Your kubeconfig default context points to the local Kubernetes cluster;
  • skaffold

The test suite is based on VK 1.0. If your VK implementation is based on legacy VK library (< v1.0.0), you will have to upgrade it to VK 1.0 using virtual-kubelet/node-cli.

Skaffold Folder

Before running the E2E test suite, you will need to copy the ./hack folder containing Skaffold-related files such as Dockerfile, manifests, and certificates to your VK project root. Skaffold essentially helps package your virtual kubelet into a container based on the given Dockerfile and deploy it as a pod (see pod.yml) to your Kubernetes test cluster. In summary, you will likely need to modify the VK name in those files, customize the VK configuration file, and the API server certificates (<vk-name>-crt.pem and <vk-name>-key.pem) before running the test suite.

Makefile.e2e

Also, you will need to copy Makefile.e2e to your VK project root. It contains necessary make commands to run the E2E test suite. Do not forget to add include Makefile.e2e in your Makefile.

File Structure

A minimal VK provider should now have a file structure similar to the one below:

.
├── Makefile
├── Makefile.e2e
├── README.md
├── cmd
│   └── virtual-kubelet
│       └── main.go
├── go.mod
├── go.sum
├── hack
│   └── skaffold
│       └── virtual-kubelet
│           ├── Dockerfile
│           ├── base.yml
│           ├── pod.yml
│           ├── skaffold.yml
│           ├── vkubelet-provider-0-cfg.json
│           ├── vkubelet-provider-0-crt.pem
│           └── vkubelet-provider-0-key.pem
├── test
│   └── e2e
│       └── main_test.go # import and run the E2E test suite here
├── provider.go # provider-specific VK implementation
├── provider_test.go # unit test

Importing the Test Suite

The test suite can be easily imported in your test files (e.g. ./test/e2e/main_test.go) with the following import statement:

import (
	vke2e "github.com/virtual-kubelet/virtual-kubelet/test/e2e"
)

Test Suite Customization

The test suite allows providers to customize the test suite using EndToEndTestSuiteConfig:

// EndToEndTestSuiteConfig is the config passed to initialize the testing framework and test suite.
type EndToEndTestSuiteConfig struct {
	// Kubeconfig is the path to the kubeconfig file to use when running the test suite outside a Kubernetes cluster.
	Kubeconfig string
	// Namespace is the name of the Kubernetes namespace to use for running the test suite (i.e. where to create pods).
	Namespace string
	// NodeName is the name of the virtual-kubelet node to test.
	NodeName string
	// WatchTimeout is the duration for which the framework watch a particular condition to be satisfied (e.g. watches a pod  becoming ready)
	WatchTimeout time.Duration
	// Setup is a function that sets up provider-specific resource in the test suite
	Setup suite.SetUpFunc
	// Teardown is a function that tears down provider-specific resources from the test suite
	Teardown suite.TeardownFunc
	// ShouldSkipTest is a function that determines whether the test suite should skip certain tests
	ShouldSkipTest suite.ShouldSkipTestFunc
}

Setup() is invoked before running the E2E test suite, and Teardown() is invoked after all the E2E tests are finished.

You will need an EndToEndTestSuiteConfig to create an EndToEndTestSuite using NewEndToEndTestSuite. After that, invoke Run from EndToEndTestSuite to start the test suite. The code snippet below is a minimal example of how to import and run the test suite in your test file.

package e2e

import (
	"time"

	vke2e "github.com/virtual-kubelet/virtual-kubelet/test/e2e"
)

var (
	kubeconfig string
	namespace string
	nodeName string
)

// Read the following variables from command-line flags
func init() {
	flag.StringVar(&kubeconfig, "kubeconfig", "", "path to the kubeconfig file to use when running the test suite outside a kubernetes cluster")
	flag.StringVar(&namespace, "namespace", defaultNamespace, "the name of the kubernetes namespace to use for running the test suite (i.e. where to create pods)")
	flag.StringVar(&nodeName, "node-name", defaultNodeName, "the name of the virtual-kubelet node to test")
	flag.Parse()
}

func setup() error {
	fmt.Println("Setting up end-to-end test suite...")
	return nil
}

func teardown() error {
	fmt.Println("Tearing down end-to-end test suite...")
	return nil
}

func shouldSkipTest(testName string) bool {
	// Skip the test 'TestGetStatsSummary'
	return testName == "TestGetStatsSummary"
}

func TestEndToEnd(t *testing.T) {
	config := vke2e.EndToEndTestSuiteConfig{
		Kubeconfig:     kubeconfig,
		Namespace:      namespace,
		NodeName:       nodeName,
		Setup:          setup,
		Teardown:       teardown,
		ShouldSkipTest: shouldSkipTest,
		WaitTimeout:    5 * time.Minute,
	}
	ts := vke2e.NewEndToEndTestSuite(config)
	ts.Run(t)
}

Running the Test Suite

Since our CI uses Minikube, we describe below how to run E2E on top of it.

To create a Minikube cluster, run the following command after installing Minikube:

minikube start

To run the E2E test suite, you can run the following command:

make e2e

You can see from the console output whether the tests in the test suite pass or not.

...
=== RUN   TestEndToEnd
=== RUN   TestEndToEnd/TestCreatePodWithMandatoryInexistentConfigMap
=== RUN   TestEndToEnd/TestCreatePodWithMandatoryInexistentSecrets
=== RUN   TestEndToEnd/TestCreatePodWithOptionalInexistentConfigMap
=== RUN   TestEndToEnd/TestCreatePodWithOptionalInexistentSecrets
=== RUN   TestEndToEnd/TestGetStatsSummary
=== RUN   TestEndToEnd/TestNodeCreateAfterDelete
=== RUN   TestEndToEnd/TestPodLifecycleForceDelete
=== RUN   TestEndToEnd/TestPodLifecycleGracefulDelete
--- PASS: TestEndToEnd (21.93s)
    --- PASS: TestEndToEnd/TestCreatePodWithMandatoryInexistentConfigMap (0.03s)
    --- PASS: TestEndToEnd/TestCreatePodWithMandatoryInexistentSecrets (0.03s)
    --- PASS: TestEndToEnd/TestCreatePodWithOptionalInexistentConfigMap (0.55s)
    --- PASS: TestEndToEnd/TestCreatePodWithOptionalInexistentSecrets (0.99s)
    --- PASS: TestEndToEnd/TestGetStatsSummary (0.80s)
    --- PASS: TestEndToEnd/TestNodeCreateAfterDelete (9.63s)
    --- PASS: TestEndToEnd/TestPodLifecycleForceDelete (2.05s)
        basic.go:158: Created pod: nginx-testpodlifecycleforcedelete-jz84g
        basic.go:164: Pod nginx-testpodlifecycleforcedelete-jz84g ready
        basic.go:197: Force deleted pod:  nginx-testpodlifecycleforcedelete-jz84g
        basic.go:214: Pod ended as phase: Running
    --- PASS: TestEndToEnd/TestPodLifecycleGracefulDelete (1.04s)
        basic.go:87: Created pod: nginx-testpodlifecyclegracefuldelete-r84v7
        basic.go:93: Pod nginx-testpodlifecyclegracefuldelete-r84v7 ready
        basic.go:120: Deleted pod: nginx-testpodlifecyclegracefuldelete-r84v7
PASS
...