Skip to content

Commit

Permalink
Add OOM integration test
Browse files Browse the repository at this point in the history
  • Loading branch information
benashz committed Dec 10, 2024
1 parent 9f2f611 commit 6a29244
Show file tree
Hide file tree
Showing 5 changed files with 421 additions and 86 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,47 @@ jobs:
VAULT_N: "1.17.2"
VAULT_N_1: "1.16.6"
VAULT_N_2: "1.15.12"
oom-tests:
runs-on: ubuntu-latest
needs:
- get-product-version
- build-pre-checks
- build-docker
- versions
strategy:
fail-fast: false
matrix:
k8s-version: ${{ fromJson(needs.versions.outputs.K8S_VERSIONS) }}
steps:
- uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
with:
name: ${{ github.event.repository.name }}_release-default_linux_amd64_${{ needs.get-product-version.outputs.product-version }}_${{ github.sha }}.docker.tar
- name: Load docker image
shell: bash
run: |
docker load --input ${{ github.event.repository.name }}_release-default_linux_amd64_${{ needs.get-product-version.outputs.product-version }}_${{ github.sha }}.docker.tar
- name: Install kind
uses: helm/kind-action@0025e74a8c7512023d06dc019c617aa3cf561fde # v1.10.0
with:
version: "v0.25.0"
install_only: true
- uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 # v4.2.0
id: setup-helm
with:
version: "v3.15.1"
- name: Add repo
shell: bash
run: |
helm repo add hashicorp https://helm.releases.hashicorp.com
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup go
uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0
with:
go-version-file: .go-version
- name: Run tests
shell: bash
run: |
make integration-test-oom KIND_K8S_VERSION="v${{ matrix.k8s-version }}"
latest-vault:
name: vault:${{ matrix.vault-version }} kind:${{ matrix.k8s-version }} ${{ matrix.installation-method }} enterprise=${{ matrix.vault-enterprise }}
needs:
Expand Down Expand Up @@ -432,6 +473,7 @@ jobs:
- unit-tests
- latest-vault
- latest-k8s
- oom-tests
steps:
- name: cancelled
if: ${{ (contains(needs.*.result, 'cancelled')) }}
Expand Down
8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,14 @@ integration-test-chart:
INTEGRATION_TESTS=true \
go test github.com/hashicorp/vault-secrets-operator/test/chart/... $(TESTARGS) -timeout=10m

.PHONY: integration-test-oom
integration-test-oom:
IMAGE_TAG_BASE=$(IMAGE_TAG_BASE) \
VERSION=$(VERSION) \
INTEGRATION_TESTS=true \
KIND_K8S_VERSION=$(KIND_K8S_VERSION) \
go test github.com/hashicorp/vault-secrets-operator/test/oom/... $(TESTARGS) -timeout=10m

.PHONY: setup-kind
setup-kind: ## create a kind cluster for running the acceptance tests locally
kind get clusters | grep --silent "^$(KIND_CLUSTER_NAME)$$" || \
Expand Down
98 changes: 98 additions & 0 deletions internal/testutils/install.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package testutils

import (
"context"
"io"
"os"
"os/exec"
"os/signal"
"syscall"
"testing"
"time"
)

var onlyOneSignalHandler = make(chan struct{})

var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM}

// InstallVSO installs a Vault Secrets Operator Helm release.
func InstallVSO(t *testing.T, ctx context.Context, extraArgs ...string) error {
t.Helper()
return RunHelm(t, ctx, time.Minute*5, nil, nil, append([]string{"install"}, extraArgs...)...)
}

// UpgradeVSO upgrades a Vault Secrets Operator Helm release.
func UpgradeVSO(t *testing.T, ctx context.Context, extraArgs ...string) error {
t.Helper()
return RunHelm(t, ctx, time.Minute*5, nil, nil, append([]string{"upgrade"}, extraArgs...)...)
}

