add unit test for webhook validation

Signed-off-by: guoyao <1015105054@qq.com>

Signed-off-by: guoyao <1015105054@qq.com>
This commit is contained in:
guoyao 2021-11-19 08:59:40 +08:00
parent b0742b2c9c
commit 69f990bf56
2 changed files with 403 additions and 0 deletions

View File

@ -0,0 +1,120 @@
package crdexplorer
import (
"strings"
"testing"
"k8s.io/apimachinery/pkg/util/validation/field"
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
)
func TestHasWildcard(t *testing.T) {
testCases := []struct {
name string
slices []string
want bool
}{
{
name: "TestHasWildcard(): nil input args",
slices: nil,
want: false,
},
{
name: "TestHasWildcard(): has wildcard",
slices: []string{
"*",
},
want: true,
},
{
name: "TestHasWildcard(): not have wildcard",
slices: []string{
"test",
},
want: false,
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
if result := hasWildcard(testCase.slices); result != testCase.want {
t.Errorf("Case: %s failed: want %v, but got %v", testCase.name, testCase.want, result)
}
})
}
}
func TestValidateRule(t *testing.T) {
fldPath := field.NewPath("webhooks")
tests := []struct {
name string
rule *configv1alpha1.Rule
expectedError string
}{
{
name: "APIGroups required",
rule: &configv1alpha1.Rule{},
expectedError: "apiGroups: Required value",
},
{
name: "APIGroups cannot specify both * and others",
rule: &configv1alpha1.Rule{
APIGroups: []string{"*", "group"},
},
expectedError: "if '*' is present, must not specify other API groups",
},
{
name: "APIVersions required",
rule: &configv1alpha1.Rule{},
expectedError: "webhooks.apiVersions: Required value",
},
{
name: "APIVersions cannot specify both * and others",
rule: &configv1alpha1.Rule{
APIVersions: []string{"*", "v1"},
},
expectedError: "if '*' is present, must not specify other API versions",
},
{
name: "APIVersions empty is not allowed",
rule: &configv1alpha1.Rule{
APIVersions: []string{""},
},
expectedError: "apiVersions[0]: Required value",
},
{
name: "Kinds required",
rule: &configv1alpha1.Rule{},
expectedError: "kinds: Required value",
},
{
name: "Kinds cannot specify both * and others",
rule: &configv1alpha1.Rule{
Kinds: []string{"*", "v1"},
},
expectedError: "if '*' is present, must not specify other kinds",
},
{
name: "Kinds empty is not allowed",
rule: &configv1alpha1.Rule{
Kinds: []string{""},
},
expectedError: "kinds[0]: Required value",
},
}
for _, test := range tests {
errs := validateRule(test.rule, fldPath)
err := errs.ToAggregate()
if err != nil {
if e, a := test.expectedError, err.Error(); !strings.Contains(a, e) || e == "" {
t.Errorf("Case: %s failed: expected to contain %s, got %s", test.name, e, a)
}
} else {
if test.expectedError != "" {
t.Errorf("unexpected no error, expected to contain %s", test.expectedError)
}
}
}
}

View File

