mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-14 18:10:21 +00:00
Feat(utils): Enhance unit test coverage and quality for pkg/utils (#6884)
* feat(env): Add comprehensive unit tests for environment management This commit introduces a comprehensive suite of unit tests for the environment management functions in `pkg/utils/env`. Key changes include: - Refactoring the test setup to use `TestMain` for better test environment control. - Adding new test cases for `CreateEnv`, `GetEnvByName`, `ListEnvs`, `SetCurrentEnv`, `SetEnvLabels`, and `DeleteEnv`. These tests improve the overall test coverage and ensure the correctness and reliability of environment-related operations. Signed-off-by: Ashvin Bambhaniya <ashvin.bambhaniya@improwised.com> * feat(errors): Add unit tests for error handling utilities This commit introduces new unit tests for the error handling utilities located in `pkg/utils/errors/`. Specifically, new test files have been added for: - `crd_test.go`: Tests for CRD-related error checks. - `list_test.go`: Tests for error list aggregation. - `reason_test.go`: Tests for specific error reasons like label conflicts and CUE path not found. - `resourcetracker_test.go`: Tests for resource tracker errors. These additions improve the test coverage and ensure the robustness of KubeVela's error handling mechanisms. Signed-off-by: Ashvin Bambhaniya <ashvin.bambhaniya@improwised.com> * refactor(schema): Refactor ui_schema_test.go to use testify/assert and add new test cases This commit refactors `pkg/utils/schema/ui_schema_test.go` to improve its readability and maintainability. Key changes include: - Migrating from Ginkgo/Gomega to testify/assert for assertions. - Restructuring `TestGetDefaultUIType` into a table-driven test. - Adding new comprehensive test cases for `Condition_Validate` function. These changes enhance the test suite for UI schema utilities, making it more robust and easier to extend. Signed-off-by: Ashvin Bambhaniya <ashvin.bambhaniya@improwised.com> * refactor(system): Refactor system_test.go and add comprehensive unit tests This commit refactors `pkg/utils/system/system_test.go` to improve its structure, readability, and test coverage. Key changes include: - Converting existing tests to a table-driven format using `testify/assert`. - Adding new comprehensive test cases for: - `CreateIfNotExist` - `GetVelaHomeDir` - `GetDirectoryFunctions` (e.g., `GetCapCenterDir`, `GetCapabilityDir`) - `InitFunctions` (e.g., `InitCapabilityDir`, `InitCapCenterDir`, `InitDirs`) - `BindEnvironmentVariables` These changes enhance the test suite for system utilities, ensuring their correctness and robustness. Signed-off-by: Ashvin Bambhaniya <ashvin.bambhaniya@improwised.com> * feat(types): Add unit tests for QL types This commit introduces new unit tests for the types defined in `pkg/utils/types`, specifically focusing on types related to KubeVela Query Language (QL). New test cases cover: - `ServiceEndpoint.String()`: Verifies the string representation of service endpoints, including various protocols, ports, and paths. - `AppliedResource.GroupVersionKind()`: Ensures correct extraction of GroupVersionKind from applied resources. - `ResourceTreeNode.GroupVersionKind()`: Verifies correct extraction of GroupVersionKind from resource tree nodes. These tests improve the coverage and reliability of core data structures used in KubeVela. Signed-off-by: Ashvin Bambhaniya <ashvin.bambhaniya@improwised.com> * feat(util): Add and refactor unit tests for utility functions This commit introduces new unit tests and refactors existing ones within the `pkg/utils/util` package. Key changes include: - **`pkg/utils/util/cmd_test.go`**: Adds comprehensive tests for `IOStreams` and its print functions, as well as `NewDefaultIOStreams` and `NewTestIOStreams`. - **`pkg/utils/util/factory_test.go`**: Refactors the `GenerateLeaderElectionID` test to a table-driven format and adds new tests for `computeDiscoverCacheDir` and `RestConfigGetter` methods, ensuring the correctness of Kubernetes client configuration and discovery. These additions and refactorings enhance the test coverage and reliability of core utility functions. Signed-off-by: Ashvin Bambhaniya <ashvin.bambhaniya@improwised.com> * feat(utils): Add and refactor unit tests for json, jwt, parse, and strings utilities This commit introduces new unit tests and refactors existing ones across several utility packages within `pkg/utils/`. Key changes include: - **`pkg/utils/json`**: Adds tests for `StrictUnmarshal` to ensure proper JSON unmarshaling. - **`pkg/utils/jwt`**: Adds tests for JWT token subject extraction and certificate subject retrieval. - **`pkg/utils/parse`**: Expands test coverage for URL parsing functions (`Parse`, `ParseGitlab`). - **`pkg/utils/strings`**: Refactors existing tests to a table-driven format and adds tests for box drawing string generation. These additions and refactorings significantly improve the test coverage and reliability of KubeVela's utility functions. Signed-off-by: Ashvin Bambhaniya <ashvin.bambhaniya@improwised.com> * fix(tests): Address test and error handling issues This commit addresses several issues identified in unit tests and error handling utilities, improving test reliability and code safety. Key fixes and improvements include: - **`pkg/utils/errors`**: - Added nil check to `IsCuePathNotFound` to prevent panics. - Corrected `fmt.Errorf` usage to `errors.New` in `reason_test.go` (SA1006 fix). - Used `assert.EqualError` for clearer error message comparisons in `resourcetracker_test.go`. - **`pkg/utils/jwt_test.go`**: Marked `generateTestCert` as a test helper using `t.Helper()` for better error reporting. - **`pkg/utils/system_test.go`**: - Removed unused `verifyCleanup` field. - Modified `TestGetVelaHomeDir` to use a temporary home directory, preventing destructive operations on the user's system. - **`pkg/utils/util/cmd_test.go`**: Swapped `assert.Equal` arguments to follow `expected, actual` convention. These changes enhance the robustness and correctness of the test suite and related utility functions. Signed-off-by: Ashvin Bambhaniya <ashvin.bambhaniya@improwised.com> * chore(tests): Apply gofmt and import ordering to test files This commit applies standard Go formatting (`gofmt`) and corrects import ordering in several test files. Affected files: - `pkg/utils/schema/ui_schema_test.go`: Added missing newline at EOF. - `pkg/utils/system/system_test.go`: Corrected import ordering. - `pkg/utils/util/factory_test.go`: Corrected import ordering. These changes ensure consistency with project coding standards. Signed-off-by: Ashvin Bambhaniya <ashvin.bambhaniya@improwised.com> --------- Signed-off-by: Ashvin Bambhaniya <ashvin.bambhaniya@improwised.com>
This commit is contained in:
committed by
GitHub
parent
70e6c9a49f
commit
2758afb1b2
342
pkg/utils/env/env_test.go
vendored
342
pkg/utils/env/env_test.go
vendored
@@ -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))
|
||||
|
||||
rawClient, err = client.New(cfg, client.Options{Scheme: testScheme})
|
||||
assert.NoError(t, err)
|
||||
|
||||
type want struct {
|
||||
data string
|
||||
}
|
||||
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",
|
||||
},
|
||||
},
|
||||
}
|
||||
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())
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := clientgoscheme.AddToScheme(testScheme); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := v1beta1.AddToScheme(testScheme); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
k8sClient, err = client.New(cfg, client.Options{Scheme: testScheme})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
singleton.KubeClient.Set(k8sClient)
|
||||
|
||||
code := m.Run()
|
||||
|
||||
if err := testEnv.Stop(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
69
pkg/utils/errors/crd_test.go
Normal file
69
pkg/utils/errors/crd_test.go
Normal file
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
95
pkg/utils/errors/list_test.go
Normal file
95
pkg/utils/errors/list_test.go
Normal file
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
102
pkg/utils/errors/reason_test.go
Normal file
102
pkg/utils/errors/reason_test.go
Normal file
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
28
pkg/utils/errors/resourcetracker_test.go
Normal file
28
pkg/utils/errors/resourcetracker_test.go
Normal file
@@ -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")
|
||||
}
|
||||
86
pkg/utils/json_test.go
Normal file
86
pkg/utils/json_test.go
Normal file
@@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
166
pkg/utils/jwt_test.go
Normal file
166
pkg/utils/jwt_test.go
Normal file
@@ -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())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,100 +19,105 @@ 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",
|
||||
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",
|
||||
},
|
||||
{
|
||||
"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"]))
|
||||
}
|
||||
})
|
||||
})
|
||||
{
|
||||
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",
|
||||
u: UISchema{
|
||||
{
|
||||
Conditions: []Condition{
|
||||
{
|
||||
JSONKey: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "test validate ui schema success",
|
||||
name: "valid schema",
|
||||
u: UISchema{
|
||||
{
|
||||
Conditions: []Condition{
|
||||
@@ -126,11 +131,148 @@ func TestUISchema_Validate(t *testing.T) {
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid condition with empty jsonkey",
|
||||
u: UISchema{
|
||||
{
|
||||
Conditions: []Condition{
|
||||
{
|
||||
JSONKey: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
errContains: "the json key of the condition can not be empty",
|
||||
},
|
||||
{
|
||||
name: "invalid condition with bad action",
|
||||
u: UISchema{
|
||||
{
|
||||
Conditions: []Condition{
|
||||
{
|
||||
JSONKey: "key",
|
||||
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) {
|
||||
if err := tt.u.Validate(); (err != nil) != tt.wantErr {
|
||||
t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
|
||||
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) {
|
||||
err := tt.c.Validate()
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), tt.errContains)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
func TestGetVelaHomeDir(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want string
|
||||
preFunc func()
|
||||
postFun func()
|
||||
wantErr assert.ErrorAssertionFunc
|
||||
testCases := []struct {
|
||||
name string
|
||||
setup func(t *testing.T) string
|
||||
wantExisted bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "test get vela home dir from env",
|
||||
preFunc: func() {
|
||||
_ = os.Setenv(VelaHomeEnv, "/tmp")
|
||||
name: "directory does not exist",
|
||||
setup: func(t *testing.T) string {
|
||||
return filepath.Join(t.TempDir(), "new-dir")
|
||||
},
|
||||
want: "/tmp",
|
||||
wantErr: assert.NoError,
|
||||
wantExisted: false,
|
||||
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: "directory already exists",
|
||||
setup: func(t *testing.T) string {
|
||||
return t.TempDir()
|
||||
},
|
||||
wantExisted: true,
|
||||
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)
|
||||
}()
|
||||
got, err := GetVelaHomeDir()
|
||||
if !tt.wantErr(t, err, "GetVelaHomeDir()") {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equalf(t, tt.want, got, "GetVelaHomeDir()")
|
||||
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) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
setup func(t *testing.T) (expectedPath string, cleanup func())
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "from VELA_HOME env var",
|
||||
setup: func(t *testing.T) (string, func()) {
|
||||
tmpDir := t.TempDir()
|
||||
t.Setenv(VelaHomeEnv, tmpDir)
|
||||
return tmpDir, func() {}
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
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 _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
expectedPath, cleanup := tc.setup(t)
|
||||
defer cleanup()
|
||||
|
||||
got, err := GetVelaHomeDir()
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
tc.setup(t)
|
||||
BindEnvironmentVariables()
|
||||
|
||||
assert.Equal(t, tc.wantVelaNS, types.DefaultKubeVelaNS)
|
||||
assert.Equal(t, tc.wantDefNS, oam.SystemDefinitionNamespace)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
180
pkg/utils/types/ql_type_test.go
Normal file
180
pkg/utils/types/ql_type_test.go
Normal file
@@ -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())
|
||||
})
|
||||
}
|
||||
}
|
||||
105
pkg/utils/util/cmd_test.go
Normal file
105
pkg/utils/util/cmd_test.go
Normal file
@@ -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)
|
||||
}
|
||||
@@ -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"},
|
||||
}
|
||||
if id := GenerateLeaderElectionID("kubevela", false); id != "kubevela" {
|
||||
t.Errorf("id is not as expected(%s != kubevela)", id)
|
||||
return
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user