Skip to content

Commit dccc832

Browse files
committed
Introduce mechanism for gathering test artifacts during individual test failures
Update the testing e2e suite and add a mechanism for gathering test artifacts during individual test failures. Currently, container logs are gathered when deprovisioning upstream kind clusters, yet we lack fine-grain ability to diagnose test failures further. Note: test failures use the `CurrentGinkgoTestDescription.Failed` field to determine failures. Testing artifacts are only gathered when the base $ARTIFACTS_DIR environment variable has been specified. Add a collect-ci-artifacts.sh bash script, responsible for gathering OLM native resources for an individual testing namespace. This bash script will be called when tearing down the generated testing namespace for relevant e2e packages. Currently, the artifact gathering process is restricted to only a single namespace - longer term, it might be possible to instead migrate towards collecting resources that all share a similar label selector, and utilizing that label selector to handle multi-namespace testing scenarios. Introduce another helper function in test/e2e/util_test.go that's responsible for gathering test artifacts (i.e. calling this newly introduced script) when the test case had failed, and in either case, delete the namespace. Signed-off-by: timflannagan <[email protected]>
1 parent 6be7d55 commit dccc832

File tree

5 files changed

+83
-6
lines changed

5 files changed

+83
-6
lines changed

Diff for: test/e2e/collect-ci-artifacts.sh

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#! /bin/bash
2+
3+
set -o pipefail
4+
set -o nounset
5+
set -o errexit
6+
7+
: "${KUBECONFIG:?}"
8+
: "${TEST_NAMESPACE:?}"
9+
: "${TEST_ARTIFACTS_DIR:?}"
10+
11+
mkdir -p "${TEST_ARTIFACTS_DIR}"
12+
13+
commands=()
14+
commands+=("get subscriptions -o yaml")
15+
commands+=("get operatorgroups -o yaml")
16+
commands+=("get clusterserviceversions -o yaml")
17+
commands+=("get installplans -o yaml")
18+
commands+=("get pods -o wide")
19+
commands+=("get events --sort-by .lastTimestamp")
20+
21+
echo "Storing the test artifact output in the ${TEST_ARTIFACTS_DIR} directory"
22+
for command in "${commands[@]}"; do
23+
echo "Collecting ${command} output..."
24+
COMMAND_OUTPUT_FILE=${TEST_ARTIFACTS_DIR}/${command// /_}
25+
kubectl -n ${TEST_NAMESPACE} ${command} >> "${COMMAND_OUTPUT_FILE}"
26+
done

Diff for: test/e2e/ctx/ctx.go

+33
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ package ctx
22

33
import (
44
"fmt"
5+
"os"
6+
"os/exec"
7+
"path/filepath"
58
"strings"
69

710
. "github.com/onsi/ginkgo"
@@ -32,6 +35,7 @@ type TestContext struct {
3235
dynamicClient dynamic.Interface
3336
packageClient pversioned.Interface
3437
ssaClient *controllerclient.ServerSideApplier
38+
artifactsDir string
3539

3640
scheme *runtime.Scheme
3741

@@ -86,6 +90,35 @@ func (ctx TestContext) SSAClient() *controllerclient.ServerSideApplier {
8690
return ctx.ssaClient
8791
}
8892

93+
func (ctx TestContext) DumpNamespaceArtifacts(namespace string) error {
94+
if ctx.artifactsDir == "" {
95+
ctx.Logf("$ARTIFACTS_DIR is unset -- not collecting failed test case logs")
96+
return nil
97+
}
98+
ctx.Logf("collecting logs in the %s artifacts directory", ctx.artifactsDir)
99+
100+
logDir := filepath.Join(ctx.artifactsDir, namespace)
101+
if err := os.MkdirAll(logDir, os.ModePerm); err != nil {
102+
return err
103+
}
104+
envvars := []string{
105+
"TEST_NAMESPACE=" + namespace,
106+
"TEST_ARTIFACTS_DIR=" + logDir,
107+
"KUBECONFIG=" + os.Getenv("KUBECONFIG"),
108+
}
109+
110+
// compiled test binary running e2e tests is run from the root ./bin directory
111+
cmd := exec.Command("../test/e2e/collect-ci-artifacts.sh")
112+
cmd.Env = append(cmd.Env, envvars...)
113+
cmd.Stdout = os.Stdout
114+
cmd.Stderr = os.Stderr
115+
if err := cmd.Run(); err != nil {
116+
return err
117+
}
118+
119+
return nil
120+
}
121+
89122
func setDerivedFields(ctx *TestContext) error {
90123
if ctx == nil {
91124
return fmt.Errorf("nil test context")

Diff for: test/e2e/ctx/provisioner_kind.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,18 @@ func Provision(ctx *TestContext) (func(), error) {
134134
if err != nil {
135135
return nil, fmt.Errorf("error loading kubeconfig: %s", err.Error())
136136
}
137-
138137
ctx.restConfig = restConfig
139138

139+
if artifactsDir := os.Getenv("ARTIFACTS_DIR"); artifactsDir != "" {
140+
ctx.artifactsDir = artifactsDir
141+
}
142+
140143
var once sync.Once
141144
deprovision := func() {
142145
once.Do(func() {
143-
if artifactsDir := os.Getenv("ARTIFACTS_DIR"); artifactsDir != "" {
146+
if ctx.artifactsDir != "" {
144147
ctx.Logf("collecting container logs for the %s cluster", name)
145-
if err := provider.CollectLogs(name, filepath.Join(artifactsDir, logDir)); err != nil {
148+
if err := provider.CollectLogs(name, filepath.Join(ctx.artifactsDir, logDir)); err != nil {
146149
ctx.Logf("failed to collect logs: %v", err)
147150
}
148151
}

Diff for: test/e2e/subscription_e2e_test.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@ var _ = Describe("Subscription", func() {
5959
})
6060

6161
AfterEach(func() {
62-
Eventually(func() error {
63-
return ctx.Ctx().Client().Delete(context.Background(), &generatedNamespace)
64-
}).Should(Succeed())
62+
TeardownNamespace(generatedNamespace.GetName())
6563
})
6664

6765
When("an entry in the middle of a channel does not provide a required GVK", func() {

Diff for: test/e2e/util_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -946,3 +946,20 @@ func SetupGeneratedTestNamespace(name string) corev1.Namespace {
946946

947947
return ns
948948
}
949+
950+
func TeardownNamespace(ns string) {
951+
log := ctx.Ctx().Logf
952+
953+
currentTest := CurrentGinkgoTestDescription()
954+
if currentTest.Failed {
955+
log("collecting the %s namespace artifacts as the '%s' test case failed", ns, currentTest.TestText)
956+
if err := ctx.Ctx().DumpNamespaceArtifacts(ns); err != nil {
957+
log("failed to collect namespace artifacts: %v", err)
958+
}
959+
}
960+
961+
log("tearing down the %s namespace", ns)
962+
Eventually(func() error {
963+
return ctx.Ctx().KubeClient().KubernetesInterface().CoreV1().Namespaces().Delete(context.Background(), ns, metav1.DeleteOptions{})
964+
}).Should(Succeed())
965+
}

0 commit comments

Comments
 (0)