1package tfe 2 3import ( 4 "context" 5 "crypto/md5" 6 "encoding/base64" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "testing" 11 "time" 12 13 "github.com/hashicorp/go-uuid" 14) 15 16const badIdentifier = "! / nope" 17 18// Memoize test account details 19var _testAccountDetails *TestAccountDetails 20 21func testClient(t *testing.T) *Client { 22 client, err := NewClient(nil) 23 if err != nil { 24 t.Fatal(err) 25 } 26 27 return client 28} 29 30func fetchTestAccountDetails(t *testing.T, client *Client) *TestAccountDetails { 31 if _testAccountDetails == nil { 32 _testAccountDetails = FetchTestAccountDetails(t, client) 33 } 34 return _testAccountDetails 35} 36 37func createAgentPool(t *testing.T, client *Client, org *Organization) (*AgentPool, func()) { 38 var orgCleanup func() 39 40 if org == nil { 41 org, orgCleanup = createOrganization(t, client) 42 } 43 44 ctx := context.Background() 45 pool, err := client.AgentPools.Create(ctx, org.Name, AgentPoolCreateOptions{ 46 Name: String(randomString(t)), 47 }) 48 if err != nil { 49 t.Fatal(err) 50 } 51 52 return pool, func() { 53 if err := client.AgentPools.Delete(ctx, pool.ID); err != nil { 54 t.Errorf("Error destroying agent pool! WARNING: Dangling resources "+ 55 "may exist! The full error is shown below.\n\n"+ 56 "Agent pool ID: %s\nError: %s", pool.ID, err) 57 } 58 59 if orgCleanup != nil { 60 orgCleanup() 61 } 62 } 63} 64 65func createAgentToken(t *testing.T, client *Client, ap *AgentPool) (*AgentToken, func()) { 66 var apCleanup func() 67 68 if ap == nil { 69 ap, apCleanup = createAgentPool(t, client, nil) 70 } 71 72 ctx := context.Background() 73 at, err := client.AgentTokens.Generate(ctx, ap.ID, AgentTokenGenerateOptions{ 74 Description: String(randomString(t)), 75 }) 76 if err != nil { 77 t.Fatal(err) 78 } 79 80 return at, func() { 81 if err := client.AgentTokens.Delete(ctx, at.ID); err != nil { 82 t.Errorf("Error destroying agent token! WARNING: Dangling resources\n"+ 83 "may exist! The full error is shown below.\n\n"+ 84 "AgentToken: %s\nError: %s", at.ID, err) 85 } 86 87 if apCleanup != nil { 88 apCleanup() 89 } 90 } 91} 92 93func createConfigurationVersion(t *testing.T, client *Client, w *Workspace) (*ConfigurationVersion, func()) { 94 var wCleanup func() 95 96 if w == nil { 97 w, wCleanup = createWorkspace(t, client, nil) 98 } 99 100 ctx := context.Background() 101 cv, err := client.ConfigurationVersions.Create( 102 ctx, 103 w.ID, 104 ConfigurationVersionCreateOptions{AutoQueueRuns: Bool(false)}, 105 ) 106 if err != nil { 107 t.Fatal(err) 108 } 109 110 return cv, func() { 111 if wCleanup != nil { 112 wCleanup() 113 } 114 } 115} 116 117func createUploadedConfigurationVersion(t *testing.T, client *Client, w *Workspace) (*ConfigurationVersion, func()) { 118 cv, cvCleanup := createConfigurationVersion(t, client, w) 119 120 ctx := context.Background() 121 err := client.ConfigurationVersions.Upload(ctx, cv.UploadURL, "test-fixtures/config-version") 122 if err != nil { 123 cvCleanup() 124 t.Fatal(err) 125 } 126 127 for i := 0; ; i++ { 128 cv, err = client.ConfigurationVersions.Read(ctx, cv.ID) 129 if err != nil { 130 cvCleanup() 131 t.Fatal(err) 132 } 133 134 if cv.Status == ConfigurationUploaded { 135 break 136 } 137 138 if i > 10 { 139 cvCleanup() 140 t.Fatal("Timeout waiting for the configuration version to be uploaded") 141 } 142 143 time.Sleep(1 * time.Second) 144 } 145 146 return cv, cvCleanup 147} 148 149func createNotificationConfiguration(t *testing.T, client *Client, w *Workspace, options *NotificationConfigurationCreateOptions) (*NotificationConfiguration, func()) { 150 var wCleanup func() 151 152 if w == nil { 153 w, wCleanup = createWorkspace(t, client, nil) 154 } 155 156 if options == nil { 157 options = &NotificationConfigurationCreateOptions{ 158 DestinationType: NotificationDestination(NotificationDestinationTypeGeneric), 159 Enabled: Bool(false), 160 Name: String(randomString(t)), 161 Token: String(randomString(t)), 162 URL: String("http://example.com"), 163 Triggers: []string{NotificationTriggerCreated}, 164 } 165 } 166 167 ctx := context.Background() 168 nc, err := client.NotificationConfigurations.Create( 169 ctx, 170 w.ID, 171 *options, 172 ) 173 if err != nil { 174 t.Fatal(err) 175 } 176 177 return nc, func() { 178 if err := client.NotificationConfigurations.Delete(ctx, nc.ID); err != nil { 179 t.Errorf("Error destroying notification configuration! WARNING: Dangling\n"+ 180 "resources may exist! The full error is shown below.\n\n"+ 181 "NotificationConfiguration: %s\nError: %s", nc.ID, err) 182 } 183 184 if wCleanup != nil { 185 wCleanup() 186 } 187 } 188} 189 190func createPolicySetParameter(t *testing.T, client *Client, ps *PolicySet) (*PolicySetParameter, func()) { 191 var psCleanup func() 192 193 if ps == nil { 194 ps, psCleanup = createPolicySet(t, client, nil, nil, nil) 195 } 196 197 ctx := context.Background() 198 v, err := client.PolicySetParameters.Create(ctx, ps.ID, PolicySetParameterCreateOptions{ 199 Key: String(randomString(t)), 200 Value: String(randomString(t)), 201 Category: Category(CategoryPolicySet), 202 }) 203 if err != nil { 204 t.Fatal(err) 205 } 206 207 return v, func() { 208 if err := client.PolicySetParameters.Delete(ctx, ps.ID, v.ID); err != nil { 209 t.Errorf("Error destroying variable! WARNING: Dangling resources\n"+ 210 "may exist! The full error is shown below.\n\n"+ 211 "Parameter: %s\nError: %s", v.Key, err) 212 } 213 214 if psCleanup != nil { 215 psCleanup() 216 } 217 } 218} 219 220func createPolicySet(t *testing.T, client *Client, org *Organization, policies []*Policy, workspaces []*Workspace) (*PolicySet, func()) { 221 var orgCleanup func() 222 223 if org == nil { 224 org, orgCleanup = createOrganization(t, client) 225 } 226 227 ctx := context.Background() 228 ps, err := client.PolicySets.Create(ctx, org.Name, PolicySetCreateOptions{ 229 Name: String(randomString(t)), 230 Policies: policies, 231 Workspaces: workspaces, 232 }) 233 if err != nil { 234 t.Fatal(err) 235 } 236 237 return ps, func() { 238 if err := client.PolicySets.Delete(ctx, ps.ID); err != nil { 239 t.Errorf("Error destroying policy set! WARNING: Dangling resources\n"+ 240 "may exist! The full error is shown below.\n\n"+ 241 "PolicySet: %s\nError: %s", ps.ID, err) 242 } 243 244 if orgCleanup != nil { 245 orgCleanup() 246 } 247 } 248} 249 250func createPolicy(t *testing.T, client *Client, org *Organization) (*Policy, func()) { 251 var orgCleanup func() 252 253 if org == nil { 254 org, orgCleanup = createOrganization(t, client) 255 } 256 257 name := randomString(t) 258 options := PolicyCreateOptions{ 259 Name: String(name), 260 Enforce: []*EnforcementOptions{ 261 { 262 Path: String(name + ".sentinel"), 263 Mode: EnforcementMode(EnforcementSoft), 264 }, 265 }, 266 } 267 268 ctx := context.Background() 269 p, err := client.Policies.Create(ctx, org.Name, options) 270 if err != nil { 271 t.Fatal(err) 272 } 273 274 return p, func() { 275 if err := client.Policies.Delete(ctx, p.ID); err != nil { 276 t.Errorf("Error destroying policy! WARNING: Dangling resources\n"+ 277 "may exist! The full error is shown below.\n\n"+ 278 "Policy: %s\nError: %s", p.ID, err) 279 } 280 281 if orgCleanup != nil { 282 orgCleanup() 283 } 284 } 285} 286 287func createUploadedPolicy(t *testing.T, client *Client, pass bool, org *Organization) (*Policy, func()) { 288 var orgCleanup func() 289 290 if org == nil { 291 org, orgCleanup = createOrganization(t, client) 292 } 293 294 p, pCleanup := createPolicy(t, client, org) 295 296 ctx := context.Background() 297 err := client.Policies.Upload(ctx, p.ID, []byte(fmt.Sprintf("main = rule { %t }", pass))) 298 if err != nil { 299 t.Fatal(err) 300 } 301 302 p, err = client.Policies.Read(ctx, p.ID) 303 if err != nil { 304 t.Fatal(err) 305 } 306 307 return p, func() { 308 pCleanup() 309 310 if orgCleanup != nil { 311 orgCleanup() 312 } 313 } 314} 315 316func createOAuthClient(t *testing.T, client *Client, org *Organization) (*OAuthClient, func()) { 317 var orgCleanup func() 318 319 if org == nil { 320 org, orgCleanup = createOrganization(t, client) 321 } 322 323 githubToken := os.Getenv("GITHUB_TOKEN") 324 if githubToken == "" { 325 t.Skip("Export a valid GITHUB_TOKEN before running this test!") 326 } 327 328 options := OAuthClientCreateOptions{ 329 APIURL: String("https://api.github.com"), 330 HTTPURL: String("https://github.com"), 331 OAuthToken: String(githubToken), 332 ServiceProvider: ServiceProvider(ServiceProviderGithub), 333 } 334 335 ctx := context.Background() 336 oc, err := client.OAuthClients.Create(ctx, org.Name, options) 337 if err != nil { 338 t.Fatal(err) 339 } 340 341 // This currently panics as the token will not be there when the client is 342 // created. To get a token, the client needs to be connected through the UI 343 // first. So the test using this (TestOAuthTokensList) is currently disabled. 344 return oc, func() { 345 if err := client.OAuthClients.Delete(ctx, oc.ID); err != nil { 346 t.Errorf("Error destroying OAuth client! WARNING: Dangling resources\n"+ 347 "may exist! The full error is shown below.\n\n"+ 348 "OAuthClient: %s\nError: %s", oc.ID, err) 349 } 350 351 if orgCleanup != nil { 352 orgCleanup() 353 } 354 } 355} 356 357func createOAuthToken(t *testing.T, client *Client, org *Organization) (*OAuthToken, func()) { 358 ocTest, ocTestCleanup := createOAuthClient(t, client, org) 359 return ocTest.OAuthTokens[0], ocTestCleanup 360} 361 362func createOrganization(t *testing.T, client *Client) (*Organization, func()) { 363 ctx := context.Background() 364 org, err := client.Organizations.Create(ctx, OrganizationCreateOptions{ 365 Name: String("tst-" + randomString(t)), 366 Email: String(fmt.Sprintf("%s@tfe.local", randomString(t))), 367 }) 368 if err != nil { 369 t.Fatal(err) 370 } 371 372 return org, func() { 373 if err := client.Organizations.Delete(ctx, org.Name); err != nil { 374 t.Errorf("Error destroying organization! WARNING: Dangling resources\n"+ 375 "may exist! The full error is shown below.\n\n"+ 376 "Organization: %s\nError: %s", org.Name, err) 377 } 378 } 379} 380 381func createOrganizationMembership(t *testing.T, client *Client, org *Organization) (*OrganizationMembership, func()) { 382 var orgCleanup func() 383 384 if org == nil { 385 org, orgCleanup = createOrganization(t, client) 386 } 387 388 ctx := context.Background() 389 mem, err := client.OrganizationMemberships.Create(ctx, org.Name, OrganizationMembershipCreateOptions{ 390 Email: String(fmt.Sprintf("%s@tfe.local", randomString(t))), 391 }) 392 if err != nil { 393 t.Fatal(err) 394 } 395 396 return mem, func() { 397 if err := client.OrganizationMemberships.Delete(ctx, mem.ID); err != nil { 398 t.Errorf("Error destroying membership! WARNING: Dangling resources\n"+ 399 "may exist! The full error is shown below.\n\n"+ 400 "Membership: %s\nError: %s", mem.ID, err) 401 } 402 403 if orgCleanup != nil { 404 orgCleanup() 405 } 406 } 407} 408 409func createOrganizationToken(t *testing.T, client *Client, org *Organization) (*OrganizationToken, func()) { 410 var orgCleanup func() 411 412 if org == nil { 413 org, orgCleanup = createOrganization(t, client) 414 } 415 416 ctx := context.Background() 417 tk, err := client.OrganizationTokens.Generate(ctx, org.Name) 418 if err != nil { 419 t.Fatal(err) 420 } 421 422 return tk, func() { 423 if err := client.OrganizationTokens.Delete(ctx, org.Name); err != nil { 424 t.Errorf("Error destroying organization token! WARNING: Dangling resources\n"+ 425 "may exist! The full error is shown below.\n\n"+ 426 "OrganizationToken: %s\nError: %s", tk.ID, err) 427 } 428 429 if orgCleanup != nil { 430 orgCleanup() 431 } 432 } 433} 434 435func createRunTrigger(t *testing.T, client *Client, w *Workspace, sourceable *Workspace) (*RunTrigger, func()) { 436 var wCleanup func() 437 var sourceableCleanup func() 438 439 if w == nil { 440 w, wCleanup = createWorkspace(t, client, nil) 441 } 442 443 if sourceable == nil { 444 sourceable, sourceableCleanup = createWorkspace(t, client, nil) 445 } 446 447 ctx := context.Background() 448 rt, err := client.RunTriggers.Create( 449 ctx, 450 w.ID, 451 RunTriggerCreateOptions{ 452 Sourceable: sourceable, 453 }, 454 ) 455 if err != nil { 456 t.Fatal(err) 457 } 458 459 return rt, func() { 460 if err := client.RunTriggers.Delete(ctx, rt.ID); err != nil { 461 t.Errorf("Error destroying run trigger! WARNING: Dangling\n"+ 462 "resources may exist! The full error is shown below.\n\n"+ 463 "RunTrigger: %s\nError: %s", rt.ID, err) 464 } 465 466 if wCleanup != nil { 467 wCleanup() 468 } 469 470 if sourceableCleanup != nil { 471 sourceableCleanup() 472 } 473 } 474} 475 476func createRun(t *testing.T, client *Client, w *Workspace) (*Run, func()) { 477 var wCleanup func() 478 479 if w == nil { 480 w, wCleanup = createWorkspace(t, client, nil) 481 } 482 483 cv, cvCleanup := createUploadedConfigurationVersion(t, client, w) 484 485 ctx := context.Background() 486 r, err := client.Runs.Create(ctx, RunCreateOptions{ 487 ConfigurationVersion: cv, 488 Workspace: w, 489 }) 490 if err != nil { 491 t.Fatal(err) 492 } 493 494 return r, func() { 495 if wCleanup != nil { 496 wCleanup() 497 } else { 498 cvCleanup() 499 } 500 } 501} 502 503func createPlannedRun(t *testing.T, client *Client, w *Workspace) (*Run, func()) { 504 r, rCleanup := createRun(t, client, w) 505 506 var err error 507 ctx := context.Background() 508 for i := 0; ; i++ { 509 r, err = client.Runs.Read(ctx, r.ID) 510 if err != nil { 511 t.Fatal(err) 512 } 513 514 switch r.Status { 515 case RunPlanned, RunCostEstimated, RunPolicyChecked, RunPolicyOverride: 516 return r, rCleanup 517 } 518 519 if i > 45 { 520 rCleanup() 521 t.Fatal("Timeout waiting for run to be planned") 522 } 523 524 time.Sleep(1 * time.Second) 525 } 526} 527 528func createCostEstimatedRun(t *testing.T, client *Client, w *Workspace) (*Run, func()) { 529 r, rCleanup := createRun(t, client, w) 530 531 var err error 532 ctx := context.Background() 533 for i := 0; ; i++ { 534 r, err = client.Runs.Read(ctx, r.ID) 535 if err != nil { 536 t.Fatal(err) 537 } 538 539 switch r.Status { 540 case RunCostEstimated, RunPolicyChecked, RunPolicyOverride: 541 return r, rCleanup 542 } 543 544 if i > 45 { 545 rCleanup() 546 t.Fatal("Timeout waiting for run to be cost estimated") 547 } 548 549 time.Sleep(2 * time.Second) 550 } 551} 552 553func createAppliedRun(t *testing.T, client *Client, w *Workspace) (*Run, func()) { 554 r, rCleanup := createPlannedRun(t, client, w) 555 ctx := context.Background() 556 557 err := client.Runs.Apply(ctx, r.ID, RunApplyOptions{}) 558 if err != nil { 559 t.Fatal(err) 560 } 561 562 for i := 0; ; i++ { 563 r, err = client.Runs.Read(ctx, r.ID) 564 if err != nil { 565 t.Fatal(err) 566 } 567 568 if r.Status == RunApplied { 569 return r, rCleanup 570 } 571 572 if i > 45 { 573 rCleanup() 574 t.Fatal("Timeout waiting for run to be applied") 575 } 576 577 time.Sleep(1 * time.Second) 578 } 579} 580 581func createPlanExport(t *testing.T, client *Client, r *Run) (*PlanExport, func()) { 582 var rCleanup func() 583 584 if r == nil { 585 r, rCleanup = createPlannedRun(t, client, nil) 586 } 587 588 ctx := context.Background() 589 pe, err := client.PlanExports.Create(ctx, PlanExportCreateOptions{ 590 Plan: r.Plan, 591 DataType: PlanExportType(PlanExportSentinelMockBundleV0), 592 }) 593 if err != nil { 594 t.Fatal(err) 595 } 596 597 for i := 0; ; i++ { 598 pe, err := client.PlanExports.Read(ctx, pe.ID) 599 if err != nil { 600 t.Fatal(err) 601 } 602 603 if pe.Status == PlanExportFinished { 604 return pe, func() { 605 if rCleanup != nil { 606 rCleanup() 607 } 608 } 609 } 610 611 if i > 45 { 612 rCleanup() 613 t.Fatal("Timeout waiting for plan export to finish") 614 } 615 616 time.Sleep(1 * time.Second) 617 } 618} 619 620func createRegistryModule(t *testing.T, client *Client, org *Organization) (*RegistryModule, func()) { 621 var orgCleanup func() 622 623 if org == nil { 624 org, orgCleanup = createOrganization(t, client) 625 } 626 627 ctx := context.Background() 628 629 options := RegistryModuleCreateOptions{ 630 Name: String("name"), 631 Provider: String("provider"), 632 } 633 rm, err := client.RegistryModules.Create(ctx, org.Name, options) 634 if err != nil { 635 t.Fatal(err) 636 } 637 638 return rm, func() { 639 if err := client.RegistryModules.Delete(ctx, org.Name, rm.Name); err != nil { 640 t.Errorf("Error destroying registry module! WARNING: Dangling resources\n"+ 641 "may exist! The full error is shown below.\n\n"+ 642 "Registry Module: %s\nError: %s", rm.Name, err) 643 } 644 645 if orgCleanup != nil { 646 orgCleanup() 647 } 648 } 649} 650 651func createRegistryModuleWithVersion(t *testing.T, client *Client, org *Organization) (*RegistryModule, func()) { 652 var orgCleanup func() 653 654 if org == nil { 655 org, orgCleanup = createOrganization(t, client) 656 } 657 658 ctx := context.Background() 659 660 options := RegistryModuleCreateOptions{ 661 Name: String("name"), 662 Provider: String("provider"), 663 } 664 rm, err := client.RegistryModules.Create(ctx, org.Name, options) 665 if err != nil { 666 t.Fatal(err) 667 } 668 669 optionsModuleVersion := RegistryModuleCreateVersionOptions{ 670 Version: String("1.0.0"), 671 } 672 _, err = client.RegistryModules.CreateVersion(ctx, org.Name, rm.Name, rm.Provider, optionsModuleVersion) 673 if err != nil { 674 t.Fatal(err) 675 } 676 677 rm, err = client.RegistryModules.Read(ctx, org.Name, rm.Name, rm.Provider) 678 if err != nil { 679 t.Fatal(err) 680 } 681 682 return rm, func() { 683 if err := client.RegistryModules.Delete(ctx, org.Name, rm.Name); err != nil { 684 t.Errorf("Error destroying registry module! WARNING: Dangling resources\n"+ 685 "may exist! The full error is shown below.\n\n"+ 686 "Registry Module: %s\nError: %s", rm.Name, err) 687 } 688 689 if orgCleanup != nil { 690 orgCleanup() 691 } 692 } 693} 694 695func createSSHKey(t *testing.T, client *Client, org *Organization) (*SSHKey, func()) { 696 var orgCleanup func() 697 698 if org == nil { 699 org, orgCleanup = createOrganization(t, client) 700 } 701 702 ctx := context.Background() 703 key, err := client.SSHKeys.Create(ctx, org.Name, SSHKeyCreateOptions{ 704 Name: String(randomString(t)), 705 Value: String(randomString(t)), 706 }) 707 if err != nil { 708 t.Fatal(err) 709 } 710 711 return key, func() { 712 if err := client.SSHKeys.Delete(ctx, key.ID); err != nil { 713 t.Errorf("Error destroying SSH key! WARNING: Dangling resources\n"+ 714 "may exist! The full error is shown below.\n\n"+ 715 "SSHKey: %s\nError: %s", key.Name, err) 716 } 717 718 if orgCleanup != nil { 719 orgCleanup() 720 } 721 } 722} 723 724func createStateVersion(t *testing.T, client *Client, serial int64, w *Workspace) (*StateVersion, func()) { 725 var wCleanup func() 726 727 if w == nil { 728 w, wCleanup = createWorkspace(t, client, nil) 729 } 730 731 state, err := ioutil.ReadFile("test-fixtures/state-version/terraform.tfstate") 732 if err != nil { 733 t.Fatal(err) 734 } 735 736 ctx := context.Background() 737 738 _, err = client.Workspaces.Lock(ctx, w.ID, WorkspaceLockOptions{}) 739 if err != nil { 740 t.Fatal(err) 741 } 742 defer func() { 743 _, err := client.Workspaces.Unlock(ctx, w.ID) 744 if err != nil { 745 t.Fatal(err) 746 } 747 }() 748 749 sv, err := client.StateVersions.Create(ctx, w.ID, StateVersionCreateOptions{ 750 MD5: String(fmt.Sprintf("%x", md5.Sum(state))), 751 Serial: Int64(serial), 752 State: String(base64.StdEncoding.EncodeToString(state)), 753 }) 754 if err != nil { 755 t.Fatal(err) 756 } 757 758 return sv, func() { 759 // There currently isn't a way to delete a state, so we 760 // can only cleanup by deleting the workspace. 761 if wCleanup != nil { 762 wCleanup() 763 } 764 } 765} 766 767func createTeam(t *testing.T, client *Client, org *Organization) (*Team, func()) { 768 var orgCleanup func() 769 770 if org == nil { 771 org, orgCleanup = createOrganization(t, client) 772 } 773 774 ctx := context.Background() 775 tm, err := client.Teams.Create(ctx, org.Name, TeamCreateOptions{ 776 Name: String(randomString(t)), 777 OrganizationAccess: &OrganizationAccessOptions{ManagePolicies: Bool(true)}, 778 }) 779 if err != nil { 780 t.Fatal(err) 781 } 782 783 return tm, func() { 784 if err := client.Teams.Delete(ctx, tm.ID); err != nil { 785 t.Errorf("Error destroying team! WARNING: Dangling resources\n"+ 786 "may exist! The full error is shown below.\n\n"+ 787 "Team: %s\nError: %s", tm.Name, err) 788 } 789 790 if orgCleanup != nil { 791 orgCleanup() 792 } 793 } 794} 795 796func createTeamAccess(t *testing.T, client *Client, tm *Team, w *Workspace, org *Organization) (*TeamAccess, func()) { 797 var orgCleanup, tmCleanup func() 798 799 if org == nil { 800 org, orgCleanup = createOrganization(t, client) 801 } 802 803 if tm == nil { 804 tm, tmCleanup = createTeam(t, client, org) 805 } 806 807 if w == nil { 808 w, _ = createWorkspace(t, client, org) 809 } 810 811 ctx := context.Background() 812 ta, err := client.TeamAccess.Add(ctx, TeamAccessAddOptions{ 813 Access: Access(AccessAdmin), 814 Team: tm, 815 Workspace: w, 816 }) 817 if err != nil { 818 t.Fatal(err) 819 } 820 821 return ta, func() { 822 if err := client.TeamAccess.Remove(ctx, ta.ID); err != nil { 823 t.Errorf("Error removing team access! WARNING: Dangling resources\n"+ 824 "may exist! The full error is shown below.\n\n"+ 825 "TeamAccess: %s\nError: %s", ta.ID, err) 826 } 827 828 if tmCleanup != nil { 829 tmCleanup() 830 } 831 832 if orgCleanup != nil { 833 orgCleanup() 834 } 835 } 836} 837 838func createTeamToken(t *testing.T, client *Client, tm *Team) (*TeamToken, func()) { 839 var tmCleanup func() 840 841 if tm == nil { 842 tm, tmCleanup = createTeam(t, client, nil) 843 } 844 845 ctx := context.Background() 846 tt, err := client.TeamTokens.Generate(ctx, tm.ID) 847 if err != nil { 848 t.Fatal(err) 849 } 850 851 return tt, func() { 852 if err := client.TeamTokens.Delete(ctx, tm.ID); err != nil { 853 t.Errorf("Error destroying team token! WARNING: Dangling resources\n"+ 854 "may exist! The full error is shown below.\n\n"+ 855 "TeamToken: %s\nError: %s", tm.ID, err) 856 } 857 858 if tmCleanup != nil { 859 tmCleanup() 860 } 861 } 862} 863 864func createVariable(t *testing.T, client *Client, w *Workspace) (*Variable, func()) { 865 var wCleanup func() 866 867 if w == nil { 868 w, wCleanup = createWorkspace(t, client, nil) 869 } 870 871 ctx := context.Background() 872 v, err := client.Variables.Create(ctx, w.ID, VariableCreateOptions{ 873 Key: String(randomString(t)), 874 Value: String(randomString(t)), 875 Category: Category(CategoryTerraform), 876 Description: String(randomString(t)), 877 }) 878 if err != nil { 879 t.Fatal(err) 880 } 881 882 return v, func() { 883 if err := client.Variables.Delete(ctx, w.ID, v.ID); err != nil { 884 t.Errorf("Error destroying variable! WARNING: Dangling resources\n"+ 885 "may exist! The full error is shown below.\n\n"+ 886 "Variable: %s\nError: %s", v.Key, err) 887 } 888 889 if wCleanup != nil { 890 wCleanup() 891 } 892 } 893} 894 895func createWorkspace(t *testing.T, client *Client, org *Organization) (*Workspace, func()) { 896 var orgCleanup func() 897 898 if org == nil { 899 org, orgCleanup = createOrganization(t, client) 900 } 901 902 ctx := context.Background() 903 w, err := client.Workspaces.Create(ctx, org.Name, WorkspaceCreateOptions{ 904 Name: String(randomString(t)), 905 }) 906 if err != nil { 907 t.Fatal(err) 908 } 909 910 return w, func() { 911 if err := client.Workspaces.Delete(ctx, org.Name, w.Name); err != nil { 912 t.Errorf("Error destroying workspace! WARNING: Dangling resources\n"+ 913 "may exist! The full error is shown below.\n\n"+ 914 "Workspace: %s\nError: %s", w.Name, err) 915 } 916 917 if orgCleanup != nil { 918 orgCleanup() 919 } 920 } 921} 922 923func createWorkspaceWithVCS(t *testing.T, client *Client, org *Organization) (*Workspace, func()) { 924 var orgCleanup func() 925 926 if org == nil { 927 org, orgCleanup = createOrganization(t, client) 928 } 929 930 oc, ocCleanup := createOAuthToken(t, client, org) 931 932 githubIdentifier := os.Getenv("GITHUB_POLICY_SET_IDENTIFIER") 933 if githubIdentifier == "" { 934 t.Fatal("Export a valid GITHUB_POLICY_SET_IDENTIFIER before running this test!") 935 } 936 937 options := WorkspaceCreateOptions{ 938 Name: String(randomString(t)), 939 VCSRepo: &VCSRepoOptions{ 940 Identifier: String(githubIdentifier), 941 OAuthTokenID: String(oc.ID), 942 }, 943 } 944 945 ctx := context.Background() 946 w, err := client.Workspaces.Create(ctx, org.Name, options) 947 if err != nil { 948 t.Fatal(err) 949 } 950 951 return w, func() { 952 if err := client.Workspaces.Delete(ctx, org.Name, w.Name); err != nil { 953 t.Errorf("Error destroying workspace! WARNING: Dangling resources\n"+ 954 "may exist! The full error is shown below.\n\n"+ 955 "Workspace: %s\nError: %s", w.Name, err) 956 } 957 958 if ocCleanup != nil { 959 ocCleanup() 960 } 961 962 if orgCleanup != nil { 963 orgCleanup() 964 } 965 } 966} 967 968func randomString(t *testing.T) string { 969 v, err := uuid.GenerateUUID() 970 if err != nil { 971 t.Fatal(err) 972 } 973 return v 974} 975