// UninstallVSO uninstalls a Vault Secrets Operator Helm release.
func UninstallVSO(t *testing.T, ctx context.Context, extraArgs ...string) error {
t.Helper()
return RunHelm(t, ctx, time.Minute*3, nil, nil, append([]string{"uninstall"}, extraArgs...)...)
}

// RunHelm runs the helm command with the given arguments.
func RunHelm(t *testing.T, ctx context.Context, timeout time.Duration, stdout, stderr io.Writer, args ...string) error {
t.Helper()
return RunCommandWithTimeout(t, ctx, timeout, stdout, stderr, "helm", args...)
}

// RunKind runs the kind command with the given arguments.
func RunKind(t *testing.T, ctx context.Context, args ...string) error {
t.Helper()
return RunCommandWithTimeout(t, ctx, time.Minute*5, nil, nil, "kind", args...)
}

// RunCommandWithTimeout runs a command with a timeout. If the timeout is 0, the command will run indefinitely.
func RunCommandWithTimeout(t *testing.T, ctx context.Context, timeout time.Duration, stdout, stderr io.Writer, name string, args ...string) error {
t.Helper()
var ctx_ context.Context
var cancel context.CancelFunc
if timeout > 0 {
ctx_, cancel = context.WithTimeout(ctx, timeout)
defer cancel()
} else {
ctx_ = ctx
}

cmd := exec.CommandContext(ctx_, name, args...)
if stdout != nil {
cmd.Stdout = stdout
} else {
cmd.Stdout = os.Stdout
}
if stderr != nil {
cmd.Stderr = stderr
} else {
cmd.Stderr = os.Stderr
}

t.Logf("Running command %q", cmd)
return cmd.Run()
}

// SetupSignalHandler registers for SIGTERM and SIGINT. A context is returned
// which is canceled on one of these signals. If a second signal is caught, the program
// is terminated with exit code 1.
// Can only be called once.
func SetupSignalHandler() (context.Context, context.CancelFunc) {
close(onlyOneSignalHandler) // panics when called twice

ctx, cancel := context.WithCancel(context.Background())

c := make(chan os.Signal, 2)
signal.Notify(c, shutdownSignals...)
go func() {
<-c
cancel()
<-c
os.Exit(1) // second signal. Exit directly.
}()

return ctx, cancel
}
96 changes: 10 additions & 86 deletions test/chart/chart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,15 @@ import (
"bytes"
"context"
"fmt"
"io"
"log"
"os"
"os/exec"
"os/signal"
"path"
"path/filepath"
"reflect"
"runtime"
"strings"
"sync"
"syscall"
"testing"
"time"

Expand All @@ -30,15 +27,14 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"

"github.com/hashicorp/vault-secrets-operator/internal/testutils"
"github.com/hashicorp/vault-secrets-operator/utils"
)

