github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/utils/tests/utils.go (about) 1 package tests 2 3 import ( 4 "bytes" 5 "errors" 6 "flag" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "os/exec" 11 "path/filepath" 12 "strconv" 13 "strings" 14 "testing" 15 16 "github.com/stretchr/testify/assert" 17 18 "github.com/jfrog/jfrog-cli-go/artifactory/commands/generic" 19 "github.com/jfrog/jfrog-cli-go/artifactory/spec" 20 "github.com/jfrog/jfrog-cli-go/utils/cliutils" 21 "github.com/jfrog/jfrog-cli-go/utils/config" 22 "github.com/jfrog/jfrog-client-go/artifactory/services/utils" 23 "github.com/jfrog/jfrog-client-go/utils/errorutils" 24 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 25 "github.com/jfrog/jfrog-client-go/utils/log" 26 ) 27 28 var RtUrl *string 29 var RtUser *string 30 var RtPassword *string 31 var RtApiKey *string 32 var RtSshKeyPath *string 33 var RtSshPassphrase *string 34 var RtAccessToken *string 35 var RtDistributionUrl *string 36 var BtUser *string 37 var BtKey *string 38 var BtOrg *string 39 var TestArtifactory *bool 40 var TestBintray *bool 41 var TestArtifactoryProxy *bool 42 var TestDistribution *bool 43 var TestDocker *bool 44 var TestGo *bool 45 var TestNpm *bool 46 var TestGradle *bool 47 var TestMaven *bool 48 var DockerRepoDomain *string 49 var DockerTargetRepo *string 50 var TestNuget *bool 51 var HideUnitTestLog *bool 52 var TestPip *bool 53 var PipVirtualEnv *string 54 55 func init() { 56 RtUrl = flag.String("rt.url", "http://127.0.0.1:8081/artifactory/", "Artifactory url") 57 RtUser = flag.String("rt.user", "admin", "Artifactory username") 58 RtPassword = flag.String("rt.password", "password", "Artifactory password") 59 RtApiKey = flag.String("rt.apikey", "", "Artifactory user API key") 60 RtSshKeyPath = flag.String("rt.sshKeyPath", "", "Ssh key file path") 61 RtSshPassphrase = flag.String("rt.sshPassphrase", "", "Ssh key passphrase") 62 RtAccessToken = flag.String("rt.accessToken", "", "Artifactory access token") 63 RtDistributionUrl = flag.String("rt.distUrl", "", "Distribution url") 64 TestArtifactory = flag.Bool("test.artifactory", false, "Test Artifactory") 65 TestArtifactoryProxy = flag.Bool("test.artifactoryProxy", false, "Test Artifactory proxy") 66 TestBintray = flag.Bool("test.bintray", false, "Test Bintray") 67 BtUser = flag.String("bt.user", "", "Bintray username") 68 BtKey = flag.String("bt.key", "", "Bintray API Key") 69 BtOrg = flag.String("bt.org", "", "Bintray organization") 70 TestDistribution = flag.Bool("test.distribution", false, "Test distribution") 71 TestDocker = flag.Bool("test.docker", false, "Test Docker build") 72 TestGo = flag.Bool("test.go", false, "Test Go") 73 TestNpm = flag.Bool("test.npm", false, "Test Npm") 74 TestGradle = flag.Bool("test.gradle", false, "Test Gradle") 75 TestMaven = flag.Bool("test.maven", false, "Test Maven") 76 DockerRepoDomain = flag.String("rt.dockerRepoDomain", "", "Docker repository domain") 77 DockerTargetRepo = flag.String("rt.dockerTargetRepo", "", "Docker repository domain") 78 TestNuget = flag.Bool("test.nuget", false, "Test Nuget") 79 HideUnitTestLog = flag.Bool("test.hideUnitTestLog", false, "Hide unit tests logs and print it in a file") 80 TestPip = flag.Bool("test.pip", false, "Test Pip") 81 PipVirtualEnv = flag.String("rt.pipVirtualEnv", "", "Pip virtual-environment path") 82 } 83 84 func CleanFileSystem() { 85 removeDirs(Out, Temp) 86 } 87 88 func removeDirs(dirs ...string) { 89 for _, dir := range dirs { 90 isExist, err := fileutils.IsDirExists(dir, false) 91 if err != nil { 92 log.Error(err) 93 } 94 if isExist { 95 os.RemoveAll(dir) 96 } 97 } 98 } 99 100 func VerifyExistLocally(expected, actual []string, t *testing.T) { 101 if len(actual) == 0 && len(expected) != 0 { 102 t.Error("Couldn't find all expected files, expected: " + strconv.Itoa(len(expected)) + ", found: " + strconv.Itoa(len(actual))) 103 } 104 err := compare(expected, actual) 105 assert.NoError(t, err) 106 } 107 108 func ValidateListsIdentical(expected, actual []string) error { 109 if len(actual) != len(expected) { 110 return errors.New("Unexpected behavior, expected: " + strconv.Itoa(len(expected)) + " files, found: " + strconv.Itoa(len(actual))) 111 } 112 err := compare(expected, actual) 113 return err 114 } 115 116 func ValidateChecksums(filePath string, expectedChecksum fileutils.ChecksumDetails, t *testing.T) { 117 localFileDetails, err := fileutils.GetFileDetails(filePath) 118 if err != nil { 119 t.Error("Couldn't calculate sha1, " + err.Error()) 120 } 121 if localFileDetails.Checksum.Sha1 != expectedChecksum.Sha1 { 122 t.Error("sha1 mismatch for "+filePath+", expected: "+expectedChecksum.Sha1, "found: "+localFileDetails.Checksum.Sha1) 123 } 124 if localFileDetails.Checksum.Md5 != expectedChecksum.Md5 { 125 t.Error("md5 mismatch for "+filePath+", expected: "+expectedChecksum.Md5, "found: "+localFileDetails.Checksum.Sha1) 126 } 127 if localFileDetails.Checksum.Sha256 != expectedChecksum.Sha256 { 128 t.Error("sha256 mismatch for "+filePath+", expected: "+expectedChecksum.Sha256, "found: "+localFileDetails.Checksum.Sha1) 129 } 130 } 131 132 func compare(expected, actual []string) error { 133 for _, v := range expected { 134 for i, r := range actual { 135 if v == r { 136 break 137 } 138 if i == len(actual)-1 { 139 return errors.New("Missing file : " + v) 140 } 141 } 142 } 143 return nil 144 } 145 146 func getPathsFromSearchResults(searchResults []generic.SearchResult) []string { 147 var paths []string 148 for _, result := range searchResults { 149 paths = append(paths, result.Path) 150 } 151 return paths 152 } 153 154 func CompareExpectedVsActual(expected []string, actual []generic.SearchResult, t *testing.T) { 155 if len(actual) != len(expected) { 156 t.Error(fmt.Sprintf("Unexpected behavior, expected: %s, \n%s\nfound: %s \n%s", strconv.Itoa(len(expected)), expected, strconv.Itoa(len(actual)), getPathsFromSearchResults(actual))) 157 } 158 for _, v := range expected { 159 for i, r := range actual { 160 if v == r.Path { 161 break 162 } 163 if i == len(actual)-1 { 164 t.Error("Missing file: " + v) 165 } 166 } 167 } 168 169 for _, r := range actual { 170 found := false 171 for _, v := range expected { 172 if v == r.Path { 173 found = true 174 break 175 } 176 } 177 if !found { 178 t.Error("Unexpected file: " + r.Path) 179 } 180 } 181 } 182 183 func GetTestResourcesPath() string { 184 dir, _ := os.Getwd() 185 return filepath.ToSlash(dir + "/testsdata/") 186 } 187 188 func GetFilePathForBintray(filename, path string, a ...string) string { 189 for i := 0; i < len(a); i++ { 190 path += a[i] + "/" 191 } 192 if filename != "" { 193 path += filename 194 } 195 return path 196 } 197 198 func GetFilePathForArtifactory(fileName string) string { 199 return GetTestResourcesPath() + "specs/" + fileName 200 } 201 202 func GetTestsLogsDir() (string, error) { 203 tempDirPath := filepath.Join(cliutils.GetCliPersistentTempDirPath(), "jfrog_tests_logs") 204 return tempDirPath, fileutils.CreateDirIfNotExist(tempDirPath) 205 } 206 207 type PackageSearchResultItem struct { 208 Name string 209 Path string 210 Package string 211 Version string 212 Repo string 213 Owner string 214 Created string 215 Size int64 216 Sha1 string 217 Published bool 218 } 219 220 type JfrogCli struct { 221 main func() error 222 prefix string 223 credentials string 224 } 225 226 func NewJfrogCli(mainFunc func() error, prefix, credentials string) *JfrogCli { 227 return &JfrogCli{mainFunc, prefix, credentials} 228 } 229 230 func (cli *JfrogCli) Exec(args ...string) error { 231 spaceSplit := " " 232 os.Args = strings.Split(cli.prefix, spaceSplit) 233 output := strings.Split(cli.prefix, spaceSplit) 234 for _, v := range args { 235 if v == "" { 236 continue 237 } 238 args := strings.Split(v, spaceSplit) 239 os.Args = append(os.Args, args...) 240 output = append(output, args...) 241 } 242 if cli.credentials != "" { 243 args := strings.Split(cli.credentials, spaceSplit) 244 os.Args = append(os.Args, args...) 245 } 246 247 log.Info("[Command]", strings.Join(output, " ")) 248 return cli.main() 249 } 250 251 func (cli *JfrogCli) LegacyBuildToolExec(args ...string) error { 252 spaceSplit := " " 253 os.Args = strings.Split(cli.prefix, spaceSplit) 254 output := strings.Split(cli.prefix, spaceSplit) 255 for _, v := range args { 256 if v == "" { 257 continue 258 } 259 os.Args = append(os.Args, v) 260 output = append(output, v) 261 } 262 if cli.credentials != "" { 263 args := strings.Split(cli.credentials, spaceSplit) 264 os.Args = append(os.Args, args...) 265 } 266 267 log.Info("[Command]", strings.Join(output, " ")) 268 return cli.main() 269 } 270 271 func (cli *JfrogCli) WithSuffix(suffix string) *JfrogCli { 272 return &JfrogCli{cli.main, cli.prefix, suffix} 273 } 274 275 type gitManager struct { 276 dotGitPath string 277 } 278 279 func GitExecutor(dotGitPath string) *gitManager { 280 return &gitManager{dotGitPath: dotGitPath} 281 } 282 283 func (m *gitManager) GetUrl() (string, string, error) { 284 return m.execGit("config", "--get", "remote.origin.url") 285 } 286 287 func (m *gitManager) GetRevision() (string, string, error) { 288 return m.execGit("show", "-s", "--format=%H", "HEAD") 289 } 290 291 func (m *gitManager) execGit(args ...string) (string, string, error) { 292 var stdout bytes.Buffer 293 var stderr bytes.Buffer 294 cmd := exec.Command("git", args...) 295 cmd.Dir = m.dotGitPath 296 cmd.Stdin = nil 297 cmd.Stdout = &stdout 298 cmd.Stderr = &stderr 299 err := cmd.Run() 300 errorutils.CheckError(err) 301 return strings.TrimSpace(stdout.String()), strings.TrimSpace(stderr.String()), err 302 } 303 304 // Prepare the .git environment for the test. Takes an existing folder and making it .git dir. 305 // sourceDirPath - Relative path to the source dir to change to .git 306 // targetDirPath - Relative path to the target created .git dir, usually 'testdata' under the parent dir. 307 func PrepareDotGitDir(t *testing.T, sourceDirPath, targetDirPath string) (string, string) { 308 // Get path to create .git folder in 309 baseDir, _ := os.Getwd() 310 baseDir = filepath.Join(baseDir, targetDirPath) 311 // Create .git path and make sure it is clean 312 dotGitPath := filepath.Join(baseDir, ".git") 313 RemovePath(dotGitPath, t) 314 // Get the path of the .git candidate path 315 dotGitPathTest := filepath.Join(baseDir, sourceDirPath) 316 // Rename the .git candidate 317 RenamePath(dotGitPathTest, dotGitPath, t) 318 return baseDir, dotGitPath 319 } 320 321 // Removing the provided path from the filesystem 322 func RemovePath(testPath string, t *testing.T) { 323 err := fileutils.RemovePath(testPath) 324 if err != nil { 325 t.Error(err) 326 t.FailNow() 327 } 328 } 329 330 // Renaming from old path to new path. 331 func RenamePath(oldPath, newPath string, t *testing.T) { 332 err := fileutils.RenamePath(oldPath, newPath) 333 if err != nil { 334 t.Error(err) 335 t.FailNow() 336 } 337 } 338 339 func DeleteFiles(deleteSpec *spec.SpecFiles, artifactoryDetails *config.ArtifactoryDetails) (successCount, failCount int, err error) { 340 deleteCommand := generic.NewDeleteCommand() 341 deleteCommand.SetThreads(3).SetSpec(deleteSpec).SetRtDetails(artifactoryDetails).SetDryRun(false) 342 err = deleteCommand.GetPathsToDelete() 343 if err != nil { 344 return 0, 0, err 345 } 346 347 return deleteCommand.DeleteFiles() 348 } 349 350 func GetNonVirtualRepositories() map[string]string { 351 nonVirtualRepos := map[string]string{ 352 Repo1: SpecsTestRepositoryConfig, 353 Repo2: MoveRepositoryConfig, 354 LfsRepo: GitLfsTestRepositoryConfig, 355 DebianRepo: DebianTestRepositoryConfig, 356 JcenterRemoteRepo: JcenterRemoteRepositoryConfig, 357 } 358 if *TestNpm { 359 nonVirtualRepos[NpmLocalRepo] = NpmLocalRepositoryConfig 360 nonVirtualRepos[NpmRemoteRepo] = NpmRemoteRepositoryConfig 361 } 362 if *TestPip { 363 nonVirtualRepos[PypiRemoteRepo] = PypiRemoteRepositoryConfig 364 } 365 366 return nonVirtualRepos 367 } 368 369 func GetVirtualRepositories() map[string]string { 370 virtualRepos := map[string]string{ 371 VirtualRepo: VirtualRepositoryConfig, 372 } 373 374 if *TestPip { 375 virtualRepos[PypiVirtualRepo] = PypiVirtualRepositoryConfig 376 } 377 378 return virtualRepos 379 } 380 381 func getRepositoriesNameMap() map[string]string { 382 return map[string]string{ 383 "${REPO1}": Repo1, 384 "${REPO2}": Repo2, 385 "${REPO_1_AND_2}": Repo1And2, 386 "${VIRTUAL_REPO}": VirtualRepo, 387 "${LFS_REPO}": LfsRepo, 388 "${DEBIAN_REPO}": DebianRepo, 389 "${JCENTER_REMOTE_REPO}": JcenterRemoteRepo, 390 "${NPM_LOCAL_REPO}": NpmLocalRepo, 391 "${NPM_REMOTE_REPO}": NpmRemoteRepo, 392 "${GO_REPO}": GoLocalRepo, 393 "${RT_SERVER_ID}": RtServerId, 394 "${RT_URL}": *RtUrl, 395 "${RT_API_KEY}": *RtApiKey, 396 "${RT_USERNAME}": *RtUser, 397 "${RT_PASSWORD}": *RtPassword, 398 "${RT_ACCESS_TOKEN}": *RtAccessToken, 399 "${PYPI_REMOTE_REPO}": PypiRemoteRepo, 400 "${PYPI_VIRTUAL_REPO}": PypiVirtualRepo, 401 } 402 } 403 404 func ReplaceTemplateVariables(path, destPath string) (string, error) { 405 content, err := ioutil.ReadFile(path) 406 if err != nil { 407 return "", errorutils.CheckError(err) 408 } 409 410 repos := getRepositoriesNameMap() 411 for repoName, repoValue := range repos { 412 content = bytes.Replace(content, []byte(repoName), []byte(repoValue), -1) 413 } 414 if destPath == "" { 415 destPath, err = os.Getwd() 416 if err != nil { 417 return "", errorutils.CheckError(err) 418 } 419 destPath = filepath.Join(destPath, Temp) 420 } 421 err = os.MkdirAll(destPath, 0700) 422 if err != nil { 423 return "", errorutils.CheckError(err) 424 } 425 specPath := filepath.Join(destPath, filepath.Base(path)) 426 log.Info("Creating spec file at:", specPath) 427 err = ioutil.WriteFile(specPath, []byte(content), 0700) 428 if err != nil { 429 return "", errorutils.CheckError(err) 430 } 431 432 return specPath, nil 433 } 434 435 func CreateSpec(fileName string) (string, error) { 436 searchFilePath := GetFilePathForArtifactory(fileName) 437 searchFilePath, err := ReplaceTemplateVariables(searchFilePath, "") 438 return searchFilePath, err 439 } 440 441 func ConvertSliceToMap(props []utils.Property) map[string]string { 442 propsMap := make(map[string]string) 443 for _, item := range props { 444 propsMap[item.Key] = item.Value 445 } 446 return propsMap 447 }