Skip to content

Commit dec0edf

Browse files
authored
terraform test: enable deferrals in Terraform Test with the specified flag (#37370)
1 parent 1841757 commit dec0edf

File tree

13 files changed

+194
-96
lines changed

13 files changed

+194
-96
lines changed

internal/backend/local/test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ type TestSuiteRunner struct {
5858
// Verbose tells the runner to print out plan files during each test run.
5959
Verbose bool
6060

61-
Concurrency int
61+
Concurrency int
62+
DeferralAllowed bool
6263
}
6364

6465
func (runner *TestSuiteRunner) Stop() {
@@ -121,6 +122,7 @@ func (runner *TestSuiteRunner) Test() (moduletest.Status, tfdiags.Diagnostics) {
121122
Render: runner.View,
122123
UnparsedVariables: currentGlobalVariables,
123124
Concurrency: runner.Concurrency,
125+
DeferralAllowed: runner.DeferralAllowed,
124126
})
125127

126128
fileRunner := &TestFileRunner{

internal/command/arguments/test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ type Test struct {
4747
// human-readable format or JSON for each run step depending on the
4848
// ViewType.
4949
Verbose bool
50+
51+
// DeferralAllowed enables deferrals during test operations. This matches
52+
// the same-named flag in the Operation struct.
53+
DeferralAllowed bool
5054
}
5155

5256
func ParseTest(args []string) (*Test, tfdiags.Diagnostics) {
@@ -65,6 +69,7 @@ func ParseTest(args []string) (*Test, tfdiags.Diagnostics) {
6569
cmdFlags.BoolVar(&test.Verbose, "verbose", false, "verbose")
6670
cmdFlags.IntVar(&test.OperationParallelism, "parallelism", DefaultParallelism, "parallelism")
6771
cmdFlags.IntVar(&test.RunParallelism, "run-parallelism", DefaultParallelism, "run-parallelism")
72+
cmdFlags.BoolVar(&test.DeferralAllowed, "allow-deferral", false, "allow-deferral")
6873

6974
// TODO: Finalise the name of this flag.
7075
cmdFlags.StringVar(&test.CloudRunSource, "cloud-run", "", "cloud-run")

internal/command/test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,17 @@ func (c *TestCommand) Run(rawArgs []string) int {
111111

112112
view := views.NewTest(args.ViewType, c.View)
113113

114+
// EXPERIMENTAL: maybe enable deferred actions
115+
if !c.AllowExperimentalFeatures && args.DeferralAllowed {
116+
diags = diags.Append(tfdiags.Sourceless(
117+
tfdiags.Error,
118+
"Failed to parse command-line flags",
119+
"The -allow-deferral flag is only valid in experimental builds of Terraform.",
120+
))
121+
view.Diagnostics(nil, nil, diags)
122+
return 1
123+
}
124+
114125
// The specified testing directory must be a relative path, and it must
115126
// point to a directory that is a descendant of the configuration directory.
116127
if !filepath.IsLocal(args.TestDirectory) {
@@ -228,6 +239,7 @@ func (c *TestCommand) Run(rawArgs []string) int {
228239
Filter: args.Filter,
229240
Verbose: args.Verbose,
230241
Concurrency: args.RunParallelism,
242+
DeferralAllowed: args.DeferralAllowed,
231243
}
232244

233245
// JUnit output is only compatible with local test execution

internal/command/test_test.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,11 @@ func TestTest_Runs(t *testing.T) {
397397
expectedOut: []string{"1 passed, 0 failed."},
398398
code: 0,
399399
},
400+
"deferred_changes": {
401+
args: []string{"-allow-deferral"},
402+
expectedOut: []string{"3 passed, 0 failed."},
403+
code: 0,
404+
},
400405
}
401406
for name, tc := range tcs {
402407
t.Run(name, func(t *testing.T) {
@@ -442,10 +447,11 @@ func TestTest_Runs(t *testing.T) {
442447
},
443448
},
444449
},
445-
Ui: ui,
446-
View: view,
447-
Streams: streams,
448-
ProviderSource: providerSource,
450+
Ui: ui,
451+
View: view,
452+
Streams: streams,
453+
ProviderSource: providerSource,
454+
AllowExperimentalFeatures: true,
449455
}
450456

451457
init := &InitCommand{
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
run "create" {
3+
variables {
4+
defer = true
5+
}
6+
7+
assert {
8+
condition = test_resource.resource.defer
9+
error_message = "deferred resource attribute should be true"
10+
}
11+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
variable "defer" {
2+
type = bool
3+
}
4+
5+
resource "test_resource" "resource" {
6+
defer = var.defer
7+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
run "create" {
3+
variables {
4+
defer = false
5+
}
6+
7+
assert {
8+
condition = !test_resource.resource.defer
9+
error_message = "deferred resource attribute should be false"
10+
}
11+
}
12+
13+
run "update" {
14+
variables {
15+
defer = true
16+
}
17+
18+
assert {
19+
condition = test_resource.resource.defer
20+
error_message = "deferred resource attribute should be true"
21+
}
22+
}

internal/command/testing/test_provider.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ var (
4040
"create_wait_seconds": {Type: cty.Number, Optional: true},
4141
"destroy_wait_seconds": {Type: cty.Number, Optional: true},
4242
"write_only": {Type: cty.String, Optional: true, WriteOnly: true},
43+
"defer": {Type: cty.Bool, Optional: true},
4344
},
4445
},
4546
},
@@ -61,6 +62,7 @@ var (
6162
"destroy_fail": {Type: cty.Bool, Computed: true},
6263
"create_wait_seconds": {Type: cty.Number, Computed: true},
6364
"destroy_wait_seconds": {Type: cty.Number, Computed: true},
65+
"defer": {Type: cty.Bool, Computed: true},
6466
},
6567
},
6668
},
@@ -227,9 +229,18 @@ func (provider *TestProvider) ConfigureProvider(request providers.ConfigureProvi
227229

228230
func (provider *TestProvider) PlanResourceChange(request providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
229231
if request.ProposedNewState.IsNull() {
232+
233+
var deferred *providers.Deferred
234+
if shouldBeDeferred := request.PriorState.GetAttr("defer"); !shouldBeDeferred.IsNull() && shouldBeDeferred.True() {
235+
deferred = &providers.Deferred{
236+
Reason: providers.DeferredReasonResourceConfigUnknown,
237+
}
238+
}
239+
230240
// Then this is a delete operation.
231241
return providers.PlanResourceChangeResponse{
232242
PlannedState: request.ProposedNewState,
243+
Deferred: deferred,
233244
}
234245
}
235246

@@ -252,8 +263,16 @@ func (provider *TestProvider) PlanResourceChange(request providers.PlanResourceC
252263
resource = cty.ObjectVal(vals)
253264
}
254265

266+
var deferred *providers.Deferred
267+
if shouldBeDeferred := resource.GetAttr("defer"); !shouldBeDeferred.IsKnown() || (!shouldBeDeferred.IsNull() && shouldBeDeferred.True()) {
268+
deferred = &providers.Deferred{
269+
Reason: providers.DeferredReasonResourceConfigUnknown,
270+
}
271+
}
272+
255273
return providers.PlanResourceChangeResponse{
256274
PlannedState: resource,
275+
Deferred: deferred,
257276
}
258277
}
259278

internal/moduletest/graph/eval_context.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ type EvalContext struct {
8080
renderer views.Test
8181
verbose bool
8282

83-
evalSem terraform.Semaphore
83+
deferralAllowed bool
84+
evalSem terraform.Semaphore
8485
}
8586

8687
type EvalContextOpts struct {
@@ -91,6 +92,7 @@ type EvalContextOpts struct {
9192
UnparsedVariables map[string]backendrun.UnparsedVariableValue
9293
Config *configs.Config
9394
Concurrency int
95+
DeferralAllowed bool
9496
}
9597

9698
// NewEvalContext constructs a new graph evaluation context for use in
@@ -119,6 +121,7 @@ func NewEvalContext(opts EvalContextOpts) *EvalContext {
119121
verbose: opts.Verbose,
120122
renderer: opts.Render,
121123
config: opts.Config,
124+
deferralAllowed: opts.DeferralAllowed,
122125
evalSem: terraform.NewSemaphore(opts.Concurrency),
123126
}
124127
}

internal/moduletest/graph/node_provider.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func (n *NodeProviderConfigure) Execute(ctx *EvalContext) {
9090
TerraformVersion: version.SemVer.String(),
9191
Config: unmarkedBody,
9292
ClientCapabilities: providers.ClientCapabilities{
93-
DeferralAllowed: false, // TODO: Enable deferrals in test framework.
93+
DeferralAllowed: ctx.deferralAllowed,
9494
WriteOnlyAttributesAllowed: true,
9595
},
9696
})

0 commit comments

Comments
 (0)