Repository: kubevela/kubevela

Issue:
Test: Improve Unit Test Coverage for Core Packages
**Description:**
To improve the overall quality, stability, and maintainability of the KubeVela codebase, we need to increase our unit test coverage, especially in core packages. Good test coverage is essential for preventing regressions and enabling developers to refactor and add new features with confidence.

#### Task Description

This task is to add comprehensive unit tests to the following core packages, which currently have coverage gaps:

- `pkg/resourcekeeper`
- `pkg/resourcetracker`
- `pkg/policy/envbinding`
- `pkg/schema`

#### Acceptance Criteria

- New unit tests are added to the packages listed above.
- The new tests should cover critical functions and logic that are currently untested.
- Tests should verify both expected behavior (happy paths) and error conditions/edge cases.
- All new tests must pass.
- The overall test coverage for these packages should be significantly increased.

#### Contributor Guidelines

- Please follow the existing testing conventions within the KubeVela project.
- Use Go's standard testing library and the `stretchr/testify` package for assertions.
- Where appropriate, use table-driven tests to keep the test code clean, readable, and easy to extend.
- Each commit should focus on a single package to keep the changes manageable and easy to review.

Hints from issue comments:

Solution patch:
diff --git a/pkg/utils/errors/reason.go b/pkg/utils/errors/reason.go
index 336cc35e..41a7ae45 100644
--- a/pkg/utils/errors/reason.go
+++ b/pkg/utils/errors/reason.go
@@ -38,5 +38,8 @@ func IsLabelConflict(err error) bool {
 
 // IsCuePathNotFound checks if the error is cue path not found error
 func IsCuePathNotFound(err error) bool {
+	if err == nil {
+		return false
+	}
 	return strings.Contains(err.Error(), "failed to lookup value") && strings.Contains(err.Error(), "not exist")
 }



Test patch:
diff --git a/pkg/policy/envbinding/placement_test.go b/pkg/policy/envbinding/placement_test.go
index a2f26796..244f66cd 100644
--- a/pkg/policy/envbinding/placement_test.go
+++ b/pkg/policy/envbinding/placement_test.go
@@ -17,9 +17,11 @@ limitations under the License.
 package envbinding
 
 import (
+	"encoding/json"
 	"testing"
 
 	"github.com/stretchr/testify/require"
+	"k8s.io/apimachinery/pkg/runtime"
 
 	"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
 	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
@@ -63,3 +65,124 @@ func TestUpdateClusterConnections(t *testing.T) {
 		r.Equal(conn.LastActiveRevision, _conn.LastActiveRevision)
 	}
 }
+
+func TestWritePlacementDecisions(t *testing.T) {
+	policyName := "test-policy"
+	envName1 := "env-1"
+	envName2 := "env-2"
+	decisions1 := []v1alpha1.PlacementDecision{{Cluster: "cluster-1"}}
+	decisions2 := []v1alpha1.PlacementDecision{{Cluster: "cluster-2"}}
+
+	makeAppWithPolicy := func(t *testing.T) *v1beta1.Application {
+		app := &v1beta1.Application{}
+		err := WritePlacementDecisions(app, policyName, envName1, decisions1)
+		require.NoError(t, err)
+		return app
+	}
+
+	testCases := []struct {
+		name      string
+		setupApp  func(t *testing.T) *v1beta1.Application
+		envName   string
+		decisions []v1alpha1.PlacementDecision
+		wantErr   bool
+		verify    func(t *testing.T, app *v1beta1.Application)
+	}{
+		{
+			name: "add to empty policy status",
+			setupApp: func(t *testing.T) *v1beta1.Application {
+				return &v1beta1.Application{}
+			},
+			envName:   envName1,
+			decisions: decisions1,
+			wantErr:   false,
+			verify: func(t *testing.T, app *v1beta1.Application) {
+				r := require.New(t)
+				r.Len(app.Status.PolicyStatus, 1)
+				r.Equal(policyName, app.Status.PolicyStatus[0].Name)
+				r.Equal(v1alpha1.EnvBindingPolicyType, app.Status.PolicyStatus[0].Type)
+				status := &v1alpha1.EnvBindingStatus{}
+				err := json.Unmarshal(app.Status.PolicyStatus[0].Status.Raw, status)
+				r.NoError(err)
+				r.Len(status.Envs, 1)
+				r.Equal(envName1, status.Envs[0].Env)
+				r.Equal(decisions1, status.Envs[0].Placements)
+			},
+		},
+		{
+			name:      "update existing env in existing policy",
+			setupApp:  makeAppWithPolicy,
+			envName:   envName1,
+			decisions: decisions2,
+			wantErr:   false,
+			verify: func(t *testing.T, app *v1beta1.Application) {
+				r := require.New(t)
+				r.Len(app.Status.PolicyStatus, 1)
+				status := &v1alpha1.EnvBindingStatus{}
+				err := json.Unmarshal(app.Status.PolicyStatus[0].Status.Raw, status)
+				r.NoError(err)
+				r.Len(status.Envs, 1)
+				r.Equal(envName1, status.Envs[0].Env)
+				r.Equal(decisions2, status.Envs[0].Placements)
+			},
+		},
+		{
+			name:      "add new env to existing policy",
+			setupApp:  makeAppWithPolicy,
+			envName:   envName2,
+			decisions: decisions2,
+			wantErr:   false,
+			verify: func(t *testing.T, app *v1beta1.Application) {
+				r := require.New(t)
+				r.Len(app.Status.PolicyStatus, 1)
+				status := &v1alpha1.EnvBindingStatus{}
+				err := json.Unmarshal(app.Status.PolicyStatus[0].Status.Raw, status)
+				r.NoError(err)
+				r.Len(status.Envs, 2)
+				envMap := make(map[string][]v1alpha1.PlacementDecision)
+				for _, envStatus := range status.Envs {
+					envMap[envStatus.Env] = envStatus.Placements
+				}
+				r.Equal(decisions1, envMap[envName1])
+				r.Equal(decisions2, envMap[envName2])
+			},
+		},
+		{
+			name: "handle malformed existing status",
+			setupApp: func(t *testing.T) *v1beta1.Application {
+				return &v1beta1.Application{
+					Status: common.AppStatus{
+						PolicyStatus: []common.PolicyStatus{
+							{
+								Name:   policyName,
+								Type:   v1alpha1.EnvBindingPolicyType,
+								Status: &runtime.RawExtension{Raw: []byte("this is not json")},
+							},
+						},
+					},
+				}
+			},
+			envName:   envName1,
+			decisions: decisions1,
+			wantErr:   true,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			r := require.New(t)
+			app := tc.setupApp(t)
+			err := WritePlacementDecisions(app, policyName, tc.envName, tc.decisions)
+
+			if tc.wantErr {
+				r.Error(err)
+			} else {
+				r.NoError(err)
+			}
+
+			if tc.verify != nil {
+				tc.verify(t, app)
+			}
+		})
+	}
+}
diff --git a/pkg/resourcekeeper/containsresources_test.go b/pkg/resourcekeeper/containsresources_test.go
new file mode 100644
index 00000000..2eccad2d
--- /dev/null
+++ b/pkg/resourcekeeper/containsresources_test.go
@@ -0,0 +1,156 @@
+/*
+Copyright 2022 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 resourcekeeper
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"sigs.k8s.io/controller-runtime/pkg/client/fake"
+
+	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
+	"github.com/oam-dev/kubevela/pkg/utils/common"
+)
+
+// newUnstructured is a helper to create a simple unstructured object for testing.
+func newUnstructured(name string) *unstructured.Unstructured {
+	return &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": "v1",
+			"kind":       "ConfigMap",
+			"metadata": map[string]interface{}{
+				"name": name,
+			},
+		},
+	}
+}
+
+func TestContainsResources(t *testing.T) {
+	res1 := newUnstructured("res-1")
+	res2 := newUnstructured("res-2")
+	res3 := newUnstructured("res-3")
+	res4Missing := newUnstructured("res-4-missing")
+
+	baseKeeperSetup := func() *resourceKeeper {
+		return &resourceKeeper{
+			Client:     fake.NewClientBuilder().WithScheme(common.Scheme).Build(),
+			_currentRT: &v1beta1.ResourceTracker{},
+			_rootRT:    &v1beta1.ResourceTracker{},
+		}
+	}
+
+	testCases := []struct {
+		name     string
+		keeper   *resourceKeeper
+		input    []*unstructured.Unstructured
+		expected bool
+	}{
+		{
+			name: "all resources exist across both trackers",
+			keeper: func() *resourceKeeper {
+				k := baseKeeperSetup()
+				k._currentRT.AddManagedResource(res1, true, false, "")
+				k._rootRT.AddManagedResource(res2, true, false, "")
+				k._rootRT.AddManagedResource(res3, true, false, "")
+				return k
+			}(),
+			input:    []*unstructured.Unstructured{res1, res2, res3},
+			expected: true,
+		},
+		{
+			name: "one resource exists in currentRT",
+			keeper: func() *resourceKeeper {
+				k := baseKeeperSetup()
+				k._currentRT.AddManagedResource(res1, true, false, "")
+				return k
+			}(),
+			input:    []*unstructured.Unstructured{res1},
+			expected: true,
+		},
+		{
+			name: "one resource exists in rootRT",
+			keeper: func() *resourceKeeper {
+				k := baseKeeperSetup()
+				k._rootRT.AddManagedResource(res2, true, false, "")
+				return k
+			}(),
+			input:    []*unstructured.Unstructured{res2},
+			expected: true,
+		},
+		{
+			name: "one resource is missing",
+			keeper: func() *resourceKeeper {
+				k := baseKeeperSetup()
+				k._currentRT.AddManagedResource(res1, true, false, "")
+				return k
+			}(),
+			input:    []*unstructured.Unstructured{res1, res4Missing},
+			expected: false,
+		},
+		{
+			name: "empty input slice should return true",
+			keeper: &resourceKeeper{
+				Client: fake.NewClientBuilder().WithScheme(common.Scheme).Build(),
+			},
+			input:    []*unstructured.Unstructured{},
+			expected: true,
+		},
+		{
+			name: "trackers are nil",
+			keeper: &resourceKeeper{
+				Client: fake.NewClientBuilder().WithScheme(common.Scheme).Build(),
+			},
+			input:    []*unstructured.Unstructured{res1},
+			expected: false,
+		},
+		{
+			name: "only rootRT is nil, resource in currentRT",
+			keeper: func() *resourceKeeper {
+				k := &resourceKeeper{
+					Client:     fake.NewClientBuilder().WithScheme(common.Scheme).Build(),
+					_currentRT: &v1beta1.ResourceTracker{},
+				}
+				k._currentRT.AddManagedResource(res1, true, false, "")
+				return k
+			}(),
+			input:    []*unstructured.Unstructured{res1},
+			expected: true,
+		},
+		{
+			name: "only rootRT is nil, resource not in currentRT",
+			keeper: func() *resourceKeeper {
+				k := &resourceKeeper{
+					Client:     fake.NewClientBuilder().WithScheme(common.Scheme).Build(),
+					_currentRT: &v1beta1.ResourceTracker{},
+				}
+				k._currentRT.AddManagedResource(res1, true, false, "")
+				return k
+			}(),
+			input:    []*unstructured.Unstructured{res2},
+			expected: false,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			r := require.New(t)
+			result := tc.keeper.ContainsResources(tc.input)
+			r.Equal(tc.expected, result)
+		})
+	}
+}
diff --git a/pkg/resourcekeeper/gc_test.go b/pkg/resourcekeeper/gc_test.go
index 6b2bbe29..d8a2a654 100644
--- a/pkg/resourcekeeper/gc_test.go
+++ b/pkg/resourcekeeper/gc_test.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"testing"
 
+	"github.com/crossplane/crossplane-runtime/pkg/test"
 	workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
 	"github.com/stretchr/testify/require"
 	appsv1 "k8s.io/api/apps/v1"
@@ -347,3 +348,105 @@ func TestEnableMarkStageGCOnWorkflowFailure(t *testing.T) {
 	cfg = h.buildGCConfig(WithPhase(context.Background(), apicommon.ApplicationWorkflowFailed), options...)
 	require.False(t, cfg.disableMark)
 }
+
+func TestUpdateSharedManagedResourceOwner(t *testing.T) {
+	ctx := context.Background()
+
+	baseCM := &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": "v1",
+			"kind":       "ConfigMap",
+			"metadata": map[string]interface{}{
+				"name":      "shared-cm",
+				"namespace": "test-ns",
+				"labels": map[string]interface{}{
+					oam.LabelAppName:      "old-app",
+					oam.LabelAppNamespace: "old-ns",
+				},
+			},
+		},
+	}
+
+	mockUpdateErr := fmt.Errorf("mock update error")
+
+	testCases := []struct {
+		name        string
+		setup       func(t *testing.T) (client.Client, *unstructured.Unstructured)
+		newSharedBy string
+		wantErr     error
+		verify      func(t *testing.T, cli client.Client, cm *unstructured.Unstructured)
+	}{
+		{
+			name: "update with multi-tenant sharer",
+			setup: func(t *testing.T) (client.Client, *unstructured.Unstructured) {
+				r := require.New(t)
+				cli := fake.NewClientBuilder().WithScheme(common.Scheme).Build()
+				cm := baseCM.DeepCopy()
+				r.NoError(cli.Create(ctx, cm))
+				return cli, cm
+			},
+			newSharedBy: "new-ns/new-app,other-ns/other-app",
+			verify: func(t *testing.T, cli client.Client, cm *unstructured.Unstructured) {
+				r := require.New(t)
+				updatedCM := &unstructured.Unstructured{}
+				updatedCM.SetGroupVersionKind(cm.GroupVersionKind())
+				r.NoError(cli.Get(ctx, client.ObjectKeyFromObject(cm), updatedCM))
+				r.Equal("new-ns/new-app,other-ns/other-app", updatedCM.GetAnnotations()[oam.AnnotationAppSharedBy])
+				r.Equal("new-app", updatedCM.GetLabels()[oam.LabelAppName])
+				r.Equal("new-ns", updatedCM.GetLabels()[oam.LabelAppNamespace])
+			},
+		},
+		{
+			name: "update with single-tenant sharer",
+			setup: func(t *testing.T) (client.Client, *unstructured.Unstructured) {
+				r := require.New(t)
+				cli := fake.NewClientBuilder().WithScheme(common.Scheme).Build()
+				cm := baseCM.DeepCopy()
+				r.NoError(cli.Create(ctx, cm))
+				return cli, cm
+			},
+			newSharedBy: "just-an-app",
+			verify: func(t *testing.T, cli client.Client, cm *unstructured.Unstructured) {
+				r := require.New(t)
+				updatedCM := &unstructured.Unstructured{}
+				updatedCM.SetGroupVersionKind(cm.GroupVersionKind())
+				r.NoError(cli.Get(ctx, client.ObjectKeyFromObject(cm), updatedCM))
+				r.Equal("just-an-app", updatedCM.GetAnnotations()[oam.AnnotationAppSharedBy])
+				r.Equal("just-an-app", updatedCM.GetLabels()[oam.LabelAppName])
+				r.Equal("default", updatedCM.GetLabels()[oam.LabelAppNamespace])
+			},
+		},
+		{
+			name: "client update fails",
+			setup: func(t *testing.T) (client.Client, *unstructured.Unstructured) {
+				cli := &test.MockClient{
+					MockUpdate: test.NewMockUpdateFn(mockUpdateErr),
+				}
+				cm := baseCM.DeepCopy()
+				return cli, cm
+			},
+			newSharedBy: "any/sharer",
+			wantErr:     mockUpdateErr,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			r := require.New(t)
+			cli, cm := tc.setup(t)
+
+			err := UpdateSharedManagedResourceOwner(ctx, cli, cm, tc.newSharedBy)
+
+			if tc.wantErr != nil {
+				r.Error(err)
+				r.Equal(tc.wantErr, err)
+			} else {
+				r.NoError(err)
+			}
+
+			if tc.verify != nil {
+				tc.verify(t, cli, cm)
+			}
+		})
+	}
+}
diff --git a/pkg/resourcetracker/tree_test.go b/pkg/resourcetracker/tree_test.go
index 4ec9d25d..7ae1f4cb 100644
--- a/pkg/resourcetracker/tree_test.go
+++ b/pkg/resourcetracker/tree_test.go
@@ -17,24 +17,63 @@ limitations under the License.
 package resourcetracker
 
 import (
+	"bytes"
+	"fmt"
 	"math"
+	"net/http"
 	"testing"
 
+	"github.com/fatih/color"
 	"github.com/stretchr/testify/require"
+	corev1 "k8s.io/api/core/v1"
 	"k8s.io/utils/ptr"
 
-	"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
+	apicommon "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
+	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
 	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
 	"github.com/oam-dev/kubevela/pkg/multicluster"
 )
 
 func TestResourceTreePrintOption_getWidthForDetails(t *testing.T) {
-	r := require.New(t)
-	options := &ResourceTreePrintOptions{}
-	r.Equal(math.MaxInt, options._getWidthForDetails(nil))
-	options.MaxWidth = ptr.To(50 + applyTimeWidth)
-	r.Equal(30, options._getWidthForDetails([]int{10, 10}))
-	r.Equal(math.MaxInt, options._getWidthForDetails([]int{20, 20}))
+	testCases := []struct {
+		name      string
+		options   *ResourceTreePrintOptions
+		colsWidth []int
+		expected  int
+	}{
+		{
+			name:      "nil max width",
+			options:   &ResourceTreePrintOptions{},
+			colsWidth: nil,
+			expected:  math.MaxInt,
+		},
+		{
+			name:      "sufficient width",
+			options:   &ResourceTreePrintOptions{MaxWidth: ptr.To(50 + applyTimeWidth)},
+			colsWidth: []int{10, 10},
+			expected:  30,
+		},
+		{
+			name:      "insufficient width",
+			options:   &ResourceTreePrintOptions{MaxWidth: ptr.To(50 + applyTimeWidth)},
+			colsWidth: []int{20, 20},
+			expected:  math.MaxInt,
+		},
+		{
+			name:      "no columns",
+			options:   &ResourceTreePrintOptions{MaxWidth: ptr.To(50 + applyTimeWidth)},
+			colsWidth: []int{},
+			expected:  50,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			r := require.New(t)
+			result := tc.options._getWidthForDetails(tc.colsWidth)
+			r.Equal(tc.expected, result)
+		})
+	}
 }
 
 func TestResourceTreePrintOptions_wrapDetails(t *testing.T) {
@@ -76,7 +115,7 @@ func TestBuildResourceRow(t *testing.T) {
 
 	for name, c := range cases {
 		mr := v1beta1.ManagedResource{
-			ClusterObjectReference: common.ClusterObjectReference{
+			ClusterObjectReference: apicommon.ClusterObjectReference{
 				Cluster: c.Cluster,
 			},
 		}
@@ -86,3 +125,243 @@ func TestBuildResourceRow(t *testing.T) {
 	}
 
 }
+
+// newManagedResource is a helper for creating a ManagedResource for tests
+func newManagedResource(cluster, namespace, kind, name string) v1beta1.ManagedResource {
+	return v1beta1.ManagedResource{
+		ClusterObjectReference: apicommon.ClusterObjectReference{
+			Cluster: cluster,
+			ObjectReference: corev1.ObjectReference{
+				Namespace: namespace,
+				Kind:      kind,
+				Name:      name,
+			},
+		},
+	}
+}
+
+func TestLoadResourceRows(t *testing.T) {
+	r := require.New(t)
+	options := &ResourceTreePrintOptions{}
+
+	mr1 := newManagedResource("c1", "ns1", "Deployment", "d1")
+	mr2 := newManagedResource("c1", "ns1", "Service", "s1")
+	mr3 := newManagedResource("c2", "ns2", "ConfigMap", "cm1")
+	mrDeleted := newManagedResource("c1", "ns1", "Secret", "sec1")
+	mrDeleted.Deleted = true
+
+	currentRT := &v1beta1.ResourceTracker{
+		Spec: v1beta1.ResourceTrackerSpec{
+			ManagedResources: []v1beta1.ManagedResource{mr1, mrDeleted},
+		},
+	}
+	historyRTs := []*v1beta1.ResourceTracker{{
+		Spec: v1beta1.ResourceTrackerSpec{
+			ManagedResources: []v1beta1.ManagedResource{mr1, mr2, mr3},
+		},
+	}}
+
+	rows := options.loadResourceRows(currentRT, historyRTs)
+	r.Len(rows, 3)
+
+	statusMap := map[string]string{}
+	for _, row := range rows {
+		statusMap[row.mr.ResourceKey()] = row.status
+	}
+
+	r.Equal(resourceRowStatusUpdated, statusMap[mr1.ResourceKey()])
+	r.Equal(resourceRowStatusOutdated, statusMap[mr2.ResourceKey()])
+	r.Equal(resourceRowStatusOutdated, statusMap[mr3.ResourceKey()])
+	_, exists := statusMap[mrDeleted.ResourceKey()]
+	r.False(exists, "Deleted resource should not be loaded")
+}
+
+func TestSortRows(t *testing.T) {
+	r := require.New(t)
+	options := &ResourceTreePrintOptions{}
+
+	rows := []*resourceRow{
+		{mr: &v1beta1.ManagedResource{ClusterObjectReference: apicommon.ClusterObjectReference{Cluster: "c2", ObjectReference: corev1.ObjectReference{Name: "res1"}}}},
+		{mr: &v1beta1.ManagedResource{ClusterObjectReference: apicommon.ClusterObjectReference{Cluster: "c1", ObjectReference: corev1.ObjectReference{Namespace: "ns2", Name: "res2"}}}},
+		{mr: &v1beta1.ManagedResource{ClusterObjectReference: apicommon.ClusterObjectReference{Cluster: "c1", ObjectReference: corev1.ObjectReference{Namespace: "ns1", Name: "res3"}}}},
+		{mr: &v1beta1.ManagedResource{ClusterObjectReference: apicommon.ClusterObjectReference{Cluster: "c1", ObjectReference: corev1.ObjectReference{Namespace: "ns2", Name: "res1"}}}},
+	}
+
+	options.sortRows(rows)
+
+	r.Equal("c1", rows[0].mr.Cluster)
+	r.Equal("ns1", rows[0].mr.Namespace)
+
+	r.Equal("c1", rows[1].mr.Cluster)
+	r.Equal("ns2", rows[1].mr.Namespace)
+	r.Equal("res1", rows[1].mr.Name)
+
+	r.Equal("c1", rows[2].mr.Cluster)
+	r.Equal("ns2", rows[2].mr.Namespace)
+	r.Equal("res2", rows[2].mr.Name)
+
+	r.Equal("c2", rows[3].mr.Cluster)
+}
+
+func TestAddNonExistingPlacementToRows(t *testing.T) {
+	r := require.New(t)
+	options := &ResourceTreePrintOptions{}
+
+	rows := []*resourceRow{
+		{mr: &v1beta1.ManagedResource{ClusterObjectReference: apicommon.ClusterObjectReference{Cluster: "cluster-a"}}},
+	}
+	placements := []v1alpha1.PlacementDecision{
+		{Cluster: "cluster-a"},
+		{Cluster: "cluster-b"},
+	}
+
+	newRows := options.addNonExistingPlacementToRows(placements, rows)
+	r.Len(newRows, 2)
+	r.Equal("cluster-a", newRows[0].mr.Cluster)
+	r.Equal("cluster-b", newRows[1].mr.Cluster)
+	r.Equal(resourceRowStatusNotDeployed, newRows[1].status)
+}
+
+// MockClusterNameMapper is a mock for testing
+type MockClusterNameMapper struct{}
+
+func (m MockClusterNameMapper) GetClusterName(cluster string) string { return cluster }
+
+func TestFillResourceRows(t *testing.T) {
+	r := require.New(t)
+	options := &ResourceTreePrintOptions{ClusterNameMapper: MockClusterNameMapper{}}
+
+	rows := []*resourceRow{
+		{mr: &v1beta1.ManagedResource{ClusterObjectReference: apicommon.ClusterObjectReference{Cluster: "c1", ObjectReference: corev1.ObjectReference{Namespace: "ns1", Kind: "Deployment", Name: "d1"}}}},
+		{mr: &v1beta1.ManagedResource{ClusterObjectReference: apicommon.ClusterObjectReference{Cluster: "c1", ObjectReference: corev1.ObjectReference{Namespace: "ns1", Kind: "Service", Name: "s1"}}}},
+		{mr: &v1beta1.ManagedResource{ClusterObjectReference: apicommon.ClusterObjectReference{Cluster: "c1", ObjectReference: corev1.ObjectReference{Namespace: "ns2", Kind: "ConfigMap", Name: "cm1"}}}},
+		{mr: &v1beta1.ManagedResource{ClusterObjectReference: apicommon.ClusterObjectReference{Cluster: "c2", ObjectReference: corev1.ObjectReference{Namespace: "ns1", Kind: "Ingress", Name: "i1"}}}},
+	}
+	colsWidth := make([]int, 4)
+	options.fillResourceRows(rows, colsWidth)
+
+	// Check blanking
+	r.Equal("c1", rows[0].cluster)
+	r.Equal("ns1", rows[0].namespace)
+	r.Equal("", rows[1].cluster, "cluster should be blanked for same group")
+	r.Equal("", rows[1].namespace, "namespace should be blanked for same group")
+	r.Equal("", rows[2].cluster, "cluster should be blanked for same group")
+	r.Equal("ns2", rows[2].namespace, "namespace should not be blanked for different ns")
+	r.Equal("c2", rows[3].cluster, "cluster should not be blanked for different cluster")
+
+	// Check connectors for row 1 (second item in ns1)
+	r.True(rows[1].connectClusterUp)
+	r.True(rows[0].connectClusterDown)
+	r.True(rows[1].connectNamespaceUp)
+	r.True(rows[0].connectNamespaceDown)
+
+	// Check connectors for row 2 (first item in ns2)
+	r.True(rows[2].connectClusterUp)
+	r.True(rows[1].connectClusterDown)
+	r.False(rows[2].connectNamespaceUp)
+	r.False(rows[1].connectNamespaceDown)
+}
+
+// mockRoundTripper for testing http clients
+type mockRoundTripper struct {
+	roundTripFunc func(req *http.Request) (*http.Response, error)
+}
+
+func (m *mockRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
+	if m.roundTripFunc != nil {
+		return m.roundTripFunc(req)
+	}
+	return &http.Response{StatusCode: http.StatusOK}, nil
+}
+
+func TestPrintResourceTree(t *testing.T) {
+	color.NoColor = true
+	defer func() { color.NoColor = false }()
+
+	mr1 := newManagedResource("c1", "ns1", "Deployment", "d1")
+	mr2 := newManagedResource("c1", "ns1", "Service", "s1")
+
+	testCases := []struct {
+		name               string
+		options            *ResourceTreePrintOptions
+		placements         []v1alpha1.PlacementDecision
+		currentRT          *v1beta1.ResourceTracker
+		historyRT          []*v1beta1.ResourceTracker
+		expectedSubstrings []string
+	}{
+		{
+			name:               "simple case with current and history",
+			options:            &ResourceTreePrintOptions{ClusterNameMapper: MockClusterNameMapper{}},
+			currentRT:          &v1beta1.ResourceTracker{Spec: v1beta1.ResourceTrackerSpec{ManagedResources: []v1beta1.ManagedResource{mr1}}},
+			historyRT:          []*v1beta1.ResourceTracker{{Spec: v1beta1.ResourceTrackerSpec{ManagedResources: []v1beta1.ManagedResource{mr1, mr2}}}},
+			expectedSubstrings: []string{"CLUSTER", "NAMESPACE", "RESOURCE", "STATUS", "c1", "ns1", "Deployment/d1", "updated", "Service/s1", "outdated"},
+		},
+		{
+			name:               "with not-deployed placement",
+			options:            &ResourceTreePrintOptions{ClusterNameMapper: MockClusterNameMapper{}},
+			placements:         []v1alpha1.PlacementDecision{{Cluster: "c2"}},
+			expectedSubstrings: []string{"c2", "not-deployed"},
+		},
+		{
+			name: "with detail retriever",
+			options: &ResourceTreePrintOptions{
+				ClusterNameMapper: MockClusterNameMapper{},
+				DetailRetriever: func(row *resourceRow, format string) error {
+					row.applyTime = "2021-01-01"
+					row.details = "detail-info"
+					return nil
+				},
+			},
+			currentRT:          &v1beta1.ResourceTracker{Spec: v1beta1.ResourceTrackerSpec{ManagedResources: []v1beta1.ManagedResource{mr1}}},
+			expectedSubstrings: []string{"APPLY_TIME", "DETAIL", "2021-01-01", "detail-info"},
+		},
+		{
+			name: "with detail retriever error",
+			options: &ResourceTreePrintOptions{
+				ClusterNameMapper: MockClusterNameMapper{},
+				DetailRetriever: func(row *resourceRow, format string) error {
+					return fmt.Errorf("mock error")
+				},
+			},
+			currentRT:          &v1beta1.ResourceTracker{Spec: v1beta1.ResourceTrackerSpec{ManagedResources: []v1beta1.ManagedResource{mr1}}},
+			expectedSubstrings: []string{"Error: mock error"},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			r := require.New(t)
+			var buf bytes.Buffer
+			tc.options.PrintResourceTree(&buf, tc.placements, tc.currentRT, tc.historyRT)
+			output := buf.String()
+			for _, sub := range tc.expectedSubstrings {
+				r.Contains(output, sub)
+			}
+		})
+	}
+}
+
+func TestTableRoundTripper(t *testing.T) {
+	r := require.New(t)
+
+	var capturedReq *http.Request
+
+	mockRT := &mockRoundTripper{
+		roundTripFunc: func(req *http.Request) (*http.Response, error) {
+			capturedReq = req
+			return &http.Response{StatusCode: http.StatusOK}, nil
+		},
+	}
+
+	tableRT := tableRoundTripper{rt: mockRT}
+
+	req, err := http.NewRequest("GET", "http://localhost", nil)
+	r.NoError(err)
+
+	_, err = tableRT.RoundTrip(req)
+	r.NoError(err)
+
+	r.NotNil(capturedReq)
+	expectedAccept := "application/json;as=Table;v=v1;g=meta.k8s.io,application/json"
+	r.Equal(expectedAccept, capturedReq.Header.Get("Accept"))
+}
diff --git a/pkg/schema/schema_test.go b/pkg/schema/schema_test.go
index f4748cd4..8089e28f 100644
--- a/pkg/schema/schema_test.go
+++ b/pkg/schema/schema_test.go
@@ -17,6 +17,7 @@ limitations under the License.
 package schema
 
 import (
+	"context"
 	"os"
 	"path/filepath"
 	"testing"
@@ -25,6 +26,7 @@ import (
 	"github.com/stretchr/testify/assert"
 
 	"github.com/oam-dev/kubevela/pkg/cue/process"
+	"github.com/oam-dev/kubevela/pkg/oam/util"
 )
 
 const TestDir = "testdata"
@@ -59,3 +61,138 @@ func TestFixOpenAPISchema(t *testing.T) {
 		})
 	}
 }
+
+func TestParsePropertiesToSchema(t *testing.T) {
+	ctx := context.Background()
+	cases := []struct {
+		name      string
+		cue       string
+		path      []string
+		wantErr   bool
+		checkFunc func(t *testing.T, schema *openapi3.Schema)
+	}{
+		{
+			name: "happy path no path",
+			cue: `parameter: {
+				name: string
+				age: int
+			}`,
+			wantErr: false,
+			checkFunc: func(t *testing.T, schema *openapi3.Schema) {
+				r := assert.New(t)
+				r.NotNil(schema)
+				r.Contains(schema.Properties, "name")
+				r.Contains(schema.Properties, "age")
+				r.Equal("string", (*schema.Properties["name"].Value.Type)[0])
+				r.Equal("integer", (*schema.Properties["age"].Value.Type)[0])
+			},
+		},
+		{
+			name: "happy path with path",
+			cue: `
+			template: {
+				parameter: {
+					address: string
+				}
+			}`,
+			path:    []string{"template"},
+			wantErr: false,
+			checkFunc: func(t *testing.T, schema *openapi3.Schema) {
+				r := assert.New(t)
+				r.NotNil(schema)
+				r.Contains(schema.Properties, "address")
+				r.Len(schema.Properties, 1)
+			},
+		},
+		{
+			name:    "invalid cue string",
+			cue:     `parameter: { name: }`,
+			wantErr: true,
+		},
+		{
+			name:    "invalid path",
+			cue:     `parameter: { name: string }`,
+			path:    []string{"bad-path"},
+			wantErr: true,
+		},
+	}
+
+	for _, tc := range cases {
+		t.Run(tc.name, func(t *testing.T) {
+			schema, err := ParsePropertiesToSchema(ctx, tc.cue, tc.path...)
+			if tc.wantErr {
+				assert.Error(t, err)
+			} else {
+				assert.NoError(t, err)
+				if tc.checkFunc != nil {
+					tc.checkFunc(t, schema)
+				}
+			}
+		})
+	}
+}
+
+func TestConvertOpenAPISchema2SwaggerObject(t *testing.T) {
+	cases := []struct {
+		name      string
+		jsonData  []byte
+		wantErr   bool
+		errString string
+		checkFunc func(*testing.T, *openapi3.Schema)
+	}{
+		{
+			name: "happy path",
+			jsonData: []byte(`{
+				"openapi": "3.0.0",
+				"info": { "title": "My API", "version": "1.0.0" },
+				"paths": {},
+				"components": {
+					"schemas": {
+						"parameter": {
+							"type": "object",
+							"properties": { "name": { "type": "string" } }
+						}
+					}
+				}
+			}`),
+			wantErr: false,
+			checkFunc: func(t *testing.T, schema *openapi3.Schema) {
+				assert.NotNil(t, schema)
+				assert.Contains(t, schema.Properties, "name")
+			},
+		},
+		{
+			name:     "invalid json",
+			jsonData: []byte(`{"bad"`),
+			wantErr:  true,
+		},
+		{
+			name: "missing parameter schema",
+			jsonData: []byte(`{
+				"openapi": "3.0.0",
+				"info": { "title": "My API", "version": "1.0.0" },
+				"paths": {},
+				"components": { "schemas": { "other": {} } }
+			}`),
+			wantErr:   true,
+			errString: util.ErrGenerateOpenAPIV2JSONSchemaForCapability,
+		},
+	}
+
+	for _, tc := range cases {
+		t.Run(tc.name, func(t *testing.T) {
+			schema, err := ConvertOpenAPISchema2SwaggerObject(tc.jsonData)
+			if tc.wantErr {
+				assert.Error(t, err)
+				if tc.errString != "" {
+					assert.EqualError(t, err, tc.errString)
+				}
+			} else {
+				assert.NoError(t, err)
+				if tc.checkFunc != nil {
+					tc.checkFunc(t, schema)
+				}
+			}
+		})
+	}
+}
diff --git a/pkg/utils/env/env_test.go b/pkg/utils/env/env_test.go
index ee1889b8..11fa49a2 100644
--- a/pkg/utils/env/env_test.go
+++ b/pkg/utils/env/env_test.go
@@ -17,85 +17,317 @@ limitations under the License.
 package env
 
 import (
+	"context"
+	"encoding/json"
+	"os"
+	"path/filepath"
 	"testing"
 	"time"
 
-	"path/filepath"
-
-	"github.com/google/go-cmp/cmp"
 	"github.com/kubevela/pkg/util/singleton"
 	"github.com/stretchr/testify/assert"
+	v1 "k8s.io/api/core/v1"
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
 	"k8s.io/client-go/rest"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/envtest"
 
+	"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/system"
 )
 
-var testEnv *envtest.Environment
 var cfg *rest.Config
-var rawClient client.Client
+var k8sClient client.Client
 var testScheme = runtime.NewScheme()
 
-func TestCreateEnv(t *testing.T) {
-
-	testEnv = &envtest.Environment{
+func TestMain(m *testing.M) {
+	testEnv := &envtest.Environment{
 		ControlPlaneStartTimeout: time.Minute,
 		ControlPlaneStopTimeout:  time.Minute,
 		CRDDirectoryPaths: []string{
-			filepath.Join("../../..", "charts/vela-core/crds"), // this has all the required CRDs,
+			filepath.Join("../../..", "charts/vela-core/crds"),
 		},
 	}
+
 	var err error
 	cfg, err = testEnv.Start()
-	assert.NoError(t, err)
-	defer func() {
-		assert.NoError(t, testEnv.Stop())
-	}()
-	assert.NoError(t, clientgoscheme.AddToScheme(testScheme))
+	if err != nil {
+		panic(err)
+	}
 
-	rawClient, err = client.New(cfg, client.Options{Scheme: testScheme})
-	assert.NoError(t, err)
+	if err := clientgoscheme.AddToScheme(testScheme); err != nil {
+		panic(err)
+	}
+	if err := v1beta1.AddToScheme(testScheme); err != nil {
+		panic(err)
+	}
 
-	type want struct {
-		data string
+	k8sClient, err = client.New(cfg, client.Options{Scheme: testScheme})
+	if err != nil {
+		panic(err)
 	}
-	testcases := []struct {
-		name    string
-		envMeta *types.EnvMeta
-		want    want
-	}{
-		{
-			name: "env-application",
-			envMeta: &types.EnvMeta{
-				Name:      "env-application",
-				Namespace: "default",
-			},
-			want: want{
-				data: "",
-			},
-		},
-		{
-			name: "default",
-			envMeta: &types.EnvMeta{
-				Name:      "default",
-				Namespace: "default",
-			},
-			want: want{
-				data: "the namespace default was already assigned to env env-application",
-			},
-		},
+	singleton.KubeClient.Set(k8sClient)
+
+	code := m.Run()
+
+	if err := testEnv.Stop(); err != nil {
+		panic(err)
 	}
-	for _, tc := range testcases {
-		t.Run(tc.name, func(t *testing.T) {
-			singleton.KubeClient.Set(rawClient)
-			err = CreateEnv(tc.envMeta)
-			if err != nil && cmp.Diff(tc.want.data, err.Error()) != "" {
-				t.Errorf("CreateEnv(...): \n -want: \n%s,\n +got:\n%s", tc.want.data, err.Error())
-			}
-		})
+
+	os.Exit(code)
+}
+
+func createTestNamespace(ctx context.Context, t *testing.T, nsName string) {
+	ns := &v1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: nsName}}
+	err := k8sClient.Create(ctx, ns)
+	if err != nil && !apierrors.IsAlreadyExists(err) {
+		assert.NoError(t, err)
 	}
+}
+
+func TestCreateEnv(t *testing.T) {
+	ctx := context.Background()
+	t.Run("create a new env successfully", func(t *testing.T) {
+		nsName := "create-env-ns-1"
+		createTestNamespace(ctx, t, nsName)
+		envMeta := &types.EnvMeta{Name: "env-create-1", Namespace: nsName}
+		err := CreateEnv(envMeta)
+		assert.NoError(t, err)
+
+		var createdNs v1.Namespace
+		err = k8sClient.Get(ctx, client.ObjectKey{Name: nsName}, &createdNs)
+		assert.NoError(t, err)
+		assert.Equal(t, "env-create-1", createdNs.Labels[oam.LabelNamespaceOfEnvName])
+		assert.Equal(t, oam.VelaNamespaceUsageEnv, createdNs.Labels[oam.LabelControlPlaneNamespaceUsage])
+	})
+
+	t.Run("create env with a name that already exists", func(t *testing.T) {
+		nsName1, nsName2 := "create-env-ns-2", "create-env-ns-3"
+		createTestNamespace(ctx, t, nsName1)
+		createTestNamespace(ctx, t, nsName2)
+
+		envMeta1 := &types.EnvMeta{Name: "env-exist", Namespace: nsName1}
+		err := CreateEnv(envMeta1)
+		assert.NoError(t, err)
+
+		envMeta2 := &types.EnvMeta{Name: "env-exist", Namespace: nsName2}
+		err = CreateEnv(envMeta2)
+		assert.Error(t, err)
+		assert.Equal(t, "env name env-exist already exists", err.Error())
+	})
+
+	t.Run("create env in a namespace that is already used by another env", func(t *testing.T) {
+		nsName := "create-env-ns-4"
+		createTestNamespace(ctx, t, nsName)
+
+		envMeta1 := &types.EnvMeta{Name: "env-ns-used-1", Namespace: nsName}
+		err := CreateEnv(envMeta1)
+		assert.NoError(t, err)
+
+		envMeta2 := &types.EnvMeta{Name: "env-ns-used-2", Namespace: nsName}
+		err = CreateEnv(envMeta2)
+		assert.Error(t, err)
+		assert.Equal(t, "the namespace create-env-ns-4 was already assigned to env env-ns-used-1", err.Error())
+	})
+}
+
+func TestGetEnvByName(t *testing.T) {
+	ctx := context.Background()
+	nsName := "get-env-ns"
+	envName := "test-get"
+	createTestNamespace(ctx, t, nsName)
+	assert.NoError(t, CreateEnv(&types.EnvMeta{Name: envName, Namespace: nsName}))
+
+	t.Run("get existing env", func(t *testing.T) {
+		env, err := GetEnvByName(envName)
+		assert.NoError(t, err)
+		assert.Equal(t, envName, env.Name)
+		assert.Equal(t, nsName, env.Namespace)
+	})
+
+	t.Run("get default env", func(t *testing.T) {
+		env, err := GetEnvByName("default")
+		assert.NoError(t, err)
+		assert.Equal(t, "default", env.Name)
+		assert.Equal(t, "default", env.Namespace)
+	})
+
+	t.Run("get non-existent env", func(t *testing.T) {
+		_, err := GetEnvByName("non-existent")
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "not exist")
+	})
+}
+
+func TestListAndCurrentEnvs(t *testing.T) {
+	ctx := context.Background()
+	// Setup a temp home for current env file
+	tmpDir, err := os.MkdirTemp("", "vela-home")
+	assert.NoError(t, err)
+	defer os.RemoveAll(tmpDir)
+	t.Setenv("HOME", tmpDir)
+
+	// Create test envs
+	nsList1, envList1 := "list-env-ns-1", "test-list-1"
+	createTestNamespace(ctx, t, nsList1)
+	assert.NoError(t, CreateEnv(&types.EnvMeta{Name: envList1, Namespace: nsList1}))
+
+	nsList2, envList2 := "list-env-ns-2", "test-list-2"
+	createTestNamespace(ctx, t, nsList2)
+	assert.NoError(t, CreateEnv(&types.EnvMeta{Name: envList2, Namespace: nsList2}))
+
+	t.Run("list specific env", func(t *testing.T) {
+		envs, err := ListEnvs(envList1)
+		assert.NoError(t, err)
+		assert.Equal(t, 1, len(envs))
+		assert.Equal(t, envList1, envs[0].Name)
+	})
+
+	t.Run("list non-existent env", func(t *testing.T) {
+		_, err := ListEnvs("non-existent-list")
+		assert.Error(t, err)
+	})
+
+	t.Run("list all envs and check current marker", func(t *testing.T) {
+		envs, err := ListEnvs("")
+		assert.NoError(t, err)
+		found1, found2, current := false, false, false
+		for _, e := range envs {
+			if e.Name == envList1 {
+				found1 = true
+			}
+			if e.Name == envList2 {
+				found2 = true
+			}
+			if e.Current == "*" {
+				current = true
+			}
+		}
+		assert.True(t, found1)
+		assert.True(t, found2)
+		assert.True(t, current) // ListEnvs should set a default current env
+	})
+
+	t.Run("set and get current env", func(t *testing.T) {
+		testEnvForCurrent := &types.EnvMeta{Name: envList2, Namespace: nsList2}
+		err := SetCurrentEnv(testEnvForCurrent)
+		assert.NoError(t, err)
+
+		curEnv, err := GetCurrentEnv()
+		assert.NoError(t, err)
+		assert.Equal(t, envList2, curEnv.Name)
+
+		// Verify ListEnvs reflects the new current env
+		envs, err := ListEnvs("")
+		assert.NoError(t, err)
+		for _, e := range envs {
+			if e.Name == envList2 {
+				assert.Equal(t, "*", e.Current)
+			} else {
+				assert.Equal(t, "", e.Current)
+			}
+		}
+	})
+
+	t.Run("get current env with legacy format", func(t *testing.T) {
+		envPath, err := system.GetCurrentEnvPath()
+		assert.NoError(t, err)
+		err = os.WriteFile(envPath, []byte(envList1), 0644)
+		assert.NoError(t, err)
+
+		curEnv, err := GetCurrentEnv()
+		assert.NoError(t, err)
+		assert.Equal(t, envList1, curEnv.Name)
+		assert.Equal(t, nsList1, curEnv.Namespace)
+
+		// Check if the format was updated
+		data, err := os.ReadFile(filepath.Clean(envPath))
+		assert.NoError(t, err)
+		var envMeta types.EnvMeta
+		assert.NoError(t, json.Unmarshal(data, &envMeta))
+		assert.Equal(t, envList1, envMeta.Name)
+	})
+}
+
+func TestSetEnvLabels(t *testing.T) {
+	ctx := context.Background()
+	nsName := "set-labels-ns"
+	envName := "test-labels"
+	createTestNamespace(ctx, t, nsName)
+	assert.NoError(t, CreateEnv(&types.EnvMeta{Name: envName, Namespace: nsName}))
+
+	t.Run("set valid labels", func(t *testing.T) {
+		envMeta := &types.EnvMeta{Name: envName, Labels: "foo=bar,hello=world"}
+		err := SetEnvLabels(envMeta)
+		assert.NoError(t, err)
+
+		ns := &v1.Namespace{}
+		err = k8sClient.Get(ctx, client.ObjectKey{Name: nsName}, ns)
+		assert.NoError(t, err)
+		assert.Equal(t, "bar", ns.Labels["foo"])
+		assert.Equal(t, "world", ns.Labels["hello"])
+	})
+
+	t.Run("set labels on non-existent env", func(t *testing.T) {
+		envMeta := &types.EnvMeta{Name: "non-existent-labels"}
+		err := SetEnvLabels(envMeta)
+		assert.Error(t, err)
+	})
+
+	t.Run("set invalid labels", func(t *testing.T) {
+		envMeta := &types.EnvMeta{Name: envName, Labels: "invalid-label"}
+		err := SetEnvLabels(envMeta)
+		assert.Error(t, err)
+	})
+}
+
+func TestDeleteEnv(t *testing.T) {
+	ctx := context.Background()
+	t.Run("delete env with application", func(t *testing.T) {
+		nsName := "delete-env-ns-with-app"
+		envName := "test-delete-with-app"
+		createTestNamespace(ctx, t, nsName)
+		assert.NoError(t, CreateEnv(&types.EnvMeta{Name: envName, Namespace: nsName}))
+
+		app := &v1beta1.Application{
+			ObjectMeta: metav1.ObjectMeta{Name: "test-app", Namespace: nsName},
+			Spec: v1beta1.ApplicationSpec{
+				Components: []common.ApplicationComponent{{Name: "c1", Type: "worker"}},
+			},
+		}
+		err := k8sClient.Create(ctx, app)
+		assert.NoError(t, err)
+
+		_, err = DeleteEnv(envName)
+		assert.Error(t, err)
+		assert.Contains(t, err.Error(), "you can't delete this environment")
+	})
+
+	t.Run("delete empty env", func(t *testing.T) {
+		nsName := "delete-env-ns-empty"
+		envName := "test-delete-empty"
+		createTestNamespace(ctx, t, nsName)
+		assert.NoError(t, CreateEnv(&types.EnvMeta{Name: envName, Namespace: nsName}))
+
+		msg, err := DeleteEnv(envName)
+		assert.NoError(t, err)
+		assert.Equal(t, "env "+envName+" deleted", msg)
+
+		ns := &v1.Namespace{}
+		err = k8sClient.Get(ctx, client.ObjectKey{Name: nsName}, ns)
+		assert.NoError(t, err)
+		assert.Equal(t, "", ns.Labels[oam.LabelNamespaceOfEnvName])
+		assert.Equal(t, "", ns.Labels[oam.LabelControlPlaneNamespaceUsage])
+	})
 
+	t.Run("delete non-existent env", func(t *testing.T) {
+		_, err := DeleteEnv("non-existent-delete")
+		assert.Error(t, err)
+	})
 }
diff --git a/pkg/utils/errors/crd_test.go b/pkg/utils/errors/crd_test.go
new file mode 100644
index 00000000..45a6825c
--- /dev/null
+++ b/pkg/utils/errors/crd_test.go
@@ -0,0 +1,69 @@
+/*
+Copyright 2020-2022 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 errors
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/pkg/errors"
+	"github.com/stretchr/testify/assert"
+	"k8s.io/apimachinery/pkg/api/meta"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+func TestIsCRDNotExists(t *testing.T) {
+	noKindMatchErr := &meta.NoKindMatchError{
+		GroupKind: schema.GroupKind{Group: "testgroup", Kind: "testkind"},
+	}
+	wrappedErr := errors.Wrap(noKindMatchErr, "wrapped")
+	otherErr := fmt.Errorf("some other error")
+
+	testCases := []struct {
+		name     string
+		err      error
+		expected bool
+	}{
+		{
+			name:     "is a NoKindMatchError",
+			err:      noKindMatchErr,
+			expected: true,
+		},
+		{
+			name:     "is a wrapped NoKindMatchError",
+			err:      wrappedErr,
+			expected: true,
+		},
+		{
+			name:     "is another error",
+			err:      otherErr,
+			expected: false,
+		},
+		{
+			name:     "is nil",
+			err:      nil,
+			expected: false,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			result := IsCRDNotExists(tc.err)
+			assert.Equal(t, tc.expected, result)
+		})
+	}
+}
diff --git a/pkg/utils/errors/list_test.go b/pkg/utils/errors/list_test.go
new file mode 100644
index 00000000..30e35c4a
--- /dev/null
+++ b/pkg/utils/errors/list_test.go
@@ -0,0 +1,95 @@
+/*
+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 errors
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestErrorList(t *testing.T) {
+	t.Run("HasError", func(t *testing.T) {
+		var nilList ErrorList
+		assert.False(t, nilList.HasError())
+
+		emptyList := ErrorList{}
+		assert.False(t, emptyList.HasError())
+
+		listWithErr := ErrorList{fmt.Errorf("err1")}
+		assert.True(t, listWithErr.HasError())
+	})
+
+	t.Run("Error", func(t *testing.T) {
+		var nilList ErrorList
+		assert.Equal(t, "", nilList.Error())
+
+		emptyList := ErrorList{}
+		assert.Equal(t, "", emptyList.Error())
+
+		listWithOneErr := ErrorList{fmt.Errorf("err1")}
+		assert.Equal(t, "Found 1 errors. [(err1)]", listWithOneErr.Error())
+
+		listWithTwoErrs := ErrorList{fmt.Errorf("err1"), fmt.Errorf("err2")}
+		assert.Equal(t, "Found 2 errors. [(err1), (err2)]", listWithTwoErrs.Error())
+	})
+}
+
+func TestAggregateErrors(t *testing.T) {
+	err1 := fmt.Errorf("err1")
+	err2 := fmt.Errorf("err2")
+
+	testCases := []struct {
+		name     string
+		errs     []error
+		expected error
+	}{
+		{
+			name:     "multiple non-nil errors",
+			errs:     []error{err1, err2},
+			expected: ErrorList{err1, err2},
+		},
+		{
+			name:     "some nil errors",
+			errs:     []error{nil, err1, nil, err2, nil},
+			expected: ErrorList{err1, err2},
+		},
+		{
+			name:     "only nil errors",
+			errs:     []error{nil, nil, nil},
+			expected: nil,
+		},
+		{
+			name:     "empty slice",
+			errs:     []error{},
+			expected: nil,
+		},
+		{
+			name:     "nil slice",
+			errs:     nil,
+			expected: nil,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			result := AggregateErrors(tc.errs)
+			assert.Equal(t, tc.expected, result)
+		})
+	}
+}
diff --git a/pkg/utils/errors/reason_test.go b/pkg/utils/errors/reason_test.go
new file mode 100644
index 00000000..4fe3cd36
--- /dev/null
+++ b/pkg/utils/errors/reason_test.go
@@ -0,0 +1,102 @@
+/*
+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 errors
+
+import (
+	"errors"
+	"fmt"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestIsLabelConflict(t *testing.T) {
+	testCases := []struct {
+		name     string
+		err      error
+		expected bool
+	}{
+		{
+			name:     "error contains LabelConflict",
+			err:      fmt.Errorf("this is a LabelConflict error"),
+			expected: true,
+		},
+		{
+			name:     "error is exactly LabelConflict",
+			err:      errors.New(LabelConflict),
+			expected: true,
+		},
+		{
+			name:     "error does not contain LabelConflict",
+			err:      fmt.Errorf("some other error"),
+			expected: false,
+		},
+		{
+			name:     "error is nil",
+			err:      nil,
+			expected: false,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			result := IsLabelConflict(tc.err)
+			assert.Equal(t, tc.expected, result)
+		})
+	}
+}
+
+func TestIsCuePathNotFound(t *testing.T) {
+	testCases := []struct {
+		name     string
+		err      error
+		expected bool
+	}{
+		{
+			name:     "error contains both substrings",
+			err:      fmt.Errorf("failed to lookup value: the path a.b.c does not exist"),
+			expected: true,
+		},
+		{
+			name:     "error contains only first substring",
+			err:      fmt.Errorf("failed to lookup value"),
+			expected: false,
+		},
+		{
+			name:     "error contains only second substring",
+			err:      fmt.Errorf("the path does not exist"),
+			expected: false,
+		},
+		{
+			name:     "error contains neither substring",
+			err:      fmt.Errorf("some other error"),
+			expected: false,
+		},
+		{
+			name:     "is nil",
+			err:      nil,
+			expected: false,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			result := IsCuePathNotFound(tc.err)
+			assert.Equal(t, tc.expected, result)
+		})
+	}
+}
diff --git a/pkg/utils/errors/resourcetracker_test.go b/pkg/utils/errors/resourcetracker_test.go
new file mode 100644
index 00000000..5bf4086d
--- /dev/null
+++ b/pkg/utils/errors/resourcetracker_test.go
@@ -0,0 +1,28 @@
+/*
+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 errors
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestManagedResourceHasNoDataError(t *testing.T) {
+	err := ManagedResourceHasNoDataError{}
+	assert.EqualError(t, err, "ManagedResource has no data")
+}
diff --git a/pkg/utils/json_test.go b/pkg/utils/json_test.go
new file mode 100644
index 00000000..d12205f6
--- /dev/null
+++ b/pkg/utils/json_test.go
@@ -0,0 +1,86 @@
+/*
+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 utils
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestStrictUnmarshal(t *testing.T) {
+	t.Parallel()
+
+	type sampleStruct struct {
+		Name string `json:"name"`
+		Age  int    `json:"age"`
+	}
+
+	testCases := []struct {
+		name       string
+		json       string
+		dest       interface{}
+		expectErr  bool
+		assertFunc func(*testing.T, interface{})
+	}{
+		{
+			name:      "valid json",
+			json:      `{"name": "test", "age": 10}`,
+			dest:      &sampleStruct{},
+			expectErr: false,
+			assertFunc: func(t *testing.T, dest interface{}) {
+				s := dest.(*sampleStruct)
+				require.Equal(t, "test", s.Name)
+				require.Equal(t, 10, s.Age)
+			},
+		},
+		{
+			name:      "unknown field",
+			json:      `{"name": "test", "age": 10, "extra": "field"}`,
+			dest:      &sampleStruct{},
+			expectErr: true,
+		},
+		{
+			name:      "invalid json",
+			json:      `{"name": "test", "age": 10,}`,
+			dest:      &sampleStruct{},
+			expectErr: true,
+		},
+		{
+			name:      "empty json",
+			json:      ``,
+			dest:      &sampleStruct{},
+			expectErr: true, // EOF
+		},
+	}
+
+	for _, tc := range testCases {
+		tc := tc
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			err := StrictUnmarshal([]byte(tc.json), tc.dest)
+			if tc.expectErr {
+				require.Error(t, err)
+			} else {
+				require.NoError(t, err)
+				if tc.assertFunc != nil {
+					tc.assertFunc(t, tc.dest)
+				}
+			}
+		})
+	}
+}
diff --git a/pkg/utils/jwt_test.go b/pkg/utils/jwt_test.go
new file mode 100644
index 00000000..e0970f66
--- /dev/null
+++ b/pkg/utils/jwt_test.go
@@ -0,0 +1,166 @@
+/*
+Copyright 2022 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 utils
+
+import (
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"crypto/x509/pkix"
+	"encoding/pem"
+	"math/big"
+	"testing"
+	"time"
+
+	"github.com/form3tech-oss/jwt-go"
+	"github.com/stretchr/testify/require"
+)
+
+func TestGetTokenSubject(t *testing.T) {
+	t.Parallel()
+
+	tokenWithSub := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{"sub": "test-user"})
+	tokenWithSubStr, err := tokenWithSub.SignedString([]byte("secret"))
+	require.NoError(t, err)
+
+	tokenWithoutSub := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{"user": "test-user"})
+	tokenWithoutSubStr, err := tokenWithoutSub.SignedString([]byte("secret"))
+	require.NoError(t, err)
+
+	testCases := []struct {
+		name        string
+		token       string
+		expectedSub string
+		expectErr   bool
+	}{
+		{
+			name:        "valid token with sub",
+			token:       tokenWithSubStr,
+			expectedSub: "test-user",
+			// An error is returned because the signature cannot be verified without a key func,
+			// but the subject should still be extracted.
+			expectErr: true,
+		},
+		{
+			name:        "valid token without sub",
+			token:       tokenWithoutSubStr,
+			expectedSub: "",
+			expectErr:   true,
+		},
+		{
+			name:        "malformed token",
+			token:       "a.b.c",
+			expectedSub: "",
+			expectErr:   true,
+		},
+		{
+			name:        "empty token",
+			token:       "",
+			expectedSub: "",
+			expectErr:   true,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			sub, err := GetTokenSubject(tc.token)
+			if tc.expectErr {
+				require.Error(t, err)
+			}
+			require.Equal(t, tc.expectedSub, sub)
+		})
+	}
+}
+
+func generateTestCert(t *testing.T, subject pkix.Name) []byte {
+	t.Helper()
+	priv, err := rsa.GenerateKey(rand.Reader, 2048)
+	require.NoError(t, err)
+
+	template := x509.Certificate{
+		SerialNumber:          big.NewInt(1),
+		Subject:               subject,
+		NotBefore:             time.Now(),
+		NotAfter:              time.Now().Add(time.Hour),
+		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+		BasicConstraintsValid: true,
+	}
+
+	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
+	require.NoError(t, err)
+
+	pemBytes := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
+	return pemBytes
+}
+
+func TestGetCertificateSubject(t *testing.T) {
+	t.Parallel()
+	subject := pkix.Name{CommonName: "test.example.com"}
+	certPEM := generateTestCert(t, subject)
+
+	testCases := []struct {
+		name            string
+		certBytes       []byte
+		expectedSubject *pkix.Name
+		expectErr       bool
+	}{
+		{
+			name:            "valid cert",
+			certBytes:       certPEM,
+			expectedSubject: &subject,
+			expectErr:       false,
+		},
+		{
+			name:            "empty bytes",
+			certBytes:       []byte{},
+			expectedSubject: nil,
+			expectErr:       false,
+		},
+		{
+			name:            "not a pem block",
+			certBytes:       []byte("not pem"),
+			expectedSubject: nil,
+			expectErr:       false,
+		},
+		{
+			name:            "invalid cert bytes in pem",
+			certBytes:       pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: []byte("invalid")}),
+			expectedSubject: nil,
+			expectErr:       true,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			s, err := GetCertificateSubject(tc.certBytes)
+			if tc.expectErr {
+				require.Error(t, err)
+			} else {
+				require.NoError(t, err)
+				if tc.expectedSubject == nil {
+					require.Nil(t, s)
+				} else {
+					require.NotNil(t, s)
+					require.Equal(t, tc.expectedSubject.String(), s.String())
+				}
+			}
+		})
+	}
+}
diff --git a/pkg/utils/parse_test.go b/pkg/utils/parse_test.go
index f6830211..e9193a50 100644
--- a/pkg/utils/parse_test.go
+++ b/pkg/utils/parse_test.go
@@ -51,3 +51,142 @@ func TestByteCountIEC(t *testing.T) {
 		})
 	}
 }
+
+func TestParse(t *testing.T) {
+	testCases := []struct {
+		name        string
+		addr        string
+		wantType    string
+		wantContent *Content
+		wantErr     bool
+	}{
+		{
+			name:        "github url with branch",
+			addr:        "https://github.com/kubevela/catalog/tree/master/addons/fluxcd",
+			wantType:    TypeGithub,
+			wantContent: &Content{GithubContent: GithubContent{Owner: "kubevela", Repo: "catalog", Path: "addons/fluxcd", Ref: "master"}},
+		},
+		{
+			name:        "github url without branch",
+			addr:        "https://github.com/kubevela/catalog/addons/fluxcd",
+			wantType:    TypeGithub,
+			wantContent: &Content{GithubContent: GithubContent{Owner: "kubevela", Repo: "catalog", Path: "addons/fluxcd", Ref: ""}},
+		},
+		{
+			name:        "github api url with single segment path",
+			addr:        "https://api.github.com/repos/kubevela/catalog/contents/my-addon?ref=master",
+			wantType:    TypeGithub,
+			wantContent: &Content{GithubContent: GithubContent{Owner: "kubevela", Repo: "catalog", Path: "my-addon", Ref: "master"}},
+		},
+		{
+			name:        "gitee url with branch",
+			addr:        "https://gitee.com/kubevela/catalog/tree/master/addons/fluxcd",
+			wantType:    TypeGitee,
+			wantContent: &Content{GiteeContent: GiteeContent{Owner: "kubevela", Repo: "catalog", Path: "addons/fluxcd", Ref: "master"}},
+		},
+		{
+			name:        "gitee url without branch",
+			addr:        "https://gitee.com/kubevela/catalog/addons/fluxcd",
+			wantType:    TypeGitee,
+			wantContent: &Content{GiteeContent: GiteeContent{Owner: "kubevela", Repo: "catalog", Path: "addons/fluxcd", Ref: ""}},
+		},
+		{
+			name:        "oss url",
+			addr:        "oss://kubevela-contrib/registry",
+			wantType:    TypeOss,
+			wantContent: &Content{OssContent: OssContent{EndPoint: "kubevela-contrib", Bucket: "/registry"}},
+		},
+		{
+			name:        "local url",
+			addr:        "file:///Users/somebody/addons",
+			wantType:    TypeLocal,
+			wantContent: &Content{LocalContent: LocalContent{AbsDir: "/Users/somebody/addons"}},
+		},
+		{
+			name:    "invalid github url",
+			addr:    "https://github.com/kubevela",
+			wantErr: true,
+		},
+		{
+			name:    "unsupported git url",
+			addr:    "https://bitbucket.org/foo/bar",
+			wantErr: true,
+		},
+		{
+			name:    "malformed url",
+			addr:    "://abc",
+			wantErr: true,
+		},
+		{
+			name:     "unknown type",
+			addr:     "myscheme://foo/bar",
+			wantType: TypeUnknown,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			gotType, gotContent, err := Parse(tc.addr)
+			if tc.wantErr {
+				require.Error(t, err)
+				return
+			}
+			require.NoError(t, err)
+			require.Equal(t, tc.wantType, gotType)
+			require.Equal(t, tc.wantContent, gotContent)
+		})
+	}
+}
+
+func TestParseGitlab(t *testing.T) {
+	testCases := []struct {
+		name        string
+		addr        string
+		repo        string
+		wantType    string
+		wantContent *Content
+		wantErr     bool
+	}{
+		{
+			name:        "gitlab url without branch",
+			addr:        "https://gitlab.com/kubevela/catalog",
+			repo:        "catalog",
+			wantType:    TypeGitlab,
+			wantContent: &Content{GitlabContent: GitlabContent{Host: "https://gitlab.com", Owner: "kubevela", Repo: "catalog", Ref: ""}},
+		},
+		{
+			name:        "gitlab url with branch",
+			addr:        "https://gitlab.com/kubevela/catalog/tree/master",
+			repo:        "catalog",
+			wantType:    TypeGitlab,
+			wantContent: &Content{GitlabContent: GitlabContent{Host: "https://gitlab.com", Owner: "kubevela", Repo: "catalog", Ref: "master"}},
+		},
+		{
+			name:    "invalid gitlab url repo not match",
+			addr:    "https://gitlab.com/kubevela/catalog",
+			repo:    "wrong-repo",
+			wantErr: true,
+		},
+		{
+			name:    "malformed gitlab url",
+			addr:    "://abc",
+			repo:    "repo",
+			wantErr: true,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			gotType, gotContent, err := ParseGitlab(tc.addr, tc.repo)
+			if tc.wantErr {
+				require.Error(t, err)
+				return
+			}
+			require.NoError(t, err)
+			require.Equal(t, tc.wantType, gotType)
+			require.Equal(t, tc.wantContent, gotContent)
+		})
+	}
+}
diff --git a/pkg/utils/schema/ui_schema_test.go b/pkg/utils/schema/ui_schema_test.go
index dfe23094..fd9dfd03 100644
--- a/pkg/utils/schema/ui_schema_test.go
+++ b/pkg/utils/schema/ui_schema_test.go
@@ -19,87 +19,120 @@ package schema
 import (
 	"testing"
 
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
+	"github.com/stretchr/testify/assert"
 )
 
-var _ = Describe("Test ui schema utils", func() {
-	It("Test GetDefaultUIType function", func() {
-		testCase := []map[string]interface{}{{
-			"apiType":     "string",
-			"haveOptions": true,
-			"subType":     "",
-			"haveSub":     true,
-			"result":      "Select",
-		}, {
-			"apiType":     "string",
-			"haveOptions": false,
-			"subType":     "",
-			"haveSub":     true,
-			"result":      "Input",
-		}, {
-			"apiType":     "number",
-			"haveOptions": false,
-			"subType":     "",
-			"haveSub":     true,
-			"result":      "Number",
-		}, {
-			"apiType":     "integer",
-			"haveOptions": false,
-			"subType":     "",
-			"haveSub":     true,
-			"result":      "Number",
-		}, {
-			"apiType":     "boolean",
-			"haveOptions": false,
-			"subType":     "",
-			"haveSub":     true,
-			"result":      "Switch",
-		},
-			{
-				"apiType":     "array",
-				"haveOptions": false,
-				"subType":     "string",
-				"haveSub":     true,
-				"result":      "Strings",
-			},
-			{
-				"apiType":     "array",
-				"haveOptions": false,
-				"subType":     "",
-				"haveSub":     true,
-				"result":      "Structs",
-			},
-			{
-				"apiType":     "object",
-				"haveOptions": false,
-				"subType":     "",
-				"haveSub":     true,
-				"result":      "Group",
-			},
-			{
-				"apiType":     "object",
-				"haveOptions": false,
-				"subType":     "",
-				"haveSub":     false,
-				"result":      "KV",
-			},
-		}
-		for _, tc := range testCase {
-			uiType := GetDefaultUIType(tc["apiType"].(string), tc["haveOptions"].(bool), tc["subType"].(string), tc["haveSub"].(bool))
-			Expect(uiType).Should(Equal(tc["result"]))
-		}
-	})
-})
+func TestGetDefaultUIType(t *testing.T) {
+	testCases := []struct {
+		name        string
+		apiType     string
+		haveOptions bool
+		subType     string
+		haveSub     bool
+		expected    string
+	}{
+		{
+			name:        "string with options",
+			apiType:     "string",
+			haveOptions: true,
+			expected:    "Select",
+		},
+		{
+			name:        "string without options",
+			apiType:     "string",
+			haveOptions: false,
+			expected:    "Input",
+		},
+		{
+			name:     "number",
+			apiType:  "number",
+			expected: "Number",
+		},
+		{
+			name:     "integer",
+			apiType:  "integer",
+			expected: "Number",
+		},
+		{
+			name:     "boolean",
+			apiType:  "boolean",
+			expected: "Switch",
+		},
+		{
+			name:     "array of strings",
+			apiType:  "array",
+			subType:  "string",
+			expected: "Strings",
+		},
+		{
+			name:     "array of numbers",
+			apiType:  "array",
+			subType:  "number",
+			expected: "Numbers",
+		},
+		{
+			name:     "array of integers",
+			apiType:  "array",
+			subType:  "integer",
+			expected: "Numbers",
+		},
+		{
+			name:     "array of structs",
+			apiType:  "array",
+			subType:  "object",
+			expected: "Structs",
+		},
+		{
+			name:     "object with sub-parameters",
+			apiType:  "object",
+			haveSub:  true,
+			expected: "Group",
+		},
+		{
+			name:     "object without sub-parameters",
+			apiType:  "object",
+			haveSub:  false,
+			expected: "KV",
+		},
+		{
+			name:     "unknown type",
+			apiType:  "unknown",
+			expected: "Input",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			uiType := GetDefaultUIType(tc.apiType, tc.haveOptions, tc.subType, tc.haveSub)
+			assert.Equal(t, tc.expected, uiType)
+		})
+	}
+}
 
 func TestUISchema_Validate(t *testing.T) {
 	tests := []struct {
-		name    string
-		u       UISchema
-		wantErr bool
+		name        string
+		u           UISchema
+		wantErr     bool
+		errContains string
 	}{
 		{
-			name: "test validate ui schema error",
+			name: "valid schema",
+			u: UISchema{
+				{
+					Conditions: []Condition{
+						{
+							JSONKey: "key",
+							Op:      "==",
+							Action:  "enable",
+						},
+					},
+				},
+			},
+			wantErr: false,
+		},
+		{
+			name: "invalid condition with empty jsonkey",
 			u: UISchema{
 				{
 					Conditions: []Condition{
@@ -109,28 +142,137 @@ func TestUISchema_Validate(t *testing.T) {
 					},
 				},
 			},
-			wantErr: true,
+			wantErr:     true,
+			errContains: "the json key of the condition can not be empty",
 		},
 		{
-			name: "test validate ui schema success",
+			name: "invalid condition with bad action",
 			u: UISchema{
 				{
 					Conditions: []Condition{
 						{
 							JSONKey: "key",
-							Op:      "==",
-							Action:  "enable",
+							Action:  "badAction",
 						},
 					},
 				},
 			},
+			wantErr:     true,
+			errContains: "the action of the condition only supports enable, disable or leave it empty",
+		},
+		{
+			name: "invalid condition with bad op",
+			u: UISchema{
+				{
+					Conditions: []Condition{
+						{
+							JSONKey: "key",
+							Op:      "badOp",
+						},
+					},
+				},
+			},
+			wantErr:     true,
+			errContains: "the op of the condition must be `==` 、`!=` and `in`",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			err := tt.u.Validate()
+			if tt.wantErr {
+				assert.Error(t, err)
+				assert.Contains(t, err.Error(), tt.errContains)
+			} else {
+				assert.NoError(t, err)
+			}
+		})
+	}
+}
+
+func TestCondition_Validate(t *testing.T) {
+	tests := []struct {
+		name        string
+		c           Condition
+		wantErr     bool
+		errContains string
+	}{
+		{
+			name: "valid case with defaults",
+			c: Condition{
+				JSONKey: "myKey",
+				Value:   "myValue",
+			},
 			wantErr: false,
 		},
+		{
+			name: "valid case with all fields",
+			c: Condition{
+				JSONKey: "myKey",
+				Op:      "==",
+				Value:   "myValue",
+				Action:  "enable",
+			},
+			wantErr: false,
+		},
+		{
+			name: "valid op !=",
+			c: Condition{
+				JSONKey: "myKey",
+				Op:      "!=",
+			},
+			wantErr: false,
+		},
+		{
+			name: "valid op in",
+			c: Condition{
+				JSONKey: "myKey",
+				Op:      "in",
+			},
+			wantErr: false,
+		},
+		{
+			name: "valid action disable",
+			c: Condition{
+				JSONKey: "myKey",
+				Action:  "disable",
+			},
+			wantErr: false,
+		},
+		{
+			name: "invalid empty jsonkey",
+			c: Condition{
+				JSONKey: "",
+			},
+			wantErr:     true,
+			errContains: "the json key of the condition can not be empty",
+		},
+		{
+			name: "invalid action",
+			c: Condition{
+				JSONKey: "myKey",
+				Action:  "invalidAction",
+			},
+			wantErr:     true,
+			errContains: "the action of the condition only supports enable, disable or leave it empty",
+		},
+		{
+			name: "invalid op",
+			c: Condition{
+				JSONKey: "myKey",
+				Op:      ">",
+			},
+			wantErr:     true,
+			errContains: "the op of the condition must be `==` 、`!=` and `in`",
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			if err := tt.u.Validate(); (err != nil) != tt.wantErr {
-				t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
+			err := tt.c.Validate()
+			if tt.wantErr {
+				assert.Error(t, err)
+				assert.Contains(t, err.Error(), tt.errContains)
+			} else {
+				assert.NoError(t, err)
 			}
 		})
 	}
diff --git a/pkg/utils/strings_test.go b/pkg/utils/strings_test.go
index 7b181568..8b40f72c 100644
--- a/pkg/utils/strings_test.go
+++ b/pkg/utils/strings_test.go
@@ -17,17 +17,157 @@
 package utils
 
 import (
+	"strings"
 	"testing"
 
 	"github.com/stretchr/testify/require"
 )
 
 func TestSanitize(t *testing.T) {
-	s := "abc\ndef\rgh"
-	require.Equal(t, "abcdefgh", Sanitize(s))
+	t.Parallel()
+	testCases := []struct {
+		name  string
+		input string
+		want  string
+	}{
+		{
+			name:  "with newlines and carriage returns",
+			input: "abc\ndef\rgh",
+			want:  "abcdefgh",
+		},
+		{
+			name:  "empty string",
+			input: "",
+			want:  "",
+		},
+		{
+			name:  "no special characters",
+			input: "cleanstring",
+			want:  "cleanstring",
+		},
+		{
+			name:  "only special characters",
+			input: "\n\r\n",
+			want:  "",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			got := Sanitize(tc.input)
+			require.Equal(t, tc.want, got)
+		})
+	}
 }
 
 func TestIgnoreVPrefix(t *testing.T) {
-	require.Equal(t, "1.2.0", IgnoreVPrefix("v1.2.0"))
-	require.Equal(t, "1.2.0", IgnoreVPrefix("1.2.0"))
+	t.Parallel()
+	testCases := []struct {
+		name  string
+		input string
+		want  string
+	}{
+		{
+			name:  "with lowercase v prefix",
+			input: "v1.2.0",
+			want:  "1.2.0",
+		},
+		{
+			name:  "without v prefix",
+			input: "1.2.0",
+			want:  "1.2.0",
+		},
+		{
+			name:  "with uppercase V prefix",
+			input: "V1.3.0",
+			want:  "V1.3.0",
+		},
+		{
+			name:  "empty string",
+			input: "",
+			want:  "",
+		},
+		{
+			name:  "string is just v",
+			input: "v",
+			want:  "",
+		},
+		{
+			name:  "string is just V",
+			input: "V",
+			want:  "V",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			got := IgnoreVPrefix(tc.input)
+			require.Equal(t, tc.want, got)
+		})
+	}
+}
+
+func TestGetBoxDrawingString_Chars(t *testing.T) {
+	t.Parallel()
+	tests := []struct {
+		name        string
+		up, down    bool
+		left, right bool
+		want        rune
+	}{
+		{"cross ┼", true, true, true, true, '┼'},
+		{"up down left ┤", true, true, true, false, '┤'},
+		{"up down right ├", true, true, false, true, '├'},
+		{"up down only │", true, true, false, false, '│'},
+		{"up left right ┴", true, false, true, true, '┴'},
+		{"up left ┘", true, false, true, false, '┘'},
+		{"up right └", true, false, false, true, '└'},
+		{"up only ╵", true, false, false, false, '╵'},
+		{"down left right ┬", false, true, true, true, '┬'},
+		{"down left ┐", false, true, true, false, '┐'},
+		{"down right ┌", false, true, false, true, '┌'},
+		{"down only ╷", false, true, false, false, '╷'},
+		{"left right ─", false, false, true, true, '─'},
+		{"left only ╴", false, false, true, false, '╴'},
+		{"right only ╶", false, false, false, true, '╶'},
+		{"none space", false, false, false, false, ' '},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			got := GetBoxDrawingString(tc.up, tc.down, tc.left, tc.right, 0, 0)
+			require.Equal(t, string(tc.want), got)
+		})
+	}
+}
+
+func TestGetBoxDrawingString_Padding(t *testing.T) {
+	t.Parallel()
+	tests := []struct {
+		name                  string
+		up, down, left, right bool
+		padLeft, padRight     int
+		center                rune
+		leftPadChar           rune
+		rightPadChar          rune
+	}{
+		{"no connectors -> spaces", false, false, false, false, 2, 3, ' ', ' ', ' '},
+		{"left connector pads with lines", false, false, true, false, 2, 1, '╴', '─', ' '},
+		{"right connector pads with lines", false, false, false, true, 1, 2, '╶', ' ', '─'},
+		{"both connectors pads with lines", false, false, true, true, 2, 2, '─', '─', '─'},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			got := GetBoxDrawingString(tc.up, tc.down, tc.left, tc.right, tc.padLeft, tc.padRight)
+			leftPad := strings.Repeat(string(tc.leftPadChar), tc.padLeft)
+			rightPad := strings.Repeat(string(tc.rightPadChar), tc.padRight)
+			expected := leftPad + string(tc.center) + rightPad
+			require.Equal(t, expected, got)
+		})
+	}
 }
diff --git a/pkg/utils/system/system_test.go b/pkg/utils/system/system_test.go
index b29cadf6..beab065a 100644
--- a/pkg/utils/system/system_test.go
+++ b/pkg/utils/system/system_test.go
@@ -22,69 +22,245 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+
+	"github.com/oam-dev/kubevela/apis/types"
+	"github.com/oam-dev/kubevela/pkg/oam"
 )
 
 func TestCreateIfNotExist(t *testing.T) {
-	testDir := "TestCreateIfNotExist"
-	defer os.RemoveAll(testDir)
-
-	normalCreate := filepath.Join(testDir, "normalCase")
-	_, err := CreateIfNotExist(normalCreate)
-	assert.NoError(t, err)
-	fi, err := os.Stat(normalCreate)
-	assert.NoError(t, err)
-	assert.Equal(t, true, fi.IsDir())
-
-	normalNestCreate := filepath.Join(testDir, "nested", "normalCase")
-	_, err = CreateIfNotExist(normalNestCreate)
-	assert.NoError(t, err)
-	fi, err = os.Stat(normalNestCreate)
-	assert.NoError(t, err)
-	assert.Equal(t, true, fi.IsDir())
+	testCases := []struct {
+		name        string
+		setup       func(t *testing.T) string
+		wantExisted bool
+		wantErr     bool
+	}{
+		{
+			name: "directory does not exist",
+			setup: func(t *testing.T) string {
+				return filepath.Join(t.TempDir(), "new-dir")
+			},
+			wantExisted: false,
+			wantErr:     false,
+		},
+		{
+			name: "directory already exists",
+			setup: func(t *testing.T) string {
+				return t.TempDir()
+			},
+			wantExisted: true,
+			wantErr:     false,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			path := tc.setup(t)
+			existed, err := CreateIfNotExist(path)
+
+			assert.Equal(t, tc.wantExisted, existed)
+			if tc.wantErr {
+				assert.Error(t, err)
+			} else {
+				assert.NoError(t, err)
+				_, statErr := os.Stat(path)
+				assert.NoError(t, statErr)
+			}
+		})
+	}
 }
 
 func TestGetVelaHomeDir(t *testing.T) {
-	tests := []struct {
+	testCases := []struct {
 		name    string
-		want    string
-		preFunc func()
-		postFun func()
-		wantErr assert.ErrorAssertionFunc
+		setup   func(t *testing.T) (expectedPath string, cleanup func())
+		wantErr bool
 	}{
 		{
-			name: "test get vela home dir from env",
-			preFunc: func() {
-				_ = os.Setenv(VelaHomeEnv, "/tmp")
+			name: "from VELA_HOME env var",
+			setup: func(t *testing.T) (string, func()) {
+				tmpDir := t.TempDir()
+				t.Setenv(VelaHomeEnv, tmpDir)
+				return tmpDir, func() {}
 			},
-			want:    "/tmp",
-			wantErr: assert.NoError,
+			wantErr: false,
 		},
 		{
-			name: "test use default vela home dir",
-			preFunc: func() {
-				_ = os.Unsetenv(VelaHomeEnv)
-			},
-			want:    filepath.Join(os.Getenv("HOME"), defaultVelaHome),
-			wantErr: assert.NoError,
-			postFun: func() {
-				_ = os.RemoveAll(filepath.Join(os.Getenv("HOME"), defaultVelaHome))
+			name: "from default user home",
+			setup: func(t *testing.T) (string, func()) {
+				tmpHome := t.TempDir()
+				t.Setenv("HOME", tmpHome)
+				t.Setenv(VelaHomeEnv, "") // Ensure VELA_HOME is not set, so it falls back to HOME
+				expectedPath := filepath.Join(tmpHome, defaultVelaHome)
+				return expectedPath, func() {} // t.TempDir() handles cleanup
 			},
+			wantErr: false,
 		},
 	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			if tt.preFunc != nil {
-				tt.preFunc()
-			}
-			defer func() {
-				_ = os.Unsetenv(VelaHomeEnv)
-			}()
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			expectedPath, cleanup := tc.setup(t)
+			defer cleanup()
+
 			got, err := GetVelaHomeDir()
-			if !tt.wantErr(t, err, "GetVelaHomeDir()") {
-				return
+
+			if tc.wantErr {
+				assert.Error(t, err)
+			} else {
+				assert.NoError(t, err)
+				assert.Equal(t, expectedPath, got)
+				_, statErr := os.Stat(got)
+				assert.NoError(t, statErr)
+			}
+		})
+	}
+}
+
+func TestGetDirectoryFunctions(t *testing.T) {
+	tmpDir := t.TempDir()
+	t.Setenv(VelaHomeEnv, tmpDir)
+
+	testCases := []struct {
+		name         string
+		getFunc      func() (string, error)
+		expectedPath string
+	}{
+		{"GetCapCenterDir", GetCapCenterDir, filepath.Join(tmpDir, "centers")},
+		{"GetRepoConfig", GetRepoConfig, filepath.Join(tmpDir, "centers", "config.yaml")},
+		{"GetCapabilityDir", GetCapabilityDir, filepath.Join(tmpDir, "capabilities")},
+		{"GetCurrentEnvPath", GetCurrentEnvPath, filepath.Join(tmpDir, "curenv")},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			got, err := tc.getFunc()
+			assert.NoError(t, err)
+			assert.Equal(t, tc.expectedPath, got)
+		})
+	}
+}
+
+func TestInitFunctions(t *testing.T) {
+	testCases := []struct {
+		name       string
+		initFunc   func() error
+		verifyFunc func(t *testing.T, velaHome string)
+	}{
+		{
+			name:     "InitCapabilityDir",
+			initFunc: InitCapabilityDir,
+			verifyFunc: func(t *testing.T, velaHome string) {
+				dir := filepath.Join(velaHome, "capabilities")
+				_, err := os.Stat(dir)
+				assert.NoError(t, err)
+			},
+		},
+		{
+			name:     "InitCapCenterDir",
+			initFunc: InitCapCenterDir,
+			verifyFunc: func(t *testing.T, velaHome string) {
+				dir := filepath.Join(velaHome, "centers", ".tmp")
+				_, err := os.Stat(dir)
+				assert.NoError(t, err)
+			},
+		},
+		{
+			name:     "InitDirs",
+			initFunc: InitDirs,
+			verifyFunc: func(t *testing.T, velaHome string) {
+				capDir := filepath.Join(velaHome, "capabilities")
+				centerDir := filepath.Join(velaHome, "centers", ".tmp")
+				_, err := os.Stat(capDir)
+				assert.NoError(t, err)
+				_, err = os.Stat(centerDir)
+				assert.NoError(t, err)
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			velaHome := t.TempDir()
+			t.Setenv(VelaHomeEnv, velaHome)
+
+			err := tc.initFunc()
+			assert.NoError(t, err)
+			tc.verifyFunc(t, velaHome)
+		})
+	}
+}
+
+func TestBindEnvironmentVariables(t *testing.T) {
+	originalVelaNS := types.DefaultKubeVelaNS
+	originalDefNS := oam.SystemDefinitionNamespace
+	defer func() {
+		types.DefaultKubeVelaNS = originalVelaNS
+		oam.SystemDefinitionNamespace = originalDefNS
+	}()
+
+	testCases := []struct {
+		name       string
+		setup      func(t *testing.T)
+		wantVelaNS string
+		wantDefNS  string
+	}{
+		{
+			name: "primary env vars",
+			setup: func(t *testing.T) {
+				t.Setenv(KubeVelaSystemNamespaceEnv, "vela-system-primary")
+				t.Setenv(KubeVelaDefinitionNamespaceEnv, "vela-def-primary")
+				t.Setenv(LegacyKubeVelaSystemNamespaceEnv, "vela-system-legacy")
+			},
+			wantVelaNS: "vela-system-primary",
+			wantDefNS:  "vela-def-primary",
+		},
+		{
+			name: "legacy fallback for vela ns",
+			setup: func(t *testing.T) {
+				t.Setenv(KubeVelaSystemNamespaceEnv, "")
+				t.Setenv(LegacyKubeVelaSystemNamespaceEnv, "vela-system-legacy")
+				t.Setenv(KubeVelaDefinitionNamespaceEnv, "vela-def-primary")
+			},
+			wantVelaNS: "vela-system-legacy",
+			wantDefNS:  "vela-def-primary",
+		},
+		{
+			name: "system ns fallback for definition ns",
+			setup: func(t *testing.T) {
+				t.Setenv(KubeVelaSystemNamespaceEnv, "vela-system-fallback")
+				t.Setenv(KubeVelaDefinitionNamespaceEnv, "")
+			},
+			wantVelaNS: "vela-system-fallback",
+			wantDefNS:  "vela-system-fallback",
+		},
+		{
+			name: "no env vars set",
+			setup: func(t *testing.T) {
+				t.Setenv(KubeVelaSystemNamespaceEnv, "")
+				t.Setenv(LegacyKubeVelaSystemNamespaceEnv, "")
+				t.Setenv(KubeVelaDefinitionNamespaceEnv, "")
+			},
+			wantVelaNS: "default-vela",
+			wantDefNS:  "default-def",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			// Reset to known state before each test
+			if tc.name == "no env vars set" {
+				types.DefaultKubeVelaNS = "default-vela"
+				oam.SystemDefinitionNamespace = "default-def"
+			} else {
+				types.DefaultKubeVelaNS = originalVelaNS
+				oam.SystemDefinitionNamespace = originalDefNS
 			}
 
-			assert.Equalf(t, tt.want, got, "GetVelaHomeDir()")
+			tc.setup(t)
+			BindEnvironmentVariables()
+
+			assert.Equal(t, tc.wantVelaNS, types.DefaultKubeVelaNS)
+			assert.Equal(t, tc.wantDefNS, oam.SystemDefinitionNamespace)
 		})
 	}
 }
diff --git a/pkg/utils/types/ql_type_test.go b/pkg/utils/types/ql_type_test.go
new file mode 100644
index 00000000..32b18dc1
--- /dev/null
+++ b/pkg/utils/types/ql_type_test.go
@@ -0,0 +1,180 @@
+/*
+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 types
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+func TestServiceEndpoint_String(t *testing.T) {
+	strPtr := func(s string) *string { return &s }
+
+	testCases := []struct {
+		name     string
+		endpoint ServiceEndpoint
+		expected string
+	}{
+		{
+			name:     "empty endpoint",
+			endpoint: ServiceEndpoint{},
+			expected: "-",
+		},
+		{
+			name: "http default port",
+			endpoint: ServiceEndpoint{
+				Endpoint: Endpoint{Host: "example.com", Port: 80, Protocol: corev1.ProtocolTCP, AppProtocol: strPtr("http")},
+			},
+			expected: "http://example.com",
+		},
+		{
+			name: "https default port",
+			endpoint: ServiceEndpoint{
+				Endpoint: Endpoint{Host: "example.com", Port: 443, Protocol: corev1.ProtocolTCP, AppProtocol: strPtr("https")},
+			},
+			expected: "https://example.com",
+		},
+		{
+			name: "http non-default port",
+			endpoint: ServiceEndpoint{
+				Endpoint: Endpoint{Host: "example.com", Port: 8080, Protocol: corev1.ProtocolTCP, AppProtocol: strPtr("http")},
+			},
+			expected: "http://example.com:8080",
+		},
+		{
+			name: "https non-default port with path",
+			endpoint: ServiceEndpoint{
+				Endpoint: Endpoint{Host: "example.com", Port: 8443, Protocol: corev1.ProtocolTCP, AppProtocol: strPtr("https"), Path: "/foo"},
+			},
+			expected: "https://example.com:8443/foo",
+		},
+		{
+			name: "path is root",
+			endpoint: ServiceEndpoint{
+				Endpoint: Endpoint{Host: "example.com", Port: 8080, Protocol: corev1.ProtocolTCP, AppProtocol: strPtr("http"), Path: "/"},
+			},
+			expected: "http://example.com:8080",
+		},
+		{
+			name: "tcp protocol",
+			endpoint: ServiceEndpoint{
+				Endpoint: Endpoint{Host: "127.0.0.1", Port: 3306, Protocol: corev1.ProtocolTCP},
+			},
+			expected: "127.0.0.1:3306",
+		},
+		{
+			name: "tcp protocol with path",
+			endpoint: ServiceEndpoint{
+				Endpoint: Endpoint{Host: "127.0.0.1", Port: 3306, Protocol: corev1.ProtocolTCP, Path: "/"},
+			},
+			expected: "127.0.0.1:3306",
+		},
+		{
+			name: "app protocol overrides protocol",
+			endpoint: ServiceEndpoint{
+				Endpoint: Endpoint{Host: "mydb", Port: 3306, Protocol: corev1.ProtocolTCP, AppProtocol: strPtr("mysql")},
+			},
+			expected: "mysql://mydb:3306",
+		},
+		{
+			name: "port is zero",
+			endpoint: ServiceEndpoint{
+				Endpoint: Endpoint{Host: "example.com", Port: 0, Protocol: corev1.ProtocolTCP, AppProtocol: strPtr("http")},
+			},
+			expected: "http://example.com",
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			assert.Equal(t, tc.expected, tc.endpoint.String())
+		})
+	}
+}
+
+func TestAppliedResource_GroupVersionKind(t *testing.T) {
+	testCases := []struct {
+		name     string
+		resource AppliedResource
+		expected schema.GroupVersionKind
+	}{
+		{
+			name:     "apps resource",
+			resource: AppliedResource{APIVersion: "apps/v1", Kind: "Deployment"},
+			expected: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
+		},
+		{
+			name:     "core resource",
+			resource: AppliedResource{APIVersion: "v1", Kind: "Service"},
+			expected: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Service"},
+		},
+		{
+			name:     "custom resource",
+			resource: AppliedResource{APIVersion: "core.oam.dev/v1beta1", Kind: "Application"},
+			expected: schema.GroupVersionKind{Group: "core.oam.dev", Version: "v1beta1", Kind: "Application"},
+		},
+		{
+			name:     "empty resource",
+			resource: AppliedResource{},
+			expected: schema.GroupVersionKind{Group: "", Version: "", Kind: ""},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			assert.Equal(t, tc.expected, tc.resource.GroupVersionKind())
+		})
+	}
+}
+
+func TestResourceTreeNode_GroupVersionKind(t *testing.T) {
+	testCases := []struct {
+		name     string
+		node     ResourceTreeNode
+		expected schema.GroupVersionKind
+	}{
+		{
+			name:     "apps resource",
+			node:     ResourceTreeNode{APIVersion: "apps/v1", Kind: "Deployment"},
+			expected: schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"},
+		},
+		{
+			name:     "core resource",
+			node:     ResourceTreeNode{APIVersion: "v1", Kind: "Service"},
+			expected: schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Service"},
+		},
+		{
+			name:     "custom resource",
+			node:     ResourceTreeNode{APIVersion: "core.oam.dev/v1beta1", Kind: "Application"},
+			expected: schema.GroupVersionKind{Group: "core.oam.dev", Version: "v1beta1", Kind: "Application"},
+		},
+		{
+			name:     "empty resource",
+			node:     ResourceTreeNode{},
+			expected: schema.GroupVersionKind{Group: "", Version: "", Kind: ""},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			assert.Equal(t, tc.expected, tc.node.GroupVersionKind())
+		})
+	}
+}
diff --git a/pkg/utils/util/cmd_test.go b/pkg/utils/util/cmd_test.go
new file mode 100644
index 00000000..3c45906d
--- /dev/null
+++ b/pkg/utils/util/cmd_test.go
@@ -0,0 +1,105 @@
+/*
+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 util
+
+import (
+	"bytes"
+	"os"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestIOStreams_PrintFunctions(t *testing.T) {
+	type printFunc func(streams IOStreams)
+	type checkFunc func(t *testing.T, buf *bytes.Buffer)
+
+	testCases := []struct {
+		name      string
+		printFunc printFunc
+		checkFunc checkFunc
+	}{
+		{
+			name: "Infonln",
+			printFunc: func(streams IOStreams) {
+				streams.Infonln("hello", " ", "world")
+			},
+			checkFunc: func(t *testing.T, buf *bytes.Buffer) {
+				assert.Equal(t, "hello world", buf.String())
+			},
+		},
+		{
+			name: "Info",
+			printFunc: func(streams IOStreams) {
+				streams.Info("hello")
+			},
+			checkFunc: func(t *testing.T, buf *bytes.Buffer) {
+				assert.Equal(t, "hello\n", buf.String())
+			},
+		},
+		{
+			name: "Infof",
+			printFunc: func(streams IOStreams) {
+				streams.Infof("hello %s", "world")
+			},
+			checkFunc: func(t *testing.T, buf *bytes.Buffer) {
+				assert.Equal(t, "hello world", buf.String())
+			},
+		},
+		{
+			name: "Error",
+			printFunc: func(streams IOStreams) {
+				streams.Error("error")
+			},
+			checkFunc: func(t *testing.T, buf *bytes.Buffer) {
+				assert.Equal(t, "error\n", buf.String())
+			},
+		},
+		{
+			name: "Errorf",
+			printFunc: func(streams IOStreams) {
+				streams.Errorf("error %s", "world")
+			},
+			checkFunc: func(t *testing.T, buf *bytes.Buffer) {
+				assert.Equal(t, "error world", buf.String())
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			streams, buf := NewTestIOStreams()
+			tc.printFunc(streams)
+			tc.checkFunc(t, buf)
+		})
+	}
+}
+
+func TestNewDefaultIOStreams(t *testing.T) {
+	streams := NewDefaultIOStreams()
+	assert.Equal(t, os.Stdin, streams.In)
+	assert.Equal(t, os.Stdout, streams.Out)
+	assert.Equal(t, os.Stderr, streams.ErrOut)
+}
+
+func TestNewTestIOStreams(t *testing.T) {
+	streams, buf := NewTestIOStreams()
+	assert.NotNil(t, streams.In)
+	assert.IsType(t, &bytes.Buffer{}, streams.In)
+	assert.Equal(t, buf, streams.Out)
+	assert.Equal(t, buf, streams.ErrOut)
+}
diff --git a/pkg/utils/util/factory_test.go b/pkg/utils/util/factory_test.go
index fbb5b4d0..f33c1625 100644
--- a/pkg/utils/util/factory_test.go
+++ b/pkg/utils/util/factory_test.go
@@ -17,19 +17,169 @@ limitations under the License.
 package util
 
 import (
+	"path/filepath"
 	"testing"
+	"time"
+
+	"github.com/stretchr/testify/require"
+	"k8s.io/client-go/rest"
+	"k8s.io/client-go/tools/clientcmd"
 
 	"github.com/oam-dev/kubevela/version"
 )
 
 func TestGenerateLeaderElectionID(t *testing.T) {
-	version.VelaVersion = "v10.13.0"
-	if id := GenerateLeaderElectionID("kubevela", true); id != "kubevela-v10-13-0" {
-		t.Errorf("id is not as expected(%s != kubevela-v10-13-0)", id)
-		return
+	orig := version.VelaVersion
+	defer func() { version.VelaVersion = orig }()
+
+	testCases := []struct {
+		name      string
+		ver       string
+		versioned bool
+		want      string
+	}{
+		{name: "versioned", ver: "v10.13.0", versioned: true, want: "kubevela-v10-13-0"},
+		{name: "unversioned", ver: "v10.13.0", versioned: false, want: "kubevela"},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			version.VelaVersion = tc.ver
+			got := GenerateLeaderElectionID("kubevela", tc.versioned)
+			require.Equal(t, tc.want, got)
+		})
 	}
-	if id := GenerateLeaderElectionID("kubevela", false); id != "kubevela" {
-		t.Errorf("id is not as expected(%s != kubevela)", id)
-		return
+}
+
+func TestComputeDiscoverCacheDir(t *testing.T) {
+	t.Parallel()
+	parent := "/parent"
+
+	testCases := []struct {
+		name string
+		host string
+		want string
+	}{
+		{name: "https scheme removed", host: "https://example.com:6443", want: "example.com_6443"},
+		{name: "http scheme removed", host: "http://example.com:6443", want: "example.com_6443"},
+		{name: "no scheme", host: "k8s.example.io:443", want: "k8s.example.io_443"},
+		{name: "sanitize special", host: "exa_mple.com:6443?x=y#frag", want: "exa_mple.com_6443_x_y_frag"},
 	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			got := computeDiscoverCacheDir(parent, tc.host)
+			want := filepath.Join(parent, tc.want)
+			require.Equal(t, want, got)
+		})
+	}
+}
+
+func TestRestConfigGetter(t *testing.T) {
+	t.Parallel()
+
+	t.Run("ToRESTConfig returns same pointer", func(t *testing.T) {
+		t.Parallel()
+		cfg := &rest.Config{Host: "https://cluster.local"}
+		r := &restConfigGetter{config: cfg, namespace: "ns"}
+		got, err := r.ToRESTConfig()
+		require.NoError(t, err)
+		require.Same(t, cfg, got)
+	})
+
+	t.Run("NewRestConfigGetterByConfig sets fields", func(t *testing.T) {
+		t.Parallel()
+		cfg := &rest.Config{Host: "https://cluster.local"}
+		g := NewRestConfigGetterByConfig(cfg, "my-ns")
+		r, ok := g.(*restConfigGetter)
+		require.True(t, ok, "unexpected underlying type for RESTClientGetter")
+		require.Equal(t, "my-ns", r.namespace)
+		require.Same(t, cfg, r.config)
+	})
+}
+
+func TestRestConfigGetter_ToRawKubeConfigLoader(t *testing.T) {
+	t.Parallel()
+
+	testCases := []struct {
+		name       string
+		config     *rest.Config
+		namespace  string
+		assertFunc func(*testing.T, clientcmd.ClientConfig)
+	}{
+		{
+			name: "simple config",
+			config: &rest.Config{
+				Host: "https://my-cluster.local",
+			},
+			namespace: "my-ns",
+			assertFunc: func(t *testing.T, clientConfig clientcmd.ClientConfig) {
+				ns, _, err := clientConfig.Namespace()
+				require.NoError(t, err)
+				require.Equal(t, "my-ns", ns)
+			},
+		},
+		{
+			name: "full config",
+			config: &rest.Config{
+				Host:        "https://my-cluster.local:6443",
+				Username:    "my-user",
+				Password:    "my-pass",
+				BearerToken: "my-token",
+				TLSClientConfig: rest.TLSClientConfig{
+					CertFile: "/path/to/cert",
+					KeyFile:  "/path/to/key",
+					CAFile:   "/path/to/ca",
+					Insecure: true,
+				},
+				Timeout: 30 * time.Second,
+				Impersonate: rest.ImpersonationConfig{
+					UserName: "impersonate-user",
+					Groups:   []string{"group1", "group2"},
+					Extra:    map[string][]string{"extra": {"val"}},
+				},
+			},
+			namespace: "full-ns",
+			assertFunc: func(t *testing.T, clientConfig clientcmd.ClientConfig) {
+				ns, _, err := clientConfig.Namespace()
+				require.NoError(t, err)
+				require.Equal(t, "full-ns", ns)
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			t.Parallel()
+			getter := NewRestConfigGetterByConfig(tc.config, tc.namespace)
+			clientConfig := getter.ToRawKubeConfigLoader()
+			require.NotNil(t, clientConfig)
+			tc.assertFunc(t, clientConfig)
+		})
+	}
+}
+
+func TestRestConfigGetter_DiscoveryAndMapper(t *testing.T) {
+	tmpHome := t.TempDir()
+	t.Setenv("HOME", tmpHome)
+
+	originalDefaultCacheDir := defaultCacheDir
+	defaultCacheDir = filepath.Join(tmpHome, ".kube", "http-cache")
+	defer func() { defaultCacheDir = originalDefaultCacheDir }()
+
+	cfg := &rest.Config{Host: "http://127.0.0.1:1"}
+	getter := NewRestConfigGetterByConfig(cfg, "default")
+
+	t.Run("ToDiscoveryClient", func(t *testing.T) {
+		discoveryClient, err := getter.ToDiscoveryClient()
+		require.NoError(t, err)
+		require.NotNil(t, discoveryClient)
+	})
+
+	t.Run("ToRESTMapper", func(t *testing.T) {
+		mapper, err := getter.ToRESTMapper()
+		require.NoError(t, err)
+		require.NotNil(t, mapper)
+	})
 }