Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

Commit

Permalink
test: run Go tests inside driver container
Browse files Browse the repository at this point in the history
This has multiple advantages:
- we test in exactly the environment in which the code will run
- it's faster than bringing up a separate VM
- no need to remember a separate make target to run all tests

Speed is important both for CI and developers. Running the tests in an
existing cluster just takes 9 seconds and can be done using the same
command as running other tests individually:

   make test_e2e TEST_E2E_FOCUS=gotests.*pmem-device-manager

Because it runs so quickly, it's okay to simply repeat this testing in
each CI step which runs E2E tests.
  • Loading branch information
pohly committed Nov 22, 2019
1 parent f99522b commit 7982fb0
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 22 deletions.
20 changes: 0 additions & 20 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -159,26 +159,6 @@ pipeline {
}
}

stage('make dm-test') {
options {
timeout(time: 30, unit: "MINUTES")
}

steps {
sh "docker run --rm ${DockerBuildArgs()} \
--privileged=true \
-e TEST_CHECK_SIGNED_FILES=false \
-e TEST_DISTRO=clear \
-e TEST_DISTRO_VERSION=${env.CLEAR_LINUX_VERSION_1_15} \
-v `pwd`:`pwd`:rshared \
-w `pwd` \
${env.BUILD_IMAGE} bash -c 'set -x; \
swupd bundle-add openssh-client && \
make run_dm_tests; \
make stop'"
}
}

