diff --git a/go.mod b/go.mod index 677e69d1f7db..01dc097102f5 100644 --- a/go.mod +++ b/go.mod @@ -28,12 +28,12 @@ require ( github.com/hashicorp/go-plugin v1.6.0 github.com/hashicorp/go-retryablehttp v0.7.7 github.com/hashicorp/go-slug v0.16.3 - github.com/hashicorp/go-tfe v1.70.0 + github.com/hashicorp/go-tfe v1.74.1 github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/hcl/v2 v2.23.0 - github.com/hashicorp/jsonapi v1.3.1 + github.com/hashicorp/jsonapi v1.3.2 github.com/hashicorp/terraform-registry-address v0.2.3 github.com/hashicorp/terraform-svchost v0.1.1 github.com/hashicorp/terraform/internal/backend/remote-state/azure v0.0.0-00010101000000-000000000000 @@ -254,7 +254,7 @@ require ( go.opentelemetry.io/proto/otlp v1.0.0 // indirect golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 // indirect golang.org/x/sync v0.10.0 // indirect - golang.org/x/time v0.7.0 // indirect + golang.org/x/time v0.9.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/api v0.126.0 // indirect google.golang.org/appengine v1.6.8 // indirect diff --git a/go.sum b/go.sum index e5e20f797de3..0568d41faad7 100644 --- a/go.sum +++ b/go.sum @@ -1147,6 +1147,8 @@ github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjG github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-tfe v1.70.0 h1:R5a9Z+jdVz6eRWtSLsl1nw+5Qe/swunZcJgeKK5NQtQ= github.com/hashicorp/go-tfe v1.70.0/go.mod h1:2rOcdTxXwbWm0W7dCKjC3Ec8KQ+HhW165GiurXNshc4= +github.com/hashicorp/go-tfe v1.74.1 h1:I/8fOwSYox17IZV7SULIQH0ZRPNL2g/biW6hHWnOTVY= +github.com/hashicorp/go-tfe v1.74.1/go.mod h1:kGHWMZ3HHjitgqON8nBZ4kPVJ3cLbzM4JMgmNVMs9aQ= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= @@ -1167,6 +1169,8 @@ github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3q github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= github.com/hashicorp/jsonapi v1.3.1 h1:GtPvnmcWgYwCuDGvYT5VZBHcUyFdq9lSyCzDjn1DdPo= github.com/hashicorp/jsonapi v1.3.1/go.mod h1:kWfdn49yCjQvbpnvY1dxxAuAFzISwrrMDQOcu6NsFoM= +github.com/hashicorp/jsonapi v1.3.2 h1:gP3fX2ZT7qXi+PbwieptzkspIohO2kCSiBUvUTBAbMs= +github.com/hashicorp/jsonapi v1.3.2/go.mod h1:kWfdn49yCjQvbpnvY1dxxAuAFzISwrrMDQOcu6NsFoM= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.3.0 h1:8+567mCcFDnS5ADl7lrpxPMWiFCElyUEeW0gtj34fMA= diff --git a/internal/cloud/test.go b/internal/cloud/test.go index e81d07494ff1..3f97be0f8d23 100644 --- a/internal/cloud/test.go +++ b/internal/cloud/test.go @@ -82,6 +82,10 @@ type TestSuiteRunner struct { // Verbose tells the runner to print out plan files during each test run. Verbose bool + // OperationParallelism is the limit Terraform places on total parallel operations + // during the plan or apply command within a single test run. + OperationParallelism int + // Filters restricts which test files will be executed. Filters []string @@ -204,6 +208,7 @@ func (runner *TestSuiteRunner) Test() (moduletest.Status, tfdiags.Diagnostics) { Filters: runner.Filters, TestDirectory: tfe.String(runner.TestingDirectory), Verbose: tfe.Bool(runner.Verbose), + Parallelism: tfe.Int(runner.OperationParallelism), Variables: func() []*tfe.RunVariable { runVariables := make([]*tfe.RunVariable, 0, len(variables)) for name, value := range variables { diff --git a/internal/cloud/test_test.go b/internal/cloud/test_test.go index 2b1dbee164dc..e33cec14df08 100644 --- a/internal/cloud/test_test.go +++ b/internal/cloud/test_test.go @@ -103,6 +103,81 @@ Success! 2 passed, 0 failed. } } +func TestTest_Parallelism(t *testing.T) { + + streams, _ := terminal.StreamsForTesting(t) + view := views.NewTest(arguments.ViewHuman, views.NewView(streams)) + + colorize := mockColorize() + colorize.Disable = true + + mock := NewMockClient() + client := &tfe.Client{ + ConfigurationVersions: mock.ConfigurationVersions, + Organizations: mock.Organizations, + RegistryModules: mock.RegistryModules, + TestRuns: mock.TestRuns, + } + + if _, err := client.Organizations.Create(context.Background(), tfe.OrganizationCreateOptions{ + Name: tfe.String("organisation"), + }); err != nil { + t.Fatalf("failed to create organisation: %v", err) + } + + if _, err := client.RegistryModules.Create(context.Background(), "organisation", tfe.RegistryModuleCreateOptions{ + Name: tfe.String("name"), + Provider: tfe.String("provider"), + RegistryName: "app.terraform.io", + Namespace: "organisation", + }); err != nil { + t.Fatalf("failed to create registry module: %v", err) + } + + runner := TestSuiteRunner{ + // Configuration data. + ConfigDirectory: "testdata/test", + TestingDirectory: "tests", + Config: nil, // We don't need this for this test. + Source: "app.terraform.io/organisation/name/provider", + + // Cancellation controls, we won't be doing any cancellations in this + // test. + Stopped: false, + Cancelled: false, + StoppedCtx: context.Background(), + CancelledCtx: context.Background(), + + // Test Options, empty for this test. + GlobalVariables: nil, + Verbose: false, + OperationParallelism: 4, + Filters: nil, + + // Outputs + Renderer: &jsonformat.Renderer{ + Streams: streams, + Colorize: colorize, + RunningInAutomation: false, + }, + View: view, + Streams: streams, + + // Networking + Services: nil, // Don't need this when the client is overridden. + clientOverride: client, + } + + _, diags := runner.Test() + if len(diags) > 0 { + t.Errorf("found diags and expected none: %s", diags.ErrWithWarnings()) + } + + if mock.TestRuns.parallelism != 4 { + t.Errorf("expected parallelism to be 4 but was %d", mock.TestRuns.parallelism) + } +} + func TestTest_JSON(t *testing.T) { streams, done := terminal.StreamsForTesting(t) diff --git a/internal/cloud/tfe_client_mock.go b/internal/cloud/tfe_client_mock.go index 53bfc374cf45..5a5ccaf33b70 100644 --- a/internal/cloud/tfe_client_mock.go +++ b/internal/cloud/tfe_client_mock.go @@ -1673,9 +1673,10 @@ type MockTestRuns struct { client *MockClient // TestRuns and modules keep track of our tfe.TestRun objects. - TestRuns map[string]*tfe.TestRun - modules map[string][]*tfe.TestRun - logs map[string]string + TestRuns map[string]*tfe.TestRun + modules map[string][]*tfe.TestRun + logs map[string]string + parallelism int // delayedCancel allows a mock test run to cancel an operation instead of // completing an operation. It's used @@ -1767,6 +1768,9 @@ func (m *MockTestRuns) Create(ctx context.Context, options tfe.TestRunCreateOpti "test.log", ) m.modules[tr.RegistryModule.ID] = append(m.modules[tr.RegistryModule.ID], tr) + if options.Parallelism != nil { + m.parallelism = *options.Parallelism + } return tr, nil } @@ -2170,6 +2174,30 @@ func (m *MockWorkspaces) UpdateByID(ctx context.Context, workspaceID string, opt return w, nil } +func (m *MockWorkspaces) ListEffectiveTagBindings(ctx context.Context, workspaceID string) ([]*tfe.EffectiveTagBinding, error) { + w, ok := m.workspaceIDs[workspaceID] + if !ok { + return nil, tfe.ErrResourceNotFound + } + var effectiveTagBindings []*tfe.EffectiveTagBinding + for _, tb := range w.TagBindings { + effectiveTagBindings = append(effectiveTagBindings, &tfe.EffectiveTagBinding{ + Key: tb.Key, + Value: tb.Value, + }) + } + return effectiveTagBindings, nil +} + +func (m *MockWorkspaces) DeleteAllTagBindings(ctx context.Context, workspaceID string) error { + w, ok := m.workspaceIDs[workspaceID] + if !ok { + return tfe.ErrResourceNotFound + } + w.TagBindings = nil + return nil +} + func updateMockWorkspaceAttributes(w *tfe.Workspace, options tfe.WorkspaceUpdateOptions) error { // for TestCloud_setUnavailableTerraformVersion if w.Name == "unavailable-terraform-version" && options.TerraformVersion != nil { diff --git a/internal/command/test.go b/internal/command/test.go index 0c1939e9e4fd..8b236fe779ac 100644 --- a/internal/command/test.go +++ b/internal/command/test.go @@ -187,21 +187,22 @@ func (c *TestCommand) Run(rawArgs []string) int { } runner = &cloud.TestSuiteRunner{ - ConfigDirectory: ".", // Always loading from the current directory. - TestingDirectory: args.TestDirectory, - Config: config, - Services: c.Services, - Source: args.CloudRunSource, - GlobalVariables: variables, - Stopped: false, - Cancelled: false, - StoppedCtx: stopCtx, - CancelledCtx: cancelCtx, - Verbose: args.Verbose, - Filters: args.Filter, - Renderer: renderer, - View: view, - Streams: c.Streams, + ConfigDirectory: ".", // Always loading from the current directory. + TestingDirectory: args.TestDirectory, + Config: config, + Services: c.Services, + Source: args.CloudRunSource, + GlobalVariables: variables, + Stopped: false, + Cancelled: false, + StoppedCtx: stopCtx, + CancelledCtx: cancelCtx, + Verbose: args.Verbose, + OperationParallelism: args.OperationParallelism, + Filters: args.Filter, + Renderer: renderer, + View: view, + Streams: c.Streams, } } else { localRunner := &local.TestSuiteRunner{