Skip to content

Commit db8f9c9

Browse files
improve error message
1 parent f786d49 commit db8f9c9

File tree

5 files changed

+289
-157
lines changed

5 files changed

+289
-157
lines changed

internal/terraform/context_apply_action_test.go

Lines changed: 106 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
package terraform
55

66
import (
7+
"path/filepath"
78
"testing"
89

10+
"github.com/hashicorp/hcl/v2"
911
"github.com/hashicorp/terraform/internal/addrs"
12+
"github.com/hashicorp/terraform/internal/configs"
1013
"github.com/hashicorp/terraform/internal/configs/configschema"
1114
"github.com/hashicorp/terraform/internal/lang/marks"
1215
"github.com/hashicorp/terraform/internal/plans"
@@ -31,7 +34,7 @@ func TestContext2Apply_actions(t *testing.T) {
3134
expectInvokeActionCalled bool
3235
expectInvokeActionCalls []providers.InvokeActionRequest
3336

34-
expectDiagnostics tfdiags.Diagnostics
37+
expectDiagnostics func(m *configs.Config) tfdiags.Diagnostics
3538
}{
3639
"unreferenced": {
3740
module: map[string]string{
@@ -147,7 +150,6 @@ resource "test_object" "a" {
147150
},
148151

149152
"before_create failing": {
150-
toBeImplemented: true, // We need to revisit the diagnostic enhancement
151153
module: map[string]string{
152154
"main.tf": `
153155
action "act_unlinked" "hello" {}
@@ -176,17 +178,21 @@ resource "test_object" "a" {
176178
}
177179
},
178180

179-
expectDiagnostics: tfdiags.Diagnostics{
180-
tfdiags.Sourceless(
181-
tfdiags.Error,
182-
"Failed to apply actions before test_object.a",
183-
"An error occured while invoking action action.act_unlinked.hello: test case for failing: this simulates a provider failing\n",
184-
),
181+
expectDiagnostics: func(m *configs.Config) tfdiags.Diagnostics {
182+
return tfdiags.Diagnostics{}.Append(&hcl.Diagnostic{
183+
Severity: hcl.DiagError,
184+
Summary: "Error when invoking action",
185+
Detail: "test case for failing: this simulates a provider failing",
186+
Subject: &hcl.Range{
187+
Filename: filepath.Join(m.Module.SourceDir, "main.tf"),
188+
Start: hcl.Pos{Line: 7, Column: 18, Byte: 146},
189+
End: hcl.Pos{Line: 7, Column: 43, Byte: 171},
190+
},
191+
})
185192
},
186193
},
187194

188195
"before_create failing with successfully completed actions": {
189-
toBeImplemented: true, // We need to revisit the diagnostic enhancement
190196
module: map[string]string{
191197
"main.tf": `
192198
action "act_unlinked" "hello" {}
@@ -227,21 +233,24 @@ resource "test_object" "a" {
227233
}
228234
},
229235

230-
expectDiagnostics: tfdiags.Diagnostics{
231-
tfdiags.Sourceless(
232-
tfdiags.Error,
233-
"Failed to apply actions before test_object.a",
234-
`An error occured while invoking action action.act_unlinked.failure: test case for failing: this simulates a provider failing
235-
The following actions were successfully invoked:
236-
- action.act_unlinked.hello
237-
- action.act_unlinked.world
238-
As the resource did not change, these actions will be re-invoked in the next apply.`,
239-
),
236+
expectDiagnostics: func(m *configs.Config) tfdiags.Diagnostics {
237+
return tfdiags.Diagnostics{}.Append(
238+
&hcl.Diagnostic{
239+
Severity: hcl.DiagError,
240+
Summary: "Error when invoking action",
241+
Detail: `test case for failing: this simulates a provider failing`,
242+
Subject: &hcl.Range{
243+
Filename: filepath.Join(m.Module.SourceDir, "main.tf"),
244+
Start: hcl.Pos{Line: 13, Column: 72, Byte: 305},
245+
End: hcl.Pos{Line: 13, Column: 99, Byte: 332},
246+
},
247+
},
248+
)
249+
240250
},
241251
},
242252

243253
"before_create failing when calling invoke": {
244-
toBeImplemented: true, // We need to revisit the diagnostic enhancement
245254
module: map[string]string{
246255
"main.tf": `
247256
action "act_unlinked" "hello" {}
@@ -265,115 +274,87 @@ resource "test_object" "a" {
265274
),
266275
}
267276
},
268-
expectDiagnostics: tfdiags.Diagnostics{
269-
tfdiags.Sourceless(
270-
tfdiags.Error,
271-
"Failed to apply actions before test_object.a",
272-
"An error occured while invoking action action.act_unlinked.hello: test case for failing: this simulates a provider failing before the action is invoked\n",
273-
),
274-
},
275-
},
276-
277-
"after_create failing": {
278-
toBeImplemented: true, // We need to revisit the diagnostic enhancement
279-
module: map[string]string{
280-
"main.tf": `
281-
action "act_unlinked" "hello" {}
282-
resource "test_object" "a" {
283-
lifecycle {
284-
action_trigger {
285-
events = [after_create]
286-
actions = [action.act_unlinked.hello]
287-
}
288-
}
289-
}
290-
`,
291-
},
292-
expectInvokeActionCalled: true,
293-
events: func(req providers.InvokeActionRequest) []providers.InvokeActionEvent {
294-
return []providers.InvokeActionEvent{
295-
providers.InvokeActionEvent_Completed{
296-
Diagnostics: tfdiags.Diagnostics{
297-
tfdiags.Sourceless(
298-
tfdiags.Error,
299-
"test case for failing",
300-
"this simulates a provider failing",
301-
),
277+
expectDiagnostics: func(m *configs.Config) tfdiags.Diagnostics {
278+
return tfdiags.Diagnostics{}.Append(
279+
&hcl.Diagnostic{
280+
Severity: hcl.DiagError,
281+
Summary: "Error when invoking action",
282+
Detail: "test case for failing: this simulates a provider failing before the action is invoked",
283+
Subject: &hcl.Range{
284+
Filename: filepath.Join(m.Module.SourceDir, "main.tf"),
285+
Start: hcl.Pos{Line: 7, Column: 18, Byte: 146},
286+
End: hcl.Pos{Line: 7, Column: 43, Byte: 171},
302287
},
303288
},
304-
}
305-
},
306-
307-
expectDiagnostics: tfdiags.Diagnostics{
308-
tfdiags.Sourceless(
309-
tfdiags.Error,
310-
"Failed to apply actions after test_object.a",
311-
`An error occured while invoking action action.act_unlinked.hello: test case for failing: this simulates a provider failing
312-
313-
The following actions were not yet invoked:
314-
- action.act_unlinked.hello
315-
These actions will not be triggered in the next apply, please run "terraform invoke" to invoke them.`,
316-
),
289+
)
317290
},
318291
},
319292

320-
"after_create failing with successfully completed actions": {
321-
toBeImplemented: true, // We need to revisit the diagnostic enhancement
293+
"failing an action by action event stops next actions in list": {
322294
module: map[string]string{
323295
"main.tf": `
324296
action "act_unlinked" "hello" {}
325-
action "act_unlinked" "world" {}
326297
action "act_unlinked" "failure" {
327298
config {
328299
attr = "failure"
329300
}
330301
}
302+
action "act_unlinked" "goodbye" {}
331303
resource "test_object" "a" {
332304
lifecycle {
333305
action_trigger {
334-
events = [after_create]
335-
actions = [action.act_unlinked.hello, action.act_unlinked.world, action.act_unlinked.failure]
306+
events = [before_create]
307+
actions = [action.act_unlinked.hello, action.act_unlinked.failure, action.act_unlinked.goodbye]
336308
}
337309
}
338310
}
339311
`,
340312
},
341313
expectInvokeActionCalled: true,
342-
events: func(req providers.InvokeActionRequest) []providers.InvokeActionEvent {
343-
if !req.PlannedActionData.IsNull() && req.PlannedActionData.GetAttr("attr").AsString() == "failure" {
314+
events: func(r providers.InvokeActionRequest) []providers.InvokeActionEvent {
315+
if !r.PlannedActionData.IsNull() && r.PlannedActionData.GetAttr("attr").AsString() == "failure" {
344316
return []providers.InvokeActionEvent{
345317
providers.InvokeActionEvent_Completed{
346-
Diagnostics: tfdiags.Diagnostics{
347-
tfdiags.Sourceless(
348-
tfdiags.Error,
349-
"test case for failing",
350-
"this simulates a provider failing",
351-
),
352-
},
318+
Diagnostics: tfdiags.Diagnostics{}.Append(tfdiags.Sourceless(tfdiags.Error, "test case for failing", "this simulates a provider failing")),
353319
},
354320
}
355-
} else {
356-
return []providers.InvokeActionEvent{
357-
providers.InvokeActionEvent_Completed{},
358-
}
359321
}
360-
},
361322

362-
expectDiagnostics: tfdiags.Diagnostics{
363-
tfdiags.Sourceless(
364-
tfdiags.Error,
365-
"Failed to apply actions after test_object.a",
366-
`An error occured while invoking action action.act_unlinked.failure: test case for failing: this simulates a provider failing
323+
return []providers.InvokeActionEvent{
324+
providers.InvokeActionEvent_Completed{},
325+
}
367326

368-
The following actions were not yet invoked:
369-
- action.act_unlinked.failure
370-
These actions will not be triggered in the next apply, please run "terraform invoke" to invoke them.`,
371-
),
372327
},
328+
expectDiagnostics: func(m *configs.Config) tfdiags.Diagnostics {
329+
return tfdiags.Diagnostics{}.Append(
330+
&hcl.Diagnostic{
331+
Severity: hcl.DiagError,
332+
Summary: "Error when invoking action",
333+
Detail: "test case for failing: this simulates a provider failing",
334+
Subject: &hcl.Range{
335+
Filename: filepath.Join(m.Module.SourceDir, "main.tf"),
336+
Start: hcl.Pos{Line: 13, Column: 45, Byte: 280},
337+
End: hcl.Pos{Line: 13, Column: 72, Byte: 307},
338+
},
339+
},
340+
)
341+
},
342+
343+
// We expect two calls but not the third one, because the second action fails
344+
expectInvokeActionCalls: []providers.InvokeActionRequest{{
345+
ActionType: "act_unlinked",
346+
PlannedActionData: cty.NullVal(cty.Object(map[string]cty.Type{
347+
"attr": cty.String,
348+
})),
349+
}, {
350+
ActionType: "act_unlinked",
351+
PlannedActionData: cty.ObjectVal(map[string]cty.Value{
352+
"attr": cty.StringVal("failure"),
353+
}),
354+
}},
373355
},
374356

375-
"failing an action stops next actions in list": {
376-
toBeImplemented: true, // We need to revisit the diagnostic enhancement
357+
"failing an action during invocation stops next actions in list": {
377358
module: map[string]string{
378359
"main.tf": `
379360
action "act_unlinked" "hello" {}
@@ -407,15 +388,19 @@ resource "test_object" "a" {
407388
}
408389
return tfdiags.Diagnostics{}
409390
},
410-
expectDiagnostics: tfdiags.Diagnostics{
411-
tfdiags.Sourceless(
412-
tfdiags.Error,
413-
"Failed to apply actions before test_object.a",
414-
`An error occured while invoking action action.act_unlinked.failure: test case for failing: this simulates a provider failing
415-
The following actions were successfully invoked:
416-
- action.act_unlinked.hello
417-
As the resource did not change, these actions will be re-invoked in the next apply.`,
418-
),
391+
expectDiagnostics: func(m *configs.Config) tfdiags.Diagnostics {
392+
return tfdiags.Diagnostics{}.Append(
393+
&hcl.Diagnostic{
394+
Severity: hcl.DiagError,
395+
Summary: "Error when invoking action",
396+
Detail: "test case for failing: this simulates a provider failing",
397+
Subject: &hcl.Range{
398+
Filename: filepath.Join(m.Module.SourceDir, "main.tf"),
399+
Start: hcl.Pos{Line: 13, Column: 45, Byte: 280},
400+
End: hcl.Pos{Line: 13, Column: 72, Byte: 307},
401+
},
402+
},
403+
)
419404
},
420405

421406
// We expect two calls but not the third one, because the second action fails
@@ -433,7 +418,6 @@ As the resource did not change, these actions will be re-invoked in the next app
433418
},
434419

435420
"failing an action stops next action triggers": {
436-
toBeImplemented: true, // We need to revisit the diagnostic enhancement
437421
module: map[string]string{
438422
"main.tf": `
439423
action "act_unlinked" "hello" {}
@@ -475,15 +459,19 @@ resource "test_object" "a" {
475459
}
476460
return tfdiags.Diagnostics{}
477461
},
478-
expectDiagnostics: tfdiags.Diagnostics{
479-
tfdiags.Sourceless(
480-
tfdiags.Error,
481-
"Failed to apply actions before test_object.a",
482-
`An error occured while invoking action action.act_unlinked.failure: test case for failing: this simulates a provider failing
483-
The following actions were successfully invoked:
484-
- action.act_unlinked.hello
485-
As the resource did not change, these actions will be re-invoked in the next apply.`,
486-
),
462+
expectDiagnostics: func(m *configs.Config) tfdiags.Diagnostics {
463+
return tfdiags.Diagnostics{}.Append(
464+
&hcl.Diagnostic{
465+
Severity: hcl.DiagError,
466+
Summary: "Error when invoking action",
467+
Detail: "test case for failing: this simulates a provider failing",
468+
Subject: &hcl.Range{
469+
Filename: filepath.Join(m.Module.SourceDir, "main.tf"),
470+
Start: hcl.Pos{Line: 17, Column: 18, Byte: 355},
471+
End: hcl.Pos{Line: 17, Column: 45, Byte: 382},
472+
},
473+
},
474+
)
487475
},
488476
// We expect two calls but not the third one, because the second action fails
489477
expectInvokeActionCalls: []providers.InvokeActionRequest{{
@@ -962,8 +950,8 @@ resource "test_object" "a" {
962950
tfdiags.AssertNoDiagnostics(t, diags)
963951

964952
_, diags = ctx.Apply(plan, m, nil)
965-
if tc.expectDiagnostics.HasErrors() {
966-
tfdiags.AssertDiagnosticsMatch(t, diags, tc.expectDiagnostics)
953+
if tc.expectDiagnostics != nil {
954+
tfdiags.AssertDiagnosticsMatch(t, diags, tc.expectDiagnostics(m))
967955
} else {
968956
tfdiags.AssertNoDiagnostics(t, diags)
969957
}

0 commit comments

Comments
 (0)