implement testEnv for e2e tests
Signed-off-by: Chanwit Kaewkasi <chanwit@gmail.com>
This commit is contained in:
54
cmd/flux/install_test.go
Normal file
54
cmd/flux/install_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
// +build e2e
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestInstallNoArgs(t *testing.T) {
|
||||
cmd := cmdTestCase{
|
||||
args: "install",
|
||||
wantError: false,
|
||||
testClusterMode: ExistingClusterMode,
|
||||
goldenFile: "testdata/install/install_no_args.golden",
|
||||
}
|
||||
cmd.runTestCmd(t)
|
||||
|
||||
testUninstallSilent(t)
|
||||
time.Sleep(30 * time.Second)
|
||||
}
|
||||
|
||||
func TestInstallExtraComponents(t *testing.T) {
|
||||
cmd := cmdTestCase{
|
||||
args: "install --components-extra=image-reflector-controller,image-automation-controller",
|
||||
wantError: false,
|
||||
testClusterMode: ExistingClusterMode,
|
||||
goldenFile: "testdata/install/install_extra_components.golden",
|
||||
}
|
||||
cmd.runTestCmd(t)
|
||||
|
||||
testUninstallSilentForExtraComponents(t)
|
||||
time.Sleep(30 * time.Second)
|
||||
}
|
||||
|
||||
func testUninstallSilent(t *testing.T) {
|
||||
cmd := cmdTestCase{
|
||||
args: "uninstall -s",
|
||||
wantError: false,
|
||||
testClusterMode: ExistingClusterMode,
|
||||
goldenFile: "testdata/uninstall/uninstall.golden",
|
||||
}
|
||||
cmd.runTestCmd(t)
|
||||
}
|
||||
|
||||
func testUninstallSilentForExtraComponents(t *testing.T) {
|
||||
cmd := cmdTestCase{
|
||||
args: "uninstall -s",
|
||||
wantError: false,
|
||||
testClusterMode: ExistingClusterMode,
|
||||
goldenFile: "testdata/uninstall/uninstall_extra_components.golden",
|
||||
}
|
||||
cmd.runTestCmd(t)
|
||||
}
|
||||
@@ -4,17 +4,23 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/mattn/go-shellwords"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@@ -49,17 +55,18 @@ func readYamlObjects(objectFile string) ([]client.Object, error) {
|
||||
}
|
||||
|
||||
// A KubeManager that can create objects that are subject to a test.
|
||||
type fakeKubeManager struct {
|
||||
fakeClient client.WithWatch
|
||||
type testEnvKubeManager struct {
|
||||
client client.WithWatch
|
||||
testEnv *envtest.Environment
|
||||
}
|
||||
|
||||
func (m *fakeKubeManager) NewClient(kubeconfig string, kubecontext string) (client.WithWatch, error) {
|
||||
return m.fakeClient, nil
|
||||
func (m *testEnvKubeManager) NewClient(kubeconfig string, kubecontext string) (client.WithWatch, error) {
|
||||
return m.client, nil
|
||||
}
|
||||
|
||||
func (m *fakeKubeManager) CreateObjects(clientObjects []client.Object) error {
|
||||
func (m *testEnvKubeManager) CreateObjects(clientObjects []client.Object) error {
|
||||
for _, obj := range clientObjects {
|
||||
err := m.fakeClient.Create(context.Background(), obj)
|
||||
err := m.client.Create(context.Background(), obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -67,32 +74,92 @@ func (m *fakeKubeManager) CreateObjects(clientObjects []client.Object) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewFakeKubeManager() *fakeKubeManager {
|
||||
c := fakeclient.NewClientBuilder().WithScheme(utils.NewScheme()).Build()
|
||||
return &fakeKubeManager{
|
||||
fakeClient: c,
|
||||
func (m *testEnvKubeManager) Stop() error {
|
||||
if m.testEnv == nil {
|
||||
return fmt.Errorf("do nothing because testEnv is nil")
|
||||
}
|
||||
return m.testEnv.Stop()
|
||||
}
|
||||
|
||||
// Run the command and return the captured output.
|
||||
func executeCommand(cmd string) (string, error) {
|
||||
args, err := shellwords.Parse(cmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
func NewTestEnvKubeManager(testClusterMode TestClusterMode) (*testEnvKubeManager, error) {
|
||||
switch testClusterMode {
|
||||
case FakeClusterMode:
|
||||
c := fakeclient.NewClientBuilder().WithScheme(utils.NewScheme()).Build()
|
||||
return &testEnvKubeManager{
|
||||
client: c,
|
||||
}, nil
|
||||
case TestEnvClusterMode:
|
||||
useExistingCluster := false
|
||||
testEnv := &envtest.Environment{
|
||||
UseExistingCluster: &useExistingCluster,
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, err := testEnv.ControlPlane.AddUser(envtest.User{
|
||||
Name: "envtest-admin",
|
||||
Groups: []string{"system:masters"},
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
kubeConfig, err := user.KubeConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmpFilename := filepath.Join("/tmp", "kubeconfig-"+time.Nanosecond.String())
|
||||
ioutil.WriteFile(tmpFilename, kubeConfig, 0644)
|
||||
rootArgs.kubeconfig = tmpFilename
|
||||
k8sClient, err := client.NewWithWatch(cfg, client.Options{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &testEnvKubeManager{
|
||||
testEnv: testEnv,
|
||||
client: k8sClient,
|
||||
}, nil
|
||||
case ExistingClusterMode:
|
||||
// TEST_KUBECONFIG is mandatory to prevent destroying a current cluster accidentally.
|
||||
testKubeConfig := os.Getenv("TEST_KUBECONFIG")
|
||||
if testKubeConfig == "" {
|
||||
return nil, fmt.Errorf("environment variable TEST_KUBECONFIG is required to run tests against an existing cluster")
|
||||
}
|
||||
rootArgs.kubeconfig = testKubeConfig
|
||||
|
||||
useExistingCluster := true
|
||||
config, err := clientcmd.BuildConfigFromFlags("", testKubeConfig)
|
||||
testEnv := &envtest.Environment{
|
||||
UseExistingCluster: &useExistingCluster,
|
||||
Config: config,
|
||||
}
|
||||
cfg, err := testEnv.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k8sClient, err := client.NewWithWatch(cfg, client.Options{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &testEnvKubeManager{
|
||||
testEnv: testEnv,
|
||||
client: k8sClient,
|
||||
}, nil
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
rootCmd.SetOut(buf)
|
||||
rootCmd.SetErr(buf)
|
||||
rootCmd.SetArgs(args)
|
||||
|
||||
_, err = rootCmd.ExecuteC()
|
||||
result := buf.String()
|
||||
|
||||
return result, err
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type TestClusterMode int
|
||||
|
||||
const (
|
||||
FakeClusterMode = TestClusterMode(iota + 1)
|
||||
TestEnvClusterMode
|
||||
ExistingClusterMode
|
||||
)
|
||||
|
||||
// Structure used for each test to load objects into kubernetes, run
|
||||
// commands and assert on the expected output.
|
||||
type cmdTestCase struct {
|
||||
@@ -106,11 +173,20 @@ type cmdTestCase struct {
|
||||
goldenFile string
|
||||
// Filename that contains yaml objects to load into Kubernetes
|
||||
objectFile string
|
||||
// TestClusterMode to bootstrap and testing, default to Fake
|
||||
testClusterMode TestClusterMode
|
||||
}
|
||||
|
||||
func (cmd *cmdTestCase) runTestCmd(t *testing.T) {
|
||||
km := NewFakeKubeManager()
|
||||
rootCtx.kubeManager = km
|
||||
km, err := NewTestEnvKubeManager(cmd.testClusterMode)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating kube manager: '%v'", err)
|
||||
}
|
||||
|
||||
if km != nil {
|
||||
rootCtx.kubeManager = km
|
||||
defer km.Stop()
|
||||
}
|
||||
|
||||
if cmd.objectFile != "" {
|
||||
clientObjects, err := readYamlObjects(cmd.objectFile)
|
||||
@@ -149,6 +225,27 @@ func (cmd *cmdTestCase) runTestCmd(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
|
||||
logger.stderr = rootCmd.ErrOrStderr()
|
||||
|
||||
_, err = rootCmd.ExecuteC()
|
||||
result := buf.String()
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
cmd := cmdTestCase{
|
||||
args: "--version",
|
||||
|
||||
11
cmd/flux/testdata/install/install_extra_components.golden
vendored
Normal file
11
cmd/flux/testdata/install/install_extra_components.golden
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
✚ generating manifests
|
||||
✔ manifests build completed
|
||||
► installing components in flux-system namespace
|
||||
◎ verifying installation
|
||||
✔ helm-controller: deployment ready
|
||||
✔ image-automation-controller: deployment ready
|
||||
✔ image-reflector-controller: deployment ready
|
||||
✔ kustomize-controller: deployment ready
|
||||
✔ notification-controller: deployment ready
|
||||
✔ source-controller: deployment ready
|
||||
✔ install finished
|
||||
9
cmd/flux/testdata/install/install_no_args.golden
vendored
Normal file
9
cmd/flux/testdata/install/install_no_args.golden
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
✚ generating manifests
|
||||
✔ manifests build completed
|
||||
► installing components in flux-system namespace
|
||||
◎ verifying installation
|
||||
✔ helm-controller: deployment ready
|
||||
✔ kustomize-controller: deployment ready
|
||||
✔ notification-controller: deployment ready
|
||||
✔ source-controller: deployment ready
|
||||
✔ install finished
|
||||
31
cmd/flux/testdata/uninstall/uninstall.golden
vendored
Normal file
31
cmd/flux/testdata/uninstall/uninstall.golden
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
► deleting components in flux-system namespace
|
||||
✔ Deployment/flux-system/helm-controller deleted
|
||||
✔ Deployment/flux-system/kustomize-controller deleted
|
||||
✔ Deployment/flux-system/notification-controller deleted
|
||||
✔ Deployment/flux-system/source-controller deleted
|
||||
✔ Service/flux-system/notification-controller deleted
|
||||
✔ Service/flux-system/source-controller deleted
|
||||
✔ Service/flux-system/webhook-receiver deleted
|
||||
✔ NetworkPolicy/flux-system/allow-egress deleted
|
||||
✔ NetworkPolicy/flux-system/allow-scraping deleted
|
||||
✔ NetworkPolicy/flux-system/allow-webhooks deleted
|
||||
✔ ServiceAccount/flux-system/helm-controller deleted
|
||||
✔ ServiceAccount/flux-system/kustomize-controller deleted
|
||||
✔ ServiceAccount/flux-system/notification-controller deleted
|
||||
✔ ServiceAccount/flux-system/source-controller deleted
|
||||
✔ ClusterRole/crd-controller-flux-system deleted
|
||||
✔ ClusterRoleBinding/cluster-reconciler-flux-system deleted
|
||||
✔ ClusterRoleBinding/crd-controller-flux-system deleted
|
||||
► deleting toolkit.fluxcd.io finalizers in all namespaces
|
||||
► deleting toolkit.fluxcd.io custom resource definitions
|
||||
✔ CustomResourceDefinition/alerts.notification.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/buckets.source.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/gitrepositories.source.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/helmcharts.source.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/helmreleases.helm.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/helmrepositories.source.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/kustomizations.kustomize.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/providers.notification.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/receivers.notification.toolkit.fluxcd.io deleted
|
||||
✔ Namespace/flux-system deleted
|
||||
✔ uninstall finished
|
||||
38
cmd/flux/testdata/uninstall/uninstall_extra_components.golden
vendored
Normal file
38
cmd/flux/testdata/uninstall/uninstall_extra_components.golden
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
► deleting components in flux-system namespace
|
||||
✔ Deployment/flux-system/helm-controller deleted
|
||||
✔ Deployment/flux-system/image-automation-controller deleted
|
||||
✔ Deployment/flux-system/image-reflector-controller deleted
|
||||
✔ Deployment/flux-system/kustomize-controller deleted
|
||||
✔ Deployment/flux-system/notification-controller deleted
|
||||
✔ Deployment/flux-system/source-controller deleted
|
||||
✔ Service/flux-system/notification-controller deleted
|
||||
✔ Service/flux-system/source-controller deleted
|
||||
✔ Service/flux-system/webhook-receiver deleted
|
||||
✔ NetworkPolicy/flux-system/allow-egress deleted
|
||||
✔ NetworkPolicy/flux-system/allow-scraping deleted
|
||||
✔ NetworkPolicy/flux-system/allow-webhooks deleted
|
||||
✔ ServiceAccount/flux-system/helm-controller deleted
|
||||
✔ ServiceAccount/flux-system/image-automation-controller deleted
|
||||
✔ ServiceAccount/flux-system/image-reflector-controller deleted
|
||||
✔ ServiceAccount/flux-system/kustomize-controller deleted
|
||||
✔ ServiceAccount/flux-system/notification-controller deleted
|
||||
✔ ServiceAccount/flux-system/source-controller deleted
|
||||
✔ ClusterRole/crd-controller-flux-system deleted
|
||||
✔ ClusterRoleBinding/cluster-reconciler-flux-system deleted
|
||||
✔ ClusterRoleBinding/crd-controller-flux-system deleted
|
||||
► deleting toolkit.fluxcd.io finalizers in all namespaces
|
||||
► deleting toolkit.fluxcd.io custom resource definitions
|
||||
✔ CustomResourceDefinition/alerts.notification.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/buckets.source.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/gitrepositories.source.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/helmcharts.source.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/helmreleases.helm.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/helmrepositories.source.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/imagepolicies.image.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/imagerepositories.image.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/imageupdateautomations.image.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/kustomizations.kustomize.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/providers.notification.toolkit.fluxcd.io deleted
|
||||
✔ CustomResourceDefinition/receivers.notification.toolkit.fluxcd.io deleted
|
||||
✔ Namespace/flux-system deleted
|
||||
✔ uninstall finished
|
||||
@@ -1,3 +1,5 @@
|
||||
// +build !e2e
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -6,39 +8,43 @@ import (
|
||||
|
||||
func TestTraceNoArgs(t *testing.T) {
|
||||
cmd := cmdTestCase{
|
||||
args: "trace",
|
||||
wantError: true,
|
||||
goldenValue: "object name is required",
|
||||
args: "trace",
|
||||
testClusterMode: FakeClusterMode,
|
||||
wantError: true,
|
||||
goldenValue: "object name is required",
|
||||
}
|
||||
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",
|
||||
args: "trace podinfo -n podinfo --kind deployment --api-version=apps/v1",
|
||||
testClusterMode: FakeClusterMode,
|
||||
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",
|
||||
args: "trace podinfo -n podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1",
|
||||
testClusterMode: FakeClusterMode,
|
||||
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",
|
||||
args: "trace podinfo -n podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1",
|
||||
testClusterMode: FakeClusterMode,
|
||||
wantError: false,
|
||||
goldenFile: "testdata/trace/helmrelease-missing-git-ref.txt",
|
||||
objectFile: "testdata/trace/helmrelease-missing-git-ref.yaml",
|
||||
}
|
||||
cmd.runTestCmd(t)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user