Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/v1.15/ENHANCEMENTS-20260223-130341.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: ENHANCEMENTS
body: "mocking: computed values are now correctly filled for nested list, set, and map attributes when using mock and override data in tests."
time: 2026-02-23T13:03:41.913383+01:00
custom:
Issue: "37939"
124 changes: 119 additions & 5 deletions internal/command/test_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ func TestTest_Runs(t *testing.T) {
code: 0,
},
"mocking": {
expectedOut: []string{"10 passed, 0 failed."},
expectedOut: []string{"11 passed, 0 failed."},
code: 0,
},
"mocking-invalid": {
Expand Down Expand Up @@ -377,12 +377,14 @@ func TestTest_Runs(t *testing.T) {
code: 0,
},
"write-only-attributes-mocked": {
expectedOut: []string{"1 passed, 0 failed."},
code: 0,
expectedOut: []string{"0 passed, 1 failed."},
expectedErr: []string{"Test assertion failed", "wrong value"},
code: 1,
},
"write-only-attributes-overridden": {
expectedOut: []string{"1 passed, 0 failed."},
code: 0,
expectedOut: []string{"0 passed, 1 failed."},
expectedErr: []string{"Test assertion failed", "wrong value"},
code: 1,
},
"with-default-variables": {
args: []string{"-var=input_two=universe"},
Expand Down Expand Up @@ -5674,6 +5676,118 @@ func TestTest_TeardownOrder(t *testing.T) {
}
}

func TestTest_OverrideDataMocking(t *testing.T) {
tcs := map[string]struct {
dir string
expectedCode int
expectedStdout string
expectedStderr string
}{
"plain_list_attribute": {
dir: "override_data_list_attribute",
expectedCode: 0,
expectedStdout: "1 passed, 0 failed.",
},
"nested_list_attribute": {
dir: "override_data_nested_list_attribute",
expectedCode: 0,
expectedStdout: "1 passed, 0 failed.",
},
"nested_list_attribute_with_object_value": {
dir: "override_data_nested_list_attribute_object",
expectedCode: 0,
expectedStdout: "1 passed, 0 failed.",
},
"nested_list_attribute_with_invalid_type_value": {
dir: "override_data_nested_list_attribute_invalid_type",
expectedCode: 1,
expectedStderr: "incompatible types; expected list of object, found",
},
"list_attribute_with_partial_element_values": {
dir: "override_data_list_attribute_partial_elements",
expectedCode: 0,
expectedStdout: "1 passed, 0 failed.",
},
"set_attribute_with_partial_element_values": {
dir: "override_data_complex_set_attribute_partial_elements",
expectedCode: 0,
expectedStdout: "1 passed, 0 failed.",
},
"nested_set_attribute_with_object_value": {
dir: "override_data_complex_nested_set_attribute_object",
expectedCode: 0,
expectedStdout: "1 passed, 0 failed.",
},
"nested_list_attribute_with_partial_element_values": {
dir: "override_data_nested_list_attribute_partial_elements",
expectedCode: 0,
expectedStdout: "1 passed, 0 failed.",
},
}

for name, tc := range tcs {
t.Run(name, func(t *testing.T) {
td := t.TempDir()
testCopyDir(t, testFixturePath(path.Join("test", tc.dir)), td)
t.Chdir(td)

provider := testing_command.NewProvider(nil)
providerSource, closeFn := newMockProviderSource(t, map[string][]string{
"test": {"1.0.0"},
})
defer closeFn()

streams, done := terminal.StreamsForTesting(t)
view := views.NewView(streams)
ui := new(cli.MockUi)

meta := Meta{
testingOverrides: metaOverridesForProvider(provider.Provider),
Ui: ui,
View: view,
Streams: streams,
ProviderSource: providerSource,
}

init := &InitCommand{
Meta: meta,
}

if code := init.Run(nil); code != 0 {
output := done(t)
t.Fatalf("expected init status code 0 but got %d: %s", code, output.All())
}

streams, done = terminal.StreamsForTesting(t)
meta.Streams = streams
meta.View = views.NewView(streams)

c := &TestCommand{
Meta: meta,
}

code := c.Run([]string{"-no-color"})
output := done(t)

if code != tc.expectedCode {
t.Fatalf("expected status code %d but got %d:\n\n%s", tc.expectedCode, code, output.All())
}

if tc.expectedStdout != "" && !strings.Contains(output.Stdout(), tc.expectedStdout) {
t.Errorf("expected stdout to contain %q but got:\n\nstdout:\n%s\nstderr:\n%s", tc.expectedStdout, output.Stdout(), output.Stderr())
}

if tc.expectedStderr != "" && !strings.Contains(output.Stderr(), tc.expectedStderr) {
t.Errorf("expected stderr to contain %q but got:\n\nstdout:\n%s\nstderr:\n%s", tc.expectedStderr, output.Stdout(), output.Stderr())
}

if tc.expectedCode == 0 && output.Stderr() != "" {
t.Errorf("unexpected stderr output:\n%s", output.Stderr())
}
})
}
}

// testModuleInline takes a map of path -> config strings and yields a config
// structure with those files loaded from disk
func testModuleInline(t *testing.T, sources map[string]string) (*configs.Config, string, func()) {
Expand Down
11 changes: 8 additions & 3 deletions internal/command/testdata/test/mocking/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ variable "child_instances" {

resource "test_resource" "primary" {
provider = test.primary
count = var.instances
count = var.instances
}

resource "test_complex_resource" "primary" {
provider = test.primary
count = var.instances
}

resource "test_resource" "secondary" {
provider = test.secondary
count = var.instances
count = var.instances
}

module "child" {
Expand All @@ -38,7 +43,7 @@ module "child" {
source = "./child"

providers = {
test.primary = test.primary
test.primary = test.primary
test.secondary = test.secondary
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
mock_provider "test" {
alias = "primary"

mock_resource "test_complex_resource" {
defaults = {
id = "aaaa"
list_value = [{name = "first"}, {name = "second"}]
nested_list_value = [{name = "first"}, {name = "second"}]
set_value = [{name = "first"}, {name = "second"}]
nested_set_value = [{name = "first"}, {name = "second"}]
map_value = tomap({
"key1": {
name = "first"
},
"key2": {
name = "third"
}
})
nested_map_value = tomap({
"key1": {
name = "first"
},
"key2": {
name = "third"
}
})
}
}
}

variables {
instances = 1
child_instances = 0
}


run "test" {

assert {
condition = test_complex_resource.primary[0].id == "aaaa"
error_message = "did not apply mocks"
}

assert {
condition = test_complex_resource.primary[0].list_value[0].name == "first"
error_message = "did not apply mocks"
}

assert {
condition = test_complex_resource.primary[0].nested_list_value[0].name == "first"
error_message = "did not apply mocks"
}

assert {
condition = test_complex_resource.primary[0].map_value["key1"].name == "first"
error_message = "did not apply mocks"
}

assert {
condition = test_complex_resource.primary[0].nested_map_value["key1"].name == "first"
error_message = "did not apply mocks"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
provider "test" {}

override_data {
target = data.test_complex_data_source.datasource
values = {
list_value = [
{
name = "first"
value = "one"
},
{
name = "second"
value = "two"
},
]
}
}

run "test_override_data_list_attribute" {
command = plan

assert {
condition = length(data.test_complex_data_source.datasource.list_value) == 2
error_message = "Expected list_value to have 2 elements, got ${length(data.test_complex_data_source.datasource.list_value)}"
}

assert {
condition = data.test_complex_data_source.datasource.list_value[0].name == "first"
error_message = "Expected first element name to be 'first'"
}
}
15 changes: 15 additions & 0 deletions internal/command/testdata/test/override_data_attribute/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
terraform {
required_providers {
test = {
source = "hashicorp/test"
}
}
}

data "test_complex_data_source" "datasource" {
id = "resource"
}

output "set_value" {
value = data.test_complex_data_source.datasource.set_value
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
provider "test" {}

override_data {
target = data.test_complex_data_source.datasource
values = {
map_value = {
"key1" = {
name = "first"
value = "one"
}
"key2" = {
name = "second"
value = "two"
}
}
}
}

run "test_override_data_map_attribute" {
command = plan

assert {
condition = length(data.test_complex_data_source.datasource.map_value) == 2
error_message = "Expected map_value to have 2 elements, got ${length(data.test_complex_data_source.datasource.map_value)}"
}

assert {
condition = data.test_complex_data_source.datasource.map_value["key1"].name == "first"
error_message = "Expected key1 name to be 'first'"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
provider "test" {}

override_data {
target = data.test_complex_data_source.datasource
values = {
nested_list_value = [
{
name = "first"
value = "one"
},
{
name = "second"
value = "two"
},
]
}
}

run "test_override_data_nested_list_attribute" {
command = plan

assert {
condition = length(data.test_complex_data_source.datasource.nested_list_value) == 2
error_message = "Expected nested_list_value to have 2 elements, got ${length(data.test_complex_data_source.datasource.nested_list_value)}"
}

assert {
condition = data.test_complex_data_source.datasource.nested_list_value[0].name == "first"
error_message = "Expected first element name to be 'first'"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
provider "test" {}

override_data {
target = data.test_complex_data_source.datasource
values = {
nested_map_value = {
"key1" = {
name = "first"
value = "one"
}
"key2" = {
name = "second"
value = "two"
}
}
}
}

run "test_override_data_nested_map_attribute" {
command = plan

assert {
condition = length(data.test_complex_data_source.datasource.nested_map_value) == 2
error_message = "Expected nested_map_value to have 2 elements, got ${length(data.test_complex_data_source.datasource.nested_map_value)}"
}

assert {
condition = data.test_complex_data_source.datasource.nested_map_value["key1"].name == "first"
error_message = "Expected key1 name to be 'first'"
}

}
Loading
Loading