Use shared envTest for unit tests

Speed up unit tests by using a shared envTest. This requires each
test to use its own namespace to avoid clobbering objects for
other tests. Tests previously took around 8 seconds each, and now
the initial test takes 2 seconds with follow up tests taking less
than a second each.

Also update existing tests that use a fixed namespace to use a
generated namespace.

Share gold file template function with yaml files.

Remove the testClusterMode, and instead rely on MainTest to do
the appropriate test setup and rootArgs flag setup. Move the
rootArg flag setup out of NewTestEnvKubeManager to avoid
side effects.

A follow up change can be to push the individual setups
from NewTestEnvKubeManager() into their respective TestMain since
the harness share little code.

Signed-off-by: Allen Porter <allen@thebends.org>
pull/1743/head
Allen Porter 3 years ago
parent def92e14ee
commit d45501a129

@ -77,6 +77,16 @@ You can run the unit tests by simply doing
make test make test
``` ```
The e2e test suite uses [kind](https://kind.sigs.k8s.io/) for running kubernetes cluster inside docker containers. You can run the e2e tests by simply doing
```bash
make setup-kind
make e2e
# When done
make cleanup-kind
```
## Acceptance policy ## Acceptance policy
These things will make a PR more likely to be accepted: These things will make a PR more likely to be accepted:

@ -27,8 +27,7 @@ func TestCheckPre(t *testing.T) {
serverVersion := strings.TrimPrefix(versions["serverVersion"].GitVersion, "v") serverVersion := strings.TrimPrefix(versions["serverVersion"].GitVersion, "v")
cmd := cmdTestCase{ cmd := cmdTestCase{
args: "check --pre", args: "check --pre",
testClusterMode: ExistingClusterMode,
assert: assertGoldenTemplateFile("testdata/check/check_pre.golden", map[string]string{ assert: assertGoldenTemplateFile("testdata/check/check_pre.golden", map[string]string{
"clientVersion": clientVersion, "clientVersion": clientVersion,
"serverVersion": serverVersion, "serverVersion": serverVersion,

@ -39,7 +39,7 @@ func TestHelmReleaseFromGit(t *testing.T) {
}, },
} }
namespace := "thrfg" namespace := allocateNamespace("thrfg")
del, err := setupTestNamespace(namespace) del, err := setupTestNamespace(namespace)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -48,9 +48,8 @@ func TestHelmReleaseFromGit(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
cmd := cmdTestCase{ cmd := cmdTestCase{
args: tc.args + " -n=" + namespace, args: tc.args + " -n=" + namespace,
assert: assertGoldenFile(tc.goldenFile), assert: assertGoldenTemplateFile(tc.goldenFile, map[string]string{"ns": namespace}),
testClusterMode: ExistingClusterMode,
} }
cmd.runTestCmd(t) cmd.runTestCmd(t)
} }

@ -31,7 +31,7 @@ func TestImageScanning(t *testing.T) {
}, },
} }
namespace := "tis" namespace := allocateNamespace("tis")
del, err := setupTestNamespace(namespace) del, err := setupTestNamespace(namespace)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -40,9 +40,8 @@ func TestImageScanning(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
cmd := cmdTestCase{ cmd := cmdTestCase{
args: tc.args + " -n=" + namespace, args: tc.args + " -n=" + namespace,
assert: assertGoldenFile(tc.goldenFile), assert: assertGoldenFile(tc.goldenFile),
testClusterMode: ExistingClusterMode,
} }
cmd.runTestCmd(t) cmd.runTestCmd(t)
} }

