diff --git a/references/common/application_test.go b/references/common/application_test.go index e8da691d5..86c88a3fc 100644 --- a/references/common/application_test.go +++ b/references/common/application_test.go @@ -16,22 +16,111 @@ limitations under the License. package common import ( + "bytes" "context" + "os" "testing" terraformapi "github.com/oam-dev/terraform-controller/api/v1beta2" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" - "sigs.k8s.io/controller-runtime/pkg/client" + sigs "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/oam-dev/kubevela/apis/core.oam.dev/common" "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" "github.com/oam-dev/kubevela/apis/types" + "github.com/oam-dev/kubevela/references/appfile/api" + + utilcommon "github.com/oam-dev/kubevela/pkg/utils/common" + querytypes "github.com/oam-dev/kubevela/pkg/utils/types" + cmdutil "github.com/oam-dev/kubevela/pkg/utils/util" ) +func TestExportFromAppFile(t *testing.T) { + s := runtime.NewScheme() + assert.NoError(t, v1beta1.AddToScheme(s)) + clt := fake.NewClientBuilder().WithScheme(s).Build() + var out bytes.Buffer + ioStream := cmdutil.IOStreams{In: os.Stdin, Out: &out, ErrOut: &out} + + o := &AppfileOptions{ + Kubecli: clt, + IO: ioStream, + Namespace: "default", + } + + appFile := &api.AppFile{ + Name: "test-app-export-from", + } + + c := utilcommon.Args{} + c.SetClient(clt) + + result, data, err := o.ExportFromAppFile(appFile, "default", true, c) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.NotNil(t, data) + assert.Contains(t, string(data), "name: test-app-export-from") + assert.Equal(t, "test-app-export-from", result.application.Name) +} + +func TestApplyApp(t *testing.T) { + s := runtime.NewScheme() + v1beta1.AddToScheme(s) + + t.Run("create app if not exist", func(t *testing.T) { + cltCreate := fake.NewClientBuilder().WithScheme(s).Build() + var outCreate bytes.Buffer + ioStreamCreate := cmdutil.IOStreams{In: os.Stdin, Out: &outCreate, ErrOut: &outCreate} + oCreate := &AppfileOptions{ + Kubecli: cltCreate, + IO: ioStreamCreate, + Namespace: "default", + } + appCreate := &v1beta1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-app-apply", + Namespace: "default", + }, + } + err := oCreate.ApplyApp(appCreate, nil) + assert.NoError(t, err) + assert.Contains(t, outCreate.String(), "App has not been deployed, creating a new deployment...") + assert.Contains(t, outCreate.String(), "vela port-forward test-app-apply") + }) + + t.Run("update app if exists", func(t *testing.T) { + existingApp := &v1beta1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-app-apply", + Namespace: "default", + }, + } + cltUpdate := fake.NewClientBuilder().WithScheme(s).WithObjects(existingApp).Build() + var outUpdate bytes.Buffer + ioStreamUpdate := cmdutil.IOStreams{In: os.Stdin, Out: &outUpdate, ErrOut: &outUpdate} + oUpdate := &AppfileOptions{ + Kubecli: cltUpdate, + IO: ioStreamUpdate, + Namespace: "default", + } + appUpdate := &v1beta1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-app-apply", + Namespace: "default", + }, + } + err := oUpdate.ApplyApp(appUpdate, nil) + assert.NoError(t, err) + assert.Contains(t, outUpdate.String(), "App exists, updating existing deployment...") + assert.Contains(t, outUpdate.String(), "vela port-forward test-app-apply") + }) +} + func TestPrepareToForceDeleteTerraformComponents(t *testing.T) { ctx := context.Background() s := runtime.NewScheme() @@ -95,7 +184,7 @@ func TestPrepareToForceDeleteTerraformComponents(t *testing.T) { k8sClient5 := fake.NewClientBuilder().WithScheme(s).WithObjects(app2, def2, conf2).Build() type args struct { - k8sClient client.Client + k8sClient sigs.Client namespace string name string } @@ -176,5 +265,115 @@ func TestPrepareToForceDeleteTerraformComponents(t *testing.T) { } }) } - +} + +func TestIsAppfile(t *testing.T) { + testCases := []struct { + name string + data []byte + expected bool + }{ + { + name: "valid appfile json", + data: []byte(`{"name": "test"}`), + expected: true, + }, + { + name: "invalid json", + data: []byte(`{"name": "test"`), + expected: false, + }, + { + name: "application yaml", + data: []byte(` +apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: test-app +`), + expected: false, + }, + { + name: "appfile yaml", + data: []byte(` +name: test-app +`), + expected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := IsAppfile(tc.data) + assert.Equal(t, tc.expected, result) + }) + } +} + +func TestInfo(t *testing.T) { + app := &v1beta1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-app", + Namespace: "test-ns", + }, + } + info := Info(app) + assert.Contains(t, info, "vela port-forward test-app -n test-ns") + assert.Contains(t, info, "vela exec test-app -n test-ns") + assert.Contains(t, info, "vela logs test-app -n test-ns") + assert.Contains(t, info, "vela status test-app -n test-ns") + assert.Contains(t, info, "vela status test-app -n test-ns --endpoint") +} + +func TestSonLeafResource(t *testing.T) { + node := &querytypes.ResourceTreeNode{ + LeafNodes: []*querytypes.ResourceTreeNode{ + { + Object: &unstructured.Unstructured{ + Object: map[string]interface{}{ + "kind": "Deployment", + "apiVersion": "apps/v1", + }, + }, + Kind: "Deployment", + APIVersion: "apps/v1", + }, + }, + } + resources := sonLeafResource(node, "Deployment", "apps/v1") + assert.Equal(t, 1, len(resources)) + assert.Equal(t, "Deployment", resources[0].GetKind()) +} + +func TestLoadAppFile(t *testing.T) { + content := "name: test-app" + tmpFile, err := os.CreateTemp("", "appfile-*.yaml") + assert.NoError(t, err) + defer os.Remove(tmpFile.Name()) + + _, err = tmpFile.WriteString(content) + assert.NoError(t, err) + assert.NoError(t, tmpFile.Close()) + + appFile, err := LoadAppFile(tmpFile.Name()) + assert.NoError(t, err) + assert.NotNil(t, appFile) + assert.Equal(t, "test-app", appFile.Name) +} + +func TestApplyApplication(t *testing.T) { + s := runtime.NewScheme() + v1beta1.AddToScheme(s) + clt := fake.NewClientBuilder().WithScheme(s).Build() + app := v1beta1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-app", + Namespace: "default", + }, + } + var out bytes.Buffer + ioStream := cmdutil.IOStreams{In: os.Stdin, Out: &out, ErrOut: &out} + err := ApplyApplication(app, ioStream, clt) + assert.NoError(t, err) + assert.Contains(t, out.String(), "Applying an application in vela K8s object format...") } diff --git a/references/common/metrics_test.go b/references/common/metrics_test.go index e751aa90f..5ab7044c4 100644 --- a/references/common/metrics_test.go +++ b/references/common/metrics_test.go @@ -18,39 +18,50 @@ package common import ( "testing" - "time" - - "k8s.io/utils/ptr" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - - "github.com/oam-dev/kubevela/pkg/utils/common" "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/metrics/pkg/apis/metrics/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/oam-dev/kubevela/apis/core.oam.dev/common" + appv1beta1 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" ) func TestToPercentageStr(t *testing.T) { - var v1, v2 int64 - v1, v2 = 10, 100 - assert.Equal(t, ToPercentageStr(v1, v2), "10%") - v1, v2 = 10, 0 - assert.Equal(t, ToPercentageStr(v1, v2), "N/A") + t.Run("valid percentage", func(t *testing.T) { + var v1, v2 int64 = 10, 100 + assert.Equal(t, "10%", ToPercentageStr(v1, v2)) + }) + t.Run("division by zero", func(t *testing.T) { + var v1, v2 int64 = 10, 0 + assert.Equal(t, "N/A", ToPercentageStr(v1, v2)) + }) +} + +func TestToPercentage(t *testing.T) { + t.Run("valid percentage", func(t *testing.T) { + var v1, v2 int64 = 10, 100 + assert.Equal(t, 10, ToPercentage(v1, v2)) + }) + t.Run("division by zero", func(t *testing.T) { + var v1, v2 int64 = 10, 0 + assert.Equal(t, 0, ToPercentage(v1, v2)) + }) + t.Run("floor", func(t *testing.T) { + var v1, v2 int64 = 1, 3 + assert.Equal(t, 33, ToPercentage(v1, v2)) + }) } func TestGetPodResourceSpecAndUsage(t *testing.T) { - testEnv := &envtest.Environment{ - ControlPlaneStartTimeout: time.Minute * 3, - ControlPlaneStopTimeout: time.Minute, - UseExistingCluster: ptr.To(false), - } - cfg, err := testEnv.Start() - assert.NoError(t, err) - - k8sClient, err := client.New(cfg, client.Options{Scheme: common.Scheme}) - assert.NoError(t, err) + s := runtime.NewScheme() + v1.AddToScheme(s) + k8sClient := fake.NewClientBuilder().WithScheme(s).Build() quantityLimitsCPU, _ := resource.ParseQuantity("10m") quantityLimitsMemory, _ := resource.ParseQuantity("10Mi") @@ -83,10 +94,157 @@ func TestGetPodResourceSpecAndUsage(t *testing.T) { } spec, usage := GetPodResourceSpecAndUsage(k8sClient, pod, podMetric) - assert.Equal(t, usage.CPU, int64(8)) - assert.Equal(t, usage.Mem, int64(20971520)) - assert.Equal(t, spec.Lcpu, int64(10)) - assert.Equal(t, spec.Lmem, int64(10485760)) - assert.Equal(t, spec.Rcpu, int64(100)) - assert.Equal(t, spec.Rmem, int64(52428800)) + assert.Equal(t, int64(8), usage.CPU) + assert.Equal(t, int64(20971520), usage.Mem) + assert.Equal(t, int64(10), spec.Lcpu) + assert.Equal(t, int64(10485760), spec.Lmem) + assert.Equal(t, int64(100), spec.Rcpu) + assert.Equal(t, int64(52428800), spec.Rmem) +} + +func TestGetPodStorage(t *testing.T) { + s := runtime.NewScheme() + v1.AddToScheme(s) + + pvc := &v1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pvc", + Namespace: "default", + }, + } + k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(pvc).Build() + + podWithPVC := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "test-storage", + VolumeSource: v1.VolumeSource{ + PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ + ClaimName: "test-pvc", + }, + }, + }, + }, + }, + } + + podWithoutPVC := &v1.Pod{ + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "test-emptydir", + VolumeSource: v1.VolumeSource{ + EmptyDir: &v1.EmptyDirVolumeSource{}, + }, + }, + }, + }, + } + + podWithNonExistentPVC := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + }, + Spec: v1.PodSpec{ + Volumes: []v1.Volume{ + { + Name: "test-storage", + VolumeSource: v1.VolumeSource{ + PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ + ClaimName: "non-existent-pvc", + }, + }, + }, + }, + }, + } + + t.Run("pod with pvc", func(t *testing.T) { + storages := GetPodStorage(k8sClient, podWithPVC) + assert.Equal(t, 1, len(storages)) + assert.Equal(t, "test-pvc", storages[0].Name) + }) + + t.Run("pod without pvc", func(t *testing.T) { + storages := GetPodStorage(k8sClient, podWithoutPVC) + assert.Equal(t, 0, len(storages)) + }) + + t.Run("pod with non-existent pvc", func(t *testing.T) { + storages := GetPodStorage(k8sClient, podWithNonExistentPVC) + assert.Equal(t, 0, len(storages)) + }) +} + +func TestGetPodOfManagedResource(t *testing.T) { + s := runtime.NewScheme() + v1.AddToScheme(s) + appv1beta1.AddToScheme(s) + + app := &appv1beta1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-app", + Namespace: "default", + }, + } + + pod := &v1.Pod{ + TypeMeta: metav1.TypeMeta{ + Kind: "Pod", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pod", + Namespace: "default", + }, + } + podUnstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(pod) + assert.NoError(t, err) + + rt := &appv1beta1.ResourceTracker{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-app-v1", // A tracker name + Namespace: "default", + Labels: map[string]string{ + "app.oam.dev/name": "test-app", + "app.oam.dev/namespace": "default", + }, + }, + Spec: appv1beta1.ResourceTrackerSpec{ + Type: appv1beta1.ResourceTrackerTypeRoot, + ManagedResources: []appv1beta1.ManagedResource{ + { + ClusterObjectReference: common.ClusterObjectReference{ + ObjectReference: v1.ObjectReference{ + Kind: "Pod", + APIVersion: "v1", + Name: "test-pod", + Namespace: "default", + }, + }, + OAMObjectReference: common.OAMObjectReference{ + Component: "test-component", + }, + }, + }, + }, + } + + k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(app, rt, &unstructured.Unstructured{Object: podUnstructured}).Build() + + t.Run("get existing pod", func(t *testing.T) { + pods := GetPodOfManagedResource(k8sClient, app, "test-component") + assert.Equal(t, 2, len(pods)) + assert.Equal(t, "test-pod", pods[0].Name) + assert.Equal(t, "test-pod", pods[1].Name) + }) + + t.Run("get pod for non-existent component", func(t *testing.T) { + pods := GetPodOfManagedResource(k8sClient, app, "non-existent-component") + assert.Equal(t, 0, len(pods)) + }) } diff --git a/references/common/registry_test.go b/references/common/registry_test.go index 44c6fe79b..d484ad087 100644 --- a/references/common/registry_test.go +++ b/references/common/registry_test.go @@ -17,16 +17,178 @@ limitations under the License. package common import ( + "bytes" + "context" "encoding/json" + "os" "reflect" "testing" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" + "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" "github.com/oam-dev/kubevela/apis/types" + cmdutil "github.com/oam-dev/kubevela/pkg/utils/util" ) +func TestInstallComponentDefinition(t *testing.T) { + s := runtime.NewScheme() + assert.NoError(t, v1beta1.AddToScheme(s)) + + validComponentData := []byte(` +apiVersion: core.oam.dev/v1beta1 +kind: ComponentDefinition +metadata: + name: test-component +spec: + workload: + definition: + apiVersion: apps/v1 + kind: Deployment +`) + + existingComponent := &v1beta1.ComponentDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-component", + Namespace: types.DefaultKubeVelaNS, + }, + } + + t.Run("success", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).Build() + var out bytes.Buffer + ioStreams := cmdutil.IOStreams{In: os.Stdin, Out: &out, ErrOut: &out} + + err := InstallComponentDefinition(k8sClient, validComponentData, ioStreams) + assert.NoError(t, err) + assert.Contains(t, out.String(), "Installing component: test-component") + + var cd v1beta1.ComponentDefinition + err = k8sClient.Get(context.Background(), client.ObjectKey{Name: "test-component", Namespace: types.DefaultKubeVelaNS}, &cd) + assert.NoError(t, err) + assert.Equal(t, "test-component", cd.Name) + }) + + t.Run("already exists", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(existingComponent).Build() + var out bytes.Buffer + ioStreams := cmdutil.IOStreams{In: os.Stdin, Out: &out, ErrOut: &out} + + err := InstallComponentDefinition(k8sClient, validComponentData, ioStreams) + assert.NoError(t, err) + }) + + t.Run("client error", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).WithInterceptorFuncs(interceptor.Funcs{ + Create: func(ctx context.Context, cl client.WithWatch, obj client.Object, opts ...client.CreateOption) error { + return errors.New("client create error") + }, + }).Build() + var out bytes.Buffer + ioStreams := cmdutil.IOStreams{In: os.Stdin, Out: &out, ErrOut: &out} + + err := InstallComponentDefinition(k8sClient, validComponentData, ioStreams) + assert.Error(t, err) + assert.EqualError(t, err, "client create error") + }) + + t.Run("invalid data", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).Build() + var out bytes.Buffer + ioStreams := cmdutil.IOStreams{In: os.Stdin, Out: &out, ErrOut: &out} + invalidData := []byte(`{"invalid": "yaml"`) + + err := InstallComponentDefinition(k8sClient, invalidData, ioStreams) + assert.Error(t, err) + }) + + t.Run("nil data", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).Build() + var out bytes.Buffer + ioStreams := cmdutil.IOStreams{In: os.Stdin, Out: &out, ErrOut: &out} + + err := InstallComponentDefinition(k8sClient, nil, ioStreams) + assert.Error(t, err) + assert.Equal(t, "componentData is nil", err.Error()) + }) +} + +func TestInstallTraitDefinition(t *testing.T) { + s := runtime.NewScheme() + v1beta1.AddToScheme(s) + + validTraitData := []byte(` +apiVersion: core.oam.dev/v1beta1 +kind: TraitDefinition +metadata: + name: test-trait +spec: + appliesToWorkloads: + - deployments.apps +`) + + existingTrait := &v1beta1.TraitDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-trait", + Namespace: types.DefaultKubeVelaNS, + }, + } + + t.Run("success", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).Build() + var out bytes.Buffer + ioStreams := cmdutil.IOStreams{In: os.Stdin, Out: &out, ErrOut: &out} + + err := InstallTraitDefinition(k8sClient, validTraitData, ioStreams) + assert.NoError(t, err) + assert.Contains(t, out.String(), "Installing trait test-trait") + + var td v1beta1.TraitDefinition + err = k8sClient.Get(context.Background(), client.ObjectKey{Name: "test-trait", Namespace: types.DefaultKubeVelaNS}, &td) + assert.NoError(t, err) + assert.Equal(t, "test-trait", td.Name) + }) + + t.Run("already exists", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(existingTrait).Build() + var out bytes.Buffer + ioStreams := cmdutil.IOStreams{In: os.Stdin, Out: &out, ErrOut: &out} + + err := InstallTraitDefinition(k8sClient, validTraitData, ioStreams) + assert.NoError(t, err) + }) + + t.Run("client error", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).WithInterceptorFuncs(interceptor.Funcs{ + Create: func(ctx context.Context, cl client.WithWatch, obj client.Object, opts ...client.CreateOption) error { + return errors.New("client create error") + }, + }).Build() + var out bytes.Buffer + ioStreams := cmdutil.IOStreams{In: os.Stdin, Out: &out, ErrOut: &out} + + err := InstallTraitDefinition(k8sClient, validTraitData, ioStreams) + assert.Error(t, err) + assert.Equal(t, "client create error", err.Error()) + }) + + t.Run("invalid data", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).Build() + var out bytes.Buffer + ioStreams := cmdutil.IOStreams{In: os.Stdin, Out: &out, ErrOut: &out} + invalidData := []byte(`{"invalid": "yaml"`) + + err := InstallTraitDefinition(k8sClient, invalidData, ioStreams) + assert.Error(t, err) + }) +} + func TestAddSourceIntoDefinition(t *testing.T) { caseJson := []byte(`{"template":""}`) wantJson := []byte(`{"source":{"repoName":"foo"},"template":""}`) diff --git a/references/common/trait_test.go b/references/common/trait_test.go new file mode 100644 index 000000000..20879c10e --- /dev/null +++ b/references/common/trait_test.go @@ -0,0 +1,90 @@ +/* +Copyright 2021 The KubeVela Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import ( + "testing" + + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" + "github.com/oam-dev/kubevela/pkg/oam" + "github.com/oam-dev/kubevela/pkg/utils/common" +) + +func TestListRawWorkloadDefinitions(t *testing.T) { + s := runtime.NewScheme() + v1beta1.AddToScheme(s) + + sysWorkload := v1beta1.WorkloadDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "sys-worker", + Namespace: oam.SystemDefinitionNamespace, + }, + } + userWorkload := v1beta1.WorkloadDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "user-worker", + Namespace: "my-ns", + }, + } + + t.Run("list from both user and system namespaces", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(&sysWorkload, &userWorkload).Build() + c := common.Args{} + c.SetClient(k8sClient) + + defs, err := ListRawWorkloadDefinitions("my-ns", c) + assert.NoError(t, err) + assert.Equal(t, 2, len(defs)) + }) + + t.Run("list from only system namespace", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(&sysWorkload).Build() + c := common.Args{} + c.SetClient(k8sClient) + + defs, err := ListRawWorkloadDefinitions("my-ns", c) + assert.NoError(t, err) + assert.Equal(t, 1, len(defs)) + assert.Equal(t, "sys-worker", defs[0].Name) + }) + + t.Run("list from only user namespace", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(&userWorkload).Build() + c := common.Args{} + c.SetClient(k8sClient) + + defs, err := ListRawWorkloadDefinitions("my-ns", c) + assert.NoError(t, err) + assert.Equal(t, 1, len(defs)) + assert.Equal(t, "user-worker", defs[0].Name) + }) + + t.Run("no definitions found", func(t *testing.T) { + k8sClient := fake.NewClientBuilder().WithScheme(s).Build() + c := common.Args{} + c.SetClient(k8sClient) + + defs, err := ListRawWorkloadDefinitions("my-ns", c) + assert.NoError(t, err) + assert.Equal(t, 0, len(defs)) + }) +} diff --git a/references/common/workload_test.go b/references/common/workload_test.go new file mode 100644 index 000000000..4549d95a1 --- /dev/null +++ b/references/common/workload_test.go @@ -0,0 +1,106 @@ +/* +Copyright 2021 The KubeVela Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import ( + "testing" + + "github.com/spf13/pflag" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + corecommon "github.com/oam-dev/kubevela/apis/core.oam.dev/common" + "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" + "github.com/oam-dev/kubevela/apis/types" + "github.com/oam-dev/kubevela/pkg/oam" + "github.com/oam-dev/kubevela/pkg/utils/common" +) + +func TestInitApplication(t *testing.T) { + c := common.Args{} + c.SetClient(fake.NewClientBuilder().Build()) + + t.Run("with appGroup", func(t *testing.T) { + app, err := InitApplication("default", c, "my-workload", "my-app") + assert.NoError(t, err) + assert.NotNil(t, app) + assert.Equal(t, "my-app", app.Name) + }) + + t.Run("without appGroup", func(t *testing.T) { + app, err := InitApplication("default", c, "my-workload", "") + assert.NoError(t, err) + assert.NotNil(t, app) + assert.Equal(t, "my-workload", app.Name) + }) +} + +func TestBaseComplete(t *testing.T) { + s := runtime.NewScheme() + assert.NoError(t, v1beta1.AddToScheme(s)) + + template := &v1beta1.ComponentDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: "worker", + Namespace: oam.SystemDefinitionNamespace, + }, + Spec: v1beta1.ComponentDefinitionSpec{ + Workload: corecommon.WorkloadTypeDescriptor{ + Type: types.AutoDetectWorkloadDefinition, + }, + Schematic: &corecommon.Schematic{ + CUE: &corecommon.CUE{ + Template: ` +parameter: { + image: string + port: *8080 | int +} +`, + }, + }, + }, + } + k8sClient := fake.NewClientBuilder().WithScheme(s).WithObjects(template).Build() + c := common.Args{} + c.SetClient(k8sClient) + + t.Run("success", func(t *testing.T) { + flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) + flagSet.String("image", "my-image", "") + flagSet.Int64("port", 80, "") + + app, err := BaseComplete(oam.SystemDefinitionNamespace, c, "my-workload", "my-app", flagSet, "worker") + assert.NoError(t, err) + assert.NotNil(t, app) + + workload, ok := app.Services["my-workload"] + assert.True(t, ok) + assert.Equal(t, "my-image", workload["image"]) + assert.Equal(t, int64(80), workload["port"]) + }) + + t.Run("missing required flag", func(t *testing.T) { + flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) + // not setting the required "image" flag + + _, err := BaseComplete(oam.SystemDefinitionNamespace, c, "my-workload", "my-app", flagSet, "worker") + assert.Error(t, err) + assert.Contains(t, err.Error(), `required flag(s) "image" not set`) + }) +}