stage('Build test image') {
options {
timeout(time: 60, unit: "MINUTES")
Expand Down
1 change: 1 addition & 0 deletions test/e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
. "github.com/onsi/ginkgo"

// test sources
_ "github.com/intel/pmem-csi/test/e2e/gotests"
_ "github.com/intel/pmem-csi/test/e2e/storage"
)

Expand Down
66 changes: 66 additions & 0 deletions test/e2e/gotests/gotests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
Copyright 2019 Intel Corporation.
SPDX-License-Identifier: Apache-2.0
*/

package gotests

import (
"fmt"
"os"
"os/exec"
"strings"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/kubernetes/test/e2e/framework"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"github.com/intel/pmem-csi/test/e2e/pod"
)

var _ = Describe("gotests", func() {
f := framework.NewDefaultFramework("gotests")
f.SkipNamespaceCreation = true

// Register one test for each package.
for _, pkg := range strings.Split(os.Getenv("TEST_PKGS"), " ") {
pkg := pkg
It(pkg, func() { runGoTest(f, pkg) })
}
})

// runGoTest builds and copies the Go test binary into the PMEM-CSI
// driver container and executes it there. This way it runs in exactly
// the same environment as the driver (the distro's kernel, our
// container user space), which may or may not expose bugs that are
// not found when running those tests on the build host.
func runGoTest(f *framework.Framework, pkg string) {
root := os.Getenv("REPO_ROOT")
var err error

build := exec.Command("/bin/sh", "-c", os.Getenv("TEST_CMD")+" -c -o _work/test.test "+pkg)
build.Stdout = GinkgoWriter
build.Stderr = GinkgoWriter
build.Dir = root
By("Compiling with: " + strings.Join(build.Args, " "))
err = build.Run()
framework.ExpectNoError(err, "compile test program for %s", pkg)

label := labels.SelectorFromSet(labels.Set(map[string]string{"app": "pmem-csi-node"}))
pods, err := f.ClientSet.CoreV1().Pods("default").List(metav1.ListOptions{LabelSelector: label.String()})
framework.ExpectNoError(err, "list PMEM-CSI pods")
Expect(pods.Items).NotTo(BeEmpty(), "have PMEM-CSI pods")
pmem := pods.Items[0]

By(fmt.Sprintf("Running in PMEM-CSI pod %s", pmem.Name))
pod.RunInPod(f, root,
[]string{"_work/test.test", "_work/evil-ca", "_work/pmem-ca"},
"if _work/test.test -h 2>&1 | grep -q ginkgo; then "+
"TEST_WORK=_work _work/test.test -test.v -ginkgo.v; else "+
"TEST_WORK=_work _work/test.test -test.v -ginkgo.v; fi",
pmem.Namespace, pmem.Name, "pmem-driver")
}
61 changes: 61 additions & 0 deletions test/e2e/pod/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
Copyright 2019 Intel Corporation.
SPDX-License-Identifier: Apache-2.0
*/

package pod

import (
"fmt"
"io"
"os/exec"

"k8s.io/kubernetes/test/e2e/framework"

. "github.com/onsi/ginkgo"
)

// RunInPod optionally tars up some files or directories, unpacks them in a container,
// and executes a shell command. Any error is treated as test failure.
func RunInPod(f *framework.Framework, rootdir string, items []string, command string, namespace, pod, container string) {
var input io.Reader
var cmdPrefix string
if len(items) > 0 {
args := []string{"-cf", "-"}
args = append(args, items...)
tar := exec.Command("tar", args...)
tar.Stderr = GinkgoWriter
tar.Dir = rootdir
pipe, err := tar.StdoutPipe()
framework.ExpectNoError(err, "create pipe for tar")
err = tar.Start()
framework.ExpectNoError(err, "run tar")
defer func() {
err = tar.Wait()
framework.ExpectNoError(err, "tar runtime error")
}()

input = pipe
cmdPrefix = "tar -xf - &&"
}

options := framework.ExecOptions{
Command: []string{
"/bin/sh",
"-c",
cmdPrefix + command,
},
Namespace: namespace,
PodName: pod,
ContainerName: container,
Stdin: input,
CaptureStdout: true,
CaptureStderr: true,
}
stdout, stderr, err := f.ExecWithOptions(options)
framework.ExpectNoError(err, "command failed in namespace %s, pod/container %s/%s:\nstderr:\n%s\nstdout:%s\n",
namespace, pod, container, stderr, stdout)
fmt.Fprintf(GinkgoWriter, "stderr:\n%s\nstdout:\n%s",
stdout, stderr)
}
12 changes: 10 additions & 2 deletions test/test.make
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
TEST_CMD=$(GO) test
TEST_ARGS=$(IMPORT_PATH)/pkg/...
TEST_PKGS=$(shell $(GO) list $(TEST_ARGS) | sed -e 's;$(IMPORT_PATH);.;')

.PHONY: vet
test: vet check-go-version-$(GO_BINARY)
Expand Down Expand Up @@ -134,18 +135,25 @@ RUN_E2E = KUBECONFIG=`pwd`/_work/$(CLUSTER)/kube.config \
TEST_DEPLOYMENTMODE=$(shell source test/test-config.sh; echo $$TEST_DEPLOYMENTMODE) \
TEST_DEVICEMODE=$(shell source test/test-config.sh; echo $$TEST_DEVICEMODE) \
TEST_KUBERNETES_VERSION=$(shell source test/test-config.sh; echo $$TEST_KUBERNETES_VERSION) \
${GO} test -count=1 -timeout 0 -v ./test/e2e \
TEST_CMD='$(TEST_CMD)' \
TEST_PKGS='$(shell for i in $(TEST_PKGS); do if ls $$i/*_test.go 2>/dev/null >&2; then echo $$i; fi; done)' \
$(GO) test -count=1 -timeout 0 -v ./test/e2e \
-ginkgo.skip='$(subst $(space),|,$(TEST_E2E_SKIP))' \
-ginkgo.focus='$(subst $(space),|,$(TEST_E2E_FOCUS))' \
-report-dir=$(TEST_E2E_REPORT_DIR)
test_e2e: start
$(RUN_E2E)

# Execute simple unit tests.
#
# pmem-device-manager gets excluded because its tests need a special
# environment. We could run it, but its tests would just be skipped
# (https://github.com/intel/pmem-csi/pull/420#discussion_r346850741).
.PHONY: run_tests
test: run_tests
RUN_TESTS = TEST_WORK=$(abspath _work) \
$(TEST_CMD) $(shell $(GO) list $(TEST_ARGS) | grep -v pmem-device-manager | sed -e 's;$(IMPORT_PATH);.;')
$(TEST_CMD) $(filter-out %/pmem-device-manager,$(TEST_PKGS))

run_tests: _work/pmem-ca/.ca-stamp _work/evil-ca/.ca-stamp check-go-version-$(GO_BINARY)
$(RUN_TESTS)

Expand Down

0 comments on commit 7982fb0

Please sign in to comment.