440 lines
13 KiB
Go
440 lines
13 KiB
Go
/*
|
|
Copyright 2024 The Karmada 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 tasks
|
|
|
|
import (
|
|
"context"
|
|
"crypto/x509"
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
fakeclientset "k8s.io/client-go/kubernetes/fake"
|
|
|
|
operatorv1alpha1 "github.com/karmada-io/karmada/operator/pkg/apis/operator/v1alpha1"
|
|
"github.com/karmada-io/karmada/operator/pkg/certs"
|
|
"github.com/karmada-io/karmada/operator/pkg/constants"
|
|
"github.com/karmada-io/karmada/operator/pkg/util"
|
|
"github.com/karmada-io/karmada/operator/pkg/workflow"
|
|
)
|
|
|
|
func TestNewCertTask(t *testing.T) {
|
|
karmada := &operatorv1alpha1.Karmada{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: "karmada",
|
|
},
|
|
Spec: operatorv1alpha1.KarmadaSpec{
|
|
Components: &operatorv1alpha1.KarmadaComponents{
|
|
Etcd: &operatorv1alpha1.Etcd{
|
|
Local: &operatorv1alpha1.LocalEtcd{},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
wantTask workflow.Task
|
|
}{
|
|
{
|
|
name: "TestNewCertTask_IsCalled_ExpectedWorkflowTask",
|
|
wantTask: workflow.Task{
|
|
Name: "Certs",
|
|
Run: runCerts,
|
|
Skip: skipCerts,
|
|
RunSubTasks: true,
|
|
Tasks: newCertSubTasks(karmada),
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
certTask := NewCertTask(karmada)
|
|
err := util.DeepEqualTasks(certTask, test.wantTask)
|
|
if err != nil {
|
|
t.Errorf("unexpected error, got %v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRunCerts(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
runData workflow.RunData
|
|
wantErr bool
|
|
errMsg string
|
|
}{
|
|
{
|
|
name: "RunCerts_InvalidTypeAssertion_TypeAssertionFailed",
|
|
runData: MyTestData{Data: "test"},
|
|
wantErr: true,
|
|
errMsg: "certs task invoked with an invalid data struct",
|
|
},
|
|
{
|
|
name: "RunCerts_ValidTypeAssertion_TypeAssertionSucceeded",
|
|
runData: &TestInitData{},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
err := runCerts(test.runData)
|
|
if err == nil && test.wantErr {
|
|
t.Errorf("expected error, but got none")
|
|
}
|
|
if err != nil && !test.wantErr {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
if err != nil && test.wantErr && !strings.Contains(err.Error(), test.errMsg) {
|
|
t.Errorf("expected %s error msg to contain %s", err.Error(), test.errMsg)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSkipCerts(t *testing.T) {
|
|
client := fakeclientset.NewSimpleClientset()
|
|
tests := []struct {
|
|
name string
|
|
runData workflow.RunData
|
|
prep func() error
|
|
cleanup func() error
|
|
wantErr bool
|
|
wantSkip bool
|
|
errMsg string
|
|
}{
|
|
{
|
|
name: "SkipCerts_InvalidTypeAssertion_TypeAssertionFailed",
|
|
runData: MyTestData{Data: "test"},
|
|
prep: func() error { return nil },
|
|
cleanup: func() error { return nil },
|
|
wantErr: true,
|
|
wantSkip: false,
|
|
errMsg: "certs task invoked with an invalid data struct",
|
|
},
|
|
{
|
|
name: "SkipCerts_ValidTypeAssertion_TypeAssertionSucceeded",
|
|
runData: &TestInitData{
|
|
Name: "karmada-demo",
|
|
Namespace: "test",
|
|
RemoteClientConnector: client,
|
|
},
|
|
prep: func() error { return nil },
|
|
cleanup: func() error { return nil },
|
|
wantErr: false,
|
|
wantSkip: false,
|
|
},
|
|
{
|
|
name: "SkipCerts_WithEmptySecretData_ErrorReturned",
|
|
runData: &TestInitData{
|
|
Name: "karmada-demo",
|
|
Namespace: "test",
|
|
RemoteClientConnector: client,
|
|
},
|
|
prep: func() error {
|
|
_, err := client.CoreV1().Secrets("test").Create(
|
|
context.TODO(), &corev1.Secret{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: util.KarmadaCertSecretName("karmada-demo"),
|
|
Namespace: "test",
|
|
},
|
|
Data: map[string][]byte{},
|
|
},
|
|
metav1.CreateOptions{},
|
|
)
|
|
return err
|
|
},
|
|
cleanup: func() error {
|
|
err := client.CoreV1().Secrets("test").Delete(
|
|
context.TODO(), util.KarmadaCertSecretName("karmada-demo"),
|
|
metav1.DeleteOptions{},
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete %s secret", "test")
|
|
}
|
|
return nil
|
|
},
|
|
wantErr: true,
|
|
wantSkip: false,
|
|
},
|
|
{
|
|
name: "SkipCerts_SecertCertDataExist_CertsSkipped",
|
|
runData: &TestInitData{
|
|
Name: "karmada-demo",
|
|
Namespace: "test",
|
|
RemoteClientConnector: client,
|
|
},
|
|
prep: func() error {
|
|
var err error
|
|
_, err = client.CoreV1().Secrets("test").Create(
|
|
context.TODO(), &corev1.Secret{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: util.KarmadaCertSecretName("karmada-demo"),
|
|
Namespace: "test",
|
|
},
|
|
Data: map[string][]byte{
|
|
"ca.crt": []byte("ca-crt-data"),
|
|
"ca.key": []byte("ca-key-data"),
|
|
},
|
|
},
|
|
metav1.CreateOptions{},
|
|
)
|
|
return err
|
|
},
|
|
cleanup: func() error {
|
|
err := client.CoreV1().Secrets("test").Delete(
|
|
context.TODO(), util.KarmadaCertSecretName("karmada-demo"),
|
|
metav1.DeleteOptions{},
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete %s secret", "test")
|
|
}
|
|
return nil
|
|
},
|
|
wantErr: false,
|
|
wantSkip: true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
err := test.prep()
|
|
if err != nil {
|
|
t.Errorf("failed to prep test: %v", err)
|
|
}
|
|
|
|
skip, err := skipCerts(test.runData)
|
|
if err == nil && test.wantErr {
|
|
t.Errorf("expected error, but got none")
|
|
}
|
|
if err != nil && !test.wantErr {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
if err != nil && test.wantErr && !strings.Contains(err.Error(), test.errMsg) {
|
|
t.Errorf("expected %s error msg to contain %s", err.Error(), test.errMsg)
|
|
}
|
|
if skip != test.wantSkip {
|
|
t.Errorf("expected %t skip, but got %t", test.wantSkip, skip)
|
|
}
|
|
err = test.cleanup()
|
|
if err != nil {
|
|
t.Errorf("failed to clean up test: %v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRunCATask(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
kc *certs.CertConfig
|
|
runData workflow.RunData
|
|
prep func(*certs.CertConfig) error
|
|
verify func(workflow.RunData) error
|
|
wantErr bool
|
|
errMsg string
|
|
}{
|
|
{
|
|
name: "RunCATask_InvalidTypeAssertion_TypeAssertionFailed",
|
|
kc: certs.KarmadaCertRootCA(),
|
|
runData: MyTestData{Data: "test"},
|
|
prep: func(*certs.CertConfig) error { return nil },
|
|
verify: func(workflow.RunData) error { return nil },
|
|
wantErr: true,
|
|
errMsg: "certs task invoked with an invalid data struct",
|
|
},
|
|
{
|
|
name: "RunCATask_WithNonCACertificate_CACertificateExpected",
|
|
kc: certs.KarmadaCertAdmin(),
|
|
runData: &TestInitData{
|
|
Name: "karmada-demo",
|
|
Namespace: "test",
|
|
},
|
|
prep: func(*certs.CertConfig) error { return nil },
|
|
verify: func(workflow.RunData) error { return nil },
|
|
wantErr: true,
|
|
errMsg: fmt.Sprintf("this function should only be used for CAs, but cert %s has CA %s", constants.KarmadaCertAndKeyName, constants.CaCertAndKeyName),
|
|
},
|
|
{
|
|
name: "RunCATask_WithEd25519UnsupportedPublicKeyAlgorithm_UnsupportedKeyType",
|
|
kc: certs.KarmadaCertRootCA(),
|
|
runData: &TestInitData{
|
|
Name: "karmada-demo",
|
|
Namespace: "test",
|
|
},
|
|
prep: func(cc *certs.CertConfig) error {
|
|
cc.PublicKeyAlgorithm = x509.Ed25519
|
|
return nil
|
|
},
|
|
verify: func(workflow.RunData) error { return nil },
|
|
wantErr: true,
|
|
errMsg: fmt.Sprintf("unsupported key type: %T", x509.Ed25519),
|
|
},
|
|
{
|
|
name: "RunCATask_GenerateCACertificate_CACertificateSuccessfullyGenerated",
|
|
kc: certs.KarmadaCertRootCA(),
|
|
runData: &TestInitData{
|
|
Name: "karmada-demo",
|
|
Namespace: "test",
|
|
},
|
|
prep: func(*certs.CertConfig) error { return nil },
|
|
verify: func(rd workflow.RunData) error {
|
|
certData := rd.(*TestInitData).CertList()
|
|
if len(certData) != 1 {
|
|
return fmt.Errorf("expected cert store to contain the generated CA certificate but found %d certs", len(certData))
|
|
}
|
|
return nil
|
|
},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if err := test.prep(test.kc); err != nil {
|
|
t.Errorf("failed to prep cert config data: %v", err)
|
|
}
|
|
caTask := runCATask(test.kc)
|
|
err := caTask(test.runData)
|
|
if err == nil && test.wantErr {
|
|
t.Errorf("expected error, but got none")
|
|
}
|
|
if err != nil && !test.wantErr {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
if err != nil && test.wantErr && !strings.Contains(err.Error(), test.errMsg) {
|
|
t.Errorf("expected %s error msg to contain %s", err.Error(), test.errMsg)
|
|
}
|
|
if err := test.verify(test.runData); err != nil {
|
|
t.Errorf("failed to verify run data: %v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRunCertTask(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
kc *certs.CertConfig
|
|
caCert *certs.CertConfig
|
|
runData workflow.RunData
|
|
prep func(*certs.CertConfig, *certs.CertConfig, workflow.RunData) error
|
|
verify func(workflow.RunData) error
|
|
wantErr bool
|
|
errMsg string
|
|
}{
|
|
{
|
|
name: "RunCertTask_InvalidTypeAssertion_TypeAssertionFailed",
|
|
kc: certs.KarmadaCertAdmin(),
|
|
runData: MyTestData{Data: "test"},
|
|
prep: func(*certs.CertConfig, *certs.CertConfig, workflow.RunData) error { return nil },
|
|
verify: func(workflow.RunData) error { return nil },
|
|
caCert: nil,
|
|
wantErr: true,
|
|
errMsg: "certs task invoked with an invalid data struct",
|
|
},
|
|
{
|
|
name: "RunCertTask_NilCACert_CACertIsNil",
|
|
kc: certs.KarmadaCertAdmin(),
|
|
runData: &TestInitData{
|
|
Name: "karmada-demo",
|
|
Namespace: "test",
|
|
},
|
|
prep: func(*certs.CertConfig, *certs.CertConfig, workflow.RunData) error { return nil },
|
|
verify: func(workflow.RunData) error { return nil },
|
|
caCert: nil,
|
|
wantErr: true,
|
|
errMsg: fmt.Sprintf("unexpected empty ca cert for %s", constants.KarmadaCertAndKeyName),
|
|
},
|
|
{
|
|
name: "RunCertTask_MismatchCAName_CANameIsMismatch",
|
|
kc: certs.KarmadaCertAdmin(),
|
|
runData: &TestInitData{
|
|
Name: "karmada-demo",
|
|
Namespace: "test",
|
|
},
|
|
prep: func(*certs.CertConfig, *certs.CertConfig, workflow.RunData) error { return nil },
|
|
verify: func(workflow.RunData) error { return nil },
|
|
caCert: &certs.CertConfig{
|
|
Name: "invalid",
|
|
},
|
|
wantErr: true,
|
|
errMsg: fmt.Sprintf("mismatched CA name: expected %s but got %s", constants.CaCertAndKeyName, "invalid"),
|
|
},
|
|
{
|
|
name: "RunCertTask_CreateCertAndKeyFileWithCA_SuccessfullyGeneratedCertificate",
|
|
kc: certs.KarmadaCertAdmin(),
|
|
caCert: certs.KarmadaCertRootCA(),
|
|
runData: &TestInitData{
|
|
Name: "karmada-demo",
|
|
Namespace: "test",
|
|
ComponentsUnits: &operatorv1alpha1.KarmadaComponents{
|
|
KarmadaAPIServer: &operatorv1alpha1.KarmadaAPIServer{},
|
|
},
|
|
},
|
|
prep: func(ca *certs.CertConfig, _ *certs.CertConfig, rd workflow.RunData) error {
|
|
newCA, err := certs.NewCertificateAuthority(ca)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create certificate authority: %v", err)
|
|
}
|
|
rd.(*TestInitData).AddCert(newCA)
|
|
return nil
|
|
},
|
|
verify: func(rd workflow.RunData) error {
|
|
certData := rd.(*TestInitData).CertList()
|
|
if len(certData) != 2 {
|
|
return fmt.Errorf("expected cert store to contain the Certificate Authority and the associated certificate but found %d certs", len(certData))
|
|
}
|
|
if rd.(*TestInitData).GetCert(constants.CaCertAndKeyName) == nil {
|
|
return fmt.Errorf("expected %s Karmada Root CA to exist in the certificates store", constants.CaCertAndKeyName)
|
|
}
|
|
if rd.(*TestInitData).GetCert(constants.KarmadaCertAndKeyName) == nil {
|
|
return fmt.Errorf("expected %s karmada admin certificate to exist in the certificate store", constants.KarmadaCertAndKeyName)
|
|
}
|
|
return nil
|
|
},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if err := test.prep(test.caCert, test.kc, test.runData); err != nil {
|
|
t.Errorf("failed to prep cert config data: %v", err)
|
|
}
|
|
certTask := runCertTask(test.kc, test.caCert)
|
|
err := certTask(test.runData)
|
|
if err == nil && test.wantErr {
|
|
t.Errorf("expected error, but got none")
|
|
}
|
|
if err != nil && !test.wantErr {
|
|
t.Errorf("unexpected error: %v", err)
|
|
}
|
|
if err != nil && test.wantErr && !strings.Contains(err.Error(), test.errMsg) {
|
|
t.Errorf("expected %s error msg to contain %s", err.Error(), test.errMsg)
|
|
}
|
|
if err := test.verify(test.runData); err != nil {
|
|
t.Errorf("failed to verify run data: %v", err)
|
|
}
|
|
})
|
|
}
|
|
}
|