@ -39,7 +39,7 @@ func TestKustomizationFromGit(t *testing.T) {
}, },
} }
namespace := "tkfg" namespace := allocateNamespace("tkfg")
del, err := setupTestNamespace(namespace) del, err := setupTestNamespace(namespace)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -48,9 +48,8 @@ func TestKustomizationFromGit(t *testing.T) {
for _, tc := range cases { for _, tc := range cases {
cmd := cmdTestCase{ cmd := cmdTestCase{
args: tc.args + " -n=" + namespace, args: tc.args + " -n=" + namespace,
assert: assertGoldenFile(tc.goldenFile), assert: assertGoldenTemplateFile(tc.goldenFile, map[string]string{"ns": namespace}),
testClusterMode: ExistingClusterMode,
} }
cmd.runTestCmd(t) cmd.runTestCmd(t)
} }

@ -15,12 +15,13 @@ func TestMain(m *testing.M) {
// Ensure tests print consistent timestamps regardless of timezone // Ensure tests print consistent timestamps regardless of timezone
os.Setenv("TZ", "UTC") os.Setenv("TZ", "UTC")
// Install Flux. testEnv, err := NewTestEnvKubeManager(ExistingClusterMode)
// Creating the test env manager sets rootArgs client flags
_, err := NewTestEnvKubeManager(ExistingClusterMode)
if err != nil { if err != nil {
panic(fmt.Errorf("error creating kube manager: '%w'", err)) panic(fmt.Errorf("error creating kube manager: '%w'", err))
} }
rootArgs.kubeconfig = testEnv.kubeConfigPath
// Install Flux.
output, err := executeCommand("install --components-extra=image-reflector-controller,image-automation-controller") output, err := executeCommand("install --components-extra=image-reflector-controller,image-automation-controller")
if err != nil { if err != nil {
panic(fmt.Errorf("install falied: %s error:'%w'", output, err)) panic(fmt.Errorf("install falied: %s error:'%w'", output, err))
@ -42,6 +43,8 @@ func TestMain(m *testing.M) {
panic(fmt.Errorf("delete namespace error:'%w'", err)) panic(fmt.Errorf("delete namespace error:'%w'", err))
} }
testEnv.Stop()
os.Exit(code) os.Exit(code)
} }

@ -9,6 +9,8 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"sync/atomic"
"testing" "testing"
"text/template" "text/template"
"time" "time"
@ -22,13 +24,18 @@ import (
"sigs.k8s.io/controller-runtime/pkg/envtest" "sigs.k8s.io/controller-runtime/pkg/envtest"
) )
func readYamlObjects(objectFile string) ([]unstructured.Unstructured, error) { var nextNamespaceId int64
obj, err := os.ReadFile(objectFile)
if err != nil { // Return a unique namespace with the specified prefix, for tests to create
return nil, err // objects that won't collide with each other.
} func allocateNamespace(prefix string) string {
id := atomic.AddInt64(&nextNamespaceId, 1)
return fmt.Sprintf("%s-%d", prefix, id)
}
func readYamlObjects(rdr io.Reader) ([]unstructured.Unstructured, error) {
objects := []unstructured.Unstructured{} objects := []unstructured.Unstructured{}
reader := k8syaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(obj))) reader := k8syaml.NewYAMLReader(bufio.NewReader(rdr))
for { for {
doc, err := reader.Read() doc, err := reader.Read()
if err != nil { if err != nil {
@ -49,15 +56,31 @@ func readYamlObjects(objectFile string) ([]unstructured.Unstructured, error) {
// A KubeManager that can create objects that are subject to a test. // A KubeManager that can create objects that are subject to a test.
type testEnvKubeManager struct { type testEnvKubeManager struct {
client client.WithWatch client client.WithWatch
testEnv *envtest.Environment testEnv *envtest.Environment
kubeConfigPath string
} }
func (m *testEnvKubeManager) NewClient(kubeconfig string, kubecontext string) (client.WithWatch, error) { func (m *testEnvKubeManager) CreateObjectFile(objectFile string, templateValues map[string]string, t *testing.T) {
return m.client, nil buf, err := os.ReadFile(objectFile)
if err != nil {
t.Fatalf("Error reading file '%s': %v", objectFile, err)
}
content, err := executeTemplate(string(buf), templateValues)
if err != nil {
t.Fatalf("Error evaluating template file '%s': '%v'", objectFile, err)
}
clientObjects, err := readYamlObjects(strings.NewReader(content))
if err != nil {
t.Fatalf("Error decoding yaml file '%s': %v", objectFile, err)
}
err = m.CreateObjects(clientObjects, t)
if err != nil {
t.Logf("Error creating test objects: '%v'", err)
}
} }
func (m *testEnvKubeManager) CreateObjects(clientObjects []unstructured.Unstructured) error { func (m *testEnvKubeManager) CreateObjects(clientObjects []unstructured.Unstructured, t *testing.T) error {
for _, obj := range clientObjects { for _, obj := range clientObjects {
// First create the object then set its status if present in the // First create the object then set its status if present in the
// yaml file. Make a copy first since creating an object may overwrite // yaml file. Make a copy first since creating an object may overwrite
@ -110,14 +133,14 @@ func NewTestEnvKubeManager(testClusterMode TestClusterMode) (*testEnvKubeManager
tmpFilename := filepath.Join("/tmp", "kubeconfig-"+time.Nanosecond.String()) tmpFilename := filepath.Join("/tmp", "kubeconfig-"+time.Nanosecond.String())
ioutil.WriteFile(tmpFilename, kubeConfig, 0644) ioutil.WriteFile(tmpFilename, kubeConfig, 0644)
rootArgs.kubeconfig = tmpFilename
k8sClient, err := client.NewWithWatch(cfg, client.Options{}) k8sClient, err := client.NewWithWatch(cfg, client.Options{})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &testEnvKubeManager{ return &testEnvKubeManager{
testEnv: testEnv, testEnv: testEnv,
client: k8sClient, client: k8sClient,
kubeConfigPath: tmpFilename,
}, nil }, nil
case ExistingClusterMode: case ExistingClusterMode:
// TEST_KUBECONFIG is mandatory to prevent destroying a current cluster accidentally. // TEST_KUBECONFIG is mandatory to prevent destroying a current cluster accidentally.
@ -125,7 +148,6 @@ func NewTestEnvKubeManager(testClusterMode TestClusterMode) (*testEnvKubeManager
if testKubeConfig == "" { if testKubeConfig == "" {
return nil, fmt.Errorf("environment variable TEST_KUBECONFIG is required to run tests against an existing cluster") return nil, fmt.Errorf("environment variable TEST_KUBECONFIG is required to run tests against an existing cluster")
} }
rootArgs.kubeconfig = testKubeConfig
useExistingCluster := true useExistingCluster := true
config, err := clientcmd.BuildConfigFromFlags("", testKubeConfig) config, err := clientcmd.BuildConfigFromFlags("", testKubeConfig)
@ -142,8 +164,9 @@ func NewTestEnvKubeManager(testClusterMode TestClusterMode) (*testEnvKubeManager
return nil, err return nil, err
} }
return &testEnvKubeManager{ return &testEnvKubeManager{
testEnv: testEnv, testEnv: testEnv,
client: k8sClient, client: k8sClient,
kubeConfigPath: testKubeConfig,
}, nil }, nil
} }
@ -217,7 +240,7 @@ func assertGoldenTemplateFile(goldenFile string, templateValues map[string]strin
} }
var expectedOutput string var expectedOutput string
if len(templateValues) > 0 { if len(templateValues) > 0 {
expectedOutput, err = executeGoldenTemplate(string(goldenFileContents), templateValues) expectedOutput, err = executeTemplate(string(goldenFileContents), templateValues)
if err != nil { if err != nil {
return fmt.Errorf("Error executing golden template file '%s': %s", goldenFile, err) return fmt.Errorf("Error executing golden template file '%s': %s", goldenFile, err)
} }
@ -243,8 +266,6 @@ const (
type cmdTestCase struct { type cmdTestCase struct {
// The command line arguments to test. // The command line arguments to test.
args string args string
// TestClusterMode to bootstrap and testing, default to Fake
testClusterMode TestClusterMode
// Tests use assertFunc to assert on an output, success or failure. This // Tests use assertFunc to assert on an output, success or failure. This
// can be a function defined by the test or existing function above. // can be a function defined by the test or existing function above.
assert assertFunc assert assertFunc
@ -253,34 +274,14 @@ type cmdTestCase struct {
} }
func (cmd *cmdTestCase) runTestCmd(t *testing.T) { func (cmd *cmdTestCase) runTestCmd(t *testing.T) {
km, err := NewTestEnvKubeManager(cmd.testClusterMode)
if err != nil {
t.Fatalf("Error creating kube manager: '%v'", err)
}
if km != nil {
defer km.Stop()
}
if cmd.objectFile != "" {
clientObjects, err := readYamlObjects(cmd.objectFile)
if err != nil {
t.Fatalf("Error loading yaml: '%v'", err)
}
err = km.CreateObjects(clientObjects)
if err != nil {
t.Fatalf("Error creating test objects: '%v'", err)
}
}
actual, testErr := executeCommand(cmd.args) actual, testErr := executeCommand(cmd.args)
if assertErr := cmd.assert(actual, testErr); assertErr != nil { if assertErr := cmd.assert(actual, testErr); assertErr != nil {
t.Error(assertErr) t.Error(assertErr)
} }
} }
func executeGoldenTemplate(goldenValue string, templateValues map[string]string) (string, error) { func executeTemplate(content string, templateValues map[string]string) (string, error) {
tmpl := template.Must(template.New("golden").Parse(goldenValue)) tmpl := template.Must(template.New("golden").Parse(content))
var out bytes.Buffer var out bytes.Buffer
if err := tmpl.Execute(&out, templateValues); err != nil { if err := tmpl.Execute(&out, templateValues); err != nil {
return "", err return "", err

@ -3,12 +3,32 @@
package main package main
import ( import (
"fmt"
"os" "os"
"testing" "testing"
) )
// The test environment is long running process shared between tests, initialized
// by a `TestMain` function depending on how the test is involved and which tests
// are a part of the build.
var testEnv *testEnvKubeManager
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
// Ensure tests print consistent timestamps regardless of timezone // Ensure tests print consistent timestamps regardless of timezone
os.Setenv("TZ", "UTC") os.Setenv("TZ", "UTC")
os.Exit(m.Run())
// Creating the test env manager sets rootArgs client flags
km, err := NewTestEnvKubeManager(TestEnvClusterMode)
if err != nil {
panic(fmt.Errorf("error creating kube manager: '%w'", err))
}
testEnv = km
rootArgs.kubeconfig = testEnv.kubeConfigPath
// Run tests
code := m.Run()
km.Stop()
os.Exit(code)
} }

@ -1,2 +1,2 @@
► deleting helmreleases thrfg in thrfg namespace ► deleting helmreleases thrfg in {{ .ns }} namespace
✔ helmreleases deleted ✔ helmreleases deleted

@ -1,9 +1,9 @@
► annotating GitRepository thrfg in thrfg namespace ► annotating GitRepository thrfg in {{ .ns }} namespace
✔ GitRepository annotated ✔ GitRepository annotated
◎ waiting for GitRepository reconciliation ◎ waiting for GitRepository reconciliation
✔ GitRepository reconciliation completed ✔ GitRepository reconciliation completed
✔ fetched revision 6.0.0/627d5c4bb67b77185f37e31d734b085019ff2951 ✔ fetched revision 6.0.0/627d5c4bb67b77185f37e31d734b085019ff2951
► annotating HelmRelease thrfg in thrfg namespace ► annotating HelmRelease thrfg in {{ .ns }} namespace
✔ HelmRelease annotated ✔ HelmRelease annotated
◎ waiting for HelmRelease reconciliation ◎ waiting for HelmRelease reconciliation
✔ HelmRelease reconciliation completed ✔ HelmRelease reconciliation completed

@ -1,4 +1,4 @@
► resuming helmreleases thrfg in thrfg namespace ► resuming helmreleases thrfg in {{ .ns }} namespace
✔ helmreleases resumed ✔ helmreleases resumed
◎ waiting for HelmRelease reconciliation ◎ waiting for HelmRelease reconciliation
✔ HelmRelease reconciliation completed ✔ HelmRelease reconciliation completed

@ -1,2 +1,2 @@
► suspending helmreleases thrfg in thrfg namespace ► suspending helmreleases thrfg in {{ .ns }} namespace
✔ helmreleases suspended ✔ helmreleases suspended

@ -1,2 +1,2 @@
► deleting kustomizations tkfg in tkfg namespace ► deleting kustomizations tkfg in {{ .ns }} namespace
✔ kustomizations deleted ✔ kustomizations deleted

@ -1,9 +1,9 @@
► annotating GitRepository tkfg in tkfg namespace ► annotating GitRepository tkfg in {{ .ns }} namespace
✔ GitRepository annotated ✔ GitRepository annotated
◎ waiting for GitRepository reconciliation ◎ waiting for GitRepository reconciliation
✔ GitRepository reconciliation completed ✔ GitRepository reconciliation completed
✔ fetched revision 6.0.0/627d5c4bb67b77185f37e31d734b085019ff2951 ✔ fetched revision 6.0.0/627d5c4bb67b77185f37e31d734b085019ff2951
► annotating Kustomization tkfg in tkfg namespace ► annotating Kustomization tkfg in {{ .ns }} namespace
✔ Kustomization annotated ✔ Kustomization annotated
◎ waiting for Kustomization reconciliation ◎ waiting for Kustomization reconciliation
✔ Kustomization reconciliation completed ✔ Kustomization reconciliation completed

@ -1,4 +1,4 @@
► resuming kustomizations tkfg in tkfg namespace ► resuming kustomizations tkfg in {{ .ns }} namespace
✔ kustomizations resumed ✔ kustomizations resumed
◎ waiting for Kustomization reconciliation ◎ waiting for Kustomization reconciliation
✔ Kustomization reconciliation completed ✔ Kustomization reconciliation completed

@ -1,2 +1,2 @@
► suspending kustomizations tkfg in tkfg namespace ► suspending kustomizations tkfg in {{ .ns }} namespace
✔ kustomizations suspended ✔ kustomizations suspended

@ -1,16 +1,16 @@
Object: deployment/podinfo Object: deployment/podinfo
Namespace: podinfo Namespace: {{ .ns }}
Status: Managed by Flux Status: Managed by Flux
--- ---
HelmRelease: podinfo HelmRelease: podinfo
Namespace: podinfo Namespace: {{ .ns }}
Revision: 6.0.0 Revision: 6.0.0
Status: Last reconciled at 2021-07-16 15:42:20 +0000 UTC Status: Last reconciled at 2021-07-16 15:42:20 +0000 UTC
Message: Release reconciliation succeeded Message: Release reconciliation succeeded
--- ---
HelmChart: podinfo-podinfo HelmChart: podinfo-podinfo
Namespace: flux-system Namespace: {{ .fluxns }}
Chart: podinfo Chart: podinfo
Version: 6.0.0 Version: 6.0.0
Revision: 6.0.0 Revision: 6.0.0
@ -18,7 +18,7 @@ Status: Last reconciled at 2021-07-16 15:32:09 +0000 UTC
Message: Fetched revision: 6.0.0 Message: Fetched revision: 6.0.0
--- ---
HelmRepository: podinfo HelmRepository: podinfo
Namespace: flux-system Namespace: {{ .fluxns }}
URL: https://stefanprodan.github.io/podinfo URL: https://stefanprodan.github.io/podinfo
Revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56 Revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56
Status: Last reconciled at 2021-07-11 00:25:46 +0000 UTC Status: Last reconciled at 2021-07-11 00:25:46 +0000 UTC

@ -2,12 +2,12 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: flux-system name: {{ .fluxns }}
--- ---
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: podinfo name: {{ .ns }}
--- ---
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
@ -15,11 +15,10 @@ metadata:
labels: labels:
app.kubernetes.io/name: podinfo app.kubernetes.io/name: podinfo
app.kubernetes.io/managed-by: Helm app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: podinfo
helm.toolkit.fluxcd.io/name: podinfo helm.toolkit.fluxcd.io/name: podinfo
helm.toolkit.fluxcd.io/namespace: podinfo helm.toolkit.fluxcd.io/namespace: {{ .ns }}
name: podinfo name: podinfo
namespace: podinfo namespace: {{ .ns }}
spec: spec:
replicas: 1 replicas: 1
selector: selector:
@ -40,9 +39,9 @@ kind: HelmRelease
metadata: metadata:
labels: labels:
kustomize.toolkit.fluxcd.io/name: infrastructure kustomize.toolkit.fluxcd.io/name: infrastructure
kustomize.toolkit.fluxcd.io/namespace: flux-system kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: podinfo name: podinfo
namespace: podinfo namespace: {{ .ns }}
spec: spec:
chart: chart:
spec: spec:
@ -50,7 +49,7 @@ spec:
sourceRef: sourceRef:
kind: HelmRepository kind: HelmRepository
name: podinfo name: podinfo
namespace: flux-system namespace: {{ .fluxns }}
interval: 5m interval: 5m
status: status:
conditions: conditions:
@ -59,7 +58,7 @@ status:
reason: ReconciliationSucceeded reason: ReconciliationSucceeded
status: "True" status: "True"
type: Ready type: Ready
helmChart: flux-system/podinfo-podinfo helmChart: {{ .fluxns }}/podinfo-podinfo
lastAppliedRevision: 6.0.0 lastAppliedRevision: 6.0.0
lastAttemptedRevision: 6.0.0 lastAttemptedRevision: 6.0.0
lastAttemptedValuesChecksum: c31db75d05b7515eba2eef47bd71038c74b2e531 lastAttemptedValuesChecksum: c31db75d05b7515eba2eef47bd71038c74b2e531
@ -68,7 +67,7 @@ apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: HelmChart kind: HelmChart
metadata: metadata:
name: podinfo-podinfo name: podinfo-podinfo
namespace: flux-system namespace: {{ .fluxns }}
spec: spec:
chart: podinfo chart: podinfo
sourceRef: sourceRef:
@ -98,7 +97,7 @@ metadata:
kustomize.toolkit.fluxcd.io/name: infrastructure kustomize.toolkit.fluxcd.io/name: infrastructure
kustomize.toolkit.fluxcd.io/namespace: flux-system kustomize.toolkit.fluxcd.io/namespace: flux-system
name: podinfo name: podinfo
namespace: flux-system namespace: {{ .fluxns }}
spec: spec:
interval: 5m interval: 5m
timeout: 1m0s timeout: 1m0s
@ -121,7 +120,7 @@ apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
kind: Kustomization kind: Kustomization
metadata: metadata:
name: infrastructure name: infrastructure
namespace: flux-system namespace: {{ .fluxns }}
spec: spec:
path: ./infrastructure/ path: ./infrastructure/
sourceRef: sourceRef:
@ -143,9 +142,9 @@ kind: GitRepository
metadata: metadata:
labels: labels:
kustomize.toolkit.fluxcd.io/name: flux-system kustomize.toolkit.fluxcd.io/name: flux-system
kustomize.toolkit.fluxcd.io/namespace: flux-system kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: flux-system name: flux-system
namespace: flux-system namespace: {{ .fluxns }}
spec: spec:
gitImplementation: go-git gitImplementation: go-git
ref: ref:

@ -1,17 +1,17 @@
Object: HelmRelease/podinfo Object: HelmRelease/podinfo
Namespace: podinfo Namespace: {{ .ns }}
Status: Managed by Flux Status: Managed by Flux
--- ---
Kustomization: infrastructure Kustomization: infrastructure
Namespace: flux-system Namespace: {{ .fluxns }}
Path: ./infrastructure Path: ./infrastructure
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
Status: Last reconciled at 2021-08-01 04:52:56 +0000 UTC Status: Last reconciled at 2021-08-01 04:52:56 +0000 UTC
Message: Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f Message: Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f
--- ---
GitRepository: flux-system GitRepository: flux-system
Namespace: flux-system Namespace: {{ .fluxns }}
URL: ssh://git@github.com/example/repo URL: ssh://git@github.com/example/repo
Branch: main Branch: main
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f Revision: main/696f056df216eea4f9401adbee0ff744d4df390f

@ -2,21 +2,21 @@
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: flux-system name: {{ .fluxns }}
--- ---
apiVersion: v1 apiVersion: v1
kind: Namespace kind: Namespace
metadata: metadata:
name: podinfo name: {{ .ns }}
--- ---
apiVersion: helm.toolkit.fluxcd.io/v2beta1 apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease kind: HelmRelease
metadata: metadata:
labels: labels:
kustomize.toolkit.fluxcd.io/name: infrastructure kustomize.toolkit.fluxcd.io/name: infrastructure
kustomize.toolkit.fluxcd.io/namespace: flux-system kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: podinfo name: podinfo
namespace: podinfo namespace: {{ .ns }}
spec: spec:
chart: chart:
spec: spec:
@ -24,7 +24,7 @@ spec:
sourceRef: sourceRef:
kind: HelmRepository kind: HelmRepository
name: podinfo name: podinfo
namespace: flux-system namespace: {{ .fluxns }}
interval: 5m interval: 5m
status: status:
conditions: conditions:
@ -33,7 +33,7 @@ status:
reason: ReconciliationSucceeded reason: ReconciliationSucceeded
status: "True" status: "True"
type: Ready type: Ready
helmChart: flux-system/podinfo-podinfo helmChart: {{ .fluxns }}/podinfo-podinfo
lastAppliedRevision: 6.0.0 lastAppliedRevision: 6.0.0
lastAttemptedRevision: 6.0.0 lastAttemptedRevision: 6.0.0
lastAttemptedValuesChecksum: c31db75d05b7515eba2eef47bd71038c74b2e531 lastAttemptedValuesChecksum: c31db75d05b7515eba2eef47bd71038c74b2e531
@ -42,7 +42,7 @@ apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
kind: Kustomization kind: Kustomization
metadata: metadata:
name: infrastructure name: infrastructure
namespace: flux-system namespace: {{ .fluxns }}
spec: spec:
path: ./infrastructure path: ./infrastructure
sourceRef: sourceRef:
@ -65,9 +65,9 @@ kind: GitRepository
metadata: metadata:
labels: labels:
kustomize.toolkit.fluxcd.io/name: flux-system kustomize.toolkit.fluxcd.io/name: flux-system
kustomize.toolkit.fluxcd.io/namespace: flux-system kustomize.toolkit.fluxcd.io/namespace: {{ .fluxns }}
name: flux-system name: flux-system
namespace: flux-system namespace: {{ .fluxns }}
spec: spec:
gitImplementation: go-git gitImplementation: go-git
ref: ref:

@ -8,29 +8,44 @@ import (
func TestTraceNoArgs(t *testing.T) { func TestTraceNoArgs(t *testing.T) {
cmd := cmdTestCase{ cmd := cmdTestCase{
args: "trace", args: "trace",
testClusterMode: TestEnvClusterMode, assert: assertError("object name is required"),
assert: assertError("object name is required"),
} }
cmd.runTestCmd(t) cmd.runTestCmd(t)
} }
func TestTraceDeployment(t *testing.T) { func TestTrace(t *testing.T) {
cmd := cmdTestCase{ cases := []struct {
args: "trace podinfo -n podinfo --kind deployment --api-version=apps/v1", name string
testClusterMode: TestEnvClusterMode, args string
assert: assertGoldenFile("testdata/trace/deployment.golden"), objectFile string
objectFile: "testdata/trace/deployment.yaml", goldenFile string
}{
{
"Deployment",
"trace podinfo --kind deployment --api-version=apps/v1",
"testdata/trace/deployment.yaml",
"testdata/trace/deployment.golden",
},
{
"HelmRelease",
"trace podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1",
"testdata/trace/helmrelease.yaml",
"testdata/trace/helmrelease.golden",
},
} }
cmd.runTestCmd(t) for _, tc := range cases {
} t.Run(tc.name, func(t *testing.T) {
tmpl := map[string]string{
func TestTraceHelmRelease(t *testing.T) { "ns": allocateNamespace("podinfo"),
cmd := cmdTestCase{ "fluxns": allocateNamespace("flux-system"),
args: "trace podinfo -n podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1", }
testClusterMode: TestEnvClusterMode, testEnv.CreateObjectFile(tc.objectFile, tmpl, t)
assert: assertGoldenFile("testdata/trace/helmrelease.golden"), cmd := cmdTestCase{
objectFile: "testdata/trace/helmrelease.yaml", args: tc.args + " -n=" + tmpl["ns"],
assert: assertGoldenTemplateFile(tc.goldenFile, tmpl),
}
cmd.runTestCmd(t)
})
} }
cmd.runTestCmd(t)
} }

@ -8,9 +8,8 @@ import (
func TestVersion(t *testing.T) { func TestVersion(t *testing.T) {
cmd := cmdTestCase{ cmd := cmdTestCase{
args: "--version", args: "--version",
testClusterMode: TestEnvClusterMode, assert: assertGoldenValue("flux version 0.0.0-dev.0\n"),
assert: assertGoldenValue("flux version 0.0.0-dev.0\n"),
} }
cmd.runTestCmd(t) cmd.runTestCmd(t)
} }

Loading…
Cancel
Save