|
9 | 9 |
|
10 | 10 | "github.com/go-resty/resty/v2" |
11 | 11 | "github.com/hashicorp/terraform-plugin-testing/helper/resource" |
| 12 | + "github.com/hashicorp/terraform-plugin-testing/terraform" |
12 | 13 | acctest "github.com/jfrog/terraform-provider-project/pkg/project/acctest" |
13 | 14 | project "github.com/jfrog/terraform-provider-project/pkg/project/resource" |
14 | 15 | "github.com/jfrog/terraform-provider-shared/testutil" |
@@ -203,7 +204,7 @@ func TestAccProject_UpgradeFromSDKv2(t *testing.T) { |
203 | 204 | }, |
204 | 205 | ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, |
205 | 206 | Config: config, |
206 | | - PlanOnly: true, |
| 207 | + PlanOnly: false, |
207 | 208 | ConfigPlanChecks: testutil.ConfigPlanChecks(resourceName), |
208 | 209 | }, |
209 | 210 | }, |
@@ -324,6 +325,133 @@ func testProjectConfig(name, key string) string { |
324 | 325 | `, params) |
325 | 326 | } |
326 | 327 |
|
| 328 | +func TestAccProject_MultiProjectsWithRepos(t *testing.T) { |
| 329 | + numberOfProjects := 50 |
| 330 | + config := testProjectConfigMultiProjectsWithRepos(numberOfProjects) |
| 331 | + |
| 332 | + // Create check functions for all projects |
| 333 | + var checks []resource.TestCheckFunc |
| 334 | + for i := 0; i < numberOfProjects; i++ { |
| 335 | + name := fmt.Sprintf("ctestproject%d", i) |
| 336 | + key := fmt.Sprintf("ckey%d", i) |
| 337 | + resourceName := fmt.Sprintf("project.%s", name) |
| 338 | + |
| 339 | + checks = append(checks, |
| 340 | + resource.TestCheckResourceAttr(resourceName, "key", key), |
| 341 | + resource.TestCheckResourceAttr(resourceName, "display_name", name), |
| 342 | + ) |
| 343 | + } |
| 344 | + |
| 345 | + resource.Test(t, resource.TestCase{ |
| 346 | + ExternalProviders: map[string]resource.ExternalProvider{ |
| 347 | + "artifactory": { |
| 348 | + Source: "jfrog/artifactory", |
| 349 | + }, |
| 350 | + }, |
| 351 | + PreCheck: func() { acctest.PreCheck(t) }, |
| 352 | + CheckDestroy: func(s *terraform.State) error { return testAccCheckProjectMultiDestroy(s, numberOfProjects) }, |
| 353 | + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, |
| 354 | + Steps: []resource.TestStep{ |
| 355 | + { |
| 356 | + Config: config, |
| 357 | + Check: resource.ComposeTestCheckFunc(checks...), |
| 358 | + }, |
| 359 | + }, |
| 360 | + }) |
| 361 | +} |
| 362 | + |
| 363 | +func testProjectConfigMultiProjectsWithRepos(n int) string { |
| 364 | + var config strings.Builder |
| 365 | + |
| 366 | + // Create global local repository (member of all virtual repos) |
| 367 | + config.WriteString(` |
| 368 | + resource "artifactory_local_maven_repository" "global_maven_local" { |
| 369 | + key = "maven-local-global" |
| 370 | + description = "Global Local Maven repository" |
| 371 | + lifecycle { |
| 372 | + ignore_changes = ["project_key", "project_environments"] |
| 373 | + } |
| 374 | + } |
| 375 | + `) |
| 376 | + |
| 377 | + // Create all projects |
| 378 | + for i := 0; i < n; i++ { |
| 379 | + name := fmt.Sprintf("ctestproject%d", i) |
| 380 | + key := fmt.Sprintf("ckey%d", i) |
| 381 | + |
| 382 | + projectConfig := fmt.Sprintf(` |
| 383 | + resource "project" "%s" { |
| 384 | + key = "%s" |
| 385 | + display_name = "%s" |
| 386 | + description = "test description %d" |
| 387 | + admin_privileges { |
| 388 | + manage_members = %t |
| 389 | + manage_resources = %t |
| 390 | + index_resources = %t |
| 391 | + } |
| 392 | + max_storage_in_gibibytes = %d |
| 393 | + block_deployments_on_limit = %t |
| 394 | + email_notification = %t |
| 395 | + } |
| 396 | + `, name, key, name, i, |
| 397 | + testutil.RandBool(), testutil.RandBool(), testutil.RandBool(), |
| 398 | + getRandomMaxStorageSize(), testutil.RandBool(), testutil.RandBool()) |
| 399 | + |
| 400 | + config.WriteString(projectConfig) |
| 401 | + } |
| 402 | + |
| 403 | + // Create all virtual repositories (dependency on global local repo) |
| 404 | + for i := 0; i < n; i++ { |
| 405 | + key := fmt.Sprintf("ckey%d", i) |
| 406 | + name := fmt.Sprintf("ctestproject%d", i) |
| 407 | + virtualRepoName := fmt.Sprintf("project_virtual_maven_%d", i) |
| 408 | + |
| 409 | + virtualRepoConfig := fmt.Sprintf(` |
| 410 | + resource "artifactory_virtual_maven_repository" "%s" { |
| 411 | + key = "maven-virtual-%s" |
| 412 | + description = "Virtual Maven repository for %s" |
| 413 | + repositories = [ |
| 414 | + artifactory_local_maven_repository.global_maven_local.key, |
| 415 | + ] |
| 416 | + lifecycle { |
| 417 | + ignore_changes = ["project_key", "project_environments"] |
| 418 | + } |
| 419 | + } |
| 420 | + `, virtualRepoName, key, name) |
| 421 | + |
| 422 | + config.WriteString(virtualRepoConfig) |
| 423 | + } |
| 424 | + |
| 425 | + // Create all project_repository assignments (implicit dependencies via resource references) |
| 426 | + for i := 0; i < n; i++ { |
| 427 | + name := fmt.Sprintf("ctestproject%d", i) |
| 428 | + virtualRepoName := fmt.Sprintf("project_virtual_maven_%d", i) |
| 429 | + |
| 430 | + projectRepoConfig := fmt.Sprintf(` |
| 431 | + resource "project_repository" "project_virtual_maven_repo_%d" { |
| 432 | + project_key = project.%s.key |
| 433 | + key = artifactory_virtual_maven_repository.%s.key |
| 434 | + } |
| 435 | + `, i, name, virtualRepoName) |
| 436 | + |
| 437 | + config.WriteString(projectRepoConfig) |
| 438 | + } |
| 439 | + |
| 440 | + return config.String() |
| 441 | +} |
| 442 | + |
| 443 | +func testAccCheckProjectMultiDestroy(s *terraform.State, n int) error { |
| 444 | + // Custom destroy check that verifies all 100 projects are deleted |
| 445 | + for i := 0; i < n; i++ { |
| 446 | + name := fmt.Sprintf("ctestproject%d", i) |
| 447 | + resourceName := fmt.Sprintf("project.%s", name) |
| 448 | + if err := acctest.VerifyDeleted(resourceName, verifyProject)(s); err != nil { |
| 449 | + return err |
| 450 | + } |
| 451 | + } |
| 452 | + return nil |
| 453 | +} |
| 454 | + |
327 | 455 | func TestAccProject_InvalidMaxStorage(t *testing.T) { |
328 | 456 | invalidMaxStorages := []struct { |
329 | 457 | Name string |
|
0 commit comments