github.com/jfrog/jfrog-cli-core/v2@v2.51.0/artifactory/commands/utils/transferconfigbase_test.go (about) 1 package utils 2 3 import ( 4 "encoding/json" 5 "io" 6 "net/http" 7 "path/filepath" 8 "testing" 9 10 "github.com/jfrog/jfrog-cli-core/v2/artifactory/utils" 11 commonTests "github.com/jfrog/jfrog-cli-core/v2/common/tests" 12 "github.com/jfrog/jfrog-cli-core/v2/utils/config" 13 "github.com/jfrog/jfrog-client-go/artifactory/services" 14 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 15 16 "github.com/stretchr/testify/assert" 17 ) 18 19 const ( 20 repoKey = "repoKey" 21 projectKey = "test-proj" 22 ) 23 24 var transferConfigTestDir = filepath.Join("testdata", "transferconfig") 25 26 func TestIsDefaultCredentialsDefault(t *testing.T) { 27 unlockCounter := 0 28 testServer, serverDetails, _ := commonTests.CreateRtRestsMockServer(t, func(w http.ResponseWriter, r *http.Request) { 29 switch r.RequestURI { 30 case "/api/security/lockedUsers": 31 w.WriteHeader(http.StatusOK) 32 _, err := w.Write([]byte("[]")) 33 assert.NoError(t, err) 34 case "/api/system/ping": 35 w.WriteHeader(http.StatusOK) 36 _, err := w.Write([]byte("OK")) 37 assert.NoError(t, err) 38 default: 39 w.WriteHeader(http.StatusOK) 40 _, err := w.Write([]byte("User admin was successfully unlocked")) 41 assert.NoError(t, err) 42 unlockCounter++ 43 } 44 }) 45 defer testServer.Close() 46 47 isDefaultCreds, err := createTransferConfigBase(t, serverDetails, serverDetails).IsDefaultCredentials() 48 assert.NoError(t, err) 49 assert.True(t, isDefaultCreds) 50 assert.Equal(t, 0, unlockCounter) 51 } 52 53 func TestIsDefaultCredentialsNotDefault(t *testing.T) { 54 unlockCounter := 0 55 testServer, serverDetails, _ := commonTests.CreateRtRestsMockServer(t, func(w http.ResponseWriter, r *http.Request) { 56 switch r.RequestURI { 57 case "/api/security/lockedUsers": 58 w.WriteHeader(http.StatusOK) 59 _, err := w.Write([]byte("[]")) 60 assert.NoError(t, err) 61 case "/api/system/ping": 62 w.WriteHeader(http.StatusUnauthorized) 63 _, err := w.Write([]byte("{\n \"errors\" : [ {\n \"status\" : 401,\n \"message\" : \"Bad credentials\"\n } ]\n}")) 64 assert.NoError(t, err) 65 default: 66 w.WriteHeader(http.StatusOK) 67 _, err := w.Write([]byte("User admin was successfully unlocked")) 68 assert.NoError(t, err) 69 unlockCounter++ 70 } 71 }) 72 defer testServer.Close() 73 74 isDefaultCreds, err := createTransferConfigBase(t, serverDetails, serverDetails).IsDefaultCredentials() 75 assert.NoError(t, err) 76 assert.False(t, isDefaultCreds) 77 assert.Equal(t, 1, unlockCounter) 78 } 79 80 func TestIsDefaultCredentialsLocked(t *testing.T) { 81 pingCounter := 0 82 unlockCounter := 0 83 testServer, serverDetails, _ := commonTests.CreateRtRestsMockServer(t, func(w http.ResponseWriter, r *http.Request) { 84 switch r.RequestURI { 85 case "/api/security/lockedUsers": 86 w.WriteHeader(http.StatusOK) 87 _, err := w.Write([]byte("[ \"admin\" ]")) 88 assert.NoError(t, err) 89 case "/api/system/ping": 90 w.WriteHeader(http.StatusUnauthorized) 91 _, err := w.Write([]byte("{\n \"errors\" : [ {\n \"status\" : 401,\n \"message\" : \"Bad credentials\"\n } ]\n}")) 92 assert.NoError(t, err) 93 pingCounter++ 94 default: 95 w.WriteHeader(http.StatusOK) 96 _, err := w.Write([]byte("User admin was successfully unlocked")) 97 assert.NoError(t, err) 98 unlockCounter++ 99 } 100 }) 101 defer testServer.Close() 102 103 isDefaultCreds, err := createTransferConfigBase(t, serverDetails, serverDetails).IsDefaultCredentials() 104 assert.NoError(t, err) 105 assert.False(t, isDefaultCreds) 106 assert.Equal(t, 0, pingCounter) 107 assert.Equal(t, 0, unlockCounter) 108 } 109 110 func TestValidateDifferentServers(t *testing.T) { 111 var sourceRtVersion string 112 // Create transfer config command 113 _, sourceServerDetails, _ := commonTests.CreateRtRestsMockServer(t, func(w http.ResponseWriter, _ *http.Request) { 114 content, err := json.Marshal(VersionResponse{Version: sourceRtVersion}) 115 assert.NoError(t, err) 116 _, err = w.Write(content) 117 assert.NoError(t, err) 118 }) 119 120 t.Run("Same source and target servers", func(t *testing.T) { 121 err := createTransferConfigBase(t, sourceServerDetails, sourceServerDetails).ValidateDifferentServers() 122 assert.ErrorContains(t, err, "The source and target Artifactory servers are identical, but should be different.") 123 }) 124 } 125 126 func TestGetSelectedRepositories(t *testing.T) { 127 sourceTestServer, sourceServerDetails, _ := commonTests.CreateRtRestsMockServer(t, func(w http.ResponseWriter, _ *http.Request) { 128 w.WriteHeader(http.StatusOK) 129 repositories := &[]services.RepositoryDetails{ 130 {Key: "generic-local", Type: "local"}, {Key: "generic-local-filter", Type: "local"}, {Key: "generic-local-existed", Type: "local"}, 131 {Key: "generic-remote", Type: "remote"}, {Key: "generic-filter-remote", Type: "remote"}, 132 {Key: "generic-virtual", Type: "virtual"}, {Key: "filter-generic-virtual", Type: "virtual"}, 133 {Key: "generic-federated", Type: "federated"}, {Key: "generic-federated-filter", Type: "federated"}, 134 } 135 reposBytes, err := json.Marshal(repositories) 136 assert.NoError(t, err) 137 _, err = w.Write(reposBytes) 138 assert.NoError(t, err) 139 }) 140 defer sourceTestServer.Close() 141 targetTestServer, targetServerDetails, _ := commonTests.CreateRtRestsMockServer(t, func(w http.ResponseWriter, _ *http.Request) { 142 w.WriteHeader(http.StatusOK) 143 repositories := &[]services.RepositoryDetails{{Key: "generic-local-existed", Type: "local"}} 144 reposBytes, err := json.Marshal(repositories) 145 assert.NoError(t, err) 146 _, err = w.Write(reposBytes) 147 assert.NoError(t, err) 148 }) 149 defer targetTestServer.Close() 150 151 transferConfigBase := createTransferConfigBase(t, sourceServerDetails, targetServerDetails) 152 transferConfigBase.SetExcludeReposPatterns([]string{"*filter*"}) 153 selectedRepos, err := transferConfigBase.GetSelectedRepositories() 154 assert.NoError(t, err) 155 assert.Len(t, selectedRepos, 4) 156 assert.Equal(t, []services.RepositoryDetails{{Key: "generic-local", Type: "local"}}, selectedRepos[utils.Local]) 157 assert.Equal(t, []services.RepositoryDetails{{Key: "generic-remote", Type: "remote"}}, selectedRepos[utils.Remote]) 158 assert.Equal(t, []services.RepositoryDetails{{Key: "generic-virtual", Type: "virtual"}}, selectedRepos[utils.Virtual]) 159 assert.Equal(t, []services.RepositoryDetails{{Key: "generic-federated", Type: "federated"}}, selectedRepos[utils.Federated]) 160 } 161 162 func TestTransferRepositoryToTarget(t *testing.T) { 163 federatedRepo := readRepoConfig(t, "federated_repo") 164 federatedRepoWithoutMembers := readRepoConfig(t, "federated_repo_without_members") 165 166 testServer, serverDetails, _ := commonTests.CreateRtRestsMockServer(t, func(w http.ResponseWriter, r *http.Request) { 167 w.WriteHeader(http.StatusOK) 168 switch r.Method { 169 case http.MethodGet: 170 switch r.RequestURI { 171 case "/api/repositories/federated-local": 172 _, err := w.Write(federatedRepo) 173 assert.NoError(t, err) 174 case "/api/repositories/federated-local-no-members": 175 _, err := w.Write(federatedRepoWithoutMembers) 176 assert.NoError(t, err) 177 default: 178 assert.Fail(t, "Unexpected request URI "+r.RequestURI) 179 } 180 case http.MethodPut: 181 body, err := io.ReadAll(r.Body) 182 assert.NoError(t, err) 183 assert.Equal(t, getRepoParamsMap(t, federatedRepoWithoutMembers), getRepoParamsMap(t, body)) 184 default: 185 assert.Fail(t, "Unexpected method "+r.Method) 186 } 187 }) 188 defer testServer.Close() 189 190 transferConfigBase := createTransferConfigBase(t, serverDetails, serverDetails) 191 assert.False(t, transferConfigBase.FederatedMembersRemoved) 192 err := transferConfigBase.transferSpecificRepositoriesToTarget([]services.RepositoryDetails{ 193 {Key: "federated-local"}, {Key: "federated-local-no-members"}}, utils.Federated) 194 assert.NoError(t, err) 195 assert.True(t, transferConfigBase.FederatedMembersRemoved) 196 } 197 198 func TestTransferVirtualRepositoriesToTarget(t *testing.T) { 199 virtualRepoA := readRepoConfig(t, "virtual_repo_a") 200 virtualRepoB := readRepoConfig(t, "virtual_repo_b") 201 202 testServer, serverDetails, _ := commonTests.CreateRtRestsMockServer(t, func(w http.ResponseWriter, r *http.Request) { 203 w.WriteHeader(http.StatusOK) 204 switch r.Method { 205 case http.MethodGet: 206 switch r.RequestURI { 207 case "/api/repositories/a-virtual": 208 _, err := w.Write(virtualRepoA) 209 assert.NoError(t, err) 210 case "/api/repositories/b-virtual": 211 _, err := w.Write(virtualRepoB) 212 assert.NoError(t, err) 213 default: 214 assert.Fail(t, "Unexpected request URI "+r.RequestURI) 215 } 216 case http.MethodPut, http.MethodPost: 217 body, err := io.ReadAll(r.Body) 218 assert.NoError(t, err) 219 220 expectedVirtualRepoAParamsMap := getRepoParamsMap(t, virtualRepoA) 221 expectedVirtualRepoBParamsMap := getRepoParamsMap(t, virtualRepoB) 222 223 if r.Method == http.MethodPut { 224 delete(expectedVirtualRepoAParamsMap, "repositories") 225 delete(expectedVirtualRepoBParamsMap, "repositories") 226 } 227 228 switch r.RequestURI { 229 case "/api/repositories/a-virtual": 230 assert.Equal(t, expectedVirtualRepoAParamsMap, getRepoParamsMap(t, body)) 231 case "/api/repositories/b-virtual": 232 assert.Equal(t, expectedVirtualRepoBParamsMap, getRepoParamsMap(t, body)) 233 default: 234 assert.Fail(t, "Unexpected request URI "+r.RequestURI) 235 } 236 } 237 }) 238 defer testServer.Close() 239 240 transferConfigBase := createTransferConfigBase(t, serverDetails, serverDetails) 241 assert.NoError(t, transferConfigBase.transferVirtualRepositoriesToTarget([]services.RepositoryDetails{{Key: "a-virtual"}, {Key: "b-virtual"}})) 242 } 243 244 func TestDeactivateKeyEncryption(t *testing.T) { 245 testDeactivateKeyEncryption(t, true) 246 } 247 248 func TestDeactivateKeyEncryptionNotEncrypted(t *testing.T) { 249 testDeactivateKeyEncryption(t, false) 250 } 251 252 func testDeactivateKeyEncryption(t *testing.T, wasEncrypted bool) { 253 decrypted := false 254 reactivated := false 255 testServer, serverDetails, _ := commonTests.CreateRtRestsMockServer(t, func(w http.ResponseWriter, r *http.Request) { 256 if r.RequestURI == "/api/system/decrypt" { 257 if wasEncrypted { 258 w.WriteHeader(http.StatusOK) 259 } else { 260 w.WriteHeader(http.StatusConflict) 261 } 262 decrypted = true 263 } else if r.RequestURI == "/api/system/encrypt" { 264 reactivated = true 265 w.WriteHeader(http.StatusOK) 266 } 267 }) 268 defer testServer.Close() 269 transferConfigBase := createTransferConfigBase(t, serverDetails, serverDetails) 270 271 reactivate, err := transferConfigBase.DeactivateKeyEncryption() 272 assert.NoError(t, err) 273 assert.True(t, decrypted) 274 275 assert.False(t, reactivated) 276 assert.NoError(t, reactivate()) 277 assert.Equal(t, reactivated, wasEncrypted) 278 } 279 280 var removeProjectKeyCases = []struct { 281 repoKey string 282 projectKey string 283 expectedProjectKey string 284 }{ 285 {repoKey: repoKey, projectKey: "", expectedProjectKey: ""}, 286 {repoKey: repoKey, projectKey: "default", expectedProjectKey: ""}, 287 {repoKey: repoKey, projectKey: projectKey, expectedProjectKey: projectKey}, 288 {repoKey: projectKey + "-" + repoKey, projectKey: projectKey, expectedProjectKey: ""}, 289 } 290 291 func TestRemoveProjectKey(t *testing.T) { 292 repoParams := services.NewLocalRepositoryBaseParams() 293 294 for _, testCase := range removeProjectKeyCases { 295 t.Run(testCase.repoKey, func(t *testing.T) { 296 repoParams.ProjectKey = testCase.projectKey 297 actualRepoParams, actualProjectKey, err := removeProjectKeyIfNeeded(repoParams, testCase.repoKey) 298 assert.NoError(t, err) 299 assert.Equal(t, testCase.expectedProjectKey, actualProjectKey) 300 if testCase.expectedProjectKey == "" { 301 assert.Equal(t, repoParams, actualRepoParams) 302 } else { 303 assert.NotEqual(t, repoParams, actualRepoParams) 304 } 305 }) 306 } 307 } 308 309 func TestRemoveProjectKeyIllegal(t *testing.T) { 310 type illegalRepoParamsStruct struct { 311 ProjectKey int `json:"projectKey"` 312 } 313 illegalRepoParams := &illegalRepoParamsStruct{ProjectKey: 7} 314 actualRepoParams, projectKey, err := removeProjectKeyIfNeeded(illegalRepoParams, repoKey) 315 assert.ErrorContains(t, err, "couldn't parse the 'projectKey' value '7' of repository 'repoKey'") 316 assert.Empty(t, projectKey) 317 assert.Nil(t, actualRepoParams) 318 } 319 320 func TestCreateRepositoryAndAssignToProject(t *testing.T) { 321 projectUnassigned := false 322 repositoryCreated := false 323 projectAssigned := false 324 testServer, serverDetails, _ := commonTests.CreateRtRestsMockServer(t, func(w http.ResponseWriter, r *http.Request) { 325 switch r.RequestURI { 326 case "/access/api/v1/projects/_/attach/repositories/local-repo": 327 projectUnassigned = true 328 case "/api/repositories/local-repo": 329 repositoryCreated = true 330 body, err := io.ReadAll(r.Body) 331 assert.NoError(t, err) 332 _, exist := getRepoParamsMap(t, body)["projectKey"] 333 assert.False(t, exist) 334 case "/access/api/v1/projects/_/attach/repositories/local-repo/test-proj?force=true": 335 projectAssigned = true 336 default: 337 assert.Fail(t, "Unexpected request URI: "+r.RequestURI) 338 } 339 w.WriteHeader(http.StatusOK) 340 }) 341 defer testServer.Close() 342 transferConfigBase := createTransferConfigBase(t, serverDetails, serverDetails) 343 344 repoParams := services.NewLocalRepositoryBaseParams() 345 repoParams.Key = "local-repo" 346 repoParams.ProjectKey = projectKey 347 err := transferConfigBase.createRepositoryAndAssignToProject(repoParams, services.RepositoryDetails{Key: repoParams.Key}) 348 assert.NoError(t, err) 349 assert.True(t, projectUnassigned) 350 assert.True(t, repositoryCreated) 351 assert.True(t, projectAssigned) 352 } 353 354 func createTransferConfigBase(t *testing.T, sourceServerDetails, targetServerDetails *config.ServerDetails) *TransferConfigBase { 355 transferConfigBase := NewTransferConfigBase(sourceServerDetails, targetServerDetails) 356 assert.NoError(t, transferConfigBase.CreateServiceManagers(false)) 357 return transferConfigBase 358 } 359 360 func getRepoParamsMap(t *testing.T, body []byte) map[string]interface{} { 361 var repoParams interface{} 362 assert.NoError(t, json.Unmarshal(body, &repoParams)) 363 repoParamsMap, err := InterfaceToMap(repoParams) 364 assert.NoError(t, err) 365 return repoParamsMap 366 } 367 368 func readRepoConfig(t *testing.T, fileName string) []byte { 369 repoConfig, err := fileutils.ReadFile(filepath.Join(transferConfigTestDir, fileName+".json")) 370 assert.NoError(t, err) 371 return repoConfig 372 }