var (
testRoot string
chartPath string
onlyOneSignalHandler = make(chan struct{})
shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM}
vsoNamespace = "vault-secrets-operator-system"
testRoot string
chartPath string
vsoNamespace = "vault-secrets-operator-system"
// kindClusterName is set in TestMain
kindClusterName string
// set in TestMain
Expand Down Expand Up @@ -104,7 +100,7 @@ func TestMain(m *testing.M) {

wg := sync.WaitGroup{}
wg.Add(1)
ctx, cancel := setupSignalHandler()
ctx, cancel := testutils.SetupSignalHandler()
{
go func() {
select {
Expand Down Expand Up @@ -154,7 +150,7 @@ func TestChart_upgradeCRDs(t *testing.T) {
b := bytes.NewBuffer([]byte{})
chart := "hashicorp/vault-secrets-operator"
require.NoError(t,
runHelm(t, context.Background(), time.Second*30, b, nil,
testutils.RunHelm(t, context.Background(), time.Second*30, b, nil,
"show", "crds",
"--version", startChartVersion,
chart,
Expand Down Expand Up @@ -204,19 +200,19 @@ func TestChart_upgradeCRDs(t *testing.T) {
releaseName := strings.Replace(strings.ToLower(t.Name()), "_", "-", -1)
ctx := context.Background()
t.Cleanup(func() {
assert.NoError(t, uninstallVSO(t, ctx,
assert.NoError(t, testutils.UninstallVSO(t, ctx,
"--wait",
"--namespace", vsoNamespace,
releaseName,
))
})

require.NoError(t, runKind(t, ctx,
require.NoError(t, testutils.RunKind(t, ctx,
"load", "docker-image", image,
"--name", kindClusterName,
))

require.NoError(t, installVSO(t, ctx,
require.NoError(t, testutils.InstallVSO(t, ctx,
"--wait",
"--create-namespace",
"--namespace", vsoNamespace,
Expand All @@ -233,7 +229,7 @@ func TestChart_upgradeCRDs(t *testing.T) {
installedCRDsMap[o.Name] = o
}

require.NoError(t, upgradeVSO(t, ctx,
require.NoError(t, testutils.UpgradeVSO(t, ctx,
"--wait",
"--namespace", vsoNamespace,
"--set", fmt.Sprintf("controller.manager.image.repository=%s", operatorImageRepo),
Expand Down Expand Up @@ -278,75 +274,3 @@ func TestChart_upgradeCRDs(t *testing.T) {
assert.Equal(t, len(updatedCRD.Status.StoredVersions), len(wantCRD.Spec.Versions), "CRD %q .status.storedVersions", wantCRD.Name)
}
}

func installVSO(t *testing.T, ctx context.Context, extraArgs ...string) error {
t.Helper()
return runHelm(t, ctx, time.Minute*5, nil, nil, append([]string{"install"}, extraArgs...)...)
}

func upgradeVSO(t *testing.T, ctx context.Context, extraArgs ...string) error {
t.Helper()
return runHelm(t, ctx, time.Minute*5, nil, nil, append([]string{"upgrade"}, extraArgs...)...)
}

func uninstallVSO(t *testing.T, ctx context.Context, extraArgs ...string) error {
t.Helper()
return runHelm(t, ctx, time.Minute*3, nil, nil, append([]string{"uninstall"}, extraArgs...)...)
}

func runHelm(t *testing.T, ctx context.Context, timeout time.Duration, stdout, stderr io.Writer, args ...string) error {
t.Helper()
return runCommandWithTimeout(t, ctx, timeout, stdout, stderr, "helm", args...)
}

func runKind(t *testing.T, ctx context.Context, args ...string) error {
t.Helper()
return runCommandWithTimeout(t, ctx, time.Minute*5, nil, nil, "kind", args...)
}

func runCommandWithTimeout(t *testing.T, ctx context.Context, timeout time.Duration, stdout, stderr io.Writer, name string, args ...string) error {
t.Helper()
var ctx_ context.Context
var cancel context.CancelFunc
if timeout > 0 {
ctx_, cancel = context.WithTimeout(ctx, timeout)
defer cancel()
} else {
ctx_ = ctx
}

cmd := exec.CommandContext(ctx_, name, args...)
if stdout != nil {
cmd.Stdout = stdout
} else {
cmd.Stdout = os.Stdout
}
if stderr != nil {
cmd.Stderr = stderr
} else {
cmd.Stderr = os.Stderr
}

t.Logf("Running command %q", cmd)
return cmd.Run()
}

// // setupSignalHandler registers for SIGTERM and SIGINT. A context is returned
// // which is canceled on one of these signals. If a second signal is caught, the program
// // is terminated with exit code 1.
func setupSignalHandler() (context.Context, context.CancelFunc) {
close(onlyOneSignalHandler) // panics when called twice

ctx, cancel := context.WithCancel(context.Background())

c := make(chan os.Signal, 2)
signal.Notify(c, shutdownSignals...)
go func() {
<-c
cancel()
<-c
os.Exit(1) // second signal. Exit directly.
}()

return ctx, cancel
}
Loading

0 comments on commit 6a29244

Please sign in to comment.