*
* Copyright (c) 2025 Bocloud Technologies Co., Ltd.
* installer is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* <http://license.coscl.org.cn/MulanPSL2>
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*
*/
package clusterapi
import (
"os"
"path/filepath"
"testing"
"time"
"github.com/agiledragon/gomonkey/v2"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
"gopkg.openfuyao.cn/bkeadm/pkg/executor/k8s"
"gopkg.openfuyao.cn/bkeadm/pkg/global"
)
const (
testZeroValue = 0
testOneValue = 1
testTwoValue = 2
testThreeVal = 3
)
func TestEnsureK8sClientWithExistingClient(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
mockK8sClient := &k8s.MockK8sClient{}
global.K8s = mockK8sClient
err := ensureK8sClient()
assert.NoError(t, err)
}
func TestEnsureK8sClientNewClientSuccess(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
global.K8s = nil
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(k8s.NewKubernetesClient, func(string) (k8s.KubernetesClient, error) {
return &k8s.MockK8sClient{}, nil
})
err := ensureK8sClient()
assert.NoError(t, err)
}
func TestEnsureK8sClientNewClientError(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
global.K8s = nil
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(k8s.NewKubernetesClient, func(string) (k8s.KubernetesClient, error) {
return nil, assert.AnError
})
err := ensureK8sClient()
assert.Error(t, err)
}
func TestWriteClusterAPITemplatesSuccess(t *testing.T) {
tempDir := t.TempDir()
tmplDir := filepath.Join(tempDir, "tmpl")
err := writeClusterAPITemplates(tmplDir)
assert.NoError(t, err)
assert.DirExists(t, tmplDir)
}
func TestWriteClusterAPITemplatesMkdirError(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.MkdirAll, func(string, os.FileMode) error {
return assert.AnError
})
err := writeClusterAPITemplates("/invalid/path/tmpl")
assert.Error(t, err)
}
func TestWriteClusterAPITemplatesWriteFileError(t *testing.T) {
tempDir := t.TempDir()
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.WriteFile, func(string, []byte, os.FileMode) error {
return assert.AnError
})
err := writeClusterAPITemplates(tempDir)
assert.Error(t, err)
}
func TestWriteClusterAPITemplatesMultipleFilesError(t *testing.T) {
tempDir := t.TempDir()
writeCount := 0
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.WriteFile, func(string, []byte, os.FileMode) error {
writeCount++
if writeCount == testTwoValue {
return assert.AnError
}
return nil
})
err := writeClusterAPITemplates(tempDir)
assert.Error(t, err)
}
func TestAreAllPodsRunningAllRunning(t *testing.T) {
pods := []corev1.Pod{
{Status: corev1.PodStatus{Phase: corev1.PodRunning}},
{Status: corev1.PodStatus{Phase: corev1.PodRunning}},
}
result := areAllPodsRunning(pods)
assert.True(t, result)
}
func TestAreAllPodsRunningNotAllRunning(t *testing.T) {
pods := []corev1.Pod{
{Status: corev1.PodStatus{Phase: corev1.PodRunning}},
{Status: corev1.PodStatus{Phase: corev1.PodPending}},
}
result := areAllPodsRunning(pods)
assert.False(t, result)
}
func TestAreAllPodsRunningWithContainerWaiting(t *testing.T) {
pods := []corev1.Pod{
{
Status: corev1.PodStatus{
Phase: corev1.PodPending,
ContainerStatuses: []corev1.ContainerStatus{
{
State: corev1.ContainerState{
Waiting: &corev1.ContainerStateWaiting{
Reason: "ImagePullBackOff",
},
},
},
},
},
},
}
result := areAllPodsRunning(pods)
assert.False(t, result)
}
func TestAreAllPodsRunningEmpty(t *testing.T) {
pods := []corev1.Pod{}
result := areAllPodsRunning(pods)
assert.True(t, result)
}
func TestAreAllPodsRunningWithSucceededPhase(t *testing.T) {
pods := []corev1.Pod{
{Status: corev1.PodStatus{Phase: corev1.PodSucceeded}},
}
result := areAllPodsRunning(pods)
assert.False(t, result)
}
func TestAreAllPodsRunningWithFailedPhase(t *testing.T) {
pods := []corev1.Pod{
{Status: corev1.PodStatus{Phase: corev1.PodFailed}},
}
result := areAllPodsRunning(pods)
assert.False(t, result)
}
func TestAreAllPodsRunningWithUnknownPhase(t *testing.T) {
pods := []corev1.Pod{
{Status: corev1.PodStatus{Phase: corev1.PodUnknown}},
}
result := areAllPodsRunning(pods)
assert.False(t, result)
}
func TestAreAllPodsRunningWithMultipleContainers(t *testing.T) {
pods := []corev1.Pod{
{
Status: corev1.PodStatus{
Phase: corev1.PodRunning,
ContainerStatuses: []corev1.ContainerStatus{
{
State: corev1.ContainerState{
Running: &corev1.ContainerStateRunning{},
},
},
{
State: corev1.ContainerState{
Waiting: &corev1.ContainerStateWaiting{
Reason: "CrashLoopBackOff",
},
},
},
},
},
},
{
Status: corev1.PodStatus{
Phase: corev1.PodPending,
},
},
}
result := areAllPodsRunning(pods)
assert.False(t, result)
}
func TestDeployClusterAPISuccess(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
mockK8sClient := &k8s.MockK8sClient{}
global.K8s = mockK8sClient
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.MkdirAll, func(string, os.FileMode) error {
return nil
})
patches.ApplyFunc(os.WriteFile, func(string, []byte, os.FileMode) error {
return nil
})
patches.ApplyMethod(mockK8sClient, "InstallYaml", func(*k8s.MockK8sClient, string, map[string]string, string) error {
return nil
})
patches.ApplyFunc(waitForClusterAPIPodsRunning, func() error {
return nil
})
patches.ApplyFunc(time.Sleep, func(time.Duration) {})
err := DeployClusterAPI("http://repo.example.com", "v1.0.0", "v1.0.0")
assert.NoError(t, err)
}
func TestDeployClusterAPIEnsureClientError(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
global.K8s = nil
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(k8s.NewKubernetesClient, func(string) (k8s.KubernetesClient, error) {
return nil, assert.AnError
})
err := DeployClusterAPI("http://repo.example.com", "v1.0.0", "v1.0.0")
assert.Error(t, err)
}
func TestDeployClusterAPIWriteTemplatesError(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
mockK8sClient := &k8s.MockK8sClient{}
global.K8s = mockK8sClient
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.MkdirAll, func(string, os.FileMode) error {
return assert.AnError
})
err := DeployClusterAPI("http://repo.example.com", "v1.0.0", "v1.0.0")
assert.Error(t, err)
}
func TestDeployClusterAPIInstallCertManagerError(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
mockK8sClient := &k8s.MockK8sClient{}
global.K8s = mockK8sClient
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.MkdirAll, func(string, os.FileMode) error {
return nil
})
patches.ApplyFunc(os.WriteFile, func(string, []byte, os.FileMode) error {
return nil
})
installCount := 0
patches.ApplyMethod(mockK8sClient, "InstallYaml", func(*k8s.MockK8sClient, string, map[string]string, string) error {
installCount++
if installCount == testOneValue {
return assert.AnError
}
return nil
})
patches.ApplyFunc(waitForClusterAPIPodsRunning, func() error {
return nil
})
err := DeployClusterAPI("http://repo.example.com", "v1.0.0", "v1.0.0")
assert.Error(t, err)
}
func TestDeployClusterAPIInstallClusterAPIError(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
mockK8sClient := &k8s.MockK8sClient{}
global.K8s = mockK8sClient
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.MkdirAll, func(string, os.FileMode) error {
return nil
})
patches.ApplyFunc(os.WriteFile, func(string, []byte, os.FileMode) error {
return nil
})
patches.ApplyMethod(mockK8sClient, "InstallYaml", func(*k8s.MockK8sClient, string, map[string]string, string) error {
return assert.AnError
})
patches.ApplyFunc(waitForClusterAPIPodsRunning, func() error {
return nil
})
patches.ApplyFunc(time.Sleep, func(time.Duration) {})
patches.ApplyFunc(installClusterAPIWithRetry, func(string, string) error {
return assert.AnError
})
err := DeployClusterAPI("http://repo.example.com", "v1.0.0", "v1.0.0")
assert.Error(t, err)
}
func TestDeployClusterAPIInstallClusterAPIBKEError(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
mockK8sClient := &k8s.MockK8sClient{}
global.K8s = mockK8sClient
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.MkdirAll, func(string, os.FileMode) error {
return nil
})
patches.ApplyFunc(os.WriteFile, func(string, []byte, os.FileMode) error {
return nil
})
installCount := 0
patches.ApplyMethod(mockK8sClient, "InstallYaml", func(*k8s.MockK8sClient, string, map[string]string, string) error {
installCount++
if installCount == testThreeVal {
return assert.AnError
}
return nil
})
patches.ApplyFunc(waitForClusterAPIPodsRunning, func() error {
return nil
})
patches.ApplyFunc(time.Sleep, func(time.Duration) {})
err := DeployClusterAPI("http://repo.example.com", "v1.0.0", "v1.0.0")
assert.Error(t, err)
}
func TestDeployClusterAPIWaitPodsError(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
mockK8sClient := &k8s.MockK8sClient{}
global.K8s = mockK8sClient
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.MkdirAll, func(string, os.FileMode) error {
return nil
})
patches.ApplyFunc(os.WriteFile, func(string, []byte, os.FileMode) error {
return nil
})
patches.ApplyMethod(mockK8sClient, "InstallYaml", func(*k8s.MockK8sClient, string, map[string]string, string) error {
return nil
})
patches.ApplyFunc(waitForClusterAPIPodsRunning, func() error {
return assert.AnError
})
patches.ApplyFunc(time.Sleep, func(time.Duration) {})
err := DeployClusterAPI("http://repo.example.com", "v1.0.0", "v1.0.0")
assert.Error(t, err)
}
func TestInstallClusterAPIWithRetrySuccess(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
mockK8sClient := &k8s.MockK8sClient{}
global.K8s = mockK8sClient
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyMethodFunc(mockK8sClient, "InstallYaml", func(string, map[string]string, string) error {
return nil
})
patches.ApplyFunc(time.Sleep, func(time.Duration) {})
err := installClusterAPIWithRetry("/test/yaml/file.yaml", "http://repo.example.com")
assert.NoError(t, err)
}
func TestInstallClusterAPIWithRetryMultipleRetriesSuccess(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
mockK8sClient := &k8s.MockK8sClient{}
global.K8s = mockK8sClient
retryCount := 0
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyMethodFunc(mockK8sClient, "InstallYaml", func(string, map[string]string, string) error {
retryCount++
if retryCount < testThreeVal {
return assert.AnError
}
return nil
})
patches.ApplyFunc(time.Sleep, func(time.Duration) {})
err := installClusterAPIWithRetry("/test/yaml/file.yaml", "http://repo.example.com")
assert.NoError(t, err)
assert.Equal(t, testThreeVal, retryCount)
}
func TestInstallClusterAPIWithRetryInstallError(t *testing.T) {
originalK8s := global.K8s
defer func() { global.K8s = originalK8s }()
mockK8sClient := &k8s.MockK8sClient{}
global.K8s = mockK8sClient
callCount := 0
maxCalls := 2
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyMethodFunc(mockK8sClient, "InstallYaml", func(string, map[string]string, string) error {
callCount++
if callCount < maxCalls {
return assert.AnError
}
return nil
})
patches.ApplyFunc(time.Sleep, func(time.Duration) {})
err := installClusterAPIWithRetry("/test/yaml/file.yaml", "http://repo.example.com")
assert.NoError(t, err)
assert.Equal(t, maxCalls, callCount)
}
func TestWaitForClusterAPIPodsRunningSuccess(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(waitForClusterAPIPodsRunning, func() error {
return nil
})
err := waitForClusterAPIPodsRunning()
assert.NoError(t, err)
}
func TestWaitForClusterAPIPodsRunningError(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(waitForClusterAPIPodsRunning, func() error {
return assert.AnError
})
err := waitForClusterAPIPodsRunning()
assert.Error(t, err)
}