Decouple implementations and unit tests in container module

Unit test should follow black-box approach.

Change-Id: I98c46c613a73b539f79d8dfe99cd73592792536d
Signed-off-by: Ruslan Aliev <raliev@mirantis.com>
Closes: #561
This commit is contained in:
Ruslan Aliev 2021-06-03 22:56:27 -05:00
parent 3cac887c7d
commit d1abe6e1ea
6 changed files with 128 additions and 111 deletions

View File

@ -51,17 +51,19 @@ type ClientV1Alpha1FactoryFunc func(
conf *v1alpha1.GenericContainer, conf *v1alpha1.GenericContainer,
targetPath string) ClientV1Alpha1 targetPath string) ClientV1Alpha1
type clientV1Alpha1 struct { // V1Alpha1 reflects inner struct of ClientV1Alpha1 Interface
type V1Alpha1 struct {
resultsDir string resultsDir string
input io.Reader input io.Reader
output io.Writer output io.Writer
conf *v1alpha1.GenericContainer conf *v1alpha1.GenericContainer
targetPath string targetPath string
containerFunc containerFunc containerFunc Func
} }
type containerFunc func(ctx context.Context, driver string, url string) (Container, error) // Func is type of function which returns Container object
type Func func(ctx context.Context, driver string, url string) (Container, error)
// NewClientV1Alpha1 constructor for ClientV1Alpha1 // NewClientV1Alpha1 constructor for ClientV1Alpha1
func NewClientV1Alpha1( func NewClientV1Alpha1(
@ -70,7 +72,7 @@ func NewClientV1Alpha1(
output io.Writer, output io.Writer,
conf *v1alpha1.GenericContainer, conf *v1alpha1.GenericContainer,
targetPath string) ClientV1Alpha1 { targetPath string) ClientV1Alpha1 {
return &clientV1Alpha1{ return &V1Alpha1{
resultsDir: resultsDir, resultsDir: resultsDir,
output: output, output: output,
input: input, input: input,
@ -80,8 +82,25 @@ func NewClientV1Alpha1(
} }
} }
// NewV1Alpha1 returns V1Alpha1 struct with desired parameters
func NewV1Alpha1(resultsDir string,
input io.Reader,
output io.Writer,
conf *v1alpha1.GenericContainer,
targetPath string,
containerFunc Func) V1Alpha1 {
return V1Alpha1{
resultsDir: resultsDir,
input: input,
output: output,
conf: conf,
targetPath: targetPath,
containerFunc: containerFunc,
}
}
// Run will perform container run action based on the configuration // Run will perform container run action based on the configuration
func (c *clientV1Alpha1) Run() error { func (c *V1Alpha1) Run() error {
// expand Src paths for mount if they are relative // expand Src paths for mount if they are relative
ExpandSourceMounts(c.conf.Spec.StorageMounts, c.targetPath) ExpandSourceMounts(c.conf.Spec.StorageMounts, c.targetPath)
// set default runtime // set default runtime
@ -95,9 +114,9 @@ func (c *clientV1Alpha1) Run() error {
} }
} }
func (c *clientV1Alpha1) runAirship() error { func (c *V1Alpha1) runAirship() error {
if c.conf.Spec.Airship.ContainerRuntime == "" { if c.conf.Spec.Airship.ContainerRuntime == "" {
c.conf.Spec.Airship.ContainerRuntime = ContainerDriverDocker c.conf.Spec.Airship.ContainerRuntime = DriverDocker
} }
var cont Container var cont Container
@ -121,7 +140,7 @@ func (c *clientV1Alpha1) runAirship() error {
// this will split the env vars into the ones to be exported and the ones that have values // this will split the env vars into the ones to be exported and the ones that have values
contEnv := runtimeutil.NewContainerEnvFromStringSlice(c.conf.Spec.EnvVars) contEnv := runtimeutil.NewContainerEnvFromStringSlice(c.conf.Spec.EnvVars)
envs := []string{} envs := make([]string, 0)
for _, key := range contEnv.VarsToExport { for _, key := range contEnv.VarsToExport {
envs = append(envs, strings.Join([]string{key, os.Getenv(key)}, "=")) envs = append(envs, strings.Join([]string{key, os.Getenv(key)}, "="))
} }
@ -199,7 +218,7 @@ func (c *clientV1Alpha1) runAirship() error {
return writeSink(c.resultsDir, parsedOut, c.output) return writeSink(c.resultsDir, parsedOut, c.output)
} }
func (c *clientV1Alpha1) runKRM() error { func (c *V1Alpha1) runKRM() error {
mounts := convertKRMMount(c.conf.Spec.StorageMounts) mounts := convertKRMMount(c.conf.Spec.StorageMounts)
fns := &runfn.RunFns{ fns := &runfn.RunFns{
Network: c.conf.Spec.HostNetwork, Network: c.conf.Spec.HostNetwork,

View File

@ -12,7 +12,7 @@
limitations under the License. limitations under the License.
*/ */
package container package container_test
import ( import (
"bytes" "bytes"
@ -29,6 +29,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"opendev.org/airship/airshipctl/pkg/api/v1alpha1" "opendev.org/airship/airshipctl/pkg/api/v1alpha1"
aircontainer "opendev.org/airship/airshipctl/pkg/container"
"opendev.org/airship/airshipctl/pkg/document" "opendev.org/airship/airshipctl/pkg/document"
"opendev.org/airship/airshipctl/pkg/phase/ifc" "opendev.org/airship/airshipctl/pkg/phase/ifc"
"opendev.org/airship/airshipctl/pkg/util" "opendev.org/airship/airshipctl/pkg/util"
@ -54,7 +55,7 @@ func TestGenericContainer(t *testing.T) {
output io.Writer output io.Writer
containerAPI *v1alpha1.GenericContainer containerAPI *v1alpha1.GenericContainer
execFunc containerFunc execFunc aircontainer.Func
executorConfig ifc.ExecutorConfig executorConfig ifc.ExecutorConfig
}{ }{
{ {
@ -65,7 +66,7 @@ func TestGenericContainer(t *testing.T) {
Type: "unknown", Type: "unknown",
}, },
}, },
execFunc: NewContainer, execFunc: aircontainer.NewContainer,
}, },
{ {
name: "error kyaml can't parse config", name: "error kyaml can't parse config",
@ -75,7 +76,7 @@ func TestGenericContainer(t *testing.T) {
}, },
Config: "~:~", Config: "~:~",
}, },
execFunc: NewContainer, execFunc: aircontainer.NewContainer,
expectedErr: "wrong Node Kind", expectedErr: "wrong Node Kind",
}, },
{ {
@ -93,7 +94,7 @@ func TestGenericContainer(t *testing.T) {
}, },
Config: `kind: ConfigMap`, Config: `kind: ConfigMap`,
}, },
execFunc: NewContainer, execFunc: aircontainer.NewContainer,
expectedErr: "no such file or directory", expectedErr: "no such file or directory",
outputPath: "directory doesn't exist", outputPath: "directory doesn't exist",
}, },
@ -115,7 +116,7 @@ func TestGenericContainer(t *testing.T) {
Config: `kind: ConfigMap`, Config: `kind: ConfigMap`,
}, },
expectedErr: "no such file or directory", expectedErr: "no such file or directory",
execFunc: func(ctx context.Context, driver, url string) (Container, error) { execFunc: func(ctx context.Context, driver, url string) (aircontainer.Container, error) {
return getDockerContainerMock(mockDockerClient{ return getDockerContainerMock(mockDockerClient{
containerAttach: func() (types.HijackedResponse, error) { containerAttach: func() (types.HijackedResponse, error) {
conn := types.HijackedResponse{ conn := types.HijackedResponse{
@ -158,7 +159,7 @@ func TestGenericContainer(t *testing.T) {
}, },
Config: `kind: ConfigMap`, Config: `kind: ConfigMap`,
}, },
execFunc: func(ctx context.Context, driver, url string) (Container, error) { execFunc: func(ctx context.Context, driver, url string) (aircontainer.Container, error) {
return getDockerContainerMock(mockDockerClient{ return getDockerContainerMock(mockDockerClient{
containerAttach: func() (types.HijackedResponse, error) { containerAttach: func() (types.HijackedResponse, error) {
conn := types.HijackedResponse{ conn := types.HijackedResponse{
@ -203,7 +204,7 @@ func TestGenericContainer(t *testing.T) {
}, },
Config: `kind: ConfigMap`, Config: `kind: ConfigMap`,
}, },
execFunc: func(ctx context.Context, driver, url string) (Container, error) { execFunc: func(ctx context.Context, driver, url string) (aircontainer.Container, error) {
return getDockerContainerMock(mockDockerClient{ return getDockerContainerMock(mockDockerClient{
containerAttach: func() (types.HijackedResponse, error) { containerAttach: func() (types.HijackedResponse, error) {
conn := types.HijackedResponse{ conn := types.HijackedResponse{
@ -240,7 +241,7 @@ func TestGenericContainer(t *testing.T) {
}, },
Config: `kind: ConfigMap`, Config: `kind: ConfigMap`,
}, },
execFunc: func(ctx context.Context, driver, url string) (Container, error) { execFunc: func(ctx context.Context, driver, url string) (aircontainer.Container, error) {
return getDockerContainerMock(mockDockerClient{ return getDockerContainerMock(mockDockerClient{
containerAttach: func() (types.HijackedResponse, error) { containerAttach: func() (types.HijackedResponse, error) {
conn := types.HijackedResponse{ conn := types.HijackedResponse{
@ -266,13 +267,7 @@ func TestGenericContainer(t *testing.T) {
tt := tt tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
input := bundlePathToInput(t, "testdata/single") input := bundlePathToInput(t, "testdata/single")
client := &clientV1Alpha1{ client := aircontainer.NewV1Alpha1(tt.outputPath, input, tt.output, tt.containerAPI, "", tt.execFunc)
input: input,
resultsDir: tt.outputPath,
output: tt.output,
conf: tt.containerAPI,
containerFunc: tt.execFunc,
}
err := client.Run() err := client.Run()
@ -288,7 +283,7 @@ func TestGenericContainer(t *testing.T) {
// Dummy test to keep up with coverage. // Dummy test to keep up with coverage.
func TestNewClientV1alpha1(t *testing.T) { func TestNewClientV1alpha1(t *testing.T) {
client := NewClientV1Alpha1("", nil, nil, v1alpha1.DefaultGenericContainer(), "") client := aircontainer.NewClientV1Alpha1("", nil, nil, v1alpha1.DefaultGenericContainer(), "")
require.NotNil(t, client) require.NotNil(t, client)
} }
@ -322,7 +317,7 @@ func TestExpandSourceMounts(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
tt := tt tt := tt
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
ExpandSourceMounts(tt.inputMounts, tt.targetPath) aircontainer.ExpandSourceMounts(tt.inputMounts, tt.targetPath)
require.Equal(t, tt.expectedMounts, tt.inputMounts) require.Equal(t, tt.expectedMounts, tt.inputMounts)
}) })
} }

View File

@ -20,8 +20,8 @@ import (
) )
const ( const (
// ContainerDriverDocker indicates that docker driver should be used in container constructor // DriverDocker indicates that docker driver should be used in container constructor
ContainerDriverDocker = "docker" DriverDocker = "docker"
) )
// Status type provides container status // Status type provides container status
@ -86,7 +86,7 @@ func NewContainer(ctx context.Context, driver string, url string) (Container, er
switch driver { switch driver {
case "": case "":
return nil, ErrNoContainerDriver{} return nil, ErrNoContainerDriver{}
case ContainerDriverDocker: case DriverDocker:
cli, err := NewDockerClient(ctx) cli, err := NewDockerClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -99,11 +99,11 @@ type DockerClient interface {
// DockerContainer docker container object wrapper // DockerContainer docker container object wrapper
type DockerContainer struct { type DockerContainer struct {
tag string Tag string
imageURL string ImageURL string
id string ID string
dockerClient DockerClient DockerClient DockerClient
ctx context.Context Ctx context.Context
} }
// NewDockerClient returns instance of DockerClient. // NewDockerClient returns instance of DockerClient.
@ -131,11 +131,11 @@ func NewDockerContainer(ctx context.Context, url string, cli DockerClient) (*Doc
} }
cnt := &DockerContainer{ cnt := &DockerContainer{
tag: t, Tag: t,
imageURL: url, ImageURL: url,
id: "", ID: "",
dockerClient: cli, DockerClient: cli,
ctx: ctx, Ctx: ctx,
} }
if err := cnt.ImagePull(); err != nil { if err := cnt.ImagePull(); err != nil {
return nil, err return nil, err
@ -143,7 +143,7 @@ func NewDockerContainer(ctx context.Context, url string, cli DockerClient) (*Doc
return cnt, nil return cnt, nil
} }
// getCmd identifies container command. Accepts list of strings each element // GetCmd identifies container command. Accepts list of strings each element
// represents command part (e.g "sample cmd --key" should be transformed to // represents command part (e.g "sample cmd --key" should be transformed to
// []string{"sample", "command", "--key"}) // []string{"sample", "command", "--key"})
// //
@ -153,17 +153,17 @@ func NewDockerContainer(ctx context.Context, url string, cli DockerClient) (*Doc
// If input parameter is empty list method identifies container image and // If input parameter is empty list method identifies container image and
// tries to extract Cmd option from this image description (i.e. tries to // tries to extract Cmd option from this image description (i.e. tries to
// identify default command specified in Dockerfile) // identify default command specified in Dockerfile)
func (c *DockerContainer) getCmd(cmd []string) ([]string, error) { func (c *DockerContainer) GetCmd(cmd []string) ([]string, error) {
if len(cmd) > 0 { if len(cmd) > 0 {
return cmd, nil return cmd, nil
} }
id, err := c.getImageID(c.imageURL) id, err := c.GetImageID(c.ImageURL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
insp, _, err := c.dockerClient.ImageInspectWithRaw(c.ctx, id) insp, _, err := c.DockerClient.ImageInspectWithRaw(c.Ctx, id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -173,12 +173,12 @@ func (c *DockerContainer) getCmd(cmd []string) ([]string, error) {
// getConfig creates configuration structures for Docker API client. // getConfig creates configuration structures for Docker API client.
func (c *DockerContainer) getConfig(opts RunCommandOptions) (container.Config, container.HostConfig, error) { func (c *DockerContainer) getConfig(opts RunCommandOptions) (container.Config, container.HostConfig, error) {
cmd, err := c.getCmd(opts.Cmd) cmd, err := c.GetCmd(opts.Cmd)
if err != nil { if err != nil {
return container.Config{}, container.HostConfig{}, err return container.Config{}, container.HostConfig{}, err
} }
mounts := []mount.Mount{} mounts := make([]mount.Mount, 0)
for _, mnt := range opts.Mounts { for _, mnt := range opts.Mounts {
mounts = append(mounts, mount.Mount{ mounts = append(mounts, mount.Mount{
Type: mount.Type(mnt.Type), Type: mount.Type(mnt.Type),
@ -189,7 +189,7 @@ func (c *DockerContainer) getConfig(opts RunCommandOptions) (container.Config, c
} }
cCfg := container.Config{ cCfg := container.Config{
Image: c.imageURL, Image: c.ImageURL,
Cmd: cmd, Cmd: cmd,
AttachStdin: true, AttachStdin: true,
@ -210,9 +210,9 @@ func (c *DockerContainer) getConfig(opts RunCommandOptions) (container.Config, c
return cCfg, hCfg, nil return cCfg, hCfg, nil
} }
// getImageID return ID of container image specified by URL. Method executes // GetImageID return ID of container image specified by URL. Method executes
// ImageList function supplied with "reference" filter // ImageList function supplied with "reference" filter
func (c *DockerContainer) getImageID(url string) (string, error) { func (c *DockerContainer) GetImageID(url string) (string, error) {
kv := filters.KeyValuePair{ kv := filters.KeyValuePair{
Key: "reference", Key: "reference",
Value: url, Value: url,
@ -222,7 +222,7 @@ func (c *DockerContainer) getImageID(url string) (string, error) {
All: false, All: false,
Filters: filter, Filters: filter,
} }
img, err := c.dockerClient.ImageList(c.ctx, opts) img, err := c.DockerClient.ImageList(c.Ctx, opts)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -236,7 +236,7 @@ func (c *DockerContainer) getImageID(url string) (string, error) {
// GetID returns ID of the container // GetID returns ID of the container
func (c *DockerContainer) GetID() string { func (c *DockerContainer) GetID() string {
return c.id return c.ID
} }
// ImagePull downloads image for container // ImagePull downloads image for container
@ -244,12 +244,12 @@ func (c *DockerContainer) ImagePull() error {
// skip image download if already downloaded // skip image download if already downloaded
// ImageInspectWithRaw returns err when image not found local and // ImageInspectWithRaw returns err when image not found local and
// in this case it will proceed for ImagePull. // in this case it will proceed for ImagePull.
_, _, err := c.dockerClient.ImageInspectWithRaw(c.ctx, c.imageURL) _, _, err := c.DockerClient.ImageInspectWithRaw(c.Ctx, c.ImageURL)
if err == nil { if err == nil {
log.Debug("Image Already exists, skip download") log.Debug("Image Already exists, skip download")
return nil return nil
} }
resp, err := c.dockerClient.ImagePull(c.ctx, c.imageURL, types.ImagePullOptions{}) resp, err := c.DockerClient.ImagePull(c.Ctx, c.ImageURL, types.ImagePullOptions{})
if err != nil { if err != nil {
return err return err
} }
@ -268,8 +268,8 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
if err != nil { if err != nil {
return err return err
} }
resp, err := c.dockerClient.ContainerCreate( resp, err := c.DockerClient.ContainerCreate(
c.ctx, c.Ctx,
&containerConfig, &containerConfig,
&hostConfig, &hostConfig,
nil, nil,
@ -280,10 +280,10 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
return err return err
} }
c.id = resp.ID c.ID = resp.ID
if opts.Input != nil { if opts.Input != nil {
conn, attachErr := c.dockerClient.ContainerAttach(c.ctx, c.id, types.ContainerAttachOptions{ conn, attachErr := c.DockerClient.ContainerAttach(c.Ctx, c.ID, types.ContainerAttachOptions{
Stream: true, Stream: true,
Stdin: true, Stdin: true,
}) })
@ -294,7 +294,7 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
defer conn.Close() defer conn.Close()
// This code is smiplified version of docker cli code // This code is simplified version of docker cli code
cErr := make(chan error, 1) cErr := make(chan error, 1)
// Write to stdin asynchronously // Write to stdin asynchronously
@ -303,7 +303,7 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
cErr <- copyErr cErr <- copyErr
}() }()
if err = c.dockerClient.ContainerStart(c.ctx, c.id, types.ContainerStartOptions{}); err != nil { if err = c.DockerClient.ContainerStart(c.Ctx, c.ID, types.ContainerStartOptions{}); err != nil {
<-cErr <-cErr
return err return err
} }
@ -311,7 +311,7 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
return <-cErr return <-cErr
} }
if err = c.dockerClient.ContainerStart(c.ctx, c.id, types.ContainerStartOptions{}); err != nil { if err = c.DockerClient.ContainerStart(c.Ctx, c.ID, types.ContainerStartOptions{}); err != nil {
return err return err
} }
@ -321,7 +321,7 @@ func (c *DockerContainer) RunCommand(opts RunCommandOptions) (err error) {
// GetContainerLogs returns logs from the container as io.ReadCloser // GetContainerLogs returns logs from the container as io.ReadCloser
func (c *DockerContainer) GetContainerLogs(opts GetLogOptions) (io.ReadCloser, error) { func (c *DockerContainer) GetContainerLogs(opts GetLogOptions) (io.ReadCloser, error) {
return c.dockerClient.ContainerLogs(c.ctx, c.id, types.ContainerLogsOptions{ return c.DockerClient.ContainerLogs(c.Ctx, c.ID, types.ContainerLogsOptions{
ShowStderr: opts.Stderr, ShowStderr: opts.Stderr,
Follow: opts.Follow, Follow: opts.Follow,
ShowStdout: opts.Stdout, ShowStdout: opts.Stdout,
@ -330,9 +330,9 @@ func (c *DockerContainer) GetContainerLogs(opts GetLogOptions) (io.ReadCloser, e
// RmContainer kills and removes a container from the docker host. // RmContainer kills and removes a container from the docker host.
func (c *DockerContainer) RmContainer() error { func (c *DockerContainer) RmContainer() error {
return c.dockerClient.ContainerRemove( return c.DockerClient.ContainerRemove(
c.ctx, c.Ctx,
c.id, c.ID,
types.ContainerRemoveOptions{ types.ContainerRemoveOptions{
Force: true, Force: true,
}, },
@ -341,7 +341,7 @@ func (c *DockerContainer) RmContainer() error {
// InspectContainer inspect the running container // InspectContainer inspect the running container
func (c *DockerContainer) InspectContainer() (State, error) { func (c *DockerContainer) InspectContainer() (State, error) {
json, err := c.dockerClient.ContainerInspect(context.Background(), c.id) json, err := c.DockerClient.ContainerInspect(context.Background(), c.ID)
if err != nil { if err != nil {
log.Debug("Failed to inspect container status") log.Debug("Failed to inspect container status")
return State{}, err return State{}, err
@ -356,7 +356,7 @@ func (c *DockerContainer) InspectContainer() (State, error) {
// WaitUntilFinished waits unit container command is finished, return an error if failed // WaitUntilFinished waits unit container command is finished, return an error if failed
func (c *DockerContainer) WaitUntilFinished() error { func (c *DockerContainer) WaitUntilFinished() error {
statusCh, errCh := c.dockerClient.ContainerWait(c.ctx, c.id, container.WaitConditionNotRunning) statusCh, errCh := c.DockerClient.ContainerWait(c.Ctx, c.ID, container.WaitConditionNotRunning)
log.Debugf("waiting until command is finished...") log.Debugf("waiting until command is finished...")
select { select {
case err := <-errCh: case err := <-errCh:
@ -365,7 +365,7 @@ func (c *DockerContainer) WaitUntilFinished() error {
} }
case retCode := <-statusCh: case retCode := <-statusCh:
if retCode.StatusCode != 0 { if retCode.StatusCode != 0 {
logsCmd := fmt.Sprintf("docker logs %s", c.id) logsCmd := fmt.Sprintf("docker logs %s", c.ID)
return ErrRunContainerCommand{Cmd: logsCmd} return ErrRunContainerCommand{Cmd: logsCmd}
} }
} }

View File

@ -12,7 +12,7 @@
limitations under the License. limitations under the License.
*/ */
package container package container_test
import ( import (
"bytes" "bytes"
@ -25,13 +25,14 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/network"
specs "github.com/opencontainers/image-spec/specs-go/v1" specs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
aircontainer "opendev.org/airship/airshipctl/pkg/container"
) )
type mockConn struct { type mockConn struct {
@ -130,11 +131,11 @@ func (mdc *mockDockerClient) ContainerInspect(context.Context, string) (types.Co
return types.ContainerJSON{}, nil return types.ContainerJSON{}, nil
} }
func getDockerContainerMock(mdc mockDockerClient) *DockerContainer { func getDockerContainerMock(mdc mockDockerClient) *aircontainer.DockerContainer {
ctx := context.Background() ctx := context.Background()
cnt := &DockerContainer{ cnt := &aircontainer.DockerContainer{
dockerClient: &mdc, DockerClient: &mdc,
ctx: ctx, Ctx: ctx,
} }
return cnt return cnt
} }
@ -187,7 +188,7 @@ func TestGetCmd(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
cnt := getDockerContainerMock(tt.mockDockerClient) cnt := getDockerContainerMock(tt.mockDockerClient)
actualRes, actualErr := cnt.getCmd(tt.cmd) actualRes, actualErr := cnt.GetCmd(tt.cmd)
assert.Equal(t, tt.expectedErr, actualErr) assert.Equal(t, tt.expectedErr, actualErr)
assert.Equal(t, tt.expectedResult, actualRes) assert.Equal(t, tt.expectedResult, actualRes)
@ -220,12 +221,12 @@ func TestGetImageId(t *testing.T) {
}, },
}, },
expectedResult: "", expectedResult: "",
expectedErr: ErrEmptyImageList{}, expectedErr: aircontainer.ErrEmptyImageList{},
}, },
} }
for _, tt := range tests { for _, tt := range tests {
cnt := getDockerContainerMock(tt.mockDockerClient) cnt := getDockerContainerMock(tt.mockDockerClient)
actualRes, actualErr := cnt.getImageID(tt.url) actualRes, actualErr := cnt.GetImageID(tt.url)
assert.Equal(t, tt.expectedErr, actualErr) assert.Equal(t, tt.expectedErr, actualErr)
assert.Equal(t, tt.expectedResult, actualRes) assert.Equal(t, tt.expectedResult, actualRes)
@ -271,7 +272,7 @@ func TestImagePull(t *testing.T) {
func TestGetId(t *testing.T) { func TestGetId(t *testing.T) {
cnt := getDockerContainerMock(mockDockerClient{}) cnt := getDockerContainerMock(mockDockerClient{})
err := cnt.RunCommand(RunCommandOptions{ err := cnt.RunCommand(aircontainer.RunCommandOptions{
Cmd: []string{"testCmd"}, Cmd: []string{"testCmd"},
}) })
require.NoError(t, err) require.NoError(t, err)
@ -289,7 +290,7 @@ func TestRunCommand(t *testing.T) {
cmd []string cmd []string
containerInput io.Reader containerInput io.Reader
volumeMounts []string volumeMounts []string
mounts []Mount mounts []aircontainer.Mount
debug bool debug bool
mockDockerClient mockDockerClient mockDockerClient mockDockerClient
expectedRunErr error expectedRunErr error
@ -334,7 +335,7 @@ func TestRunCommand(t *testing.T) {
}, },
}, },
expectedRunErr: nil, expectedRunErr: nil,
mounts: []Mount{ mounts: []aircontainer.Mount{
{ {
ReadOnly: true, ReadOnly: true,
Type: "bind", Type: "bind",
@ -434,7 +435,7 @@ func TestRunCommand(t *testing.T) {
}, },
}, },
expectedRunErr: nil, expectedRunErr: nil,
expectedWaitErr: ErrRunContainerCommand{Cmd: "docker logs testID"}, expectedWaitErr: aircontainer.ErrRunContainerCommand{Cmd: "docker logs testID"},
assertF: func(t *testing.T) {}, assertF: func(t *testing.T) {},
}, },
{ {
@ -455,13 +456,13 @@ func TestRunCommand(t *testing.T) {
}, },
}, },
expectedRunErr: nil, expectedRunErr: nil,
expectedWaitErr: ErrRunContainerCommand{Cmd: "docker logs testID"}, expectedWaitErr: aircontainer.ErrRunContainerCommand{Cmd: "docker logs testID"},
assertF: func(t *testing.T) {}, assertF: func(t *testing.T) {},
}, },
} }
for _, tt := range tests { for _, tt := range tests {
cnt := getDockerContainerMock(tt.mockDockerClient) cnt := getDockerContainerMock(tt.mockDockerClient)
actualErr := cnt.RunCommand(RunCommandOptions{ actualErr := cnt.RunCommand(aircontainer.RunCommandOptions{
Input: tt.containerInput, Input: tt.containerInput,
Cmd: tt.cmd, Cmd: tt.cmd,
Binds: tt.volumeMounts, Binds: tt.volumeMounts,
@ -508,13 +509,13 @@ func TestRunCommandOutput(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
cnt := getDockerContainerMock(tt.mockDockerClient) cnt := getDockerContainerMock(tt.mockDockerClient)
actualErr := cnt.RunCommand(RunCommandOptions{ actualErr := cnt.RunCommand(aircontainer.RunCommandOptions{
Input: tt.containerInput, Input: tt.containerInput,
Cmd: tt.cmd, Cmd: tt.cmd,
Binds: tt.volumeMounts, Binds: tt.volumeMounts,
}) })
assert.Equal(t, tt.expectedErr, actualErr) assert.Equal(t, tt.expectedErr, actualErr)
actualRes, actualErr := cnt.GetContainerLogs(GetLogOptions{Stdout: true, Follow: true}) actualRes, actualErr := cnt.GetContainerLogs(aircontainer.GetLogOptions{Stdout: true, Follow: true})
require.NoError(t, actualErr) require.NoError(t, actualErr)
var actualResBytes []byte var actualResBytes []byte
@ -579,7 +580,7 @@ func TestNewDockerContainer(t *testing.T) {
}, },
} }
for _, tt := range tests { for _, tt := range tests {
actualRes, actualErr := NewDockerContainer((tt.ctx), tt.url, &(tt.cli)) actualRes, actualErr := aircontainer.NewDockerContainer(tt.ctx, tt.url, &(tt.cli))
assert.Equal(t, tt.expectedErr, actualErr) assert.Equal(t, tt.expectedErr, actualErr)
@ -588,9 +589,9 @@ func TestNewDockerContainer(t *testing.T) {
actualResStruct = resultStruct{} actualResStruct = resultStruct{}
} else { } else {
actualResStruct = resultStruct{ actualResStruct = resultStruct{
tag: actualRes.tag, tag: actualRes.Tag,
imageURL: actualRes.imageURL, imageURL: actualRes.ImageURL,
id: actualRes.id, id: actualRes.ID,
} }
} }
assert.Equal(t, tt.expectedResult, actualResStruct) assert.Equal(t, tt.expectedResult, actualResStruct)
@ -618,7 +619,7 @@ func TestRmContainer(t *testing.T) {
func TestInspectContainer(t *testing.T) { func TestInspectContainer(t *testing.T) {
tests := []struct { tests := []struct {
cli mockDockerClient cli mockDockerClient
expectedState State expectedState aircontainer.State
expectedErr error expectedErr error
}{ }{
{ {
@ -630,13 +631,13 @@ func TestInspectContainer(t *testing.T) {
json.ContainerJSONBase = &types.ContainerJSONBase{} json.ContainerJSONBase = &types.ContainerJSONBase{}
json.ContainerJSONBase.State = &types.ContainerState{} json.ContainerJSONBase.State = &types.ContainerState{}
json.ContainerJSONBase.State.ExitCode = 0 json.ContainerJSONBase.State.ExitCode = 0
json.ContainerJSONBase.State.Status = CreatedContainerStatus json.ContainerJSONBase.State.Status = aircontainer.CreatedContainerStatus
return json, nil return json, nil
}, },
}, },
expectedState: State{ expectedState: aircontainer.State{
ExitCode: 0, ExitCode: 0,
Status: CreatedContainerStatus, Status: aircontainer.CreatedContainerStatus,
}, },
expectedErr: nil, expectedErr: nil,
}, },
@ -649,13 +650,13 @@ func TestInspectContainer(t *testing.T) {
json.ContainerJSONBase = &types.ContainerJSONBase{} json.ContainerJSONBase = &types.ContainerJSONBase{}
json.ContainerJSONBase.State = &types.ContainerState{} json.ContainerJSONBase.State = &types.ContainerState{}
json.ContainerJSONBase.State.ExitCode = 0 json.ContainerJSONBase.State.ExitCode = 0
json.ContainerJSONBase.State.Status = RunningContainerStatus json.ContainerJSONBase.State.Status = aircontainer.RunningContainerStatus
return json, nil return json, nil
}, },
}, },
expectedState: State{ expectedState: aircontainer.State{
ExitCode: 0, ExitCode: 0,
Status: RunningContainerStatus, Status: aircontainer.RunningContainerStatus,
}, },
expectedErr: nil, expectedErr: nil,
}, },
@ -668,13 +669,13 @@ func TestInspectContainer(t *testing.T) {
json.ContainerJSONBase = &types.ContainerJSONBase{} json.ContainerJSONBase = &types.ContainerJSONBase{}
json.ContainerJSONBase.State = &types.ContainerState{} json.ContainerJSONBase.State = &types.ContainerState{}
json.ContainerJSONBase.State.ExitCode = 0 json.ContainerJSONBase.State.ExitCode = 0
json.ContainerJSONBase.State.Status = ExitedContainerStatus json.ContainerJSONBase.State.Status = aircontainer.ExitedContainerStatus
return json, nil return json, nil
}, },
}, },
expectedState: State{ expectedState: aircontainer.State{
ExitCode: 0, ExitCode: 0,
Status: ExitedContainerStatus, Status: aircontainer.ExitedContainerStatus,
}, },
expectedErr: nil, expectedErr: nil,
}, },
@ -687,13 +688,13 @@ func TestInspectContainer(t *testing.T) {
json.ContainerJSONBase = &types.ContainerJSONBase{} json.ContainerJSONBase = &types.ContainerJSONBase{}
json.ContainerJSONBase.State = &types.ContainerState{} json.ContainerJSONBase.State = &types.ContainerState{}
json.ContainerJSONBase.State.ExitCode = 1 json.ContainerJSONBase.State.ExitCode = 1
json.ContainerJSONBase.State.Status = ExitedContainerStatus json.ContainerJSONBase.State.Status = aircontainer.ExitedContainerStatus
return json, nil return json, nil
}, },
}, },
expectedState: State{ expectedState: aircontainer.State{
ExitCode: 1, ExitCode: 1,
Status: ExitedContainerStatus, Status: aircontainer.ExitedContainerStatus,
}, },
expectedErr: nil, expectedErr: nil,
}, },

View File

@ -12,29 +12,31 @@
limitations under the License. limitations under the License.
*/ */
package container package container_test
import ( import (
"context" "context"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"opendev.org/airship/airshipctl/pkg/container"
) )
func TestNewContainer(t *testing.T) { func TestNewContainer(t *testing.T) {
assert := assert.New(t) a := assert.New(t)
ctx := context.Background() ctx := context.Background()
t.Run("not-supported-container", func(t *testing.T) { t.Run("not-supported-container", func(t *testing.T) {
cnt, err := NewContainer(ctx, "test_drv", "") cnt, err := container.NewContainer(ctx, "test_drv", "")
assert.Equal(nil, cnt) a.Equal(nil, cnt)
assert.Equal(ErrContainerDrvNotSupported{Driver: "test_drv"}, err) a.Equal(container.ErrContainerDrvNotSupported{Driver: "test_drv"}, err)
}) })
t.Run("empty-container", func(t *testing.T) { t.Run("empty-container", func(t *testing.T) {
cnt, err := NewContainer(ctx, "", "") cnt, err := container.NewContainer(ctx, "", "")
assert.Equal(nil, cnt) a.Equal(nil, cnt)
assert.Equal(ErrNoContainerDriver{}, err) a.Equal(container.ErrNoContainerDriver{}, err)
}) })
} }