github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/docker_test.go (about)

     1  package main
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"os/exec"
     7  	"path"
     8  	"path/filepath"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  
    14  	gofrogcmd "github.com/jfrog/gofrog/io"
    15  	"github.com/jfrog/jfrog-cli-go/artifactory/commands/generic"
    16  	"github.com/jfrog/jfrog-cli-go/artifactory/spec"
    17  	"github.com/jfrog/jfrog-cli-go/artifactory/utils/docker"
    18  	"github.com/jfrog/jfrog-cli-go/inttestutils"
    19  	"github.com/jfrog/jfrog-cli-go/utils/cliutils"
    20  	"github.com/jfrog/jfrog-cli-go/utils/tests"
    21  )
    22  
    23  const DockerTestImage string = "jfrog_cli_test_image"
    24  
    25  // Image get parent image id command
    26  type buildDockerImage struct {
    27  	dockerFilePath string
    28  	dockerTag      string
    29  }
    30  
    31  func (image *buildDockerImage) GetCmd() *exec.Cmd {
    32  	var cmd []string
    33  	cmd = append(cmd, "docker")
    34  	cmd = append(cmd, "build")
    35  	cmd = append(cmd, image.dockerFilePath)
    36  	cmd = append(cmd, "--tag", image.dockerTag)
    37  	return exec.Command(cmd[0], cmd[1:]...)
    38  }
    39  
    40  func (image *buildDockerImage) GetEnv() map[string]string {
    41  	return map[string]string{}
    42  }
    43  
    44  func (image *buildDockerImage) GetStdWriter() io.WriteCloser {
    45  	return nil
    46  }
    47  
    48  func (image *buildDockerImage) GetErrWriter() io.WriteCloser {
    49  	return nil
    50  }
    51  
    52  type deleteDockerImage struct {
    53  	dockerImageTag string
    54  }
    55  
    56  func (image *deleteDockerImage) GetCmd() *exec.Cmd {
    57  	var cmd []string
    58  	cmd = append(cmd, "docker")
    59  	cmd = append(cmd, "image")
    60  	cmd = append(cmd, "rm")
    61  	cmd = append(cmd, image.dockerImageTag)
    62  	return exec.Command(cmd[0], cmd[1:]...)
    63  }
    64  
    65  func (image *deleteDockerImage) GetEnv() map[string]string {
    66  	return map[string]string{}
    67  }
    68  
    69  func (image *deleteDockerImage) GetStdWriter() io.WriteCloser {
    70  	return nil
    71  }
    72  
    73  func (image *deleteDockerImage) GetErrWriter() io.WriteCloser {
    74  	return nil
    75  }
    76  
    77  func TestDockerPush(t *testing.T) {
    78  	if !*tests.TestDocker {
    79  		t.Skip("Skipping docker test. To run docker test add the '-test.docker=true' option.")
    80  	}
    81  	runDockerPushTest(DockerTestImage, DockerTestImage+":1", false, t)
    82  }
    83  
    84  func TestDockerPushWithModuleName(t *testing.T) {
    85  	if !*tests.TestDocker {
    86  		t.Skip("Skipping docker test. To run docker test add the '-test.docker=true' option.")
    87  	}
    88  	runDockerPushTest(DockerTestImage, ModuleNameJFrogTest, true, t)
    89  }
    90  
    91  func TestDockerPushWithMultipleSlash(t *testing.T) {
    92  	if !*tests.TestDocker {
    93  		t.Skip("Skipping docker test. To run docker test add the '-test.docker=true' option.")
    94  	}
    95  	runDockerPushTest(DockerTestImage+"/multiple", "multiple:1", false, t)
    96  }
    97  
    98  // Run docker push to Artifactory
    99  func runDockerPushTest(imageName, module string, withModule bool, t *testing.T) {
   100  	imageTag := buildTestDockerImage(imageName)
   101  	buildName := "docker-build"
   102  	buildNumber := "1"
   103  
   104  	// Push docker image using docker client
   105  	if withModule {
   106  		artifactoryCli.Exec("docker-push", imageTag, *tests.DockerTargetRepo, "--build-name="+buildName, "--build-number="+buildNumber, "--module="+module)
   107  	} else {
   108  		artifactoryCli.Exec("docker-push", imageTag, *tests.DockerTargetRepo, "--build-name="+buildName, "--build-number="+buildNumber)
   109  	}
   110  	artifactoryCli.Exec("build-publish", buildName, buildNumber)
   111  
   112  	imagePath := path.Join(*tests.DockerTargetRepo, imageName, "1") + "/"
   113  	validateDockerBuild(buildName, buildNumber, imagePath, module, 7, 5, 7, t)
   114  
   115  	dockerTestCleanup(imageName, buildName)
   116  }
   117  
   118  func TestDockerPushBuildNameNumberFromEnv(t *testing.T) {
   119  	if !*tests.TestDocker {
   120  		t.Skip("Skipping docker test. To run docker test add the '-test.docker=true' option.")
   121  	}
   122  
   123  	imageName := DockerTestImage
   124  	imageTag := buildTestDockerImage(imageName)
   125  	buildName := "docker-build"
   126  	buildNumber := "1"
   127  	os.Setenv(cliutils.BuildName, buildName)
   128  	os.Setenv(cliutils.BuildNumber, buildNumber)
   129  	defer os.Unsetenv(cliutils.BuildName)
   130  	defer os.Unsetenv(cliutils.BuildNumber)
   131  
   132  	// Push docker image using docker client
   133  	artifactoryCli.Exec("docker-push", imageTag, *tests.DockerTargetRepo)
   134  	artifactoryCli.Exec("build-publish")
   135  
   136  	imagePath := path.Join(*tests.DockerTargetRepo, imageName, "1") + "/"
   137  	validateDockerBuild(buildName, buildNumber, imagePath, DockerTestImage+":1", 7, 5, 7, t)
   138  
   139  	dockerTestCleanup(imageName, buildName)
   140  }
   141  
   142  func TestDockerPull(t *testing.T) {
   143  	if !*tests.TestDocker {
   144  		t.Skip("Skipping docker test. To run docker test add the '-test.docker=true' option.")
   145  	}
   146  
   147  	imageName := DockerTestImage
   148  	imageTag := buildTestDockerImage(imageName)
   149  
   150  	// Push docker image using docker client
   151  	artifactoryCli.Exec("docker-push", imageTag, *tests.DockerTargetRepo)
   152  
   153  	buildName := "docker-pull"
   154  	buildNumber := "1"
   155  
   156  	// Pull docker image using docker client
   157  	artifactoryCli.Exec("docker-pull", imageTag, *tests.DockerTargetRepo, "--build-name="+buildName, "--build-number="+buildNumber)
   158  	artifactoryCli.Exec("build-publish", buildName, buildNumber)
   159  
   160  	imagePath := path.Join(*tests.DockerTargetRepo, imageName, "1") + "/"
   161  	validateDockerBuild(buildName, buildNumber, imagePath, imageName+":1", 0, 7, 7, t)
   162  
   163  	buildNumber = "2"
   164  	artifactoryCli.Exec("docker-pull", imageTag, *tests.DockerTargetRepo, "--build-name="+buildName, "--build-number="+buildNumber, "--module="+ModuleNameJFrogTest)
   165  	artifactoryCli.Exec("build-publish", buildName, buildNumber)
   166  	validateDockerBuild(buildName, buildNumber, imagePath, ModuleNameJFrogTest, 0, 7, 7, t)
   167  
   168  	dockerTestCleanup(imageName, buildName)
   169  }
   170  
   171  func buildTestDockerImage(imageName string) string {
   172  	imageTag := path.Join(*tests.DockerRepoDomain, imageName+":1")
   173  	dockerFilePath := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "docker")
   174  	imageBuilder := &buildDockerImage{dockerTag: imageTag, dockerFilePath: dockerFilePath}
   175  	gofrogcmd.RunCmd(imageBuilder)
   176  	return imageTag
   177  }
   178  
   179  func deleteTestDockerImage(imageTag string) {
   180  	imageBuilder := &deleteDockerImage{dockerImageTag: imageTag}
   181  	gofrogcmd.RunCmd(imageBuilder)
   182  }
   183  
   184  func validateDockerBuild(buildName, buildNumber, imagePath, module string, expectedArtifacts, expectedDependencies, expectedItemsInArtifactory int, t *testing.T) {
   185  	specFile := spec.NewBuilder().Pattern(imagePath + "*").BuildSpec()
   186  	searchCmd := generic.NewSearchCommand()
   187  	searchCmd.SetRtDetails(artifactoryDetails).SetSpec(specFile)
   188  	assert.NoError(t, searchCmd.Search())
   189  	assert.Len(t, searchCmd.SearchResult(), expectedItemsInArtifactory, "Docker build info was not pushed correctly")
   190  
   191  	buildInfo := inttestutils.GetBuildInfo(artifactoryDetails.Url, buildName, buildNumber, t, artHttpDetails)
   192  	validateBuildInfo(buildInfo, t, expectedDependencies, expectedArtifacts, module)
   193  }
   194  
   195  func dockerTestCleanup(imageName, buildName string) {
   196  	// Remove build from Artifactory
   197  	inttestutils.DeleteBuild(artifactoryDetails.Url, buildName, artHttpDetails)
   198  
   199  	// Remove image from Artifactory
   200  	deleteSpec := spec.NewBuilder().Pattern(path.Join(*tests.DockerTargetRepo, imageName)).BuildSpec()
   201  	tests.DeleteFiles(deleteSpec, artifactoryDetails)
   202  }
   203  
   204  func TestDockerClientApiVersionCmd(t *testing.T) {
   205  	if !*tests.TestDocker {
   206  		t.Skip("Skipping docker test. To run docker test add the '-test.docker=true' option.")
   207  	}
   208  
   209  	// Run docker version command and expect no errors
   210  	cmd := &docker.VersionCmd{}
   211  	content, err := gofrogcmd.RunCmdOutput(cmd)
   212  	assert.NoError(t, err)
   213  
   214  	// Expect VersionRegex to match the output API version
   215  	content = strings.TrimSpace(content)
   216  	assert.True(t, docker.ApiVersionRegex.Match([]byte(content)))
   217  
   218  	// Assert docker min API version
   219  	assert.True(t, docker.IsCompatibleApiVersion(content))
   220  }
   221  
   222  func TestDockerFatManifestPull(t *testing.T) {
   223  	if !*tests.TestDocker {
   224  		t.Skip("Skipping docker test. To run docker test add the '-test.docker=true' option.")
   225  	}
   226  
   227  	imageName := "traefik"
   228  	imageTag := path.Join(*tests.DockerRepoDomain, imageName+":2.2")
   229  	buildName := "docker-pull"
   230  	buildNumber := "1"
   231  
   232  	// Pull docker image using docker client
   233  	artifactoryCli.Exec("docker-pull", imageTag, *tests.DockerTargetRepo, "--build-name="+buildName, "--build-number="+buildNumber)
   234  	artifactoryCli.Exec("build-publish", buildName, buildNumber)
   235  
   236  	//Validate
   237  	buildInfo := inttestutils.GetBuildInfo(artifactoryDetails.Url, buildName, buildNumber, t, artHttpDetails)
   238  	validateBuildInfo(buildInfo, t, 6, 0, imageName+":2.2")
   239  
   240  	dockerTestCleanup(imageName, buildName)
   241  	deleteTestDockerImage(imageTag)
   242  }