Skip to content

Commit 36dd4c2

Browse files
re-add test cases lost to rebasing
1 parent 5e4ffbe commit 36dd4c2

File tree

1 file changed

+246
-0
lines changed

1 file changed

+246
-0
lines changed

internal/terraform/context_plan_actions_test.go

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,6 +2781,252 @@ resource "test_object" "a" {
27812781
}
27822782
},
27832783
},
2784+
"action expansion with unknown instances": {
2785+
module: map[string]string{
2786+
"main.tf": `
2787+
variable "each" {
2788+
type = set(string)
2789+
}
2790+
action "test_unlinked" "hello" {
2791+
for_each = var.each
2792+
}
2793+
resource "test_object" "a" {
2794+
lifecycle {
2795+
action_trigger {
2796+
events = [before_create]
2797+
actions = [action.test_unlinked.hello["a"]]
2798+
}
2799+
}
2800+
}
2801+
`,
2802+
},
2803+
expectPlanActionCalled: false,
2804+
planOpts: &PlanOpts{
2805+
Mode: plans.NormalMode,
2806+
DeferralAllowed: true,
2807+
SetVariables: InputValues{
2808+
"each": &InputValue{
2809+
Value: cty.UnknownVal(cty.Set(cty.String)),
2810+
SourceType: ValueFromCLIArg,
2811+
},
2812+
},
2813+
},
2814+
assertPlan: func(t *testing.T, p *plans.Plan) {
2815+
if len(p.DeferredActionInvocations) != 1 {
2816+
t.Fatalf("expected exactly one invocation, and found %d", len(p.DeferredActionInvocations))
2817+
}
2818+
2819+
if p.DeferredActionInvocations[0].DeferredReason != providers.DeferredReasonDeferredPrereq {
2820+
t.Fatalf("expected.DeferredReasonDeferredPrereq, got %s", p.DeferredActionInvocations[0].DeferredReason)
2821+
}
2822+
2823+
ai := p.DeferredActionInvocations[0].ActionInvocationInstanceSrc
2824+
if ai.Addr.String() != `action.test_unlinked.hello["a"]` {
2825+
t.Fatalf(`expected action invocation for action.test_unlinked.hello["a"], got %s`, ai.Addr.String())
2826+
}
2827+
},
2828+
},
2829+
"action with unknown module expansion": {
2830+
// We have an unknown module expansion (for_each over an unknown value). The
2831+
// action and its triggering resource both live inside the (currently
2832+
// un-expanded) module instances. Since we cannot expand the module yet, the
2833+
// action invocation must be deferred.
2834+
module: map[string]string{
2835+
"main.tf": `
2836+
variable "mods" {
2837+
type = set(string)
2838+
}
2839+
module "mod" {
2840+
source = "./mod"
2841+
for_each = var.mods
2842+
}
2843+
`,
2844+
"mod/mod.tf": `
2845+
action "test_unlinked" "hello" {
2846+
config {
2847+
attr = "static"
2848+
}
2849+
}
2850+
resource "other_object" "a" {
2851+
lifecycle {
2852+
action_trigger {
2853+
events = [before_create]
2854+
actions = [action.test_unlinked.hello]
2855+
}
2856+
}
2857+
}
2858+
`,
2859+
},
2860+
expectPlanActionCalled: true,
2861+
planOpts: &PlanOpts{
2862+
Mode: plans.NormalMode,
2863+
DeferralAllowed: true,
2864+
SetVariables: InputValues{
2865+
"mods": &InputValue{
2866+
Value: cty.UnknownVal(cty.Set(cty.String)),
2867+
SourceType: ValueFromCLIArg,
2868+
},
2869+
},
2870+
},
2871+
assertPlan: func(t *testing.T, p *plans.Plan) {
2872+
// No concrete action invocations can be produced yet.
2873+
if got := len(p.Changes.ActionInvocations); got != 0 {
2874+
t.Fatalf("expected 0 planned action invocations, got %d", got)
2875+
}
2876+
2877+
if got := len(p.DeferredActionInvocations); got != 0 {
2878+
t.Fatalf("expected 0 deferred action invocations, got %d", got)
2879+
}
2880+
2881+
if got := len(p.DeferredPartialActionInvocations); got != 1 {
2882+
t.Fatalf("expected 1 deferred action invocations, got %d", got)
2883+
}
2884+
ac, err := p.DeferredPartialActionInvocations[0].Decode(&unlinkedActionSchema)
2885+
if err != nil {
2886+
t.Fatalf("error decoding action invocation: %s", err)
2887+
}
2888+
if ac.DeferredReason != providers.DeferredReasonInstanceCountUnknown {
2889+
t.Fatalf("expected DeferredReasonInstanceCountUnknown, got %s", ac.DeferredReason)
2890+
}
2891+
if ac.ActionInvocationInstance.ConfigValue.GetAttr("attr").AsString() != "static" {
2892+
t.Fatalf("expected attr to be static, got %s", ac.ActionInvocationInstance.ConfigValue.GetAttr("attr").AsString())
2893+
}
2894+
2895+
},
2896+
},
2897+
"action with unknown module expansion and unknown instances": {
2898+
// Here both the module expansion and the action for_each expansion are unknown.
2899+
// The action is referenced (with a specific key) inside the module so we should
2900+
// get a single deferred action invocation for that specific (yet still
2901+
// unresolved) instance address.
2902+
module: map[string]string{
2903+
"main.tf": `
2904+
variable "mods" {
2905+
type = set(string)
2906+
}
2907+
variable "actions" {
2908+
type = set(string)
2909+
}
2910+
module "mod" {
2911+
source = "./mod"
2912+
for_each = var.mods
2913+
2914+
actions = var.actions
2915+
}
2916+
`,
2917+
"mod/mod.tf": `
2918+
variable "actions" {
2919+
type = set(string)
2920+
}
2921+
action "test_unlinked" "hello" {
2922+
// Unknown for_each inside the module instance.
2923+
for_each = var.actions
2924+
}
2925+
resource "other_object" "a" {
2926+
lifecycle {
2927+
action_trigger {
2928+
events = [before_create]
2929+
// We reference a specific (yet unknown) action instance key.
2930+
actions = [action.test_unlinked.hello["a"]]
2931+
}
2932+
}
2933+
}
2934+
`,
2935+
},
2936+
expectPlanActionCalled: true,
2937+
planOpts: &PlanOpts{
2938+
Mode: plans.NormalMode,
2939+
DeferralAllowed: true,
2940+
SetVariables: InputValues{
2941+
"mods": &InputValue{
2942+
Value: cty.UnknownVal(cty.Set(cty.String)),
2943+
SourceType: ValueFromCLIArg,
2944+
},
2945+
"actions": &InputValue{
2946+
Value: cty.UnknownVal(cty.Set(cty.String)),
2947+
SourceType: ValueFromCLIArg,
2948+
},
2949+
},
2950+
},
2951+
assertPlan: func(t *testing.T, p *plans.Plan) {
2952+
if len(p.Changes.ActionInvocations) != 0 {
2953+
t.Fatalf("expected 0 planned action invocations, got %d", len(p.Changes.ActionInvocations))
2954+
}
2955+
if got := len(p.DeferredActionInvocations); got != 0 {
2956+
t.Fatalf("expected 0 deferred action invocations, got %d", got)
2957+
}
2958+
2959+
if len(p.DeferredPartialActionInvocations) != 1 {
2960+
t.Fatalf("expected 1 deferred partial action invocations, got %d", len(p.DeferredPartialActionInvocations))
2961+
}
2962+
2963+
ac, err := p.DeferredPartialActionInvocations[0].Decode(&unlinkedActionSchema)
2964+
if err != nil {
2965+
t.Fatalf("error decoding action invocation: %s", err)
2966+
}
2967+
if ac.DeferredReason != providers.DeferredReasonInstanceCountUnknown {
2968+
t.Fatalf("expected deferred reason to be DeferredReasonInstanceCountUnknown, got %s", ac.DeferredReason)
2969+
}
2970+
if !ac.ActionInvocationInstance.ConfigValue.IsNull() {
2971+
t.Fatalf("expected config value to be null")
2972+
}
2973+
},
2974+
},
2975+
2976+
"deferring resource dependencies should defer action": {
2977+
module: map[string]string{
2978+
"main.tf": `
2979+
resource "test_object" "origin" {
2980+
name = "origin"
2981+
}
2982+
action "test_unlinked" "hello" {
2983+
config {
2984+
attr = test_object.origin.name
2985+
}
2986+
}
2987+
resource "test_object" "a" {
2988+
name = "a"
2989+
lifecycle {
2990+
action_trigger {
2991+
events = [after_create]
2992+
actions = [action.test_unlinked.hello]
2993+
}
2994+
}
2995+
}
2996+
`,
2997+
},
2998+
expectPlanActionCalled: false,
2999+
planOpts: &PlanOpts{
3000+
Mode: plans.NormalMode,
3001+
DeferralAllowed: true,
3002+
},
3003+
planResourceFn: func(t *testing.T, req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
3004+
if req.Config.GetAttr("name").AsString() == "origin" {
3005+
return providers.PlanResourceChangeResponse{
3006+
Deferred: &providers.Deferred{
3007+
Reason: providers.DeferredReasonAbsentPrereq,
3008+
},
3009+
}
3010+
}
3011+
return providers.PlanResourceChangeResponse{
3012+
PlannedState: req.ProposedNewState,
3013+
PlannedPrivate: req.PriorPrivate,
3014+
PlannedIdentity: req.PriorIdentity,
3015+
}
3016+
},
3017+
3018+
assertPlan: func(t *testing.T, p *plans.Plan) {
3019+
if len(p.DeferredActionInvocations) != 1 {
3020+
t.Errorf("Expected 1 deferred action invocation, got %d", len(p.DeferredActionInvocations))
3021+
}
3022+
if p.DeferredActionInvocations[0].ActionInvocationInstanceSrc.Addr.String() != "action.test_unlinked.hello" {
3023+
t.Errorf("Expected action.test_unlinked.hello, got %s", p.DeferredActionInvocations[0].ActionInvocationInstanceSrc.Addr.String())
3024+
}
3025+
if p.DeferredActionInvocations[0].DeferredReason != providers.DeferredReasonDeferredPrereq {
3026+
t.Errorf("Expected DeferredReasonDeferredPrereq, got %s", p.DeferredActionInvocations[0].DeferredReason)
3027+
}
3028+
},
3029+
},
27843030
} {
27853031
t.Run(name, func(t *testing.T) {
27863032
if tc.toBeImplemented {

0 commit comments

Comments
 (0)