*
* 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"
"testing"
"github.com/agiledragon/gomonkey/v2"
"github.com/stretchr/testify/assert"
"gopkg.openfuyao.cn/bkeadm/pkg/executor/exec"
"gopkg.openfuyao.cn/bkeadm/pkg/executor/docker"
"gopkg.openfuyao.cn/bkeadm/pkg/global"
"gopkg.openfuyao.cn/bkeadm/pkg/server"
"gopkg.openfuyao.cn/bkeadm/utils"
"gopkg.openfuyao.cn/bkeadm/utils/log"
)
const (
testChannelBufferOne = 1
testChannelBufferHundred = 100
)
func TestBuildRegistry(t *testing.T) {
arch := []string{"amd64"}
tests := []struct {
name string
source string
mockPull func(*docker.Client, docker.ImageRef, utils.RetryOptions) error
mockTag func(*docker.Client, string, string) error
mockSave func(*docker.Client, string, string) error
mockRemove func(*docker.Client, docker.ImageRef) error
expectError bool
}{
{
name: "successful build",
source: "test-image:latest",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error { return nil },
mockTag: func(c *docker.Client, source, target string) error { return nil },
mockSave: func(c *docker.Client, source, target string) error { return nil },
mockRemove: func(c *docker.Client, ref docker.ImageRef) error { return nil },
expectError: false,
},
{
name: "pull fails",
source: "test-image:latest",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error {
return fmt.Errorf("pull error")
},
expectError: true,
},
{
name: "tag fails",
source: "test-image:latest",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error { return nil },
mockTag: func(c *docker.Client, source, target string) error { return fmt.Errorf("tag error") },
expectError: true,
},
{
name: "save fails",
source: "test-image:latest",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error { return nil },
mockTag: func(c *docker.Client, source, target string) error { return nil },
mockSave: func(c *docker.Client, source, target string) error { return fmt.Errorf("save error") },
expectError: true,
},
{
name: "remove fails",
source: "test-image:latest",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error { return nil },
mockTag: func(c *docker.Client, source, target string) error { return nil },
mockSave: func(c *docker.Client, source, target string) error { return nil },
mockRemove: func(c *docker.Client, ref docker.ImageRef) error { return fmt.Errorf("remove error") },
expectError: true,
},
}
if global.Docker == nil {
global.Docker = &docker.Client{}
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc((*docker.Client).Pull, tt.mockPull)
patches.ApplyFunc((*docker.Client).Tag, tt.mockTag)
patches.ApplyFunc((*docker.Client).Save, tt.mockSave)
patches.ApplyFunc((*docker.Client).Remove, tt.mockRemove)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
patches.ApplyGlobalVar(&bke, "/tmp/bke")
originalNeedRemoveImage := needRemoveImage
needRemoveImage = []string{}
defer func() {
needRemoveImage = originalNeedRemoveImage
}()
err := buildRegistry(tt.source, arch)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Contains(t, needRemoveImage, tt.source)
}
})
}
}
func TestSyncImageTag(t *testing.T) {
cr := Repo{
Architecture: []string{"amd64"},
}
subImage := SubImage{
SourceRepo: "source-repo",
TargetRepo: "target-repo",
}
image := Image{
Name: "test-image",
Tag: []string{"v1.0.0"},
}
imageChan := make(chan docker.ImageRef, testChannelBufferOne)
defer close(imageChan)
tests := []struct {
name string
imageTag string
mockImageTrack func(string, string, string, string, []string) (string, error)
mockSyncImage func(string, string, []string, chan<- docker.ImageRef) error
expectError bool
}{
{
name: "successful sync",
imageTag: "v1.0.0",
mockImageTrack: func(sourceRepo, imageTrack, imageName, tag string, arch []string) (string, error) {
return "source:image", nil
},
mockSyncImage: func(source, target string, arch []string, imageChan chan<- docker.ImageRef) error {
return nil
},
expectError: false,
},
{
name: "image track fails",
imageTag: "v1.0.0",
mockImageTrack: func(sourceRepo, imageTrack, imageName, tag string, arch []string) (string, error) {
return "", fmt.Errorf("track error")
},
expectError: true,
},
{
name: "sync image fails",
imageTag: "v1.0.0",
mockImageTrack: func(sourceRepo, imageTrack, imageName, tag string, arch []string) (string, error) {
return "source:image", nil
},
mockSyncImage: func(source, target string, arch []string, imageChan chan<- docker.ImageRef) error {
return fmt.Errorf("sync error")
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(imageTrack, tt.mockImageTrack)
patches.ApplyFunc(syncImage, tt.mockSyncImage)
err := syncImageTag(subImage, image, tt.imageTag, cr, imageChan)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestCollectRepo(t *testing.T) {
stopChan := make(chan struct{})
defer close(stopChan)
cfg := &BuildConfig{
Registry: registry{
ImageAddress: "registry.example.com",
Architecture: []string{"amd64"},
},
Repos: []Repo{
{
NeedDownload: true,
SubImages: []SubImage{
{
Images: []Image{
{
Name: "test-image",
Tag: []string{"v1.0.0"},
},
},
},
},
},
},
}
tests := []struct {
name string
mockRemoveImageRegistry func(string) error
mockStartImageRegistry func(string, string, string, string) error
mockSyncAllRepoImages func(*BuildConfig, *syncChannels) error
mockPackImageAndCleanup func() error
expectError bool
}{
{
name: "successful collection",
mockRemoveImageRegistry: func(name string) error { return nil },
mockStartImageRegistry: func(name, image, port, dir string) error { return nil },
mockSyncAllRepoImages: func(cfg *BuildConfig, channels *syncChannels) error { return nil },
mockPackImageAndCleanup: func() error { return nil },
expectError: false,
},
{
name: "start image registry fails",
mockRemoveImageRegistry: func(name string) error { return nil },
mockStartImageRegistry: func(name, image, port, dir string) error { return fmt.Errorf("start error") },
expectError: true,
},
{
name: "sync all repo images fails",
mockRemoveImageRegistry: func(name string) error { return nil },
mockStartImageRegistry: func(name, image, port, dir string) error { return nil },
mockSyncAllRepoImages: func(cfg *BuildConfig, channels *syncChannels) error { return fmt.Errorf("sync error") },
expectError: true,
},
{
name: "pack image and cleanup fails",
mockRemoveImageRegistry: func(name string) error { return nil },
mockStartImageRegistry: func(name, image, port, dir string) error { return nil },
mockSyncAllRepoImages: func(cfg *BuildConfig, channels *syncChannels) error { return nil },
mockPackImageAndCleanup: func() error { return fmt.Errorf("pack error") },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(server.RemoveImageRegistry, tt.mockRemoveImageRegistry)
patches.ApplyFunc(server.StartImageRegistry, tt.mockStartImageRegistry)
patches.ApplyFunc(syncAllRepoImages, tt.mockSyncAllRepoImages)
patches.ApplyFunc(packImageAndCleanup, tt.mockPackImageAndCleanup)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
patches.ApplyGlobalVar(&tmpRegistry, "/tmp/registry")
err := collectRepo(cfg, stopChan)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestSyncRepoImageTags(t *testing.T) {
stopChan := make(chan struct{})
defer close(stopChan)
internalStopChan := make(chan struct{})
pullCompleteChan := make(chan struct{})
imageChan := make(chan docker.ImageRef, testChannelBufferHundred)
defer close(imageChan)
channels := &syncChannels{
stopChan: stopChan,
internalStopChan: internalStopChan,
pullCompleteChan: pullCompleteChan,
imageChan: imageChan,
}
cr := Repo{
Architecture: []string{"amd64"},
}
subImage := SubImage{
Images: []Image{
{
Name: "test-image",
Tag: []string{"v1.0.0", "v1.0.1"},
},
},
}
tests := []struct {
name string
mockSyncImageTag func(SubImage, Image, string, Repo, chan<- docker.ImageRef) error
expectError bool
}{
{
name: "successful sync",
mockSyncImageTag: func(subImage SubImage, image Image, imageTag string, cr Repo, imageChan chan<- docker.ImageRef) error {
return nil
},
expectError: false,
},
{
name: "sync image tag fails",
mockSyncImageTag: func(subImage SubImage, image Image, imageTag string, cr Repo, imageChan chan<- docker.ImageRef) error {
return fmt.Errorf("sync error")
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(syncImageTag, tt.mockSyncImageTag)
patches.ApplyFunc(closeChanStruct, func(ch chan struct{}) {})
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := syncRepoImageTags(cr, subImage, channels)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestSyncAllRepoImages(t *testing.T) {
cfg := &BuildConfig{
Repos: []Repo{
{
NeedDownload: true,
SubImages: []SubImage{
{
Images: []Image{
{
Name: "test-image",
Tag: []string{"v1.0.0"},
},
},
},
},
},
},
}
stopChan := make(chan struct{})
internalStopChan := make(chan struct{})
pullCompleteChan := make(chan struct{})
imageChan := make(chan docker.ImageRef, testChannelBufferHundred)
defer close(imageChan)
channels := &syncChannels{
stopChan: stopChan,
internalStopChan: internalStopChan,
pullCompleteChan: pullCompleteChan,
imageChan: imageChan,
}
tests := []struct {
name string
mockSyncRepoImageTags func(Repo, SubImage, *syncChannels) error
expectError bool
}{
{
name: "successful sync",
mockSyncRepoImageTags: func(cr Repo, subImage SubImage, channels *syncChannels) error {
return nil
},
expectError: false,
},
{
name: "sync repo image tags fails",
mockSyncRepoImageTags: func(cr Repo, subImage SubImage, channels *syncChannels) error {
return fmt.Errorf("sync error")
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(syncRepoImageTags, tt.mockSyncRepoImageTags)
err := syncAllRepoImages(cfg, channels)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestPullAndTagSingleArchImage(t *testing.T) {
tests := []struct {
name string
source string
target string
arch string
mockPull func(*docker.Client, docker.ImageRef, utils.RetryOptions) error
mockTag func(*docker.Client, string, string) error
expectError bool
}{
{
name: "successful pull and tag",
source: "source:image",
target: "target:image",
arch: "amd64",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error { return nil },
mockTag: func(c *docker.Client, source, target string) error { return nil },
expectError: false,
},
{
name: "pull fails",
source: "source:image",
target: "target:image",
arch: "amd64",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error {
return fmt.Errorf("pull error")
},
expectError: true,
},
{
name: "tag fails",
source: "source:image",
target: "target:image",
arch: "amd64",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error { return nil },
mockTag: func(c *docker.Client, source, target string) error { return fmt.Errorf("tag error") },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc((*docker.Client).Pull, tt.mockPull)
patches.ApplyFunc((*docker.Client).Tag, tt.mockTag)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
originalNeedRemoveImage := needRemoveImage
needRemoveImage = []string{}
defer func() {
needRemoveImage = originalNeedRemoveImage
}()
err := pullAndTagSingleArchImage(tt.source, tt.target, tt.arch)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Contains(t, needRemoveImage, tt.source)
assert.Contains(t, needRemoveImage, tt.target)
}
})
}
}
func TestPullAndPushMultiArchImage(t *testing.T) {
arch := []string{"amd64", "arm64"}
tests := []struct {
name string
source string
target string
mockPull func(*docker.Client, docker.ImageRef, utils.RetryOptions) error
mockTag func(*docker.Client, string, string) error
mockRemove func(*docker.Client, docker.ImageRef) error
mockPush func(*docker.Client, docker.ImageRef) error
expectError bool
}{
{
name: "successful pull and push",
source: "source:image",
target: "target:image",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error { return nil },
mockTag: func(c *docker.Client, source, target string) error { return nil },
mockRemove: func(c *docker.Client, ref docker.ImageRef) error { return nil },
mockPush: func(c *docker.Client, ref docker.ImageRef) error { return nil },
expectError: false,
},
{
name: "pull fails",
source: "source:image",
target: "target:image",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error {
return fmt.Errorf("pull error")
},
expectError: true,
},
{
name: "tag fails",
source: "source:image",
target: "target:image",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error { return nil },
mockTag: func(c *docker.Client, source, target string) error { return fmt.Errorf("tag error") },
expectError: true,
},
{
name: "remove fails",
source: "source:image",
target: "target:image",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error { return nil },
mockTag: func(c *docker.Client, source, target string) error { return nil },
mockRemove: func(c *docker.Client, ref docker.ImageRef) error { return fmt.Errorf("remove error") },
expectError: true,
},
{
name: "push fails",
source: "source:image",
target: "target:image",
mockPull: func(c *docker.Client, ref docker.ImageRef, opts utils.RetryOptions) error { return nil },
mockTag: func(c *docker.Client, source, target string) error { return nil },
mockRemove: func(c *docker.Client, ref docker.ImageRef) error { return nil },
mockPush: func(c *docker.Client, ref docker.ImageRef) error { return fmt.Errorf("push error") },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc((*docker.Client).Pull, tt.mockPull)
patches.ApplyFunc((*docker.Client).Tag, tt.mockTag)
patches.ApplyFunc((*docker.Client).Remove, tt.mockRemove)
patches.ApplyFunc((*docker.Client).Push, tt.mockPush)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
patches.ApplyFunc(log.Infof, func(format string, args ...interface{}) {})
originalNeedRemoveImage := needRemoveImage
needRemoveImage = []string{}
defer func() {
needRemoveImage = originalNeedRemoveImage
}()
manifestCreateCmd, manifestAnnotate, err := pullAndPushMultiArchImage(tt.source, tt.target, arch)
if tt.expectError {
assert.Error(t, err)
assert.Empty(t, manifestCreateCmd)
assert.Empty(t, manifestAnnotate)
} else {
assert.NoError(t, err)
assert.NotEmpty(t, manifestCreateCmd)
assert.NotEmpty(t, manifestAnnotate)
}
})
}
}
func TestExecuteManifestCommands(t *testing.T) {
manifestCreateCmd := "docker manifest create --insecure target:image source1 source2"
manifestAnnotate := []string{
"docker manifest annotate target:image --os linux --arch amd64 source1",
"docker manifest annotate target:image --os linux --arch arm64 source2",
}
tests := []struct {
name string
mockExecuteCommand func(*exec.CommandExecutor, []string, string, ...string) error
expectError bool
}{
{
name: "successful execution",
mockExecuteCommand: func(executor *exec.CommandExecutor, env []string, command string, args ...string) error { return nil },
expectError: false,
},
{
name: "execute command fails",
mockExecuteCommand: func(executor *exec.CommandExecutor, env []string, command string, args ...string) error {
return fmt.Errorf("exec error")
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc((*exec.CommandExecutor).ExecuteCommandWithEnv, tt.mockExecuteCommand)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
patches.ApplyFunc(log.Infof, func(format string, args ...interface{}) {})
err := global.ExecuteManifestCommands("target:image", manifestCreateCmd, manifestAnnotate)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestSyncImage(t *testing.T) {
imageChan := make(chan docker.ImageRef, testOneValue)
defer close(imageChan)
tests := []struct {
name string
source string
target string
arch []string
mockPullAndTagSingleArchImage func(string, string, string) error
mockPullAndPushMultiArchImage func(string, string, []string) (string, []string, error)
mockExecuteManifestCommands func(string, string, []string) error
expectError bool
}{
{
name: "single arch successful sync",
source: "source:image",
target: "target:image",
arch: []string{"amd64"},
mockPullAndTagSingleArchImage: func(source, target, arch string) error { return nil },
expectError: false,
},
{
name: "multi arch successful sync",
source: "source:image",
target: "target:image",
arch: []string{"amd64", "arm64"},
mockPullAndPushMultiArchImage: func(source, target string, arch []string) (string, []string, error) {
return "manifest cmd", []string{"annotate cmd"}, nil
},
mockExecuteManifestCommands: func(target, manifestCreateCmd string, manifestAnnotate []string) error {
return nil
},
expectError: false,
},
{
name: "single arch sync fails",
source: "source:image",
target: "target:image",
arch: []string{"amd64"},
mockPullAndTagSingleArchImage: func(source, target, arch string) error { return fmt.Errorf("pull error") },
expectError: true,
},
{
name: "multi arch pull fails",
source: "source:image",
target: "target:image",
arch: []string{"amd64", "arm64"},
mockPullAndPushMultiArchImage: func(source, target string, arch []string) (string, []string, error) {
return "", nil, fmt.Errorf("pull error")
},
expectError: true,
},
{
name: "multi arch execute fails",
source: "source:image",
target: "target:image",
arch: []string{"amd64", "arm64"},
mockPullAndPushMultiArchImage: func(source, target string, arch []string) (string, []string, error) {
return "manifest cmd", []string{"annotate cmd"}, nil
},
mockExecuteManifestCommands: func(target, manifestCreateCmd string, manifestAnnotate []string) error {
return fmt.Errorf("exec error")
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
if len(tt.arch) == testOneValue {
patches.ApplyFunc(pullAndTagSingleArchImage, tt.mockPullAndTagSingleArchImage)
} else {
patches.ApplyFunc(pullAndPushMultiArchImage, tt.mockPullAndPushMultiArchImage)
patches.ApplyFunc(global.ExecuteManifestCommands, tt.mockExecuteManifestCommands)
}
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
err := syncImage(tt.source, tt.target, tt.arch, imageChan)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestCleanBuildImage(t *testing.T) {
originalNeedRemoveImage := needRemoveImage
needRemoveImage = []string{"image1", "image2", "image3"}
defer func() {
needRemoveImage = originalNeedRemoveImage
}()
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc((*docker.Client).Remove, func(c *docker.Client, ref docker.ImageRef) error {
return nil
})
cleanBuildImage()
assert.True(t, true)
}
func TestCloseChanStruct(t *testing.T) {
ch := make(chan struct{})
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(utils.IsChanClosed, func(ch interface{}) bool {
return false
})
closeChanStruct(ch)
assert.True(t, true)
ch2 := make(chan struct{})
close(ch2)
patches.ApplyFunc(utils.IsChanClosed, func(ch interface{}) bool {
return true
})
closeChanStruct(ch2)
assert.True(t, true)
}
func TestPackImageAndCleanup(t *testing.T) {
tests := []struct {
name string
mockTarGZ func(prefix, target string) error
mockRemoveImageRegistry func(string) error
expectError bool
}{
{
name: "successful pack and cleanup",
mockTarGZ: func(src, dst string) error { return nil },
mockRemoveImageRegistry: func(name string) error { return nil },
expectError: false,
},
{
name: "tar gz fails",
mockTarGZ: func(src, dst string) error { return fmt.Errorf("tar error") },
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc(global.TarGZ, tt.mockTarGZ)
patches.ApplyFunc(server.RemoveImageRegistry, tt.mockRemoveImageRegistry)
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
patches.ApplyGlobalVar(&bke, "/tmp/bke")
err := packImageAndCleanup()
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
func TestPushImageWithError(t *testing.T) {
imageChan := make(chan docker.ImageRef, testOneValue)
pullCompleteChan := make(chan struct{})
pushCompleteChan := make(chan string)
stopChan := make(chan struct{})
imageChan <- docker.ImageRef{Image: "test-image", Platform: "amd64"}
patches := gomonkey.NewPatches()
defer patches.Reset()
patches.ApplyFunc((*docker.Client).Push, func(c *docker.Client, ref docker.ImageRef) error {
return fmt.Errorf("push error")
})
patches.ApplyFunc(log.SteppedInfo, func(stepName string, args ...any) {})
patches.ApplyFunc(log.Infof, func(format string, args ...interface{}) {})
go func() {
pushImage(imageChan, pullCompleteChan, pushCompleteChan, stopChan)
}()
close(imageChan)
result := <-pushCompleteChan
assert.Contains(t, result, "push error")
}
func TestSyncChannelsStruct(t *testing.T) {
stopChan := make(<-chan struct{})
internalStopChan := make(chan struct{})
pullCompleteChan := make(chan struct{})
imageChan := make(chan<- docker.ImageRef)
channels := &syncChannels{
stopChan: stopChan,
internalStopChan: internalStopChan,
pullCompleteChan: pullCompleteChan,
imageChan: imageChan,
}
assert.Equal(t, stopChan, channels.stopChan)
assert.Equal(t, internalStopChan, channels.internalStopChan)
assert.Equal(t, pullCompleteChan, channels.pullCompleteChan)
assert.Equal(t, imageChan, channels.imageChan)
}