mirror of
https://github.com/fluxcd/flux2.git
synced 2025-11-02 18:58:33 +08:00
Add tests for flux trace command
Add tests for flux trace command that fake out the kubernetes client, load objects from a yaml file and create them in the client, and assert on the output of the trace command to an expected golden file. This is a follow up from the suggestions in PR https://github.com/fluxcd/flux2/pull/1626 which suggested that additional testing would be helpful. This test approach is modeled after the helm command tests. This required some changes to the kubernetes client setup to make it possible to use a fake. If we agree this pattern makes sense, it can be applied to other commands. Signed-off-by: Allen Porter <allen@thebends.org>
This commit is contained in:
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
"github.com/fluxcd/flux2/pkg/manifestgen/install"
|
"github.com/fluxcd/flux2/pkg/manifestgen/install"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -126,6 +127,18 @@ func NewRootFlags() rootFlags {
|
|||||||
return rf
|
return rf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type rootContext struct {
|
||||||
|
kubeManager utils.KubeManager
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootCtx = NewRootContext()
|
||||||
|
|
||||||
|
func NewRootContext() rootContext {
|
||||||
|
var rc rootContext
|
||||||
|
rc.kubeManager = utils.DefaultKubeManager()
|
||||||
|
return rc
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
configureKubeconfig()
|
configureKubeconfig()
|
||||||
|
|||||||
26
cmd/flux/testdata/trace/deployment.txt
vendored
Normal file
26
cmd/flux/testdata/trace/deployment.txt
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
Object: deployment/podinfo
|
||||||
|
Namespace: podinfo
|
||||||
|
Status: Managed by Flux
|
||||||
|
---
|
||||||
|
HelmRelease: podinfo
|
||||||
|
Namespace: podinfo
|
||||||
|
Revision: 6.0.0
|
||||||
|
Status: Last reconciled at 2021-07-16 15:42:20 +0000 UTC
|
||||||
|
Message: Release reconciliation succeeded
|
||||||
|
---
|
||||||
|
HelmChart: podinfo-podinfo
|
||||||
|
Namespace: flux-system
|
||||||
|
Chart: podinfo
|
||||||
|
Version: 6.0.0
|
||||||
|
Revision: 6.0.0
|
||||||
|
Status: Last reconciled at 2021-07-16 15:32:09 +0000 UTC
|
||||||
|
Message: Fetched revision: 6.0.0
|
||||||
|
---
|
||||||
|
HelmRepository: podinfo
|
||||||
|
Namespace: flux-system
|
||||||
|
URL: https://stefanprodan.github.io/podinfo
|
||||||
|
Revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56
|
||||||
|
Status: Last reconciled at 2021-07-11 00:25:46 +0000 UTC
|
||||||
|
Message: Fetched revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56
|
||||||
|
|
||||||
129
cmd/flux/testdata/trace/deployment.yaml
vendored
Normal file
129
cmd/flux/testdata/trace/deployment.yaml
vendored
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/managed-by: Helm
|
||||||
|
app.kubernetes.io/name: podinfo
|
||||||
|
helm.toolkit.fluxcd.io/name: podinfo
|
||||||
|
helm.toolkit.fluxcd.io/namespace: podinfo
|
||||||
|
name: podinfo
|
||||||
|
namespace: podinfo
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: podinfo
|
||||||
|
spec:
|
||||||
|
---
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2beta1
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: infrastructure
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: podinfo
|
||||||
|
namespace: podinfo
|
||||||
|
spec:
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: podinfo
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: podinfo
|
||||||
|
namespace: flux-system
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-16T15:42:20Z"
|
||||||
|
message: Release reconciliation succeeded
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
helmChart: flux-system/podinfo-podinfo
|
||||||
|
lastAppliedRevision: 6.0.0
|
||||||
|
lastAttemptedRevision: 6.0.0
|
||||||
|
lastAttemptedValuesChecksum: c31db75d05b7515eba2eef47bd71038c74b2e531
|
||||||
|
---
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: HelmChart
|
||||||
|
metadata:
|
||||||
|
name: podinfo-podinfo
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
chart: podinfo
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: podinfo
|
||||||
|
version: 6.0.0
|
||||||
|
status:
|
||||||
|
artifact:
|
||||||
|
checksum: cf13ba96773d9a879cd052c86e73199b3f96c854
|
||||||
|
lastUpdateTime: "2021-08-01T04:42:55Z"
|
||||||
|
revision: 6.0.0
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-16T15:32:09Z"
|
||||||
|
message: 'Fetched revision: 6.0.0'
|
||||||
|
reason: ChartPullSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: HelmRepository
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: infrastructure
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: podinfo
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
interval: 5m
|
||||||
|
timeout: 1m0s
|
||||||
|
url: https://stefanprodan.github.io/podinfo
|
||||||
|
status:
|
||||||
|
artifact:
|
||||||
|
checksum: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56
|
||||||
|
lastUpdateTime: "2021-07-11T00:25:46Z"
|
||||||
|
revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-11T00:25:46Z"
|
||||||
|
message: 'Fetched revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56'
|
||||||
|
reason: IndexationSucceed
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
---
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: infrastructure
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
path: ./infrastructure/
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: flux-system
|
||||||
|
validation: client
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-08-01T04:52:56Z"
|
||||||
|
message: 'Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f'
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
---
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: GitRepository
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: flux-system
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: flux-system
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
gitImplementation: go-git
|
||||||
|
ref:
|
||||||
|
branch: main
|
||||||
|
secretRef:
|
||||||
|
name: flux-system
|
||||||
|
|
||||||
19
cmd/flux/testdata/trace/helmrelease-missing-git-ref.txt
vendored
Normal file
19
cmd/flux/testdata/trace/helmrelease-missing-git-ref.txt
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
|
||||||
|
Object: HelmRelease/podinfo
|
||||||
|
Namespace: podinfo
|
||||||
|
Status: Managed by Flux
|
||||||
|
---
|
||||||
|
Kustomization: infrastructure
|
||||||
|
Namespace: flux-system
|
||||||
|
Path: ./infrastructure
|
||||||
|
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
Status: Last reconciled at 2021-08-01 04:52:56 +0000 UTC
|
||||||
|
Message: Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
---
|
||||||
|
GitRepository: flux-system
|
||||||
|
Namespace: flux-system
|
||||||
|
URL: ssh://git@github.com/example/repo
|
||||||
|
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
Status: Last reconciled at 2021-07-20 00:48:16 +0000 UTC
|
||||||
|
Message: Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
|
||||||
73
cmd/flux/testdata/trace/helmrelease-missing-git-ref.yaml
vendored
Normal file
73
cmd/flux/testdata/trace/helmrelease-missing-git-ref.yaml
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2beta1
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: infrastructure
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: podinfo
|
||||||
|
namespace: podinfo
|
||||||
|
spec:
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: podinfo
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: podinfo
|
||||||
|
namespace: flux-system
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-16T15:42:20Z"
|
||||||
|
message: Release reconciliation succeeded
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
helmChart: flux-system/podinfo-podinfo
|
||||||
|
lastAppliedRevision: 6.0.0
|
||||||
|
lastAttemptedRevision: 6.0.0
|
||||||
|
lastAttemptedValuesChecksum: c31db75d05b7515eba2eef47bd71038c74b2e531
|
||||||
|
---
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: infrastructure
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
path: ./infrastructure
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: flux-system
|
||||||
|
validation: client
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-08-01T04:52:56Z"
|
||||||
|
message: 'Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f'
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
lastAppliedRevision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
---
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: GitRepository
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: flux-system
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: flux-system
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
gitImplementation: go-git
|
||||||
|
secretRef:
|
||||||
|
name: flux-system
|
||||||
|
url: ssh://git@github.com/example/repo
|
||||||
|
status:
|
||||||
|
artifact:
|
||||||
|
lastUpdateTime: "2021-08-01T04:28:42Z"
|
||||||
|
revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-20T00:48:16Z"
|
||||||
|
message: 'Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f'
|
||||||
|
reason: GitOperationSucceed
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
|
||||||
20
cmd/flux/testdata/trace/helmrelease.txt
vendored
Normal file
20
cmd/flux/testdata/trace/helmrelease.txt
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
Object: HelmRelease/podinfo
|
||||||
|
Namespace: podinfo
|
||||||
|
Status: Managed by Flux
|
||||||
|
---
|
||||||
|
Kustomization: infrastructure
|
||||||
|
Namespace: flux-system
|
||||||
|
Path: ./infrastructure
|
||||||
|
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
Status: Last reconciled at 2021-08-01 04:52:56 +0000 UTC
|
||||||
|
Message: Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
---
|
||||||
|
GitRepository: flux-system
|
||||||
|
Namespace: flux-system
|
||||||
|
URL: ssh://git@github.com/example/repo
|
||||||
|
Branch: main
|
||||||
|
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
Status: Last reconciled at 2021-07-20 00:48:16 +0000 UTC
|
||||||
|
Message: Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
|
||||||
75
cmd/flux/testdata/trace/helmrelease.yaml
vendored
Normal file
75
cmd/flux/testdata/trace/helmrelease.yaml
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2beta1
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: infrastructure
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: podinfo
|
||||||
|
namespace: podinfo
|
||||||
|
spec:
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: podinfo
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: podinfo
|
||||||
|
namespace: flux-system
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-16T15:42:20Z"
|
||||||
|
message: Release reconciliation succeeded
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
helmChart: flux-system/podinfo-podinfo
|
||||||
|
lastAppliedRevision: 6.0.0
|
||||||
|
lastAttemptedRevision: 6.0.0
|
||||||
|
lastAttemptedValuesChecksum: c31db75d05b7515eba2eef47bd71038c74b2e531
|
||||||
|
---
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: infrastructure
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
path: ./infrastructure
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: flux-system
|
||||||
|
validation: client
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-08-01T04:52:56Z"
|
||||||
|
message: 'Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f'
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
lastAppliedRevision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
---
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: GitRepository
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: flux-system
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: flux-system
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
gitImplementation: go-git
|
||||||
|
ref:
|
||||||
|
branch: main
|
||||||
|
secretRef:
|
||||||
|
name: flux-system
|
||||||
|
url: ssh://git@github.com/example/repo
|
||||||
|
status:
|
||||||
|
artifact:
|
||||||
|
lastUpdateTime: "2021-08-01T04:28:42Z"
|
||||||
|
revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-20T00:48:16Z"
|
||||||
|
message: 'Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f'
|
||||||
|
reason: GitOperationSucceed
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
|
||||||
1
cmd/flux/testdata/trace/no-args.txt
vendored
Normal file
1
cmd/flux/testdata/trace/no-args.txt
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
object name is required
|
||||||
@ -89,7 +89,7 @@ func traceCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
kubeClient, err := rootCtx.kubeManager.NewClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -121,7 +121,7 @@ func traceCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println(report)
|
rootCmd.Print(report)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ func traceCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println(report)
|
rootCmd.Print(report)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
180
cmd/flux/trace_test.go
Normal file
180
cmd/flux/trace_test.go
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
shellwords "github.com/mattn/go-shellwords"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Ensure tests print consistent timestamps regardless of timezone
|
||||||
|
os.Setenv("TZ", "UTC")
|
||||||
|
}
|
||||||
|
|
||||||
|
func readYamlObjects(objectFile string) ([]client.Object, error) {
|
||||||
|
obj, err := ioutil.ReadFile(objectFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
objects := []client.Object{}
|
||||||
|
reader := k8syaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(obj)))
|
||||||
|
for {
|
||||||
|
doc, err := reader.Read()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unstructuredObj := &unstructured.Unstructured{}
|
||||||
|
decoder := k8syaml.NewYAMLOrJSONDecoder(bytes.NewBuffer(doc), len(doc))
|
||||||
|
err = decoder.Decode(unstructuredObj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
objects = append(objects, unstructuredObj)
|
||||||
|
}
|
||||||
|
return objects, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A KubeManager that can create objects that are subject to a test.
|
||||||
|
type fakeKubeManager struct {
|
||||||
|
fakeClient client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *fakeKubeManager) NewClient(kubeconfig string, kubecontext string) (client.Client, error) {
|
||||||
|
return m.fakeClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *fakeKubeManager) CreateObjects(clientObjects []client.Object) error {
|
||||||
|
for _, obj := range clientObjects {
|
||||||
|
err := m.fakeClient.Create(context.Background(), obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFakeKubeManager() *fakeKubeManager {
|
||||||
|
c := fakeclient.NewClientBuilder().WithScheme(utils.NewScheme()).Build()
|
||||||
|
return &fakeKubeManager{
|
||||||
|
fakeClient: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the command and return the captured output.
|
||||||
|
func executeCommand(cmd string) (string, error) {
|
||||||
|
args, err := shellwords.Parse(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
rootCmd.SetOut(buf)
|
||||||
|
rootCmd.SetErr(buf)
|
||||||
|
rootCmd.SetArgs(args)
|
||||||
|
|
||||||
|
_, err = rootCmd.ExecuteC()
|
||||||
|
result := buf.String()
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Structure used for each test to load objects into kubernetes, run
|
||||||
|
// commands and assert on the expected output.
|
||||||
|
type cmdTestCase struct {
|
||||||
|
// The command line arguments to test.
|
||||||
|
args string
|
||||||
|
// When true, the test expects the command to fail.
|
||||||
|
wantError bool
|
||||||
|
// Filename that contains the expected test output.
|
||||||
|
goldenFile string
|
||||||
|
// Filename that contains yaml objects to load into Kubernetes
|
||||||
|
objectFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *cmdTestCase) runTestCmd(t *testing.T) {
|
||||||
|
km := NewFakeKubeManager()
|
||||||
|
rootCtx.kubeManager = km
|
||||||
|
|
||||||
|
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, err := executeCommand(cmd.args)
|
||||||
|
if (err != nil) != cmd.wantError {
|
||||||
|
t.Fatalf("Expected error='%v', Got: %v", cmd.wantError, err)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
actual = err.Error()
|
||||||
|
}
|
||||||
|
contents, err := ioutil.ReadFile(cmd.goldenFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error reading golden file: '%s'", err)
|
||||||
|
}
|
||||||
|
expected := strings.TrimSuffix(string(contents), "\n")
|
||||||
|
diff := cmp.Diff(expected, actual)
|
||||||
|
if diff != "" {
|
||||||
|
t.Errorf("Mismatch from '%s' (-want +got):\n%s", cmd.goldenFile, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTraceNoArgs(t *testing.T) {
|
||||||
|
cmd := cmdTestCase{
|
||||||
|
args: "trace",
|
||||||
|
wantError: true,
|
||||||
|
goldenFile: "testdata/trace/no-args.txt",
|
||||||
|
}
|
||||||
|
cmd.runTestCmd(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTraceDeployment(t *testing.T) {
|
||||||
|
cmd := cmdTestCase{
|
||||||
|
args: "trace podinfo -n podinfo --kind deployment --api-version=apps/v1",
|
||||||
|
wantError: false,
|
||||||
|
goldenFile: "testdata/trace/deployment.txt",
|
||||||
|
objectFile: "testdata/trace/deployment.yaml",
|
||||||
|
}
|
||||||
|
cmd.runTestCmd(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTraceHelmRelease(t *testing.T) {
|
||||||
|
cmd := cmdTestCase{
|
||||||
|
args: "trace podinfo -n podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1",
|
||||||
|
wantError: false,
|
||||||
|
goldenFile: "testdata/trace/helmrelease.txt",
|
||||||
|
objectFile: "testdata/trace/helmrelease.yaml",
|
||||||
|
}
|
||||||
|
cmd.runTestCmd(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTraceHelmReleaseMissingGitRef(t *testing.T) {
|
||||||
|
cmd := cmdTestCase{
|
||||||
|
args: "trace podinfo -n podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1",
|
||||||
|
wantError: false,
|
||||||
|
goldenFile: "testdata/trace/helmrelease-missing-git-ref.txt",
|
||||||
|
objectFile: "testdata/trace/helmrelease-missing-git-ref.yaml",
|
||||||
|
}
|
||||||
|
cmd.runTestCmd(t)
|
||||||
|
}
|
||||||
2
go.mod
2
go.mod
@ -18,8 +18,10 @@ require (
|
|||||||
github.com/fluxcd/pkg/version v0.0.1
|
github.com/fluxcd/pkg/version v0.0.1
|
||||||
github.com/fluxcd/source-controller/api v0.15.3
|
github.com/fluxcd/source-controller/api v0.15.3
|
||||||
github.com/go-git/go-git/v5 v5.4.2
|
github.com/go-git/go-git/v5 v5.4.2
|
||||||
|
github.com/google/go-cmp v0.5.5
|
||||||
github.com/google/go-containerregistry v0.2.0
|
github.com/google/go-containerregistry v0.2.0
|
||||||
github.com/manifoldco/promptui v0.7.0
|
github.com/manifoldco/promptui v0.7.0
|
||||||
|
github.com/mattn/go-shellwords v1.0.12
|
||||||
github.com/olekukonko/tablewriter v0.0.4
|
github.com/olekukonko/tablewriter v0.0.4
|
||||||
github.com/spf13/cobra v1.1.3
|
github.com/spf13/cobra v1.1.3
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
|
|||||||
2
go.sum
2
go.sum
@ -537,6 +537,8 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
|
|||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||||
|
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
|
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
|
||||||
|
|||||||
@ -131,12 +131,39 @@ func KubeConfig(kubeConfigPath string, kubeContext string) (*rest.Config, error)
|
|||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func KubeClient(kubeConfigPath string, kubeContext string) (client.Client, error) {
|
// KubeManger creates a Kubernetes client.Client. This interface exists to
|
||||||
|
// facilitate unit testing and provide a fake client.
|
||||||
|
type KubeManager interface {
|
||||||
|
NewClient(string, string) (client.Client, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultKubeManager struct{}
|
||||||
|
|
||||||
|
func DefaultKubeManager() KubeManager {
|
||||||
|
var manager defaultKubeManager
|
||||||
|
return manager
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m defaultKubeManager) NewClient(kubeConfigPath string, kubeContext string) (client.Client, error) {
|
||||||
cfg, err := KubeConfig(kubeConfigPath, kubeContext)
|
cfg, err := KubeConfig(kubeConfigPath, kubeContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("kubernetes client initialization failed: %w", err)
|
return nil, fmt.Errorf("kubernetes client initialization failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scheme := NewScheme()
|
||||||
|
kubeClient, err := client.New(cfg, client.Options{
|
||||||
|
Scheme: scheme,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("kubernetes client initialization failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return kubeClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the Scheme, methods for serializing and deserializing API objects
|
||||||
|
// which can be shared by tests.
|
||||||
|
func NewScheme() *apiruntime.Scheme {
|
||||||
scheme := apiruntime.NewScheme()
|
scheme := apiruntime.NewScheme()
|
||||||
_ = apiextensionsv1.AddToScheme(scheme)
|
_ = apiextensionsv1.AddToScheme(scheme)
|
||||||
_ = corev1.AddToScheme(scheme)
|
_ = corev1.AddToScheme(scheme)
|
||||||
@ -149,15 +176,13 @@ func KubeClient(kubeConfigPath string, kubeContext string) (client.Client, error
|
|||||||
_ = notificationv1.AddToScheme(scheme)
|
_ = notificationv1.AddToScheme(scheme)
|
||||||
_ = imagereflectv1.AddToScheme(scheme)
|
_ = imagereflectv1.AddToScheme(scheme)
|
||||||
_ = imageautov1.AddToScheme(scheme)
|
_ = imageautov1.AddToScheme(scheme)
|
||||||
|
return scheme
|
||||||
kubeClient, err := client.New(cfg, client.Options{
|
|
||||||
Scheme: scheme,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("kubernetes client initialization failed: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return kubeClient, nil
|
func KubeClient(kubeConfigPath string, kubeContext string) (client.Client, error) {
|
||||||
|
m := DefaultKubeManager()
|
||||||
|
kubeClient, err := m.NewClient(kubeConfigPath, kubeContext)
|
||||||
|
return kubeClient, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SplitKubeConfigPath splits the given KUBECONFIG path based on the runtime OS
|
// SplitKubeConfigPath splits the given KUBECONFIG path based on the runtime OS
|
||||||
|
|||||||
Reference in New Issue
Block a user