@ -0,0 +1,283 @@
package crdexplorer
import (
"fmt"
"strings"
"testing"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/apimachinery/pkg/util/validation/field"
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
)
func strPtr(s string) *string { return &s }
func int32Ptr(i int32) *int32 { return &i }
func TestHasWildcardOperation(t *testing.T) {
tests := []struct {
name string
operations []configv1alpha1.OperationType
expected bool
}{
{
name: "no operations",
operations: nil,
expected: false,
},
{
name: "has wildcard operation",
operations: []configv1alpha1.OperationType{
configv1alpha1.OperationAll,
},
expected: true,
},
{
name: "no have wildcard operation",
operations: []configv1alpha1.OperationType{
configv1alpha1.ExploreReplica,
},
expected: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := hasWildcardOperation(test.operations)
if result != test.expected {
t.Errorf("Case: %s failed: expected get %v, but got %v", test.name, test.expected, result)
}
})
}
}
func TestIsAcceptedExploreReviewVersions(t *testing.T) {
tests := []struct {
name string
version string
expected bool
}{
{
name: "is accepted explore review versions",
version: acceptedExploreReviewVersions[0],
expected: true,
},
{
name: "is not accepted explore review versions",
version: "",
expected: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := isAcceptedExploreReviewVersions(test.version)
if result != test.expected {
t.Errorf("Case: %s failed: expected get %v, but got %v", test.name, test.expected, result)
}
})
}
}
func TestValidateRuleWithOperations(t *testing.T) {
fldPath := field.NewPath("webhooks").Child("rules")
notSupportedOperation := []configv1alpha1.OperationType{(configv1alpha1.OperationType)("notsupported")}
tests := []struct {
name string
ruleWithOperations *configv1alpha1.RuleWithOperations
expectedError string
}{
{
name: "no operations",
ruleWithOperations: &configv1alpha1.RuleWithOperations{},
expectedError: "operations: Required value",
},
{
name: "2 operations with wildcard",
ruleWithOperations: &configv1alpha1.RuleWithOperations{
Operations: []configv1alpha1.OperationType{
configv1alpha1.OperationAll,
configv1alpha1.ExploreReplica,
},
},
expectedError: "if '*' is present, must not specify other operations",
},
{
name: "not supported operations",
ruleWithOperations: &configv1alpha1.RuleWithOperations{Operations: notSupportedOperation},
expectedError: "operations[0]: Unsupported value",
},
{
name: "not validated rule",
ruleWithOperations: &configv1alpha1.RuleWithOperations{
Operations: []configv1alpha1.OperationType{
configv1alpha1.OperationAll,
},
Rule: configv1alpha1.Rule{
APIGroups: []string{""},
}},
expectedError: "apiVersions: Required value",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
errs := validateRuleWithOperations(test.ruleWithOperations, fldPath)
err := errs.ToAggregate()
if err != nil {
if e, a := test.expectedError, err.Error(); !strings.Contains(a, e) || e == "" {
t.Errorf("Case: %s failed: expected to contain %s, got %s", test.name, e, a)
}
} else {
if test.expectedError != "" {
t.Errorf("Case: %s failed: unexpected no error, expected to contain %s", test.name, test.expectedError)
}
}
})
}
}
func TestValidateExploreReviewVersions(t *testing.T) {
fldPath := field.NewPath("webhooks").Child("exploreReviewVersions")
tests := []struct {
name string
versions []string
expectedError string
}{
{
name: "no versions",
versions: nil,
expectedError: fmt.Sprintf("must specify one of %v", strings.Join(acceptedExploreReviewVersions, ", ")),
},
{
name: "duplicate versions",
versions: []string{"v1", "v1"},
expectedError: "duplicate version",
},
{
name: "invalid versions",
versions: []string{"test", "test"},
expectedError: fmt.Sprintf("must include at least one of %v", strings.Join(acceptedExploreReviewVersions, ", ")),
},
{
name: "invalid DNS (RFC 1035) label",
versions: []string{"a b"},
expectedError: "a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
errs := validateExploreReviewVersions(test.versions, fldPath)
err := errs.ToAggregate()
if err != nil {
if e, a := test.expectedError, err.Error(); !strings.Contains(a, e) || e == "" {
t.Errorf("Case: %s failed: expected to contain %s, got %s", test.name, e, a)
}
} else {
if test.expectedError != "" {
t.Errorf("Case: %s failed: unexpected no error, expected to contain %s", test.name, test.expectedError)
}
}
})
}
}
func TestValidateWebhook(t *testing.T) {
fldPath := field.NewPath("webhooks")
policy := admissionregistrationv1.FailurePolicyType("fake policy")
tests := []struct {
name string
hook *configv1alpha1.ResourceExploringWebhook
expectedError string
}{
{
name: "not qualified domain name",
hook: &configv1alpha1.ResourceExploringWebhook{
Name: "",
},
expectedError: "webhooks.name: Required value",
},
{
name: "invalid rules",
hook: &configv1alpha1.ResourceExploringWebhook{
Rules: []configv1alpha1.RuleWithOperations{
{
Operations: []configv1alpha1.OperationType{},
},
},
},
expectedError: "operations: Required value",
},
{
name: "invalid policy",
hook: &configv1alpha1.ResourceExploringWebhook{
FailurePolicy: &policy,
},
expectedError: "matchPolicy",
},
{
name: "invalid timeout",
hook: &configv1alpha1.ResourceExploringWebhook{
TimeoutSeconds: int32Ptr(60),
},
expectedError: "the timeout value must be between 1 and 30 seconds",
},
{
name: "ClientConfig: exactly one of url or service is required",
hook: &configv1alpha1.ResourceExploringWebhook{
ClientConfig: admissionregistrationv1.WebhookClientConfig{},
},
expectedError: "exactly one of url or service is required",
},
{
name: "ClientConfig: invalid URL",
hook: &configv1alpha1.ResourceExploringWebhook{
ClientConfig: admissionregistrationv1.WebhookClientConfig{
URL: strPtr(""),
},
},
expectedError: "host must be provided",
},
{
name: "ClientConfig: invalid service",
hook: &configv1alpha1.ResourceExploringWebhook{
ClientConfig: admissionregistrationv1.WebhookClientConfig{
Service: &admissionregistrationv1.ServiceReference{
Name: "",
Port: int32Ptr(8080),
Path: strPtr(""),
},
},
},
expectedError: "service name is required",
},
{
name: "invalid explore review versions",
hook: &configv1alpha1.ResourceExploringWebhook{
ExploreReviewVersions: []string{""},
},
expectedError: fmt.Sprintf("must include at least one of %v", strings.Join(acceptedExploreReviewVersions, ", ")),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
errs := validateWebhook(test.hook, fldPath)
err := errs.ToAggregate()
if err != nil {
if e, a := test.expectedError, err.Error(); !strings.Contains(a, e) || e == "" {
t.Errorf("Case: %s failed: expected to contain %s, got %s", test.name, e, a)
}
} else {
if test.expectedError != "" {
t.Errorf("Case: %s failed: unexpected no error, expected to contain %s", test.name, test.expectedError)
}
}
})
}
}