*
* 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 repository
import (
"errors"
"fmt"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"time"
"github.com/agiledragon/gomonkey/v2"
"github.com/stretchr/testify/assert"
"gopkg.openfuyao.cn/bkeadm/pkg/build"
"gopkg.openfuyao.cn/bkeadm/pkg/common"
econd "gopkg.openfuyao.cn/bkeadm/pkg/executor/containerd"
"gopkg.openfuyao.cn/bkeadm/pkg/registry"
"gopkg.openfuyao.cn/bkeadm/pkg/server"
"gopkg.openfuyao.cn/bkeadm/utils"
"gopkg.openfuyao.cn/bkeadm/utils/log"
)
const (
testZeroValue = 0
testOneValue = 1
testTwoValue = 2
testThreeValue = 3
testDefaultPort = 443
testRegistryPort = "5000"
)
const (
testIPv4SegmentA = 192
testIPv4SegmentB = 168
testIPv4SegmentC = 1
testIPv4SegmentD = 100
)
const (
testIPv4SegmentD2 = 102
)
var (
testIPAddress = fmt.Sprintf("%d.%d.%d.%d", testIPv4SegmentA, testIPv4SegmentB, testIPv4SegmentC, testIPv4SegmentD)
testIPAddress2 = fmt.Sprintf("%d.%d.%d.%d", testIPv4SegmentA, testIPv4SegmentB, testIPv4SegmentC, testIPv4SegmentD2)
)
func TestParseOnlineConfig(t *testing.T) {
tests := []struct {
name string
domain string
image string
repo string
source string
chartRepo string
mockLoopIP func(string) ([]string, error)
expectError bool
}{
{
name: "empty repo and chartRepo",
domain: "example.com",
image: "",
repo: "",
source: "",
chartRepo: "",
mockLoopIP: func(s string) ([]string, error) { return nil, nil },
expectError: false,
},
{
name: "repo with image tag and IP resolution success",
domain: "example.com",
image: "",
repo: "registry.example.com/test/image:v1.0",
source: "",
chartRepo: "",
mockLoopIP: func(s string) ([]string, error) { return []string{testIPAddress}, nil },
expectError: false,
},
{
name: "repo with IP address",
domain: "example.com",
image: "",
repo: testIPAddress + ":5000/test/repo",
source: "http://" + testIPAddress + ":5000/source",
chartRepo: "",
mockLoopIP: func(s string) ([]string, error) { return nil, nil },
expectError: false,
},
{
name: "repo with domain name resolution success",
domain: "example.com",
image: "",
repo: "registry.example.com/test/repo",
source: "",
chartRepo: "",
mockLoopIP: func(s string) ([]string, error) { return []string{testIPAddress}, nil },
expectError: false,
},
{
name: "repo with domain name resolution failure",
domain: "example.com",
image: "",
repo: "nonexistent.example.com/test/repo",
source: "",
chartRepo: "",
mockLoopIP: func(s string) ([]string, error) { return []string{}, errors.New("resolution failed") },
expectError: true,
},
{
name: "chartRepo with IP address",
domain: "example.com",
image: "",
repo: "",
source: "",
chartRepo: testIPAddress2 + ":8443/charts/repo",
mockLoopIP: func(s string) ([]string, error) { return nil, nil },
expectError: false,
},
{
name: "chartRepo with domain name and resolution",
domain: "example.com",
image: "",
repo: "",
source: "",
chartRepo: "chart.example.com/charts/repo",
mockLoopIP: func(s string) ([]string, error) { return []string{testIPAddress}, nil },
expectError: false,
},
{
name: "source is preserved when provided",
domain: "example.com",
image: "",
repo: "",
source: "http://source.example.com/data",
chartRepo: "",
mockLoopIP: func(s string) ([]string, error) { return nil, nil },
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.LoopIP, tt.mockLoopIP)
_, err := ParseOnlineConfig(tt.domain, tt.image, tt.repo, tt.source, tt.chartRepo)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestSetupCACertificate(t *testing.T) {
tests := []struct {
name string
config CertificateConfig
mockMkdirAll func(string, os.FileMode) error
mockCopyFile func(string, string) error
expectError bool
}{
{
name: "nil CA file path",
config: CertificateConfig{CAFile: ""},
mockMkdirAll: nil,
mockCopyFile: nil,
expectError: false,
},
{
name: "successful certificate setup",
config: CertificateConfig{
CAFile: "/tmp/ca.crt",
RegistryHost: "registry.example.com",
RegistryPort: testRegistryPort,
},
mockMkdirAll: func(s string, m os.FileMode) error { return nil },
mockCopyFile: func(s string, s2 string) error { return nil },
expectError: false,
},
{
name: "mkdir fails for first directory",
config: CertificateConfig{
CAFile: "/tmp/ca.crt",
RegistryHost: "registry.example.com",
RegistryPort: testRegistryPort,
},
mockMkdirAll: func(s string, m os.FileMode) error { return errors.New("mkdir error") },
mockCopyFile: nil,
expectError: true,
},
{
name: "copy file fails",
config: CertificateConfig{
CAFile: "/tmp/ca.crt",
RegistryHost: "registry.example.com",
RegistryPort: testRegistryPort,
},
mockMkdirAll: func(s string, m os.FileMode) error { return nil },
mockCopyFile: func(s string, s2 string) error { return errors.New("copy error") },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
if tt.mockMkdirAll != nil {
patches.ApplyFunc(os.MkdirAll, tt.mockMkdirAll)
}
if tt.mockCopyFile != nil {
patches.ApplyFunc(copyFile, tt.mockCopyFile)
}
err := SetupCACertificate(&tt.config)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestCopyFile(t *testing.T) {
tests := []struct {
name string
mockOpen func(string) (*os.File, error)
mockCreate func(string) (*os.File, error)
expectError bool
}{
{
name: "source file open error",
mockOpen: func(s string) (*os.File, error) {
return nil, errors.New("open error")
},
expectError: true,
},
{
name: "destination file create error",
mockOpen: func(s string) (*os.File, error) {
tmpFile, _ := os.CreateTemp("", "source")
return tmpFile, nil
},
mockCreate: func(s string) (*os.File, error) {
return nil, errors.New("create error")
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
if tt.mockOpen != nil {
patches.ApplyFunc(os.Open, tt.mockOpen)
}
if tt.mockCreate != nil {
patches.ApplyFunc(os.Create, tt.mockCreate)
}
err := copyFile("/tmp/source.txt", "/tmp/dest.txt")
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestParseRegistryHostPort(t *testing.T) {
tests := []struct {
name string
imageRepo string
expectHost string
expectPort string
}{
{
name: "empty input",
imageRepo: "",
expectHost: "",
expectPort: "",
},
{
name: "registry with https prefix",
imageRepo: "https://registry.example.com/repo/image:v1",
expectHost: "registry.example.com",
expectPort: "443",
},
{
name: "registry with http prefix",
imageRepo: "http://registry.example.com:8080/repo/image:v1",
expectHost: "registry.example.com",
expectPort: "8080",
},
{
name: "registry without prefix and custom port",
imageRepo: "registry.example.com:5000/repo/image:v1",
expectHost: "registry.example.com",
expectPort: "5000",
},
{
name: "registry without port uses default 443",
imageRepo: "registry.example.com/repo/image:v1",
expectHost: "registry.example.com",
expectPort: "443",
},
{
name: "IP address with port",
imageRepo: testIPAddress + ":5000/repo/image:v1",
expectHost: testIPAddress,
expectPort: "5000",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
host, port := ParseRegistryHostPort(tt.imageRepo)
assert.Equal(t, tt.expectHost, host)
assert.Equal(t, tt.expectPort, port)
})
}
}
func TestCleanTempYumDataFile(t *testing.T) {
tests := []struct {
name string
mockExists bool
expectError bool
}{
{
name: "temp file does not exist",
mockExists: false,
expectError: false,
},
{
name: "temp file removed successfully",
mockExists: true,
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, func(s string) bool {
return tt.mockExists
})
patches.ApplyFunc(os.RemoveAll, func(s string) error {
return nil
})
err := cleanTempYumDataFile()
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestBuildDownloadOptions(t *testing.T) {
tests := []struct {
name string
oc OtherRepo
certConfig *CertificateConfig
expectImage string
expectUser string
}{
{
name: "build options with all fields",
oc: OtherRepo{
Image: "registry.example.com/image:v1",
},
certConfig: &CertificateConfig{
TLSVerify: true,
Username: "user",
Password: "pass",
CAFile: "/tmp/ca.crt",
},
expectImage: "registry.example.com/image:v1",
expectUser: "user",
},
{
name: "build options with empty config",
oc: OtherRepo{
Image: "registry.example.com/image:v1",
},
certConfig: &CertificateConfig{},
expectImage: "registry.example.com/image:v1",
expectUser: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := buildDownloadOptions(tt.oc, tt.certConfig)
assert.Equal(t, tt.expectImage, result.Image)
assert.Equal(t, tt.expectUser, result.Username)
assert.Equal(t, tt.certConfig.TLSVerify, result.SrcTLSVerify)
})
}
}
func TestFinalizeYumDataFile(t *testing.T) {
tests := []struct {
name string
mockRename func(string, string) error
expectError bool
}{
{
name: "rename error",
mockRename: func(s string, s2 string) error {
return errors.New("rename error")
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.Rename, tt.mockRename)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := finalizeYumDataFile()
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestSourceBaseFile(t *testing.T) {
tests := []struct {
name string
httpRepo string
mockExists func(string) bool
mockDownload func(string, string) error
expectError bool
}{
{
name: "all files already exist",
httpRepo: "http://example.com",
mockExists: func(s string) bool { return true },
expectError: false,
},
{
name: "download chart fails but continues",
httpRepo: "http://example.com",
mockExists: func(s string) bool {
if strings.Contains(s, "charts.tar.gz") {
return false
}
return true
},
mockDownload: func(s string, s2 string) error {
if strings.Contains(s, "charts.tar.gz") {
return errors.New("download error")
}
return nil
},
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, tt.mockExists)
if tt.mockDownload != nil {
patches.ApplyFunc(utils.DownloadFile, tt.mockDownload)
}
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := sourceBaseFile(tt.httpRepo)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestCheckLocalRuntimeFilesExist(t *testing.T) {
tests := []struct {
name string
mockReadDir func(string) ([]os.DirEntry, error)
mockValidateExtra func(map[string]string) error
expectResult bool
expectError bool
}{
{
name: "all files exist",
mockReadDir: func(s string) ([]os.DirEntry, error) {
return []os.DirEntry{
&mockDirEntry{name: "containerd-1.7.0-linux-amd64.tar.gz"},
&mockDirEntry{name: "cni-plugins-linux-amd64-v1.3.0.tgz"},
&mockDirEntry{name: "kubectl-v1.27.0-linux-amd64"},
}, nil
},
mockValidateExtra: func(m map[string]string) error { return nil },
expectResult: true,
expectError: false,
},
{
name: "missing containerd files",
mockReadDir: func(s string) ([]os.DirEntry, error) {
return []os.DirEntry{
&mockDirEntry{name: "cni-plugins-linux-amd64-v1.3.0.tgz"},
&mockDirEntry{name: "kubectl-v1.27.0-linux-amd64"},
}, nil
},
mockValidateExtra: func(m map[string]string) error { return nil },
expectResult: false,
expectError: false,
},
{
name: "read dir error",
mockReadDir: func(s string) ([]os.DirEntry, error) {
return nil, errors.New("read dir error")
},
expectResult: false,
expectError: true,
},
{
name: "invalid containerd files are skipped",
mockReadDir: func(s string) ([]os.DirEntry, error) {
return []os.DirEntry{
&mockDirEntry{name: "invalid-file"},
&mockDirEntry{name: "cni-plugins-linux-amd64-v1.3.0.tgz"},
&mockDirEntry{name: "kubectl-v1.27.0-linux-amd64"},
}, nil
},
mockValidateExtra: func(m map[string]string) error { return errors.New("invalid") },
expectResult: false,
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.ReadDir, tt.mockReadDir)
if tt.mockValidateExtra != nil {
patches.ApplyFunc(validateCustomExtra, tt.mockValidateExtra)
}
result, err := checkLocalRuntimeFilesExist()
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.expectResult, result)
}
})
}
}
type testHTTPHandler struct {
content string
status int
}
func (h *testHTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(h.status)
w.Write([]byte(h.content))
}
func TestFetchRemoteFileList(t *testing.T) {
tests := []struct {
name string
handler *testHTTPHandler
expectError bool
}{
{
name: "HTTP error response",
handler: &testHTTPHandler{
status: http.StatusNotFound,
},
expectError: true,
},
{
name: "HTTP request error",
handler: nil,
expectError: true,
},
{
name: "empty HTML content",
handler: &testHTTPHandler{
content: "",
status: http.StatusOK,
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var server *httptest.Server
if tt.handler != nil {
server = httptest.NewServer(tt.handler)
defer server.Close()
}
var url string
if server != nil {
url = server.URL + "/files/"
} else {
url = "http://invalid.example.com/files/"
}
_, err := fetchRemoteFileList(url)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestParseFileListFromHTML(t *testing.T) {
tests := []struct {
name string
htmlData string
check func(*runtimeFiles) bool
}{
{
name: "parse all file types",
htmlData: `<html>
<body>
<a href="containerd-1.7.0-linux-amd64.tar.gz">containerd-1.7.0-linux-amd64.tar.gz</a>
<a href="containerd-1.6.0-linux-amd64.tar.gz">containerd-1.6.0-linux-amd64.tar.gz</a>
<a href="cni-plugins-linux-amd64-v1.3.0.tgz">cni-plugins-linux-amd64-v1.3.0.tgz</a>
<a href="cni-plugins-linux-amd64-v1.2.0.tgz">cni-plugins-linux-amd64-v1.2.0.tgz</a>
<a href="kubectl-v1.27.0-linux-amd64">kubectl-v1.27.0-linux-amd64</a>
<a href="kubectl-v1.26.0-linux-amd64">kubectl-v1.26.0-linux-amd64</a>
</body>
</html>`,
check: func(rf *runtimeFiles) bool {
return len(rf.containerd) == testTwoValue &&
len(rf.cni) == testTwoValue &&
len(rf.kubectl) == testTwoValue
},
},
{
name: "empty HTML",
htmlData: "",
check: func(rf *runtimeFiles) bool {
return len(rf.containerd) == testZeroValue &&
len(rf.cni) == testZeroValue &&
len(rf.kubectl) == testZeroValue
},
},
{
name: "no matching files",
htmlData: `<html><body>
<a href="readme.txt">readme.txt</a>
<a href="config.yaml">config.yaml</a>
</body></html>`,
check: func(rf *runtimeFiles) bool {
return len(rf.containerd) == testZeroValue &&
len(rf.cni) == testZeroValue &&
len(rf.kubectl) == testZeroValue
},
},
{
name: "mixed content with some matches",
htmlData: `<html><body>
<a href="containerd-1.7.0.tar.gz">containerd-1.7.0.tar.gz</a>
<a href="random-file.txt">random-file.txt</a>
<a href="kubectl-v1.27.0">kubectl-v1.27.0</a>
</body></html>`,
check: func(rf *runtimeFiles) bool {
return len(rf.containerd) == testOneValue &&
len(rf.cni) == testZeroValue &&
len(rf.kubectl) == testOneValue
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := parseFileListFromHTML(tt.htmlData)
assert.NoError(t, err)
assert.True(t, tt.check(result), "check failed for test case: %s", tt.name)
})
}
}
func TestDownloadRuntimeFiles(t *testing.T) {
tests := []struct {
name string
files *runtimeFiles
mockDownload func(string, string) error
expectError bool
}{
{
name: "download containerd fails",
files: &runtimeFiles{
containerd: []string{"containerd-1.7.0.tar.gz"},
cni: []string{"cni-plugins-v1.3.0.tgz"},
kubectl: []string{"kubectl-v1.27.0"},
},
mockDownload: func(s string, s2 string) error {
if strings.Contains(s, "containerd") {
return errors.New("download containerd error")
}
return nil
},
expectError: true,
},
{
name: "download cni fails",
files: &runtimeFiles{
containerd: []string{"containerd-1.7.0.tar.gz"},
cni: []string{"cni-plugins-v1.3.0.tgz"},
kubectl: []string{"kubectl-v1.27.0"},
},
mockDownload: func(s string, s2 string) error {
if strings.Contains(s, "cni") {
return errors.New("download cni error")
}
return nil
},
expectError: true,
},
{
name: "no kubectl files error",
files: &runtimeFiles{
containerd: []string{"containerd-1.7.0.tar.gz"},
cni: []string{"cni-plugins-v1.3.0.tgz"},
kubectl: []string{},
},
expectError: true,
},
{
name: "download kubectl fails",
files: &runtimeFiles{
containerd: []string{"containerd-1.7.0.tar.gz"},
cni: []string{"cni-plugins-v1.3.0.tgz"},
kubectl: []string{"kubectl-v1.27.0"},
},
mockDownload: func(s string, s2 string) error {
if strings.Contains(s, "kubectl") {
return errors.New("download kubectl error")
}
return nil
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
if tt.mockDownload != nil {
patches.ApplyFunc(utils.DownloadFile, tt.mockDownload)
}
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := downloadRuntimeFiles("http://example.com/files/", tt.files.containerd, tt.files.cni, tt.files.kubectl)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestSourceRuntimeKylin(t *testing.T) {
tests := []struct {
name string
httpRepo string
mockExists func(string) bool
mockDownload func(string, string) error
expectError bool
}{
{
name: "files already exist",
httpRepo: "http://example.com",
mockExists: func(s string) bool {
return true
},
expectError: false,
},
{
name: "download kylin docker files",
httpRepo: "http://example.com",
mockExists: func(s string) bool {
return false
},
mockDownload: func(s string, s2 string) error { return nil },
expectError: false,
},
{
name: "download fails for one file",
httpRepo: "http://example.com",
mockExists: func(s string) bool {
return false
},
mockDownload: func(s string, s2 string) error {
if strings.Contains(s, "arm64") {
return nil
}
return errors.New("download error")
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, tt.mockExists)
if tt.mockDownload != nil {
patches.ApplyFunc(utils.DownloadFile, tt.mockDownload)
}
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
patches.ApplyFunc(log.Errorf, func(format string, args ...interface{}) {})
err := sourceRuntimeKylin(tt.httpRepo)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestSetupTLSCertificate(t *testing.T) {
tests := []struct {
name string
oc OtherRepo
certConfig *CertificateConfig
mockSetupCA func(*CertificateConfig) error
mockSetClient func(string) error
expectError bool
}{
{
name: "TLSVerify is false",
oc: OtherRepo{
Image: "registry.example.com/image:v1",
},
certConfig: &CertificateConfig{
TLSVerify: false,
},
expectError: false,
},
{
name: "TLSVerify true with SetupCA error",
oc: OtherRepo{
Image: "registry.example.com/image:v1",
},
certConfig: &CertificateConfig{
TLSVerify: true,
CAFile: "/tmp/ca.crt",
},
mockSetupCA: func(c *CertificateConfig) error {
return errors.New("setup CA error")
},
expectError: true,
},
{
name: "default image repo with SetClientCertificate error",
oc: OtherRepo{
Image: "deploy.bocloud.k8s:5000/image:v1",
},
certConfig: &CertificateConfig{
TLSVerify: true,
CAFile: "/tmp/ca.crt",
},
mockSetClient: func(s string) error {
return errors.New("set client error")
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
if tt.mockSetupCA != nil {
patches.ApplyFunc(SetupCACertificate, tt.mockSetupCA)
}
if tt.mockSetClient != nil {
patches.ApplyFunc(warehouseSetClientCertificate, tt.mockSetClient)
}
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
od := ®istry.OptionsDownload{}
err := setupTLSCertificate(tt.oc, tt.certConfig, od)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestSourceInit(t *testing.T) {
tests := []struct {
name string
oc OtherRepo
mockExists func(string) bool
mockMkdirAll func(string, os.FileMode) error
mockSourceBase func(string) error
mockSourceRun func(string) error
mockSourceRunKyl func(string) error
expectError bool
}{
{
name: "empty source",
oc: OtherRepo{
Source: "",
},
expectError: false,
},
{
name: "source init with all steps successful",
oc: OtherRepo{
Source: "http://example.com/source",
},
mockExists: func(s string) bool { return true },
mockMkdirAll: func(s string, m os.FileMode) error { return nil },
mockSourceBase: func(s string) error { return nil },
mockSourceRun: func(s string) error { return nil },
mockSourceRunKyl: func(s string) error { return nil },
expectError: false,
},
{
name: "source init with mkdir error",
oc: OtherRepo{
Source: "http://example.com/source",
},
mockExists: func(s string) bool { return false },
mockMkdirAll: func(s string, m os.FileMode) error { return errors.New("mkdir error") },
expectError: true,
},
{
name: "source init with sourceBaseFile error",
oc: OtherRepo{
Source: "http://example.com/source",
},
mockExists: func(s string) bool { return true },
mockSourceBase: func(s string) error { return errors.New("base error") },
expectError: true,
},
{
name: "source init with sourceRuntime error",
oc: OtherRepo{
Source: "http://example.com/source",
},
mockExists: func(s string) bool { return true },
mockSourceBase: func(s string) error { return nil },
mockSourceRun: func(s string) error { return errors.New("runtime error") },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, tt.mockExists)
if tt.mockMkdirAll != nil {
patches.ApplyFunc(os.MkdirAll, tt.mockMkdirAll)
}
if tt.mockSourceBase != nil {
patches.ApplyFunc(sourceBaseFile, tt.mockSourceBase)
}
if tt.mockSourceRun != nil {
patches.ApplyFunc(sourceRuntime, tt.mockSourceRun)
}
if tt.mockSourceRunKyl != nil {
patches.ApplyFunc(sourceRuntimeKylin, tt.mockSourceRunKyl)
}
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := SourceInit(tt.oc)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestRepoInit(t *testing.T) {
tests := []struct {
name string
oc OtherRepo
certConfig *CertificateConfig
mockExistsYum func(string) bool
mockCleanTemp func() error
mockSetupTLS func(OtherRepo, *CertificateConfig, *registry.OptionsDownload) error
expectError bool
}{
{
name: "empty image",
oc: OtherRepo{
Image: "",
},
certConfig: &CertificateConfig{},
expectError: false,
},
{
name: "yum data file already exists",
oc: OtherRepo{
Image: "registry.example.com/image:v1",
},
certConfig: &CertificateConfig{},
mockExistsYum: func(s string) bool { return true },
expectError: false,
},
{
name: "clean temp file error",
oc: OtherRepo{
Image: "registry.example.com/image:v1",
},
certConfig: &CertificateConfig{},
mockExistsYum: func(s string) bool { return false },
mockCleanTemp: func() error { return errors.New("clean error") },
expectError: true,
},
{
name: "setup TLS error",
oc: OtherRepo{
Image: "registry.example.com/image:v1",
},
certConfig: &CertificateConfig{
TLSVerify: true,
},
mockExistsYum: func(s string) bool { return false },
mockCleanTemp: func() error { return nil },
mockSetupTLS: func(o OtherRepo, c *CertificateConfig, od *registry.OptionsDownload) error {
return errors.New("TLS error")
},
expectError: true,
},
{
name: "download error",
oc: OtherRepo{
Image: "registry.example.com/image:v1",
},
certConfig: &CertificateConfig{},
mockExistsYum: func(s string) bool { return false },
mockCleanTemp: func() error { return nil },
mockSetupTLS: func(o OtherRepo, c *CertificateConfig, od *registry.OptionsDownload) error {
return nil
},
expectError: true,
},
{
name: "successful repo init",
oc: OtherRepo{
Image: "registry.example.com/image:v1",
},
certConfig: &CertificateConfig{},
mockExistsYum: func(s string) bool { return false },
mockCleanTemp: func() error { return nil },
mockSetupTLS: func(o OtherRepo, c *CertificateConfig, od *registry.OptionsDownload) error { return nil },
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, tt.mockExistsYum)
if tt.mockCleanTemp != nil {
patches.ApplyFunc(cleanTempYumDataFile, tt.mockCleanTemp)
}
if tt.mockSetupTLS != nil {
patches.ApplyFunc(setupTLSCertificate, tt.mockSetupTLS)
}
if tt.expectError {
patches.ApplyFunc((*registry.OptionsDownload).Download, func(o *registry.OptionsDownload) error {
return errors.New("download error")
})
} else {
patches.ApplyFunc((*registry.OptionsDownload).Download, func(o *registry.OptionsDownload) error {
return nil
})
}
patches.ApplyFunc(finalizeYumDataFile, func() error { return nil })
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := RepoInit(tt.oc, tt.certConfig)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestSourceRuntime(t *testing.T) {
tests := []struct {
name string
httpRepo string
mockCheckLocalExist func() (bool, error)
mockFetchRemote func(string) (*runtimeFiles, error)
mockDownloadRun func(string, []string, []string, []string) error
expectError bool
}{
{
name: "local files already exist",
httpRepo: "http://example.com",
mockCheckLocalExist: func() (bool, error) {
return true, nil
},
expectError: false,
},
{
name: "check local exist error",
httpRepo: "http://example.com",
mockCheckLocalExist: func() (bool, error) {
return false, errors.New("check error")
},
expectError: true,
},
{
name: "fetch remote file list error",
httpRepo: "http://example.com",
mockCheckLocalExist: func() (bool, error) {
return false, nil
},
mockFetchRemote: func(s string) (*runtimeFiles, error) {
return nil, errors.New("fetch error")
},
expectError: true,
},
{
name: "download runtime files error",
httpRepo: "http://example.com",
mockCheckLocalExist: func() (bool, error) {
return false, nil
},
mockFetchRemote: func(s string) (*runtimeFiles, error) {
return &runtimeFiles{}, nil
},
mockDownloadRun: func(s string, c []string, cn []string, k []string) error {
return errors.New("download error")
},
expectError: true,
},
{
name: "successful runtime download",
httpRepo: "http://example.com",
mockCheckLocalExist: func() (bool, error) {
return false, nil
},
mockFetchRemote: func(s string) (*runtimeFiles, error) {
return &runtimeFiles{}, nil
},
mockDownloadRun: func(s string, c []string, cn []string, k []string) error {
return nil
},
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
if tt.mockCheckLocalExist != nil {
patches.ApplyFunc(checkLocalRuntimeFilesExist, tt.mockCheckLocalExist)
}
if tt.mockFetchRemote != nil {
patches.ApplyFunc(fetchRemoteFileList, tt.mockFetchRemote)
}
if tt.mockDownloadRun != nil {
patches.ApplyFunc(downloadRuntimeFiles, tt.mockDownloadRun)
}
err := sourceRuntime(tt.httpRepo)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
type mockDirEntry struct {
name string
}
func (m *mockDirEntry) Name() string { return m.name }
func (m *mockDirEntry) IsDir() bool { return false }
func (m *mockDirEntry) Type() os.FileMode { return 0 }
func (m *mockDirEntry) Info() (os.FileInfo, error) {
return nil, nil
}
func validateCustomExtra(m map[string]string) error {
return nil
}
func warehouseSetClientCertificate(s string) error {
return nil
}
func TestPrepareTempDirectory(t *testing.T) {
tests := []struct {
name string
targetTemp string
mockExists func(string) bool
mockRemove func(string) error
expectError bool
}{
{
name: "temp directory does not exist",
targetTemp: "/tmp/nonexistent",
mockExists: func(s string) bool {
return false
},
expectError: false,
},
{
name: "temp directory exists and removed successfully",
targetTemp: "/tmp/existing",
mockExists: func(s string) bool {
return true
},
mockRemove: func(s string) error {
return nil
},
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, tt.mockExists)
if tt.mockRemove != nil {
patches = patches.ApplyFunc(os.RemoveAll, tt.mockRemove)
} else {
patches = patches.ApplyFunc(os.RemoveAll, func(_ string) error { return nil })
}
err := prepareTempDirectory(tt.targetTemp)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestVerifyDirectoryExists(t *testing.T) {
tests := []struct {
name string
dir string
mockExists func(string) bool
expectError bool
}{
{
name: "directory exists",
dir: "/tmp/existing",
mockExists: func(s string) bool { return true },
expectError: false,
},
{
name: "directory does not exist",
dir: "/tmp/nonexistent",
mockExists: func(s string) bool { return false },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, tt.mockExists)
err := verifyDirectoryExists(tt.dir)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestRemoveArchiveExtensions(t *testing.T) {
tests := []struct {
name string
filename string
expected string
}{
{
name: "tar.gz extension",
filename: "image_amd64.tar.gz",
expected: "image_amd64",
},
{
name: "tgz extension",
filename: "image_amd64.tgz",
expected: "image_amd64",
},
{
name: "no extension",
filename: "image_amd64",
expected: "image_amd64",
},
{
name: "multiple extensions only remove first",
filename: "image.tar.gz.bak",
expected: "image.tar.gz.bak",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := removeArchiveExtensions(tt.filename)
assert.Equal(t, tt.expected, result)
})
}
}
func TestCleanYumDataDirectory(t *testing.T) {
tests := []struct {
name string
mockRemove func(string) error
expectError bool
}{
{
name: "remove succeeds",
mockRemove: func(s string) error { return nil },
expectError: false,
},
{
name: "remove fails with non-notexist error",
mockRemove: func(s string) error { return errors.New("remove error") },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.Remove, tt.mockRemove)
err := cleanYumDataDirectory()
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestDecompressYumDataFile(t *testing.T) {
t.Skip("Skipping due to gomonkey issues on this platform")
}
func TestPrepareChartData(t *testing.T) {
t.Skip("Skipping due to gomonkey issues on this platform")
}
func TestVerifyContainerdFile(t *testing.T) {
tests := []struct {
name string
localImage string
mockReadDir func(string) ([]os.DirEntry, error)
mockValidateExtra func(map[string]string) error
expectError bool
checkResult func(result ContainerdFileResult) bool
}{
{
name: "all files exist",
localImage: "",
mockReadDir: func(s string) ([]os.DirEntry, error) {
return []os.DirEntry{
&mockDirEntry{name: "containerd-1.7.0-linux-amd64.tar.gz"},
&mockDirEntry{name: "cni-plugins-linux-amd64-v1.3.0.tgz"},
}, nil
},
mockValidateExtra: func(m map[string]string) error { return nil },
expectError: false,
checkResult: func(result ContainerdFileResult) bool {
return len(result.ContainerdList) > 0 && len(result.CniPluginList) > 0
},
},
{
name: "no containerd files",
localImage: "",
mockReadDir: func(s string) ([]os.DirEntry, error) {
return []os.DirEntry{
&mockDirEntry{name: "cni-plugins-linux-amd64-v1.3.0.tgz"},
}, nil
},
mockValidateExtra: func(m map[string]string) error { return nil },
expectError: true,
checkResult: nil,
},
{
name: "no cni plugin files",
localImage: "",
mockReadDir: func(s string) ([]os.DirEntry, error) {
return []os.DirEntry{
&mockDirEntry{name: "containerd-1.7.0-linux-amd64.tar.gz"},
}, nil
},
mockValidateExtra: func(m map[string]string) error { return nil },
expectError: true,
checkResult: nil,
},
{
name: "read dir error",
localImage: "",
mockReadDir: func(s string) ([]os.DirEntry, error) {
return nil, errors.New("read dir error")
},
expectError: true,
checkResult: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.ReadDir, tt.mockReadDir)
if tt.mockValidateExtra != nil {
patches.ApplyFunc(validateCustomExtra, tt.mockValidateExtra)
}
result, err := VerifyContainerdFile(tt.localImage)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.True(t, tt.checkResult(result), "checkResult failed")
}
})
}
}
func TestDecompressDataPackage(t *testing.T) {
tests := []struct {
name string
mockExistsDir func(string) bool
mockDirectoryIsEmpty func(string) bool
mockMkdirAll func(string, os.FileMode) error
cfg decompressConfig
expectError bool
}{
{
name: "directory already exists and not empty skip",
mockExistsDir: func(s string) bool { return true },
mockDirectoryIsEmpty: func(s string) bool { return false },
cfg: decompressConfig{
dataFile: "/test/data.tar.gz",
dataDirectory: "/test/data",
name: "test",
logMessage: "Decompressing...",
skipMessage: "Skip if exists",
},
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, func(s string) bool {
if strings.HasSuffix(s, ".tar.gz") {
return true
}
return tt.mockExistsDir(s)
})
patches.ApplyFunc(utils.DirectoryIsEmpty, tt.mockDirectoryIsEmpty)
if tt.mockMkdirAll != nil {
patches.ApplyFunc(os.MkdirAll, tt.mockMkdirAll)
}
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
patches.ApplyFunc(verifyDirectoryExists, func(s string) error { return nil })
err := decompressDataPackage(tt.cfg)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestPrepareRepositoryDependOn(t *testing.T) {
tests := []struct {
name string
imageFilePath string
mockDecompress func(decompressConfig) error
mockPrepareChart func() error
expectError bool
}{
{
name: "successful preparation without local image",
imageFilePath: "",
mockDecompress: func(cfg decompressConfig) error { return nil },
mockPrepareChart: func() error { return nil },
expectError: false,
},
{
name: "successful preparation with local image",
imageFilePath: "/test/local.tar.gz",
mockDecompress: func(cfg decompressConfig) error { return nil },
mockPrepareChart: func() error { return nil },
expectError: false,
},
{
name: "prepare chart data fails",
imageFilePath: "",
mockDecompress: func(cfg decompressConfig) error { return nil },
mockPrepareChart: func() error { return errors.New("chart prep error") },
expectError: true,
},
{
name: "decompress image data fails",
imageFilePath: "",
mockDecompress: func(cfg decompressConfig) error {
if cfg.name == "image" {
return errors.New("image decompress error")
}
return nil
},
mockPrepareChart: func() error { return nil },
expectError: true,
},
{
name: "decompress nfs data fails",
imageFilePath: "",
mockDecompress: func(cfg decompressConfig) error {
if cfg.name == "NFS" {
return errors.New("nfs decompress error")
}
return nil
},
mockPrepareChart: func() error { return nil },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
decompressCallCount := 0
patches.ApplyFunc(decompressDataPackage, func(cfg decompressConfig) error {
decompressCallCount++
return tt.mockDecompress(cfg)
})
patches.ApplyFunc(prepareChartData, tt.mockPrepareChart)
err := PrepareRepositoryDependOn(tt.imageFilePath)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestPrepareChartDataFunctional(t *testing.T) {
tests := []struct {
name string
mockExistsDir func(string) bool
mockDirectoryIsEmpty func(string) bool
expectError bool
}{
{
name: "directory already exists and not empty skip",
mockExistsDir: func(s string) bool { return true },
mockDirectoryIsEmpty: func(s string) bool { return false },
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, tt.mockExistsDir)
patches.ApplyFunc(utils.DirectoryIsEmpty, tt.mockDirectoryIsEmpty)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := prepareChartData()
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestNfsPostProcessFunctional(t *testing.T) {
tests := []struct {
name string
targetTemp string
mockExists func(string) bool
mockRename func(string, string) error
mockRemoveAll func(string) error
expectError bool
}{
{
name: "nfsshare subdir rename fails",
targetTemp: "/tmp/nfs.tmp",
mockExists: func(s string) bool { return strings.Contains(s, "nfsshare") },
mockRename: func(s string, s2 string) error { return errors.New("rename error") },
mockRemoveAll: func(s string) error { return nil },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, tt.mockExists)
patches.ApplyFunc(os.Rename, tt.mockRename)
if tt.mockRemoveAll != nil {
patches.ApplyFunc(os.RemoveAll, tt.mockRemoveAll)
}
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := nfsPostProcess(tt.targetTemp)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestCreateImageLocalPostProcessFunctional(t *testing.T) {
tests := []struct {
name string
imageFilePath string
mockExists func(string) bool
mockRename func(string, string) error
mockRemoveAll func(string) error
expectError bool
}{
{
name: "expected subdir exists rename successfully",
imageFilePath: "/test/image_amd64.tar.gz",
mockExists: func(s string) bool {
return strings.Contains(s, "image_amd64")
},
mockRename: func(s string, s2 string) error { return nil },
mockRemoveAll: func(s string) error { return nil },
expectError: false,
},
{
name: "expected subdir does not exist rename temp",
imageFilePath: "/test/image_amd64.tar.gz",
mockExists: func(s string) bool {
return strings.Contains(s, "image_amd64.tar.gz.tmp")
},
mockRename: func(s string, s2 string) error { return nil },
mockRemoveAll: func(s string) error { return nil },
expectError: false,
},
{
name: "subdir rename fails",
imageFilePath: "/test/image_amd64.tar.gz",
mockExists: func(s string) bool {
return strings.Contains(s, "image_amd64")
},
mockRename: func(s string, s2 string) error { return errors.New("rename error") },
mockRemoveAll: func(s string) error { return nil },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, tt.mockExists)
patches.ApplyFunc(os.Rename, tt.mockRename)
if tt.mockRemoveAll != nil {
patches.ApplyFunc(os.RemoveAll, tt.mockRemoveAll)
}
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
postProcess := createImageLocalPostProcess(tt.imageFilePath)
err := postProcess(tt.imageFilePath + ".tmp")
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestLoadLocalRepository(t *testing.T) {
tests := []struct {
name string
mockLoadLocalRepo func(string) error
expectError bool
}{
{
name: "load local repository success",
mockLoadLocalRepo: func(s string) error { return nil },
expectError: false,
},
{
name: "load local repository fails",
mockLoadLocalRepo: func(s string) error { return errors.New("load error") },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(common.LoadLocalRepositoryFromFile, tt.mockLoadLocalRepo)
err := LoadLocalRepository()
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestLoadLocalImage(t *testing.T) {
tests := []struct {
name string
mockLoadLocalRepo func(string) error
expectError bool
}{
{
name: "load local image success",
mockLoadLocalRepo: func(s string) error { return nil },
expectError: false,
},
{
name: "load local image fails",
mockLoadLocalRepo: func(s string) error { return errors.New("load error") },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(common.LoadLocalRepositoryFromFile, tt.mockLoadLocalRepo)
err := LoadLocalImage()
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestContainerServer(t *testing.T) {
tests := []struct {
name string
localImage string
imageRegistryPort string
otherRepo string
onlineImage string
mockStartImageReg func(int) error
mockRemoveImageReg func(string) error
mockSleep func(time.Duration)
expectError bool
}{
{
name: "start image registry success on first try",
localImage: "",
imageRegistryPort: "5000",
otherRepo: "",
onlineImage: "",
mockStartImageReg: func(callCount int) error { return nil },
mockRemoveImageReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
{
name: "start image registry fails after retries",
localImage: "",
imageRegistryPort: "5000",
otherRepo: "",
onlineImage: "",
mockStartImageReg: func(callCount int) error { return errors.New("start error") },
mockRemoveImageReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: true,
},
{
name: "start image registry success on retry",
localImage: "",
imageRegistryPort: "5000",
otherRepo: "",
onlineImage: "",
mockStartImageReg: func(callCount int) error {
if callCount > 1 {
return nil
}
return errors.New("start error")
},
mockRemoveImageReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
{
name: "with local image uses default registry",
localImage: "/test/image.tar.gz",
imageRegistryPort: "5000",
otherRepo: "",
onlineImage: "",
mockStartImageReg: func(callCount int) error { return nil },
mockRemoveImageReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
startImageRegCallCount := 0
patches.ApplyFunc(server.StartImageRegistry, func(s1 string, s2 string, s3 string, s4 string) error {
startImageRegCallCount++
return tt.mockStartImageReg(startImageRegCallCount)
})
patches.ApplyFunc(server.RemoveImageRegistry, tt.mockRemoveImageReg)
patches.ApplyFunc(time.Sleep, tt.mockSleep)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := ContainerServer(tt.localImage, tt.imageRegistryPort, tt.otherRepo, tt.onlineImage)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestSyncLocalImage(t *testing.T) {
tests := []struct {
name string
imageRegistryPort string
mockSpecificSync func(string, string)
mockEnsureImage func(string) error
expectError bool
}{
{
name: "sync local image success",
imageRegistryPort: "5000",
mockSpecificSync: func(s1 string, s2 string) {},
mockEnsureImage: func(s string) error { return nil },
expectError: false,
},
{
name: "sync local image ensure image fails",
imageRegistryPort: "5000",
mockSpecificSync: func(s1 string, s2 string) {},
mockEnsureImage: func(s string) error { return errors.New("ensure error") },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(build.SpecificSync, tt.mockSpecificSync)
patches.ApplyFunc(econd.EnsureImageExists, tt.mockEnsureImage)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := SyncLocalImage(tt.imageRegistryPort)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestYumServer(t *testing.T) {
tests := []struct {
name string
localImage string
imageRegistryPort string
yumRegistryPort string
otherRepo string
onlineImage string
mockStartYumReg func(int) error
mockRemoveYumReg func(string) error
mockSleep func(time.Duration)
expectError bool
}{
{
name: "start yum registry success",
localImage: "",
imageRegistryPort: "5000",
yumRegistryPort: "6000",
otherRepo: "",
mockStartYumReg: func(callCount int) error { return nil },
mockRemoveYumReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
{
name: "start yum registry fails",
localImage: "",
imageRegistryPort: "5000",
yumRegistryPort: "6000",
otherRepo: "",
mockStartYumReg: func(callCount int) error { return errors.New("start error") },
mockRemoveYumReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: true,
},
{
name: "start yum registry success on retry",
localImage: "",
imageRegistryPort: "5000",
yumRegistryPort: "6000",
otherRepo: "",
mockStartYumReg: func(callCount int) error {
if callCount > 1 {
return nil
}
return errors.New("start error")
},
mockRemoveYumReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
{
name: "with other repo and no local image uses other repo",
localImage: "",
imageRegistryPort: "5000",
yumRegistryPort: "6000",
otherRepo: "myrepo.com/",
mockStartYumReg: func(callCount int) error { return nil },
mockRemoveYumReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
startYumRegCallCount := 0
patches.ApplyFunc(server.StartYumRegistry, func(s1 string, s2 string, s3 string, s4 string) error {
startYumRegCallCount++
return tt.mockStartYumReg(startYumRegCallCount)
})
patches.ApplyFunc(server.RemoveYumRegistry, tt.mockRemoveYumReg)
patches.ApplyFunc(time.Sleep, tt.mockSleep)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := YumServer(tt.localImage, tt.imageRegistryPort, tt.yumRegistryPort, tt.otherRepo, tt.onlineImage)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestChartServer(t *testing.T) {
tests := []struct {
name string
localImage string
imageRegistryPort string
chartRegistryPort string
otherRepo string
onlineImage string
mockStartChartReg func(int) error
mockRemoveChartReg func(string) error
mockSleep func(time.Duration)
expectError bool
}{
{
name: "start chart registry success",
localImage: "",
imageRegistryPort: "5000",
chartRegistryPort: "7000",
otherRepo: "",
mockStartChartReg: func(callCount int) error { return nil },
mockRemoveChartReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
{
name: "start chart registry fails",
localImage: "",
imageRegistryPort: "5000",
chartRegistryPort: "7000",
otherRepo: "",
mockStartChartReg: func(callCount int) error { return errors.New("start error") },
mockRemoveChartReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: true,
},
{
name: "start chart registry success on retry",
localImage: "",
imageRegistryPort: "5000",
chartRegistryPort: "7000",
otherRepo: "",
mockStartChartReg: func(callCount int) error {
if callCount > 1 {
return nil
}
return errors.New("start error")
},
mockRemoveChartReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
{
name: "with other repo and no local image uses other repo",
localImage: "",
imageRegistryPort: "5000",
chartRegistryPort: "7000",
otherRepo: "myrepo.com/",
mockStartChartReg: func(callCount int) error { return nil },
mockRemoveChartReg: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
startChartRegCallCount := 0
patches.ApplyFunc(server.StartChartRegistry, func(s1 string, s2 string, s3 string, s4 string) error {
startChartRegCallCount++
return tt.mockStartChartReg(startChartRegCallCount)
})
patches.ApplyFunc(server.RemoveChartRegistry, tt.mockRemoveChartReg)
patches.ApplyFunc(time.Sleep, tt.mockSleep)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := ChartServer(tt.localImage, tt.imageRegistryPort, tt.chartRegistryPort, tt.otherRepo, tt.onlineImage)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestNFSServer(t *testing.T) {
tests := []struct {
name string
imageRegistryPort string
otherRepo string
onlineImage string
mockStartNFSServ func(int) error
mockRemoveNFSServ func(string) error
mockSleep func(time.Duration)
expectError bool
}{
{
name: "start nfs server success",
imageRegistryPort: "5000",
otherRepo: "",
mockStartNFSServ: func(callCount int) error { return nil },
mockRemoveNFSServ: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
{
name: "start nfs server fails",
imageRegistryPort: "5000",
otherRepo: "",
mockStartNFSServ: func(callCount int) error { return errors.New("start error") },
mockRemoveNFSServ: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: true,
},
{
name: "start nfs server success on retry",
imageRegistryPort: "5000",
otherRepo: "",
mockStartNFSServ: func(callCount int) error {
if callCount > 1 {
return nil
}
return errors.New("start error")
},
mockRemoveNFSServ: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
{
name: "with other repo uses other repo",
imageRegistryPort: "5000",
otherRepo: "myrepo.com/",
mockStartNFSServ: func(callCount int) error { return nil },
mockRemoveNFSServ: func(s string) error { return nil },
mockSleep: func(d time.Duration) {},
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
startNFSServCallCount := 0
patches.ApplyFunc(server.StartNFSServer, func(s1 string, s2 string, s3 string) error {
startNFSServCallCount++
return tt.mockStartNFSServ(startNFSServCallCount)
})
patches.ApplyFunc(server.RemoveNFSServer, tt.mockRemoveNFSServ)
patches.ApplyFunc(time.Sleep, tt.mockSleep)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := NFSServer(tt.imageRegistryPort, tt.otherRepo, tt.onlineImage)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestDecompressionSystemSourceFileFunctional(t *testing.T) {
tests := []struct {
name string
mockExistsDir func(string) bool
mockDirectoryIsEmpty func(string) bool
expectError bool
}{
{
name: "directory already exists and not empty skip",
mockExistsDir: func(s string) bool { return true },
mockDirectoryIsEmpty: func(s string) bool { return false },
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.Exists, tt.mockExistsDir)
patches.ApplyFunc(utils.DirectoryIsEmpty, tt.mockDirectoryIsEmpty)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := DecompressionSystemSourceFile()
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}