*
* 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 build
import (
"fmt"
"os"
"testing"
"github.com/agiledragon/gomonkey/v2"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
"gopkg.openfuyao.cn/bkeadm/pkg/global"
"gopkg.openfuyao.cn/bkeadm/pkg/infrastructure"
"gopkg.openfuyao.cn/bkeadm/utils/log"
)
func TestBuildOnlineImage(t *testing.T) {
tests := []struct {
name string
isDockerEnvironment bool
readFileError error
yamlUnmarshalError error
prepareError error
buildRpmsError error
buildImageError error
expectError bool
}{
{
name: "successful build",
isDockerEnvironment: true,
readFileError: nil,
yamlUnmarshalError: nil,
prepareError: nil,
buildRpmsError: nil,
buildImageError: nil,
expectError: false,
},
{
name: "not in docker environment",
isDockerEnvironment: false,
expectError: true,
},
{
name: "read file fails",
isDockerEnvironment: true,
readFileError: fmt.Errorf("read error"),
expectError: true,
},
{
name: "yaml unmarshal fails",
isDockerEnvironment: true,
readFileError: nil,
yamlUnmarshalError: fmt.Errorf("unmarshal error"),
expectError: true,
},
{
name: "prepare fails",
isDockerEnvironment: true,
readFileError: nil,
yamlUnmarshalError: nil,
prepareError: fmt.Errorf("prepare error"),
expectError: true,
},
{
name: "build rpms fails",
isDockerEnvironment: true,
readFileError: nil,
yamlUnmarshalError: nil,
prepareError: nil,
buildRpmsError: fmt.Errorf("build rpms error"),
expectError: true,
},
{
name: "build image fails",
isDockerEnvironment: true,
readFileError: nil,
yamlUnmarshalError: nil,
prepareError: nil,
buildRpmsError: nil,
buildImageError: fmt.Errorf("build image error"),
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &Options{
File: "test-config.yaml",
Target: "test-image:latest",
Arch: "amd64",
}
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(infrastructure.IsDocker, func() bool {
return tt.isDockerEnvironment
})
if tt.isDockerEnvironment {
patches.ApplyFunc(os.ReadFile, func(filename string) ([]byte, error) {
if tt.readFileError != nil {
return nil, tt.readFileError
}
return []byte("version: v1.0.0"), nil
})
patches.ApplyFunc(yaml.Unmarshal, func(data []byte, v interface{}) error {
if tt.yamlUnmarshalError != nil {
return tt.yamlUnmarshalError
}
cfg := v.(*BuildConfig)
cfg.OpenFuyaoVersion = "v1.0.0"
return nil
})
patches.ApplyFunc(prepare, func() error {
return tt.prepareError
})
patches.ApplyFunc(buildRpms, func(cfg *BuildConfig, stopChan <-chan struct{}) error {
return tt.buildRpmsError
})
patches.ApplyFunc(buildImage, func(imageName string, arch string) error {
return tt.buildImageError
})
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
patches.ApplyFunc(closeChanStruct, func(ch chan struct{}) {})
patches.ApplyFunc(os.RemoveAll, func(path string) error {
return nil
})
}
o.BuildOnlineImage()
assert.True(t, true)
})
}
}
func TestBuildImage(t *testing.T) {
tests := []struct {
name string
imageName string
arch string
mockMkdir func(string, os.FileMode) error
mockWriteFile func(string, []byte, os.FileMode) error
mockRename func(string, string) error
mockExecuteCommandWithOutput func(string, ...string) (string, error)
expectError bool
}{
{
name: "single architecture build",
imageName: "test-image:latest",
arch: "amd64",
mockMkdir: func(path string, perm os.FileMode) error { return nil },
mockWriteFile: func(filename string, data []byte, perm os.FileMode) error { return nil },
mockRename: func(oldpath, newpath string) error { return nil },
mockExecuteCommandWithOutput: func(command string, arg ...string) (string, error) {
return "", nil
},
expectError: true,
},
{
name: "multi architecture build",
imageName: "test-image:latest",
arch: "amd64,arm64",
mockMkdir: func(path string, perm os.FileMode) error { return nil },
mockWriteFile: func(filename string, data []byte, perm os.FileMode) error { return nil },
mockRename: func(oldpath, newpath string) error { return nil },
mockExecuteCommandWithOutput: func(command string, arg ...string) (string, error) {
return "", nil
},
expectError: true,
},
{
name: "mkdir fails",
imageName: "test-image:latest",
arch: "amd64",
mockMkdir: func(path string, perm os.FileMode) error { return fmt.Errorf("mkdir error") },
expectError: true,
},
{
name: "write file fails",
imageName: "test-image:latest",
arch: "amd64",
mockMkdir: func(path string, perm os.FileMode) error { return nil },
mockWriteFile: func(filename string, data []byte, perm os.FileMode) error { return fmt.Errorf("write error") },
expectError: true,
},
{
name: "rename fails",
imageName: "test-image:latest",
arch: "amd64",
mockMkdir: func(path string, perm os.FileMode) error { return nil },
mockWriteFile: func(filename string, data []byte, perm os.FileMode) error { return nil },
mockRename: func(oldpath, newpath string) error { return fmt.Errorf("rename error") },
expectError: true,
},
{
name: "docker build fails",
imageName: "test-image:latest",
arch: "amd64",
mockMkdir: func(path string, perm os.FileMode) error { return nil },
mockWriteFile: func(filename string, data []byte, perm os.FileMode) error { return nil },
mockRename: func(oldpath, newpath string) error { return nil },
mockExecuteCommandWithOutput: func(command string, arg ...string) (string, error) {
return "docker error output", fmt.Errorf("docker error")
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(os.Mkdir, tt.mockMkdir)
if tt.mockWriteFile != nil {
patches.ApplyFunc(os.WriteFile, tt.mockWriteFile)
}
if tt.mockRename != nil {
patches.ApplyFunc(os.Rename, tt.mockRename)
} else {
patches.ApplyFunc(os.Rename, func(oldpath, newpath string) error {
return nil
})
}
if tt.mockExecuteCommandWithOutput != nil {
patches.ApplyFunc(global.Command.ExecuteCommandWithOutput, tt.mockExecuteCommandWithOutput)
}
patches.ApplyFunc(os.RemoveAll, func(path string) error { return nil })
patches.ApplyGlobalVar(&pwd, "/tmp")
patches.ApplyGlobalVar(&bke, "/tmp/bke")
err := buildImage(tt.imageName, tt.arch)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}