github.com/argoproj/argo-cd/v2@v2.10.9/test/e2e/fixture/app/actions.go (about) 1 package app 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 8 log "github.com/sirupsen/logrus" 9 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 10 11 client "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" 12 . "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" 13 "github.com/argoproj/argo-cd/v2/test/e2e/fixture" 14 "github.com/argoproj/argo-cd/v2/util/errors" 15 "github.com/argoproj/argo-cd/v2/util/grpc" 16 ) 17 18 // this implements the "when" part of given/when/then 19 // 20 // none of the func implement error checks, and that is complete intended, you should check for errors 21 // using the Then() 22 type Actions struct { 23 context *Context 24 lastOutput string 25 lastError error 26 ignoreErrors bool 27 } 28 29 func (a *Actions) IgnoreErrors() *Actions { 30 a.ignoreErrors = true 31 return a 32 } 33 34 func (a *Actions) DoNotIgnoreErrors() *Actions { 35 a.ignoreErrors = false 36 return a 37 } 38 39 func (a *Actions) PatchFile(file string, jsonPath string) *Actions { 40 a.context.t.Helper() 41 fixture.Patch(a.context.path+"/"+file, jsonPath) 42 return a 43 } 44 45 func (a *Actions) DeleteFile(file string) *Actions { 46 a.context.t.Helper() 47 fixture.Delete(a.context.path + "/" + file) 48 return a 49 } 50 51 func (a *Actions) WriteFile(fileName, fileContents string) *Actions { 52 a.context.t.Helper() 53 fixture.WriteFile(a.context.path+"/"+fileName, fileContents) 54 return a 55 } 56 57 func (a *Actions) AddFile(fileName, fileContents string) *Actions { 58 a.context.t.Helper() 59 fixture.AddFile(a.context.path+"/"+fileName, fileContents) 60 return a 61 } 62 63 func (a *Actions) AddSignedFile(fileName, fileContents string) *Actions { 64 a.context.t.Helper() 65 fixture.AddSignedFile(a.context.path+"/"+fileName, fileContents) 66 return a 67 } 68 69 func (a *Actions) AddSignedTag(name string) *Actions { 70 a.context.t.Helper() 71 fixture.AddSignedTag(name) 72 return a 73 } 74 75 func (a *Actions) AddTag(name string) *Actions { 76 a.context.t.Helper() 77 fixture.AddTag(name) 78 return a 79 } 80 81 func (a *Actions) RemoveSubmodule() *Actions { 82 a.context.t.Helper() 83 fixture.RemoveSubmodule() 84 return a 85 } 86 87 func (a *Actions) CreateFromPartialFile(data string, flags ...string) *Actions { 88 a.context.t.Helper() 89 tmpFile, err := os.CreateTemp("", "") 90 errors.CheckError(err) 91 _, err = tmpFile.Write([]byte(data)) 92 errors.CheckError(err) 93 94 args := append([]string{ 95 "app", "create", 96 "-f", tmpFile.Name(), 97 "--name", a.context.AppName(), 98 "--repo", fixture.RepoURL(a.context.repoURLType), 99 "--dest-server", a.context.destServer, 100 "--dest-namespace", fixture.DeploymentNamespace(), 101 }, flags...) 102 if a.context.appNamespace != "" { 103 args = append(args, "--app-namespace", a.context.appNamespace) 104 } 105 defer tmpFile.Close() 106 a.runCli(args...) 107 return a 108 } 109 func (a *Actions) CreateFromFile(handler func(app *Application), flags ...string) *Actions { 110 a.context.t.Helper() 111 app := &Application{ 112 ObjectMeta: v1.ObjectMeta{ 113 Name: a.context.AppName(), 114 Namespace: a.context.AppNamespace(), 115 }, 116 Spec: ApplicationSpec{ 117 Project: a.context.project, 118 Source: &ApplicationSource{ 119 RepoURL: fixture.RepoURL(a.context.repoURLType), 120 Path: a.context.path, 121 }, 122 Destination: ApplicationDestination{ 123 Server: a.context.destServer, 124 Namespace: fixture.DeploymentNamespace(), 125 }, 126 }, 127 } 128 source := app.Spec.GetSource() 129 if a.context.namePrefix != "" || a.context.nameSuffix != "" { 130 source.Kustomize = &ApplicationSourceKustomize{ 131 NamePrefix: a.context.namePrefix, 132 NameSuffix: a.context.nameSuffix, 133 } 134 } 135 if a.context.configManagementPlugin != "" { 136 source.Plugin = &ApplicationSourcePlugin{ 137 Name: a.context.configManagementPlugin, 138 } 139 } 140 141 if len(a.context.parameters) > 0 { 142 log.Fatal("Application parameters or json tlas are not supported") 143 } 144 145 if a.context.directoryRecurse { 146 source.Directory = &ApplicationSourceDirectory{Recurse: true} 147 } 148 app.Spec.Source = &source 149 150 handler(app) 151 data := grpc.MustMarshal(app) 152 tmpFile, err := os.CreateTemp("", "") 153 errors.CheckError(err) 154 _, err = tmpFile.Write(data) 155 errors.CheckError(err) 156 157 args := append([]string{ 158 "app", "create", 159 "-f", tmpFile.Name(), 160 }, flags...) 161 defer tmpFile.Close() 162 a.runCli(args...) 163 return a 164 } 165 166 func (a *Actions) CreateMultiSourceAppFromFile(flags ...string) *Actions { 167 a.context.t.Helper() 168 app := &Application{ 169 ObjectMeta: v1.ObjectMeta{ 170 Name: a.context.AppName(), 171 Namespace: a.context.AppNamespace(), 172 }, 173 Spec: ApplicationSpec{ 174 Project: a.context.project, 175 Sources: a.context.sources, 176 Destination: ApplicationDestination{ 177 Server: a.context.destServer, 178 Namespace: fixture.DeploymentNamespace(), 179 }, 180 SyncPolicy: &SyncPolicy{ 181 Automated: &SyncPolicyAutomated{ 182 SelfHeal: true, 183 }, 184 }, 185 }, 186 } 187 188 data := grpc.MustMarshal(app) 189 tmpFile, err := os.CreateTemp("", "") 190 errors.CheckError(err) 191 _, err = tmpFile.Write(data) 192 errors.CheckError(err) 193 194 args := append([]string{ 195 "app", "create", 196 "-f", tmpFile.Name(), 197 }, flags...) 198 defer tmpFile.Close() 199 a.runCli(args...) 200 return a 201 } 202 203 func (a *Actions) CreateWithNoNameSpace(args ...string) *Actions { 204 args = a.prepareCreateAppArgs(args) 205 // are you adding new context values? if you only use them for this func, then use args instead 206 a.runCli(args...) 207 return a 208 } 209 210 func (a *Actions) CreateApp(args ...string) *Actions { 211 args = a.prepareCreateAppArgs(args) 212 args = append(args, "--dest-namespace", fixture.DeploymentNamespace()) 213 214 // are you adding new context values? if you only use them for this func, then use args instead 215 a.runCli(args...) 216 217 return a 218 } 219 220 func (a *Actions) prepareCreateAppArgs(args []string) []string { 221 a.context.t.Helper() 222 args = append([]string{ 223 "app", "create", a.context.AppQualifiedName(), 224 "--repo", fixture.RepoURL(a.context.repoURLType), 225 }, args...) 226 227 if a.context.destName != "" { 228 args = append(args, "--dest-name", a.context.destName) 229 } else { 230 args = append(args, "--dest-server", a.context.destServer) 231 } 232 if a.context.path != "" { 233 args = append(args, "--path", a.context.path) 234 } 235 236 if a.context.chart != "" { 237 args = append(args, "--helm-chart", a.context.chart) 238 } 239 240 if a.context.env != "" { 241 args = append(args, "--env", a.context.env) 242 } 243 244 for _, parameter := range a.context.parameters { 245 args = append(args, "--parameter", parameter) 246 } 247 248 args = append(args, "--project", a.context.project) 249 250 if a.context.namePrefix != "" { 251 args = append(args, "--nameprefix", a.context.namePrefix) 252 } 253 254 if a.context.nameSuffix != "" { 255 args = append(args, "--namesuffix", a.context.nameSuffix) 256 } 257 258 if a.context.configManagementPlugin != "" { 259 args = append(args, "--config-management-plugin", a.context.configManagementPlugin) 260 } 261 262 if a.context.revision != "" { 263 args = append(args, "--revision", a.context.revision) 264 } 265 if a.context.helmPassCredentials { 266 args = append(args, "--helm-pass-credentials") 267 } 268 if a.context.helmSkipCrds { 269 args = append(args, "--helm-skip-crds") 270 } 271 return args 272 } 273 274 func (a *Actions) Declarative(filename string) *Actions { 275 a.context.t.Helper() 276 return a.DeclarativeWithCustomRepo(filename, fixture.RepoURL(a.context.repoURLType)) 277 } 278 279 func (a *Actions) DeclarativeWithCustomRepo(filename string, repoURL string) *Actions { 280 a.context.t.Helper() 281 values := map[string]interface{}{ 282 "ArgoCDNamespace": fixture.TestNamespace(), 283 "DeploymentNamespace": fixture.DeploymentNamespace(), 284 "Name": a.context.AppName(), 285 "Path": a.context.path, 286 "Project": a.context.project, 287 "RepoURL": repoURL, 288 } 289 a.lastOutput, a.lastError = fixture.Declarative(filename, values) 290 a.verifyAction() 291 return a 292 } 293 294 func (a *Actions) PatchApp(patch string) *Actions { 295 a.context.t.Helper() 296 a.runCli("app", "patch", a.context.AppQualifiedName(), "--patch", patch) 297 return a 298 } 299 300 func (a *Actions) PatchAppHttp(patch string) *Actions { 301 a.context.t.Helper() 302 var application Application 303 var patchType = "merge" 304 var appName = a.context.AppQualifiedName() 305 var appNamespace = a.context.AppNamespace() 306 patchRequest := &client.ApplicationPatchRequest{ 307 Name: &appName, 308 PatchType: &patchType, 309 Patch: &patch, 310 AppNamespace: &appNamespace, 311 } 312 jsonBytes, err := json.MarshalIndent(patchRequest, "", " ") 313 errors.CheckError(err) 314 err = fixture.DoHttpJsonRequest("PATCH", 315 fmt.Sprintf("/api/v1/applications/%v", appName), 316 &application, 317 jsonBytes...) 318 errors.CheckError(err) 319 return a 320 } 321 322 func (a *Actions) AppSet(flags ...string) *Actions { 323 a.context.t.Helper() 324 args := []string{"app", "set", a.context.AppQualifiedName()} 325 args = append(args, flags...) 326 a.runCli(args...) 327 return a 328 } 329 330 func (a *Actions) AppUnSet(flags ...string) *Actions { 331 a.context.t.Helper() 332 args := []string{"app", "unset", a.context.AppQualifiedName()} 333 args = append(args, flags...) 334 a.runCli(args...) 335 return a 336 } 337 338 func (a *Actions) Sync(args ...string) *Actions { 339 a.context.t.Helper() 340 args = append([]string{"app", "sync"}, args...) 341 if a.context.name != "" { 342 args = append(args, a.context.AppQualifiedName()) 343 } 344 args = append(args, "--timeout", fmt.Sprintf("%v", a.context.timeout)) 345 346 if a.context.async { 347 args = append(args, "--async") 348 } 349 350 if a.context.prune { 351 args = append(args, "--prune") 352 } 353 354 if a.context.resource != "" { 355 // Waiting for the app to be successfully created. 356 // Else the sync would fail to retrieve the app resources. 357 a.context.Sleep(5) 358 args = append(args, "--resource", a.context.resource) 359 } 360 361 if a.context.localPath != "" { 362 args = append(args, "--local", a.context.localPath) 363 } 364 365 if a.context.force { 366 args = append(args, "--force") 367 } 368 369 if a.context.applyOutOfSyncOnly { 370 args = append(args, "--apply-out-of-sync-only") 371 } 372 373 if a.context.replace { 374 args = append(args, "--replace") 375 } 376 377 // are you adding new context values? if you only use them for this func, then use args instead 378 379 a.runCli(args...) 380 381 return a 382 } 383 384 func (a *Actions) TerminateOp() *Actions { 385 a.context.t.Helper() 386 a.runCli("app", "terminate-op", a.context.AppQualifiedName()) 387 return a 388 } 389 390 func (a *Actions) Refresh(refreshType RefreshType) *Actions { 391 a.context.t.Helper() 392 flag := map[RefreshType]string{ 393 RefreshTypeNormal: "--refresh", 394 RefreshTypeHard: "--hard-refresh", 395 }[refreshType] 396 397 a.runCli("app", "get", a.context.AppQualifiedName(), flag) 398 399 return a 400 } 401 402 func (a *Actions) Get() *Actions { 403 a.context.t.Helper() 404 a.runCli("app", "get", a.context.AppQualifiedName()) 405 return a 406 } 407 408 func (a *Actions) Delete(cascade bool) *Actions { 409 a.context.t.Helper() 410 a.runCli("app", "delete", a.context.AppQualifiedName(), fmt.Sprintf("--cascade=%v", cascade), "--yes") 411 return a 412 } 413 414 func (a *Actions) DeleteBySelector(selector string) *Actions { 415 a.context.t.Helper() 416 a.runCli("app", "delete", fmt.Sprintf("--selector=%s", selector), "--yes") 417 return a 418 } 419 420 func (a *Actions) Wait(args ...string) *Actions { 421 a.context.t.Helper() 422 args = append([]string{"app", "wait"}, args...) 423 if a.context.name != "" { 424 args = append(args, a.context.AppQualifiedName()) 425 } 426 args = append(args, "--timeout", fmt.Sprintf("%v", a.context.timeout)) 427 a.runCli(args...) 428 return a 429 } 430 431 func (a *Actions) SetParamInSettingConfigMap(key, value string) *Actions { 432 fixture.SetParamInSettingConfigMap(key, value) 433 return a 434 } 435 436 func (a *Actions) And(block func()) *Actions { 437 a.context.t.Helper() 438 block() 439 return a 440 } 441 442 func (a *Actions) Then() *Consequences { 443 a.context.t.Helper() 444 return &Consequences{a.context, a, 15} 445 } 446 447 func (a *Actions) runCli(args ...string) { 448 a.context.t.Helper() 449 a.lastOutput, a.lastError = fixture.RunCli(args...) 450 a.verifyAction() 451 } 452 453 func (a *Actions) verifyAction() { 454 a.context.t.Helper() 455 if !a.ignoreErrors { 456 a.Then().Expect(Success("")) 457 } 458 } 459 460 func (a *Actions) SetTrackingMethod(trackingMethod string) *Actions { 461 fixture.SetTrackingMethod(trackingMethod) 462 return a 463 } 464 465 func (a *Actions) SetTrackingLabel(trackingLabel string) *Actions { 466 fixture.SetTrackingLabel(trackingLabel) 467 return a 468 }