Skip to content

Commit 408f323

Browse files
author
Liam Cervante
authored
test: also allow mock_data and mock_resource blocks to generate data during planning (#36317)
1 parent e5d4a51 commit 408f323

File tree

12 files changed

+120
-80
lines changed

12 files changed

+120
-80
lines changed

internal/command/test_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ func TestTest_Runs(t *testing.T) {
221221
code: 0,
222222
},
223223
"mocking": {
224-
expectedOut: []string{"9 passed, 0 failed."},
224+
expectedOut: []string{"10 passed, 0 failed."},
225225
code: 0,
226226
},
227227
"mocking-invalid": {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
mock_resource "test_resource" {
2+
override_during = plan
3+
defaults = {
4+
id = "aaaa"
5+
}
6+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
mock_provider "test" {
2+
alias = "primary"
3+
4+
source ="./tests/mocks"
5+
}
6+
7+
mock_provider "test" {
8+
alias = "secondary"
9+
10+
mock_resource "test_resource" {
11+
override_during = plan
12+
defaults = {
13+
id = "bbbb"
14+
}
15+
}
16+
}
17+
18+
variables {
19+
instances = 1
20+
child_instances = 1
21+
}
22+
23+
24+
run "test" {
25+
command = plan
26+
27+
assert {
28+
condition = test_resource.primary[0].id == "aaaa"
29+
error_message = "did not apply mocks"
30+
}
31+
32+
assert {
33+
condition = module.child[0].primary[0].id == "aaaa"
34+
error_message = "did not apply mocks"
35+
}
36+
37+
assert {
38+
condition = test_resource.secondary[0].id == "bbbb"
39+
error_message = "wrongly applied mocks"
40+
}
41+
42+
assert {
43+
condition = module.child[0].secondary[0].id == "bbbb"
44+
error_message = "wrongly applied mocks"
45+
}
46+
47+
}

internal/configs/config_build_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ func TestBuildConfig_WithMockDataSources(t *testing.T) {
308308

309309
cfg, diags := BuildConfig(mod, nil, MockDataLoaderFunc(func(provider *Provider) (*MockData, hcl.Diagnostics) {
310310
sourcePath := filepath.Join("testdata/valid-modules/with-mock-sources", provider.MockDataExternalSource)
311-
return parser.LoadMockDataDir(sourcePath, hcl.Range{})
311+
return parser.LoadMockDataDir(sourcePath, provider.MockDataDuringPlan, hcl.Range{})
312312
}))
313313
assertNoDiagnostics(t, diags)
314314
if cfg == nil {
@@ -339,7 +339,7 @@ func TestBuildConfig_WithMockDataSourcesInline(t *testing.T) {
339339

340340
cfg, diags := BuildConfig(mod, nil, MockDataLoaderFunc(func(provider *Provider) (*MockData, hcl.Diagnostics) {
341341
sourcePath := filepath.Join("testdata/valid-modules/with-mock-sources-inline", provider.MockDataExternalSource)
342-
return parser.LoadMockDataDir(sourcePath, hcl.Range{})
342+
return parser.LoadMockDataDir(sourcePath, provider.MockDataDuringPlan, hcl.Range{})
343343
}))
344344
assertNoDiagnostics(t, diags)
345345
if cfg == nil {

internal/configs/configload/loader_load.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (l *Loader) LoadExternalMockData(provider *configs.Provider) (*configs.Mock
5858
}
5959

6060
// Otherwise, just hand this off to the parser to handle.
61-
return l.parser.LoadMockDataDir(provider.MockDataExternalSource, provider.DeclRange)
61+
return l.parser.LoadMockDataDir(provider.MockDataExternalSource, provider.MockDataDuringPlan, provider.DeclRange)
6262
}
6363

6464
// moduleWalkerLoad is a configs.ModuleWalkerFunc for loading modules that

internal/configs/mock_provider.go

Lines changed: 44 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,12 @@ func decodeMockProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
6060
}
6161
}
6262

63+
useForPlan, useForPlanDiags := useForPlan(content, false)
64+
diags = append(diags, useForPlanDiags...)
65+
provider.MockDataDuringPlan = useForPlan
66+
6367
var dataDiags hcl.Diagnostics
64-
provider.MockData, dataDiags = decodeMockDataBody(config, MockProviderOverrideSource)
68+
provider.MockData, dataDiags = decodeMockDataBody(config, useForPlan, MockProviderOverrideSource)
6569
diags = append(diags, dataDiags...)
6670

6771
if attr, exists := content.Attributes["source"]; exists {
@@ -72,23 +76,25 @@ func decodeMockProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
7276
return provider, diags
7377
}
7478

75-
func extractOverrideDuring(content *hcl.BodyContent) (*string, hcl.Diagnostics) {
79+
func useForPlan(content *hcl.BodyContent, def bool) (bool, hcl.Diagnostics) {
7680
var diags hcl.Diagnostics
77-
7881
if attr, exists := content.Attributes[overrideDuringCommand]; exists {
79-
overrideComputedStr := hcl.ExprAsKeyword(attr.Expr)
80-
if overrideComputedStr != "plan" && overrideComputedStr != "apply" {
82+
switch hcl.ExprAsKeyword(attr.Expr) {
83+
case "plan":
84+
return true, diags
85+
case "apply":
86+
return false, diags
87+
default:
8188
diags = diags.Append(&hcl.Diagnostic{
8289
Severity: hcl.DiagError,
8390
Summary: fmt.Sprintf("Invalid %s value", overrideDuringCommand),
8491
Detail: fmt.Sprintf("The %s attribute must be a value of plan or apply.", overrideDuringCommand),
8592
Subject: attr.Range.Ptr(),
8693
})
94+
return def, diags
8795
}
88-
return &overrideComputedStr, diags
8996
}
90-
91-
return nil, diags
97+
return def, diags
9298
}
9399

94100
// MockData packages up all the available mock and override data available to
@@ -97,10 +103,6 @@ type MockData struct {
97103
MockResources map[string]*MockResource
98104
MockDataSources map[string]*MockResource
99105
Overrides addrs.Map[addrs.Targetable, *Override]
100-
101-
// UseForPlan returns true if the provider-level setting for overrideComputed
102-
// is true, meaning that computed values can be overridden with the mocked values during planning.
103-
UseForPlan bool
104106
}
105107

106108
// Merge will merge the target MockData object into the current MockData.
@@ -180,6 +182,10 @@ type MockResource struct {
180182

181183
Defaults cty.Value
182184

185+
// UseForPlan is true if the values should be computed during the planning
186+
// phase.
187+
UseForPlan bool
188+
183189
Range hcl.Range
184190
TypeRange hcl.Range
185191
DefaultsRange hcl.Range
@@ -202,12 +208,9 @@ type Override struct {
202208
Target *addrs.Target
203209
Values cty.Value
204210

205-
// By default, overridden computed values are ignored during planning,
206-
// and the computed values are set to unknown to simulate the behavior
207-
// of a real plan. This attribute indicates that the computed values
208-
// should be overridden with the values specified in the override block,
209-
// even when planning.
210-
useForPlan *bool
211+
// UseForPlan is true if the values should be computed during the planning
212+
// phase.
213+
UseForPlan bool
211214

212215
// Source tells us where this Override was defined.
213216
Source OverrideSource
@@ -218,33 +221,22 @@ type Override struct {
218221
ValuesRange hcl.Range
219222
}
220223

221-
// UseForPlan returns true if the computed values in the target
222-
// resource can be overridden with the values specified in the override block.
223-
func (o *Override) UseForPlan() bool {
224-
return o.useForPlan != nil && *o.useForPlan
225-
}
226-
227-
func decodeMockDataBody(body hcl.Body, source OverrideSource) (*MockData, hcl.Diagnostics) {
224+
func decodeMockDataBody(body hcl.Body, useForPlanDefault bool, source OverrideSource) (*MockData, hcl.Diagnostics) {
228225
var diags hcl.Diagnostics
229226

230227
content, contentDiags := body.Content(mockDataSchema)
231228
diags = append(diags, contentDiags...)
232229

233-
// provider-level setting for overrideComputed
234-
providerOverrideComputed, valueDiags := extractOverrideDuring(content)
235-
diags = append(diags, valueDiags...)
236-
useForPlan := providerOverrideComputed != nil && *providerOverrideComputed == "plan"
237230
data := &MockData{
238231
MockResources: make(map[string]*MockResource),
239232
MockDataSources: make(map[string]*MockResource),
240233
Overrides: addrs.MakeMap[addrs.Targetable, *Override](),
241-
UseForPlan: useForPlan,
242234
}
243235

244236
for _, block := range content.Blocks {
245237
switch block.Type {
246238
case "mock_resource", "mock_data":
247-
resource, resourceDiags := decodeMockResourceBlock(block)
239+
resource, resourceDiags := decodeMockResourceBlock(block, useForPlanDefault)
248240
diags = append(diags, resourceDiags...)
249241

250242
if resource != nil {
@@ -274,7 +266,7 @@ func decodeMockDataBody(body hcl.Body, source OverrideSource) (*MockData, hcl.Di
274266
}
275267
}
276268
case "override_resource":
277-
override, overrideDiags := decodeOverrideResourceBlock(block, source)
269+
override, overrideDiags := decodeOverrideResourceBlock(block, useForPlanDefault, source)
278270
diags = append(diags, overrideDiags...)
279271

280272
if override != nil && override.Target != nil {
@@ -291,7 +283,7 @@ func decodeMockDataBody(body hcl.Body, source OverrideSource) (*MockData, hcl.Di
291283
data.Overrides.Put(subject, override)
292284
}
293285
case "override_data":
294-
override, overrideDiags := decodeOverrideDataBlock(block, source)
286+
override, overrideDiags := decodeOverrideDataBlock(block, useForPlanDefault, source)
295287
diags = append(diags, overrideDiags...)
296288

297289
if override != nil && override.Target != nil {
@@ -310,19 +302,10 @@ func decodeMockDataBody(body hcl.Body, source OverrideSource) (*MockData, hcl.Di
310302
}
311303
}
312304

313-
for _, elem := range data.Overrides.Elements() {
314-
// use the provider-level setting if there is none set for this override
315-
useForPlan := providerOverrideComputed != nil && *providerOverrideComputed == "plan"
316-
if elem.Value.useForPlan == nil {
317-
elem.Value.useForPlan = &useForPlan
318-
}
319-
data.Overrides.Put(elem.Key, elem.Value)
320-
}
321-
322305
return data, diags
323306
}
324307

325-
func decodeMockResourceBlock(block *hcl.Block) (*MockResource, hcl.Diagnostics) {
308+
func decodeMockResourceBlock(block *hcl.Block, useForPlanDefault bool) (*MockResource, hcl.Diagnostics) {
326309
var diags hcl.Diagnostics
327310

328311
content, contentDiags := block.Body.Content(mockResourceSchema)
@@ -352,11 +335,15 @@ func decodeMockResourceBlock(block *hcl.Block) (*MockResource, hcl.Diagnostics)
352335
resource.Defaults = cty.NilVal
353336
}
354337

338+
useForPlan, useForPlanDiags := useForPlan(content, useForPlanDefault)
339+
diags = append(diags, useForPlanDiags...)
340+
resource.UseForPlan = useForPlan
341+
355342
return resource, diags
356343
}
357344

358-
func decodeOverrideModuleBlock(block *hcl.Block, source OverrideSource) (*Override, hcl.Diagnostics) {
359-
override, diags := decodeOverrideBlock(block, "outputs", "override_module", source)
345+
func decodeOverrideModuleBlock(block *hcl.Block, useForPlanDefault bool, source OverrideSource) (*Override, hcl.Diagnostics) {
346+
override, diags := decodeOverrideBlock(block, "outputs", "override_module", useForPlanDefault, source)
360347

361348
if override.Target != nil {
362349
switch override.Target.Subject.AddrType() {
@@ -376,8 +363,8 @@ func decodeOverrideModuleBlock(block *hcl.Block, source OverrideSource) (*Overri
376363
return override, diags
377364
}
378365

379-
func decodeOverrideResourceBlock(block *hcl.Block, source OverrideSource) (*Override, hcl.Diagnostics) {
380-
override, diags := decodeOverrideBlock(block, "values", "override_resource", source)
366+
func decodeOverrideResourceBlock(block *hcl.Block, useForPlanDefault bool, source OverrideSource) (*Override, hcl.Diagnostics) {
367+
override, diags := decodeOverrideBlock(block, "values", "override_resource", useForPlanDefault, source)
381368

382369
if override.Target != nil {
383370
var mode addrs.ResourceMode
@@ -413,8 +400,8 @@ func decodeOverrideResourceBlock(block *hcl.Block, source OverrideSource) (*Over
413400
return override, diags
414401
}
415402

416-
func decodeOverrideDataBlock(block *hcl.Block, source OverrideSource) (*Override, hcl.Diagnostics) {
417-
override, diags := decodeOverrideBlock(block, "values", "override_data", source)
403+
func decodeOverrideDataBlock(block *hcl.Block, useForPlanDefault bool, source OverrideSource) (*Override, hcl.Diagnostics) {
404+
override, diags := decodeOverrideBlock(block, "values", "override_data", useForPlanDefault, source)
418405

419406
if override.Target != nil {
420407
var mode addrs.ResourceMode
@@ -450,7 +437,7 @@ func decodeOverrideDataBlock(block *hcl.Block, source OverrideSource) (*Override
450437
return override, diags
451438
}
452439

453-
func decodeOverrideBlock(block *hcl.Block, attributeName string, blockName string, source OverrideSource) (*Override, hcl.Diagnostics) {
440+
func decodeOverrideBlock(block *hcl.Block, attributeName string, blockName string, useForPlanDefault bool, source OverrideSource) (*Override, hcl.Diagnostics) {
454441
var diags hcl.Diagnostics
455442

456443
content, contentDiags := block.Body.Content(&hcl.BodySchema{
@@ -498,13 +485,9 @@ func decodeOverrideBlock(block *hcl.Block, attributeName string, blockName strin
498485
override.Values = cty.EmptyObjectVal
499486
}
500487

501-
// Override computed values during planning if override_during is plan.
502-
overrideComputedStr, valueDiags := extractOverrideDuring(content)
503-
diags = append(diags, valueDiags...)
504-
if overrideComputedStr != nil {
505-
useForPlan := *overrideComputedStr == "plan"
506-
override.useForPlan = &useForPlan
507-
}
488+
useForPlan, useForPlanDiags := useForPlan(content, useForPlanDefault)
489+
diags = append(diags, useForPlanDiags...)
490+
override.UseForPlan = useForPlan
508491

509492
if !override.Values.Type().IsObjectType() {
510493

@@ -535,13 +518,13 @@ var mockProviderSchema = &hcl.BodySchema{
535518
{
536519
Name: "source",
537520
},
521+
{
522+
Name: overrideDuringCommand,
523+
},
538524
},
539525
}
540526

541527
var mockDataSchema = &hcl.BodySchema{
542-
Attributes: []hcl.AttributeSchema{
543-
{Name: overrideDuringCommand},
544-
},
545528
Blocks: []hcl.BlockHeaderSchema{
546529
{Type: "mock_resource", LabelNames: []string{"type"}},
547530
{Type: "mock_data", LabelNames: []string{"type"}},
@@ -553,5 +536,6 @@ var mockDataSchema = &hcl.BodySchema{
553536
var mockResourceSchema = &hcl.BodySchema{
554537
Attributes: []hcl.AttributeSchema{
555538
{Name: "defaults"},
539+
{Name: overrideDuringCommand},
556540
},
557541
}

internal/configs/parser_config.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ func (p *Parser) LoadTestFile(path string) (*TestFile, hcl.Diagnostics) {
5353
//
5454
// It references the same LoadHCLFile as LoadConfigFile, so inherits the same
5555
// syntax selection behaviours.
56-
func (p *Parser) LoadMockDataFile(path string) (*MockData, hcl.Diagnostics) {
56+
func (p *Parser) LoadMockDataFile(path string, useForPlanDefault bool) (*MockData, hcl.Diagnostics) {
5757
body, diags := p.LoadHCLFile(path)
5858
if body == nil {
5959
return nil, diags
6060
}
6161

62-
data, dataDiags := decodeMockDataBody(body, MockDataFileOverrideSource)
62+
data, dataDiags := decodeMockDataBody(body, useForPlanDefault, MockDataFileOverrideSource)
6363
diags = append(diags, dataDiags...)
6464
return data, diags
6565
}

internal/configs/parser_config_dir.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func (p *Parser) LoadConfigDirWithTests(path string, testDirectory string) (*Mod
7878
return mod, diags
7979
}
8080

81-
func (p *Parser) LoadMockDataDir(dir string, source hcl.Range) (*MockData, hcl.Diagnostics) {
81+
func (p *Parser) LoadMockDataDir(dir string, useForPlanDefault bool, source hcl.Range) (*MockData, hcl.Diagnostics) {
8282
var diags hcl.Diagnostics
8383

8484
infos, err := p.fs.ReadDir(dir)
@@ -113,7 +113,7 @@ func (p *Parser) LoadMockDataDir(dir string, source hcl.Range) (*MockData, hcl.D
113113

114114
var data *MockData
115115
for _, file := range files {
116-
current, currentDiags := p.LoadMockDataFile(file)
116+
current, currentDiags := p.LoadMockDataFile(file, useForPlanDefault)
117117
diags = append(diags, currentDiags...)
118118
if data != nil {
119119
diags = append(diags, data.Merge(current, false)...)

internal/configs/provider.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,12 @@ type Provider struct {
3838

3939
// Mock and MockData declare this provider as a "mock_provider", which means
4040
// it should use the data in MockData instead of actually initialising the
41-
// provider.
42-
Mock bool
43-
MockData *MockData
41+
// provider. MockDataDuringPlan tells the provider that, by default, it
42+
// should generate values during the planning stage instead of waiting for
43+
// the apply stage.
44+
Mock bool
45+
MockDataDuringPlan bool
46+
MockData *MockData
4447

4548
// MockDataExternalSource is a file path pointing to the external data
4649
// file for a mock provider. An empty string indicates all data should be

0 commit comments

Comments
 (0)