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

     1  package main
     2  
     3  import (
     4  	"github.com/stretchr/testify/assert"
     5  	"github.com/stretchr/testify/require"
     6  	"io/ioutil"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"testing"
    11  
    12  	"github.com/jfrog/gocmd/executers"
    13  	"github.com/jfrog/jfrog-cli-go/inttestutils"
    14  	"github.com/jfrog/jfrog-cli-go/utils/cliutils"
    15  	"github.com/jfrog/jfrog-cli-go/utils/tests"
    16  	_go "github.com/jfrog/jfrog-client-go/artifactory/services/go"
    17  	"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
    18  	"github.com/jfrog/jfrog-client-go/utils/log"
    19  	"github.com/jfrog/jfrog-client-go/utils/version"
    20  )
    21  
    22  // Testing build info capabilities for go project.
    23  // Build project using go without Artifactory ->
    24  // Publish dependencies to Artifactory ->
    25  // Publish project to Artifactory->
    26  // Publish and validate build-info
    27  func TestGoBuildInfo(t *testing.T) {
    28  	initGoTest(t)
    29  	wd, err := os.Getwd()
    30  	assert.NoError(t, err)
    31  	project1Path := createGoProject(t, "project1", false)
    32  	testsdataTarget := filepath.Join(tests.Out, "testsdata")
    33  	testsdataSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "go", "testsdata")
    34  	assert.NoError(t, fileutils.CopyDir(testsdataSrc, testsdataTarget, true))
    35  	assert.NoError(t, os.Chdir(project1Path))
    36  	defer os.Chdir(wd)
    37  
    38  	log.Info("Using Go project located at ", project1Path)
    39  
    40  	buildName := "go-build"
    41  
    42  	// 1. Download dependencies.
    43  	// 2. Publish build-info.
    44  	// 3. Validate the total count of dependencies added to the build-info.
    45  	buildNumber := "1"
    46  
    47  	artifactoryCli.Exec("go", "build", tests.GoLocalRepo, "--build-name="+buildName, "--build-number="+buildNumber)
    48  	cleanGoCache(t)
    49  
    50  	artifactoryCli.Exec("bp", buildName, buildNumber)
    51  	module := "github.com/jfrog/dependency"
    52  	buildInfo := inttestutils.GetBuildInfo(artifactoryDetails.Url, buildName, buildNumber, t, artHttpDetails)
    53  	artifactoryVersion, err := artAuth.GetVersion()
    54  	assert.NoError(t, err)
    55  
    56  	// Since Artifactory doesn't support info file before version 6.10.0, the artifacts count in the build info is different between versions
    57  	version := version.NewVersion(artifactoryVersion)
    58  	expectedDependencies := 8
    59  	expectedArtifacts := 2
    60  	if version.AtLeast(_go.ArtifactoryMinSupportedVersionForInfoFile) {
    61  		expectedDependencies = 4
    62  		expectedArtifacts = 3
    63  	}
    64  	validateBuildInfo(buildInfo, t, expectedDependencies, 0, module)
    65  
    66  	// Now, using a new build number, do the following:
    67  	// 1. Build the project again.
    68  	// 2. Publish the go package.
    69  	// 3. Validate the total count of dependencies and artifacts added to the build-info.
    70  	// 4. Validate that the artifacts are tagged with the build.name and build.number properties.
    71  	buildNumber = "2"
    72  
    73  	artifactoryCli.Exec("go", "build", tests.GoLocalRepo, "--build-name="+buildName, "--build-number="+buildNumber, "--module="+ModuleNameJFrogTest)
    74  	cleanGoCache(t)
    75  
    76  	artifactoryCli.Exec("gp", tests.GoLocalRepo, "v1.0.0", "--build-name="+buildName, "--build-number="+buildNumber, "--deps=rsc.io/quote:v1.5.2", "--module="+ModuleNameJFrogTest)
    77  	cleanGoCache(t)
    78  
    79  	artifactoryCli.Exec("bp", buildName, buildNumber)
    80  	buildInfo = inttestutils.GetBuildInfo(artifactoryDetails.Url, buildName, buildNumber, t, artHttpDetails)
    81  	validateBuildInfo(buildInfo, t, expectedDependencies, expectedArtifacts, ModuleNameJFrogTest)
    82  
    83  	assert.NoError(t, os.Chdir(filepath.Join(wd, "testsdata", "go")))
    84  
    85  	resultItems := getResultItemsFromArtifactory(tests.SearchGo, t)
    86  	assert.Equal(t, len(buildInfo.Modules[0].Artifacts), len(resultItems), "Incorrect number of artifacts were uploaded")
    87  	propsMap := map[string]string{
    88  		"build.name":   buildName,
    89  		"build.number": buildNumber,
    90  		"go.version":   "v1.0.0",
    91  	}
    92  	validateArtifactsProperties(resultItems, t, propsMap)
    93  
    94  	assert.NoError(t, os.Chdir(wd))
    95  	inttestutils.DeleteBuild(artifactoryDetails.Url, buildName, artHttpDetails)
    96  	cleanGoTest()
    97  }
    98  
    99  func TestGoConfigWithModuleNameChange(t *testing.T) {
   100  	initGoTest(t)
   101  	buildName := "go-build"
   102  	buildNumber := "1"
   103  	oldHomeDir, newHomeDir := prepareHomeDir(t)
   104  	defer os.Setenv(cliutils.HomeDir, oldHomeDir)
   105  	defer os.RemoveAll(newHomeDir)
   106  
   107  	wd, err := os.Getwd()
   108  	assert.NoError(t, err)
   109  
   110  	prepareGoProject("", t, true)
   111  	runGo(ModuleNameJFrogTest, buildName, buildNumber, t, "go", "build", "--build-name="+buildName, "--build-number="+buildNumber, "--module="+ModuleNameJFrogTest)
   112  
   113  	assert.NoError(t, os.Chdir(wd))
   114  
   115  	cleanGoTest()
   116  }
   117  
   118  func TestGoConfigWithoutModuleChange(t *testing.T) {
   119  	initGoTest(t)
   120  	buildName := "go-build"
   121  	buildNumber := "1"
   122  	oldHomeDir, newHomeDir := prepareHomeDir(t)
   123  	defer os.Setenv(cliutils.HomeDir, oldHomeDir)
   124  	defer os.RemoveAll(newHomeDir)
   125  
   126  	wd, err := os.Getwd()
   127  	assert.NoError(t, err)
   128  
   129  	prepareGoProject("", t, true)
   130  	runGo("", buildName, buildNumber, t, "go", "build", "--build-name="+buildName, "--build-number="+buildNumber)
   131  
   132  	assert.NoError(t, os.Chdir(wd))
   133  
   134  	cleanGoTest()
   135  }
   136  
   137  func TestGoWithGlobalConfig(t *testing.T) {
   138  	initGoTest(t)
   139  	buildName := "go-build"
   140  	buildNumber := "1"
   141  	oldHomeDir, newHomeDir := prepareHomeDir(t)
   142  
   143  	defer os.Setenv(cliutils.HomeDir, oldHomeDir)
   144  	defer os.RemoveAll(newHomeDir)
   145  
   146  	wd, err := os.Getwd()
   147  	assert.NoError(t, err)
   148  
   149  	prepareGoProject(newHomeDir, t, false)
   150  	runGo(ModuleNameJFrogTest, buildName, buildNumber, t, "go", "build", "--build-name="+buildName, "--build-number="+buildNumber, "--module="+ModuleNameJFrogTest)
   151  
   152  	assert.NoError(t, os.Chdir(wd))
   153  
   154  	cleanGoTest()
   155  }
   156  
   157  func runGo(module, buildName, buildNumber string, t *testing.T, args ...string) {
   158  	artifactoryGoCli := tests.NewJfrogCli(execMain, "jfrog rt", "")
   159  	assert.NoError(t, artifactoryGoCli.Exec(args...))
   160  	cleanGoCache(t)
   161  	artifactoryCli.Exec("bp", buildName, buildNumber)
   162  	buildInfo := inttestutils.GetBuildInfo(artifactoryDetails.Url, buildName, buildNumber, t, artHttpDetails)
   163  	if module == "" {
   164  		module = "github.com/jfrog/dependency"
   165  	}
   166  	artifactoryVersion, err := artAuth.GetVersion()
   167  	assert.NoError(t, err)
   168  
   169  	// Since Artifactory doesn't support info file before version 6.10.0, the artifacts count in the build info is different between versions
   170  	version := version.NewVersion(artifactoryVersion)
   171  	if version.AtLeast(_go.ArtifactoryMinSupportedVersionForInfoFile) {
   172  		validateBuildInfo(buildInfo, t, 4, 0, module)
   173  	} else {
   174  		validateBuildInfo(buildInfo, t, 8, 0, module)
   175  	}
   176  
   177  	inttestutils.DeleteBuild(artifactoryDetails.Url, buildName, artHttpDetails)
   178  }
   179  
   180  func prepareGoProject(configDestDir string, t *testing.T, copyDirs bool) {
   181  	project1Path := createGoProject(t, "project1", copyDirs)
   182  	testsdataTarget := filepath.Join(tests.Out, "testsdata")
   183  	testsdataSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "go", "testsdata")
   184  	err := fileutils.CopyDir(testsdataSrc, testsdataTarget, copyDirs)
   185  	assert.NoError(t, err)
   186  	if configDestDir == "" {
   187  		configDestDir = filepath.Join(project1Path, ".jfrog")
   188  	}
   189  	configFileDir := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "go", "project1", ".jfrog", "projects")
   190  	configFileDir, err = tests.ReplaceTemplateVariables(filepath.Join(configFileDir, "go.yaml"), filepath.Join(configDestDir, "projects"))
   191  	assert.NoError(t, err)
   192  	assert.NoError(t, os.Chdir(project1Path))
   193  	log.Info("Using Go project located at ", project1Path)
   194  }
   195  
   196  // Testing publishing and resolution capabilities for go projects.
   197  // Build first project using go without Artifactory ->
   198  // Publish dependencies to Artifactory ->
   199  // Publish first project to Artifactory ->
   200  // Set go to resolve from Artifactory (set GOPROXY) ->
   201  // Build second project using go resolving from Artifactory, should download project1 as dependency.
   202  func TestGoPublishResolve(t *testing.T) {
   203  	initGoTest(t)
   204  
   205  	wd, err := os.Getwd()
   206  	assert.NoError(t, err)
   207  	project1Path := createGoProject(t, "project1", false)
   208  	project2Path := createGoProject(t, "project2", false)
   209  	assert.NoError(t, os.Chdir(project1Path))
   210  
   211  	// Download dependencies without Artifactory
   212  	artifactoryCli.Exec("go", "build", tests.GoLocalRepo)
   213  	cleanGoCache(t)
   214  
   215  	// Publish dependency project to Artifactory
   216  	artifactoryCli.Exec("gp", tests.GoLocalRepo, "v1.0.0")
   217  	cleanGoCache(t)
   218  
   219  	assert.NoError(t, os.Chdir(project2Path))
   220  
   221  	// Build the second project, download dependencies from Artifactory
   222  	artifactoryCli.Exec("go", "build", tests.GoLocalRepo)
   223  	cleanGoCache(t)
   224  
   225  	// Restore workspace
   226  	assert.NoError(t, os.Chdir(wd))
   227  	cleanGoTest()
   228  }
   229  
   230  // Testing the fallback mechanism
   231  // 1. Building a project with a dependency that doesn't exists not in Artifactory and not in VCS.
   232  // 2. The fallback mechanism will try to download from both VCS and Artifactory and then fail with an error
   233  // 3. Testing that the error that is returned is the right error of the fallback.
   234  func TestGoFallback(t *testing.T) {
   235  	initGoTest(t)
   236  
   237  	wd, err := os.Getwd()
   238  	assert.NoError(t, err)
   239  
   240  	projectBuild := createGoProject(t, "projectbuild", false)
   241  
   242  	assert.NoError(t, os.Chdir(projectBuild))
   243  
   244  	err = artifactoryCli.Exec("go", "build", tests.GoLocalRepo)
   245  	if err != nil {
   246  		log.Warn(err)
   247  		assert.Contains(t, err.Error(), executers.FailedToRetrieve)
   248  		assert.Contains(t, err.Error(), executers.FromBothArtifactoryAndVcs)
   249  	} else {
   250  		assert.Fail(t, "Expected error but got success")
   251  	}
   252  
   253  	assert.NoError(t, os.Chdir(wd))
   254  	cleanGoTest()
   255  }
   256  
   257  // Builds a project with a dependency of gofrog that is missing a mod file.
   258  // Test the recursive overwrite capability.
   259  // 1. Upload dependency.
   260  // 2. Upload a project that is using that dependency
   261  // 3. Build with recursive-tidy-overwrite set to true so the gofrog dependency will be downloaded from VCS
   262  // 4. Check mod file (in Artifactory) of the dependency gofrog that populated.
   263  // 5. Check mod file (in Artifactory) of the gofrog dependency (pkg/errors) that exists with the right content
   264  func TestGoRecursivePublish(t *testing.T) {
   265  	initGoTest(t)
   266  	wd, err := os.Getwd()
   267  	assert.NoError(t, err)
   268  
   269  	testsdataTarget := filepath.Join(tests.Out, "testsdata")
   270  	testsdataSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "go", "testsdata")
   271  	assert.NoError(t, fileutils.CopyDir(testsdataSrc, testsdataTarget, true))
   272  	project1Path := createGoProject(t, "dependency", false)
   273  	projectMissingDependency := createGoProject(t, "projectmissingdependency", false)
   274  	projectBuild := createGoProject(t, "projectbuild", false)
   275  
   276  	uploadGoProject(project1Path, t)
   277  	uploadGoProject(projectMissingDependency, t)
   278  
   279  	assert.NoError(t, os.Chdir(projectBuild))
   280  	defer os.Chdir(wd)
   281  
   282  	assert.NoError(t, artifactoryCli.Exec("grp", tests.GoLocalRepo))
   283  	sumFileExists, err := fileutils.IsFileExists("go.sum", false)
   284  	assert.NoError(t, err)
   285  	if sumFileExists {
   286  		assert.NoError(t, os.Remove("go.sum"))
   287  	}
   288  	cleanGoCache(t)
   289  
   290  	assert.NoError(t, os.Chdir(filepath.Join(wd, "testsdata", "go")))
   291  
   292  	// Need to check the mod file within Artifactory of the gofrog dependency.
   293  	content := downloadModFile(tests.DownloadModFileGo, wd, "gofrog", t)
   294  
   295  	// Check that the file was signed:
   296  	assert.NotContains(t, string(content), "// Generated by JFrog", "Expected file to be not signed")
   297  	// Check that the mod file was populated with the dependency
   298  	assert.NotContains(t, string(content), "require github.com/pkg/errors", "Expected to get empty mod file")
   299  
   300  	assert.NoError(t, os.Chdir(filepath.Join(wd, "testsdata", "go")))
   301  
   302  	// Need to check the mod file within Artifactory of the dependency of gofrog => pkg/errors.
   303  	content = downloadModFile(tests.DownloadModOfDependencyGo, wd, "errors", t)
   304  
   305  	// Check that the file was signed:
   306  	assert.NotContains(t, string(content), "// Generated by JFrog", "Expected file to be not signed")
   307  	// Check that the mod file contains dependency module.
   308  	assert.Contains(t, string(content), "module github.com/pkg/errors", "Expected to get module github.com/pkg/errors")
   309  
   310  	assert.NoError(t, os.Chdir(wd))
   311  
   312  	cleanGoTest()
   313  }
   314  
   315  // Publish also the missing dependencies to Artifactory with the publishDeps flag.
   316  // Checks that the dependency exists in Artifactory.
   317  func TestGoWithPublishDeps(t *testing.T) {
   318  	initGoTest(t)
   319  	wd, err := os.Getwd()
   320  	assert.NoError(t, err)
   321  	project1Path := createGoProject(t, "project1", false)
   322  	testsdataTarget := filepath.Join(tests.Out, "testsdata")
   323  	testsdataSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "go", "testsdata")
   324  	assert.NoError(t, fileutils.CopyDir(testsdataSrc, testsdataTarget, true))
   325  	assert.NoError(t, os.Chdir(project1Path))
   326  	defer os.Chdir(wd)
   327  
   328  	log.Info("Using Go project located at ", project1Path)
   329  	artifactoryCli.Exec("go", "build", tests.GoLocalRepo, "--publish-deps=true")
   330  	cleanGoCache(t)
   331  
   332  	assert.NoError(t, os.Chdir(filepath.Join(wd, "testsdata", "go")))
   333  
   334  	content := downloadModFile(tests.DownloadModOfDependencyGo, wd, "errors", t)
   335  	assert.NotContains(t, string(content), " module github.com/pkg/errors", "Wrong mod content was downloaded")
   336  
   337  	assert.NoError(t, os.Chdir(wd))
   338  
   339  	cleanGoTest()
   340  }
   341  
   342  func initGoTest(t *testing.T) {
   343  	if !*tests.TestGo {
   344  		t.Skip("Skipping go test. To run go test add the '-test.go=true' option.")
   345  	}
   346  
   347  	os.Setenv("GONOSUMDB", "github.com/jfrog")
   348  
   349  	// Move when go will be supported and check Artifactory version.
   350  	if !isRepoExist(tests.GoLocalRepo) {
   351  		repoConfig := filepath.FromSlash(tests.GetTestResourcesPath()) + tests.GoLocalRepositoryConfig
   352  		repoConfig, err := tests.ReplaceTemplateVariables(repoConfig, "")
   353  		require.NoError(t, err)
   354  		execCreateRepoRest(repoConfig, tests.GoLocalRepo)
   355  	}
   356  	authenticate()
   357  }
   358  
   359  func cleanGoTest() {
   360  	os.Unsetenv("GONOSUMDB")
   361  	if isRepoExist(tests.GoLocalRepo) {
   362  		execDeleteRepoRest(tests.GoLocalRepo)
   363  	}
   364  	cleanBuildToolsTest()
   365  }
   366  
   367  func uploadGoProject(projectPath string, t *testing.T) {
   368  	assert.NoError(t, os.Chdir(projectPath))
   369  	// Publish project to Artifactory
   370  	assert.NoError(t, artifactoryCli.Exec("gp", tests.GoLocalRepo, "v1.0.0"))
   371  	cleanGoCache(t)
   372  }
   373  
   374  func cleanGoCache(t *testing.T) {
   375  	log.Info("Cleaning go cache by running: 'go clean -modcache'")
   376  
   377  	cmd := exec.Command("go", "clean", "-modcache")
   378  	assert.NoError(t, cmd.Run())
   379  }
   380  
   381  func createGoProject(t *testing.T, projectName string, includeDirs bool) string {
   382  	projectSrc := filepath.Join(filepath.FromSlash(tests.GetTestResourcesPath()), "go", projectName)
   383  	projectTarget := filepath.Join(tests.Out, projectName)
   384  	err := fileutils.CopyDir(projectSrc, projectTarget, includeDirs)
   385  	assert.NoError(t, err)
   386  	projectTarget, err = filepath.Abs(projectTarget)
   387  	assert.NoError(t, err)
   388  	return projectTarget
   389  }
   390  
   391  func downloadModFile(specName, wd, subDir string, t *testing.T) []byte {
   392  	specFile, err := tests.CreateSpec(specName)
   393  	assert.NoError(t, err)
   394  
   395  	modDir := filepath.Join(wd, tests.Out, subDir)
   396  	assert.NoError(t, os.MkdirAll(modDir, 0777))
   397  
   398  	assert.NoError(t, os.Chdir(modDir))
   399  	artifactoryCli.Exec("download", "--spec="+specFile, "--flat=true")
   400  	files, err := fileutils.ListFiles(modDir, false)
   401  	assert.NoError(t, err)
   402  	assert.Len(t, files, 1, "Expected to get one mod file")
   403  
   404  	content, err := ioutil.ReadFile(files[0])
   405  	assert.NoError(t, err)
   406  	return content
   407  }