Skip to content

Commit 4de0e32

Browse files
add tests involving config
1 parent 2f6c454 commit 4de0e32

File tree

1 file changed

+126
-1
lines changed

1 file changed

+126
-1
lines changed

internal/terraform/context_apply_action_test.go

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/hashicorp/terraform/internal/addrs"
1010
"github.com/hashicorp/terraform/internal/configs/configschema"
11+
"github.com/hashicorp/terraform/internal/lang/marks"
1112
"github.com/hashicorp/terraform/internal/plans"
1213
"github.com/hashicorp/terraform/internal/providers"
1314
testing_provider "github.com/hashicorp/terraform/internal/providers/testing"
@@ -23,8 +24,10 @@ func TestContext2Apply_actions(t *testing.T) {
2324
prevRunState *states.State
2425
events []providers.InvokeActionEvent
2526
callingInvokeReturnsDiagnostics tfdiags.Diagnostics
27+
planOpts *PlanOpts
2628

2729
expectInvokeActionCalled bool
30+
expectInvokeActionCalls []providers.InvokeActionRequest
2831

2932
expectDiagnostics tfdiags.Diagnostics
3033
}{
@@ -207,6 +210,110 @@ resource "test_object" "a" {
207210
),
208211
},
209212
},
213+
214+
"action with configuration": {
215+
module: map[string]string{
216+
"main.tf": `
217+
resource "test_object" "a" {
218+
name = "foo"
219+
}
220+
action "test_unlinked" "hello" {
221+
config {
222+
attr = resource.test_object.a.name
223+
}
224+
}
225+
resource "test_object" "b" {
226+
lifecycle {
227+
action_trigger {
228+
events = [before_create]
229+
actions = [action.test_unlinked.hello]
230+
}
231+
}
232+
}
233+
`,
234+
},
235+
expectInvokeActionCalled: true,
236+
expectInvokeActionCalls: []providers.InvokeActionRequest{{
237+
ActionType: "test_unlinked",
238+
PlannedActionData: cty.ObjectVal(map[string]cty.Value{
239+
"attr": cty.StringVal("foo"),
240+
}),
241+
}},
242+
},
243+
244+
// Providers can handle unknown values in the configuration
245+
"action with unknown configuration": {
246+
module: map[string]string{
247+
"main.tf": `
248+
variable "unknown_value" {
249+
type = string
250+
}
251+
action "test_unlinked" "hello" {
252+
config {
253+
attr = var.unknown_value
254+
}
255+
}
256+
resource "test_object" "b" {
257+
lifecycle {
258+
action_trigger {
259+
events = [before_create]
260+
actions = [action.test_unlinked.hello]
261+
}
262+
}
263+
}
264+
`,
265+
},
266+
planOpts: SimplePlanOpts(plans.NormalMode, InputValues{
267+
"unknown_value": &InputValue{
268+
Value: cty.UnknownVal(cty.String),
269+
},
270+
}),
271+
272+
expectInvokeActionCalled: true,
273+
expectInvokeActionCalls: []providers.InvokeActionRequest{{
274+
ActionType: "test_unlinked",
275+
PlannedActionData: cty.ObjectVal(map[string]cty.Value{
276+
"attr": cty.UnknownVal(cty.String),
277+
}),
278+
}},
279+
},
280+
281+
"action with secrets in configuration": {
282+
module: map[string]string{
283+
"main.tf": `
284+
variable "secret_value" {
285+
type = string
286+
sensitive = true
287+
}
288+
action "test_unlinked" "hello" {
289+
config {
290+
attr = var.secret_value
291+
}
292+
}
293+
resource "test_object" "b" {
294+
lifecycle {
295+
action_trigger {
296+
events = [before_create]
297+
actions = [action.test_unlinked.hello]
298+
}
299+
}
300+
}
301+
`,
302+
},
303+
planOpts: SimplePlanOpts(plans.NormalMode, InputValues{
304+
"secret_value": &InputValue{
305+
Value: cty.StringVal("psst, I'm secret").Mark(marks.Sensitive), // Not sure if we need the mark here, but it doesn't hurt
306+
},
307+
}),
308+
309+
expectInvokeActionCalled: true,
310+
expectInvokeActionCalls: []providers.InvokeActionRequest{{
311+
ActionType: "test_unlinked",
312+
PlannedActionData: cty.ObjectVal(map[string]cty.Value{
313+
"attr": cty.StringVal("psst, I'm secret"),
314+
}),
315+
}},
316+
},
210317
} {
211318
t.Run(name, func(t *testing.T) {
212319
m := testModuleInline(t, tc.module)
@@ -286,7 +393,12 @@ resource "test_object" "a" {
286393
diags := ctx.Validate(m, &ValidateOpts{})
287394
tfdiags.AssertNoDiagnostics(t, diags)
288395

289-
plan, diags := ctx.Plan(m, tc.prevRunState, SimplePlanOpts(plans.NormalMode, InputValues{}))
396+
planOpts := SimplePlanOpts(plans.NormalMode, InputValues{})
397+
if tc.planOpts != nil {
398+
planOpts = tc.planOpts
399+
}
400+
401+
plan, diags := ctx.Plan(m, tc.prevRunState, planOpts)
290402
tfdiags.AssertNoDiagnostics(t, diags)
291403

292404
_, diags = ctx.Apply(plan, m, nil)
@@ -299,6 +411,19 @@ resource "test_object" "a" {
299411
if tc.expectInvokeActionCalled && len(invokeActionCalls) == 0 {
300412
t.Fatalf("expected invoke action to be called, but it was not")
301413
}
414+
415+
if len(tc.expectInvokeActionCalls) > 0 && len(invokeActionCalls) != len(tc.expectInvokeActionCalls) {
416+
t.Fatalf("expected %d invoke action calls, got %d", len(tc.expectInvokeActionCalls), len(invokeActionCalls))
417+
}
418+
for i, expectedCall := range tc.expectInvokeActionCalls {
419+
actualCall := invokeActionCalls[i]
420+
if actualCall.ActionType != expectedCall.ActionType {
421+
t.Fatalf("expected invoke action call %d ActionType to be %s, got %s", i, expectedCall.ActionType, actualCall.ActionType)
422+
}
423+
if !actualCall.PlannedActionData.RawEquals(expectedCall.PlannedActionData) {
424+
t.Fatalf("expected invoke action call %d PlannedActionData to be %s, got %s", i, expectedCall.PlannedActionData, actualCall.PlannedActionData)
425+
}
426+
}
302427
})
303428
}
304429
}

0 commit comments

Comments
 (0)