From 7c0a5a34afd6258727e75c729a877cd36b06ef9b Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 12:50:00 -0700 Subject: [PATCH 01/14] `ExpectError` is supported --- internal/service/ec2/vpc_list_test.go | 2 -- internal/service/ec2/vpc_subnet_list_test.go | 2 -- 2 files changed, 4 deletions(-) diff --git a/internal/service/ec2/vpc_list_test.go b/internal/service/ec2/vpc_list_test.go index 761fa852f20a..cdd5086c69e6 100644 --- a/internal/service/ec2/vpc_list_test.go +++ b/internal/service/ec2/vpc_list_test.go @@ -433,8 +433,6 @@ func TestAccVPC_List_filteredVPCIDs(t *testing.T) { } func TestAccVPC_List_Filtered_isDefault(t *testing.T) { - t.Skip("Skipping because ExpectError is not currently supported for Query mode") - ctx := acctest.Context(t) acctest.ParallelTest(ctx, t, resource.TestCase{ diff --git a/internal/service/ec2/vpc_subnet_list_test.go b/internal/service/ec2/vpc_subnet_list_test.go index 8c025bfba4c7..c82d846bbc02 100644 --- a/internal/service/ec2/vpc_subnet_list_test.go +++ b/internal/service/ec2/vpc_subnet_list_test.go @@ -428,8 +428,6 @@ func TestAccVPCSubnet_List_filteredSubnetIDs(t *testing.T) { } func TestAccVPCSubnet_List_Filtered_defaultForAZ(t *testing.T) { - t.Skip("Skipping because ExpectError is not currently supported for Query mode") - ctx := acctest.Context(t) acctest.ParallelTest(ctx, t, resource.TestCase{ From a1837b3aa9e525d1e550a106de813251914813ee Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 12:56:57 -0700 Subject: [PATCH 02/14] Updates `basic` test --- internal/service/ec2/vpc_list_test.go | 33 +++++++++++++++------------ 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/internal/service/ec2/vpc_list_test.go b/internal/service/ec2/vpc_list_test.go index cdd5086c69e6..b3dd4b03439c 100644 --- a/internal/service/ec2/vpc_list_test.go +++ b/internal/service/ec2/vpc_list_test.go @@ -16,6 +16,8 @@ import ( "github.com/hashicorp/terraform-plugin-testing/tfversion" "github.com/hashicorp/terraform-provider-aws/internal/acctest" tfknownvalue "github.com/hashicorp/terraform-provider-aws/internal/acctest/knownvalue" + tfquerycheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/querycheck" + tfqueryfilter "github.com/hashicorp/terraform-provider-aws/internal/acctest/queryfilter" tfstatecheck "github.com/hashicorp/terraform-provider-aws/internal/acctest/statecheck" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -31,6 +33,10 @@ func TestAccVPC_List_basic(t *testing.T) { id2 := tfstatecheck.StateValue() id3 := tfstatecheck.StateValue() + identity1 := tfstatecheck.Identity() + identity2 := tfstatecheck.Identity() + identity3 := tfstatecheck.Identity() + acctest.ParallelTest(ctx, t, resource.TestCase{ TerraformVersionChecks: []tfversion.TerraformVersionCheck{ tfversion.SkipBelow(tfversion.Version1_14_0), @@ -44,12 +50,15 @@ func TestAccVPC_List_basic(t *testing.T) { { ConfigDirectory: config.StaticDirectory("testdata/VPC/list_basic"), ConfigStateChecks: []statecheck.StateCheck{ + identity1.GetIdentity(resourceName1), id1.GetStateValue(resourceName1, tfjsonpath.New(names.AttrID)), tfstatecheck.ExpectRegionalARNFormat(resourceName1, tfjsonpath.New(names.AttrARN), "ec2", "vpc/{id}"), + identity2.GetIdentity(resourceName2), id2.GetStateValue(resourceName2, tfjsonpath.New(names.AttrID)), tfstatecheck.ExpectRegionalARNFormat(resourceName2, tfjsonpath.New(names.AttrARN), "ec2", "vpc/{id}"), + identity3.GetIdentity(resourceName3), id3.GetStateValue(resourceName3, tfjsonpath.New(names.AttrID)), tfstatecheck.ExpectRegionalARNFormat(resourceName3, tfjsonpath.New(names.AttrARN), "ec2", "vpc/{id}"), }, @@ -60,23 +69,17 @@ func TestAccVPC_List_basic(t *testing.T) { Query: true, ConfigDirectory: config.StaticDirectory("testdata/VPC/list_basic"), QueryResultChecks: []querycheck.QueryResultCheck{ - querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ - names.AttrAccountID: tfknownvalue.AccountID(), - names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id1.Value(), - }), + tfquerycheck.ExpectIdentityFunc("aws_vpc.test", identity1.Checks()), + querycheck.ExpectResourceDisplayName("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity1.Checks()), id1.Value()), + tfquerycheck.ExpectNoResourceObject("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity1.Checks())), - querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ - names.AttrAccountID: tfknownvalue.AccountID(), - names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id2.Value(), - }), + tfquerycheck.ExpectIdentityFunc("aws_vpc.test", identity2.Checks()), + querycheck.ExpectResourceDisplayName("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity2.Checks()), id2.Value()), + tfquerycheck.ExpectNoResourceObject("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity2.Checks())), - querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ - names.AttrAccountID: tfknownvalue.AccountID(), - names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id3.Value(), - }), + tfquerycheck.ExpectIdentityFunc("aws_vpc.test", identity3.Checks()), + querycheck.ExpectResourceDisplayName("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity3.Checks()), id3.Value()), + tfquerycheck.ExpectNoResourceObject("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity3.Checks())), }, }, }, From 5e58a5a2ba33745d4c731332b8a5ebaeaf9c8c0f Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 13:36:43 -0700 Subject: [PATCH 03/14] Renames `Value` function to `ValueCheck` --- internal/acctest/statecheck/state_value.go | 6 +-- .../acctest/statecheck/state_value_test.go | 6 +-- .../service/batch/job_definition_list_test.go | 4 +- .../ec2/ec2_secondary_subnet_list_test.go | 4 +- internal/service/ec2/vpc_list_test.go | 38 ++++++++--------- internal/service/ec2/vpc_route_list_test.go | 24 +++++------ .../service/ec2/vpc_route_table_list_test.go | 8 ++-- ...pc_security_group_egress_rule_list_test.go | 12 +++--- ...c_security_group_ingress_rule_list_test.go | 12 +++--- internal/service/ec2/vpc_subnet_list_test.go | 42 +++++++++---------- internal/service/ecr/repository_list_test.go | 6 +-- internal/service/iam/policy_list_test.go | 14 +++---- .../service/lambda/permission_list_test.go | 8 ++-- .../rule_association_list_test.go | 4 +- .../secretsmanager/secret_list_test.go | 4 +- .../secret_version_list_test.go | 8 ++-- 16 files changed, 100 insertions(+), 100 deletions(-) diff --git a/internal/acctest/statecheck/state_value.go b/internal/acctest/statecheck/state_value.go index 51d3bf404030..2a4c90bb6166 100644 --- a/internal/acctest/statecheck/state_value.go +++ b/internal/acctest/statecheck/state_value.go @@ -31,9 +31,9 @@ func (v *stateValue) GetStateValue(resourceAddress string, attributePath tfjsonp return newStateValueStateChecker(v) } -// Value checks the stored state value against the provided value. -// Calls to Value occur before any TestStep is run. -func (v *stateValue) Value() knownvalue.Check { +// ValueCheck checks the stored state value against the provided value. +// Calls to ValueCheck occur before any TestStep is run. +func (v *stateValue) ValueCheck() knownvalue.Check { return newStateValueKnownValueChecker(v) } diff --git a/internal/acctest/statecheck/state_value_test.go b/internal/acctest/statecheck/state_value_test.go index 2022ffec772a..6ce48fca7223 100644 --- a/internal/acctest/statecheck/state_value_test.go +++ b/internal/acctest/statecheck/state_value_test.go @@ -43,7 +43,7 @@ func TestStateValue_ValuesSame(t *testing.T) { //nolint:paralleltest // false po } `, ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue("test_resource.one", tfjsonpath.New("string_attribute"), stateValue.Value()), + statecheck.ExpectKnownValue("test_resource.one", tfjsonpath.New("string_attribute"), stateValue.ValueCheck()), }, }, }, @@ -77,7 +77,7 @@ func TestStateValue_ValuesNotSame(t *testing.T) { //nolint:paralleltest // false } `, ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue("test_resource.one", tfjsonpath.New("string_attribute"), stateValue.Value()), + statecheck.ExpectKnownValue("test_resource.one", tfjsonpath.New("string_attribute"), stateValue.ValueCheck()), }, ExpectError: regexache.MustCompile(`expected value same for StateValue check, got: not same`), }, @@ -103,7 +103,7 @@ func TestStateValue_NotInitialized(t *testing.T) { //nolint:paralleltest // fals } `, ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue("test_resource.one", tfjsonpath.New("string_attribute"), stateValue.Value()), + statecheck.ExpectKnownValue("test_resource.one", tfjsonpath.New("string_attribute"), stateValue.ValueCheck()), }, ExpectError: regexache.MustCompile(`state value has not been set`), }, diff --git a/internal/service/batch/job_definition_list_test.go b/internal/service/batch/job_definition_list_test.go index 31369e8b7089..42c658cb6b7f 100644 --- a/internal/service/batch/job_definition_list_test.go +++ b/internal/service/batch/job_definition_list_test.go @@ -64,11 +64,11 @@ func TestAccBatchJobDefinition_List_basic(t *testing.T) { }, QueryResultChecks: []querycheck.QueryResultCheck{ querycheck.ExpectIdentity("aws_batch_job_definition.test", map[string]knownvalue.Check{ - names.AttrARN: arn1.Value(), + names.AttrARN: arn1.ValueCheck(), }), querycheck.ExpectIdentity("aws_batch_job_definition.test", map[string]knownvalue.Check{ - names.AttrARN: arn2.Value(), + names.AttrARN: arn2.ValueCheck(), }), }, }, diff --git a/internal/service/ec2/ec2_secondary_subnet_list_test.go b/internal/service/ec2/ec2_secondary_subnet_list_test.go index 7a1aca387f45..4e5944d812b5 100644 --- a/internal/service/ec2/ec2_secondary_subnet_list_test.go +++ b/internal/service/ec2/ec2_secondary_subnet_list_test.go @@ -146,13 +146,13 @@ func testAccEC2SecondarySubnet_List_filtered(t *testing.T) { querycheck.ExpectNoIdentity("aws_ec2_secondary_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: notExpected1.Value(), + names.AttrID: notExpected1.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_ec2_secondary_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: notExpected2.Value(), + names.AttrID: notExpected2.ValueCheck(), }), }, }, diff --git a/internal/service/ec2/vpc_list_test.go b/internal/service/ec2/vpc_list_test.go index b3dd4b03439c..6c99f28618ac 100644 --- a/internal/service/ec2/vpc_list_test.go +++ b/internal/service/ec2/vpc_list_test.go @@ -70,15 +70,15 @@ func TestAccVPC_List_basic(t *testing.T) { ConfigDirectory: config.StaticDirectory("testdata/VPC/list_basic"), QueryResultChecks: []querycheck.QueryResultCheck{ tfquerycheck.ExpectIdentityFunc("aws_vpc.test", identity1.Checks()), - querycheck.ExpectResourceDisplayName("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity1.Checks()), id1.Value()), + querycheck.ExpectResourceDisplayName("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity1.Checks()), id1.ValueCheck()), tfquerycheck.ExpectNoResourceObject("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity1.Checks())), tfquerycheck.ExpectIdentityFunc("aws_vpc.test", identity2.Checks()), - querycheck.ExpectResourceDisplayName("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity2.Checks()), id2.Value()), + querycheck.ExpectResourceDisplayName("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity2.Checks()), id2.ValueCheck()), tfquerycheck.ExpectNoResourceObject("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity2.Checks())), tfquerycheck.ExpectIdentityFunc("aws_vpc.test", identity3.Checks()), - querycheck.ExpectResourceDisplayName("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity3.Checks()), id3.Value()), + querycheck.ExpectResourceDisplayName("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity3.Checks()), id3.ValueCheck()), tfquerycheck.ExpectNoResourceObject("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity3.Checks())), }, }, @@ -135,19 +135,19 @@ func TestAccVPC_List_regionOverride(t *testing.T) { querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: id1.Value(), + names.AttrID: id1.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: id2.Value(), + names.AttrID: id2.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: id3.Value(), + names.AttrID: id3.ValueCheck(), }), }, }, @@ -211,25 +211,25 @@ func TestAccVPC_List_filtered(t *testing.T) { querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: expected1.Value(), + names.AttrID: expected1.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: expected2.Value(), + names.AttrID: expected2.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: notExpected1.Value(), + names.AttrID: notExpected1.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: notExpected2.Value(), + names.AttrID: notExpected2.ValueCheck(), }), }, }, @@ -272,13 +272,13 @@ func TestAccVPC_List_DefaultVPC_exclude(t *testing.T) { querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id.Value(), + names.AttrID: id.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: defaultVPCID.Value(), + names.AttrID: defaultVPCID.ValueCheck(), }), }, }, @@ -331,19 +331,19 @@ func TestAccVPC_List_vpcIDs(t *testing.T) { querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id1.Value(), + names.AttrID: id1.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id2.Value(), + names.AttrID: id2.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id3.Value(), + names.AttrID: id3.ValueCheck(), }), }, }, @@ -409,25 +409,25 @@ func TestAccVPC_List_filteredVPCIDs(t *testing.T) { querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: expected1.Value(), + names.AttrID: expected1.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: expected2.Value(), + names.AttrID: expected2.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: notExpected1.Value(), + names.AttrID: notExpected1.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_vpc.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: notExpected2.Value(), + names.AttrID: notExpected2.ValueCheck(), }), }, }, diff --git a/internal/service/ec2/vpc_route_list_test.go b/internal/service/ec2/vpc_route_list_test.go index 3bdfafb6b4d3..fb92c7b4c1b5 100644 --- a/internal/service/ec2/vpc_route_list_test.go +++ b/internal/service/ec2/vpc_route_list_test.go @@ -62,16 +62,16 @@ func TestAccVPCRoute_List_basic(t *testing.T) { querycheck.ExpectIdentity("aws_route.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - "route_table_id": routeTableID.Value(), - "destination_cidr_block": destination1.Value(), + "route_table_id": routeTableID.ValueCheck(), + "destination_cidr_block": destination1.ValueCheck(), "destination_ipv6_cidr_block": knownvalue.Null(), "destination_prefix_list_id": knownvalue.Null(), }), querycheck.ExpectIdentity("aws_route.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - "route_table_id": routeTableID.Value(), - "destination_cidr_block": destination2.Value(), + "route_table_id": routeTableID.ValueCheck(), + "destination_cidr_block": destination2.ValueCheck(), "destination_ipv6_cidr_block": knownvalue.Null(), "destination_prefix_list_id": knownvalue.Null(), }), @@ -121,9 +121,9 @@ func TestAccVPCRoute_List_ipv6Destination(t *testing.T) { querycheck.ExpectIdentity("aws_route.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - "route_table_id": routeTableID.Value(), + "route_table_id": routeTableID.ValueCheck(), "destination_cidr_block": knownvalue.Null(), - "destination_ipv6_cidr_block": destinationIPv6.Value(), + "destination_ipv6_cidr_block": destinationIPv6.ValueCheck(), "destination_prefix_list_id": knownvalue.Null(), }), }, @@ -172,10 +172,10 @@ func TestAccVPCRoute_List_prefixListDestination(t *testing.T) { querycheck.ExpectIdentity("aws_route.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - "route_table_id": routeTableID.Value(), + "route_table_id": routeTableID.ValueCheck(), "destination_cidr_block": knownvalue.Null(), "destination_ipv6_cidr_block": knownvalue.Null(), - "destination_prefix_list_id": prefixListID.Value(), + "destination_prefix_list_id": prefixListID.ValueCheck(), }), }, }, @@ -228,16 +228,16 @@ func TestAccVPCRoute_List_regionOverride(t *testing.T) { querycheck.ExpectIdentity("aws_route.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - "route_table_id": routeTableID.Value(), - "destination_cidr_block": destination1.Value(), + "route_table_id": routeTableID.ValueCheck(), + "destination_cidr_block": destination1.ValueCheck(), "destination_ipv6_cidr_block": knownvalue.Null(), "destination_prefix_list_id": knownvalue.Null(), }), querycheck.ExpectIdentity("aws_route.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - "route_table_id": routeTableID.Value(), - "destination_cidr_block": destination2.Value(), + "route_table_id": routeTableID.ValueCheck(), + "destination_cidr_block": destination2.ValueCheck(), "destination_ipv6_cidr_block": knownvalue.Null(), "destination_prefix_list_id": knownvalue.Null(), }), diff --git a/internal/service/ec2/vpc_route_table_list_test.go b/internal/service/ec2/vpc_route_table_list_test.go index bcf42b246d4f..2a1df96818aa 100644 --- a/internal/service/ec2/vpc_route_table_list_test.go +++ b/internal/service/ec2/vpc_route_table_list_test.go @@ -62,12 +62,12 @@ func TestAccVPCRouteTable_List_basic(t *testing.T) { querycheck.ExpectIdentity("aws_route_table.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id1.Value(), + names.AttrID: id1.ValueCheck(), }), querycheck.ExpectIdentity("aws_route_table.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id2.Value(), + names.AttrID: id2.ValueCheck(), }), }, }, @@ -115,12 +115,12 @@ func TestAccVPCRouteTable_List_regionOverride(t *testing.T) { querycheck.ExpectIdentity("aws_route_table.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: id1.Value(), + names.AttrID: id1.ValueCheck(), }), querycheck.ExpectIdentity("aws_route_table.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: id2.Value(), + names.AttrID: id2.ValueCheck(), }), }, }, diff --git a/internal/service/ec2/vpc_security_group_egress_rule_list_test.go b/internal/service/ec2/vpc_security_group_egress_rule_list_test.go index bbeb86404b60..614fa146c7a0 100644 --- a/internal/service/ec2/vpc_security_group_egress_rule_list_test.go +++ b/internal/service/ec2/vpc_security_group_egress_rule_list_test.go @@ -60,12 +60,12 @@ func TestAccVPCSecurityGroupEgressRule_List_basic(t *testing.T) { querycheck.ExpectIdentity("aws_vpc_security_group_egress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: ruleID1.Value(), + names.AttrID: ruleID1.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc_security_group_egress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: ruleID2.Value(), + names.AttrID: ruleID2.ValueCheck(), }), }, }, @@ -114,12 +114,12 @@ func TestAccVPCSecurityGroupEgressRule_List_filter(t *testing.T) { querycheck.ExpectIdentity("aws_vpc_security_group_egress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: ruleID1.Value(), + names.AttrID: ruleID1.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc_security_group_egress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: ruleID2.Value(), + names.AttrID: ruleID2.ValueCheck(), }), }, }, @@ -167,12 +167,12 @@ func TestAccVPCSecurityGroupEgressRule_List_regionOverride(t *testing.T) { querycheck.ExpectIdentity("aws_vpc_security_group_egress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: ruleID1.Value(), + names.AttrID: ruleID1.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc_security_group_egress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: ruleID2.Value(), + names.AttrID: ruleID2.ValueCheck(), }), }, }, diff --git a/internal/service/ec2/vpc_security_group_ingress_rule_list_test.go b/internal/service/ec2/vpc_security_group_ingress_rule_list_test.go index 993f37c7a2b8..e2f39591134c 100644 --- a/internal/service/ec2/vpc_security_group_ingress_rule_list_test.go +++ b/internal/service/ec2/vpc_security_group_ingress_rule_list_test.go @@ -60,12 +60,12 @@ func TestAccVPCSecurityGroupIngressRule_List_basic(t *testing.T) { querycheck.ExpectIdentity("aws_vpc_security_group_ingress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: ruleID1.Value(), + names.AttrID: ruleID1.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc_security_group_ingress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: ruleID2.Value(), + names.AttrID: ruleID2.ValueCheck(), }), }, }, @@ -114,12 +114,12 @@ func TestAccVPCSecurityGroupIngressRule_List_filter(t *testing.T) { querycheck.ExpectIdentity("aws_vpc_security_group_ingress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: ruleID1.Value(), + names.AttrID: ruleID1.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc_security_group_ingress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: ruleID2.Value(), + names.AttrID: ruleID2.ValueCheck(), }), }, }, @@ -167,12 +167,12 @@ func TestAccVPCSecurityGroupIngressRule_List_regionOverride(t *testing.T) { querycheck.ExpectIdentity("aws_vpc_security_group_ingress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: ruleID1.Value(), + names.AttrID: ruleID1.ValueCheck(), }), querycheck.ExpectIdentity("aws_vpc_security_group_ingress_rule.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: ruleID2.Value(), + names.AttrID: ruleID2.ValueCheck(), }), }, }, diff --git a/internal/service/ec2/vpc_subnet_list_test.go b/internal/service/ec2/vpc_subnet_list_test.go index c82d846bbc02..e53806fe10b3 100644 --- a/internal/service/ec2/vpc_subnet_list_test.go +++ b/internal/service/ec2/vpc_subnet_list_test.go @@ -63,19 +63,19 @@ func TestAccVPCSubnet_List_basic(t *testing.T) { querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id1.Value(), + names.AttrID: id1.ValueCheck(), }), querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id2.Value(), + names.AttrID: id2.ValueCheck(), }), querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id3.Value(), + names.AttrID: id3.ValueCheck(), }), }, }, @@ -132,19 +132,19 @@ func TestAccVPCSubnet_List_regionOverride(t *testing.T) { querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: id1.Value(), + names.AttrID: id1.ValueCheck(), }), querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: id2.Value(), + names.AttrID: id2.ValueCheck(), }), querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrID: id3.Value(), + names.AttrID: id3.ValueCheck(), }), }, }, @@ -200,25 +200,25 @@ func TestAccVPCSubnet_List_filtered(t *testing.T) { querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: expected1.Value(), + names.AttrID: expected1.ValueCheck(), }), querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: expected2.Value(), + names.AttrID: expected2.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: notExpected1.Value(), + names.AttrID: notExpected1.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: notExpected2.Value(), + names.AttrID: notExpected2.ValueCheck(), }), }, }, @@ -264,18 +264,18 @@ func TestAccVPCSubnet_List_excludeDefaultSubnets(t *testing.T) { querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id.Value(), + names.AttrID: id.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: defaultSubnetID0.Value(), + names.AttrID: defaultSubnetID0.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: defaultSubnetID1.Value(), + names.AttrID: defaultSubnetID1.ValueCheck(), }), }, }, @@ -326,25 +326,25 @@ func TestAccVPCSubnet_List_subnetIDs(t *testing.T) { querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id1.Value(), + names.AttrID: id1.ValueCheck(), }), querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id2.Value(), + names.AttrID: id2.ValueCheck(), }), querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id3.Value(), + names.AttrID: id3.ValueCheck(), }), querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: id4.Value(), + names.AttrID: id4.ValueCheck(), }), }, }, @@ -401,25 +401,25 @@ func TestAccVPCSubnet_List_filteredSubnetIDs(t *testing.T) { querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: expected1.Value(), + names.AttrID: expected1.ValueCheck(), }), querycheck.ExpectIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: expected2.Value(), + names.AttrID: expected2.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: notExpected1.Value(), + names.AttrID: notExpected1.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_subnet.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrID: notExpected2.Value(), + names.AttrID: notExpected2.ValueCheck(), }), }, }, diff --git a/internal/service/ecr/repository_list_test.go b/internal/service/ecr/repository_list_test.go index 8603e26f6a50..36f1b300599d 100644 --- a/internal/service/ecr/repository_list_test.go +++ b/internal/service/ecr/repository_list_test.go @@ -62,12 +62,12 @@ func TestAccECRRepository_List_basic(t *testing.T) { querycheck.ExpectIdentity("aws_ecr_repository.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrName: name1.Value(), + names.AttrName: name1.ValueCheck(), }), querycheck.ExpectIdentity("aws_ecr_repository.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - names.AttrName: name2.Value(), + names.AttrName: name2.ValueCheck(), }), }, }, @@ -166,7 +166,7 @@ func TestAccECRRepository_List_regionOverride(t *testing.T) { querycheck.ExpectIdentity("aws_ecr_repository.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.AlternateRegion()), - names.AttrName: name.Value(), + names.AttrName: name.ValueCheck(), }), }, }, diff --git a/internal/service/iam/policy_list_test.go b/internal/service/iam/policy_list_test.go index 0bfbd7ec0f20..c31f7a1ab6eb 100644 --- a/internal/service/iam/policy_list_test.go +++ b/internal/service/iam/policy_list_test.go @@ -68,15 +68,15 @@ func TestAccIAMPolicy_List_basic(t *testing.T) { }, QueryResultChecks: []querycheck.QueryResultCheck{ querycheck.ExpectIdentity("aws_iam_policy.test", map[string]knownvalue.Check{ - names.AttrARN: arn1.Value(), + names.AttrARN: arn1.ValueCheck(), }), querycheck.ExpectIdentity("aws_iam_policy.test", map[string]knownvalue.Check{ - names.AttrARN: arn2.Value(), + names.AttrARN: arn2.ValueCheck(), }), querycheck.ExpectIdentity("aws_iam_policy.test", map[string]knownvalue.Check{ - names.AttrARN: arn3.Value(), + names.AttrARN: arn3.ValueCheck(), }), }, }, @@ -137,16 +137,16 @@ func TestAccIAMPolicy_List_pathPrefix(t *testing.T) { }, QueryResultChecks: []querycheck.QueryResultCheck{ querycheck.ExpectIdentity("aws_iam_policy.expected", map[string]knownvalue.Check{ - names.AttrARN: expected1.Value(), + names.AttrARN: expected1.ValueCheck(), }), querycheck.ExpectIdentity("aws_iam_policy.expected", map[string]knownvalue.Check{ - names.AttrARN: expected2.Value(), + names.AttrARN: expected2.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_iam_policy.expected", map[string]knownvalue.Check{ - names.AttrARN: notExpected1.Value(), + names.AttrARN: notExpected1.ValueCheck(), }), querycheck.ExpectNoIdentity("aws_iam_policy.expected", map[string]knownvalue.Check{ - names.AttrARN: notExpected2.Value(), + names.AttrARN: notExpected2.ValueCheck(), }), }, }, diff --git a/internal/service/lambda/permission_list_test.go b/internal/service/lambda/permission_list_test.go index 370ff6cc357e..326b300dd9f7 100644 --- a/internal/service/lambda/permission_list_test.go +++ b/internal/service/lambda/permission_list_test.go @@ -64,15 +64,15 @@ func TestAccLambdaPermission_List_basic(t *testing.T) { querycheck.ExpectIdentity("aws_lambda_permission.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - "function_name": functionName.Value(), - "statement_id": statementID1.Value(), + "function_name": functionName.ValueCheck(), + "statement_id": statementID1.ValueCheck(), "qualifier": knownvalue.Null(), }), querycheck.ExpectIdentity("aws_lambda_permission.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - "function_name": functionName.Value(), - "statement_id": statementID2.Value(), + "function_name": functionName.ValueCheck(), + "statement_id": statementID2.ValueCheck(), "qualifier": knownvalue.Null(), }), }, diff --git a/internal/service/route53resolver/rule_association_list_test.go b/internal/service/route53resolver/rule_association_list_test.go index b894c3762275..c4d311d98a03 100644 --- a/internal/service/route53resolver/rule_association_list_test.go +++ b/internal/service/route53resolver/rule_association_list_test.go @@ -66,12 +66,12 @@ func TestAccRoute53ResolverRuleAssociation_List_basic(t *testing.T) { }, QueryResultChecks: []querycheck.QueryResultCheck{ querycheck.ExpectIdentity("aws_route53_resolver_rule_association.test", map[string]knownvalue.Check{ - names.AttrID: id1.Value(), + names.AttrID: id1.ValueCheck(), names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), }), querycheck.ExpectIdentity("aws_route53_resolver_rule_association.test", map[string]knownvalue.Check{ - names.AttrID: id2.Value(), + names.AttrID: id2.ValueCheck(), names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), }), diff --git a/internal/service/secretsmanager/secret_list_test.go b/internal/service/secretsmanager/secret_list_test.go index fcddfba2e9eb..2bfda1ca6400 100644 --- a/internal/service/secretsmanager/secret_list_test.go +++ b/internal/service/secretsmanager/secret_list_test.go @@ -68,10 +68,10 @@ func TestAccSecretsManagerSecret_List_basic(t *testing.T) { }, QueryResultChecks: []querycheck.QueryResultCheck{ querycheck.ExpectIdentity("aws_secretsmanager_secret.test", map[string]knownvalue.Check{ - names.AttrARN: arn1.Value(), + names.AttrARN: arn1.ValueCheck(), }), querycheck.ExpectIdentity("aws_secretsmanager_secret.test", map[string]knownvalue.Check{ - names.AttrARN: arn2.Value(), + names.AttrARN: arn2.ValueCheck(), }), }, }, diff --git a/internal/service/secretsmanager/secret_version_list_test.go b/internal/service/secretsmanager/secret_version_list_test.go index 11595193012c..36d184783c62 100644 --- a/internal/service/secretsmanager/secret_version_list_test.go +++ b/internal/service/secretsmanager/secret_version_list_test.go @@ -62,14 +62,14 @@ func TestAccSecretsManagerSecretVersion_List_basic(t *testing.T) { querycheck.ExpectIdentity("aws_secretsmanager_secret_version.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - "secret_id": secretID.Value(), - "version_id": versionID1.Value(), + "secret_id": secretID.ValueCheck(), + "version_id": versionID1.ValueCheck(), }), querycheck.ExpectIdentity("aws_secretsmanager_secret_version.test", map[string]knownvalue.Check{ names.AttrAccountID: tfknownvalue.AccountID(), names.AttrRegion: knownvalue.StringExact(acctest.Region()), - "secret_id": secretID.Value(), - "version_id": versionID2.Value(), + "secret_id": secretID.ValueCheck(), + "version_id": versionID2.ValueCheck(), }), }, }, From 6756ab63fe11090b640910f8f394a6dbb2f1277d Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 14:38:22 -0700 Subject: [PATCH 04/14] Adds `Value` function --- internal/acctest/statecheck/state_value.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/acctest/statecheck/state_value.go b/internal/acctest/statecheck/state_value.go index 2a4c90bb6166..e30b97d0fced 100644 --- a/internal/acctest/statecheck/state_value.go +++ b/internal/acctest/statecheck/state_value.go @@ -31,6 +31,13 @@ func (v *stateValue) GetStateValue(resourceAddress string, attributePath tfjsonp return newStateValueStateChecker(v) } +func (v *stateValue) Value() string { + if v.value == nil { + return "" + } + return *v.value +} + // ValueCheck checks the stored state value against the provided value. // Calls to ValueCheck occur before any TestStep is run. func (v *stateValue) ValueCheck() knownvalue.Check { From 17451753421cfb8c96fd5ba87bed29fd773f3e3a Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 14:38:52 -0700 Subject: [PATCH 05/14] Adds `includeResource` test --- .../VPC/list_include_resource/main.tf | 22 +++++ .../list_include_resource/main.tfquery.hcl | 8 ++ internal/service/ec2/vpc_list_test.go | 89 +++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 internal/service/ec2/testdata/VPC/list_include_resource/main.tf create mode 100644 internal/service/ec2/testdata/VPC/list_include_resource/main.tfquery.hcl diff --git a/internal/service/ec2/testdata/VPC/list_include_resource/main.tf b/internal/service/ec2/testdata/VPC/list_include_resource/main.tf new file mode 100644 index 000000000000..68f510fcecf6 --- /dev/null +++ b/internal/service/ec2/testdata/VPC/list_include_resource/main.tf @@ -0,0 +1,22 @@ +# Copyright IBM Corp. 2014, 2026 +# SPDX-License-Identifier: MPL-2.0 + +resource "aws_vpc" "test" { + count = var.resource_count + + cidr_block = "10.1.0.0/16" + + tags = var.resource_tags +} + +variable "resource_count" { + description = "Number of resources to create" + type = number + nullable = false +} + +variable "resource_tags" { + description = "Tags to set on resource" + type = map(string) + nullable = false +} diff --git a/internal/service/ec2/testdata/VPC/list_include_resource/main.tfquery.hcl b/internal/service/ec2/testdata/VPC/list_include_resource/main.tfquery.hcl new file mode 100644 index 000000000000..a2859ab12369 --- /dev/null +++ b/internal/service/ec2/testdata/VPC/list_include_resource/main.tfquery.hcl @@ -0,0 +1,8 @@ +# Copyright IBM Corp. 2014, 2026 +# SPDX-License-Identifier: MPL-2.0 + +list "aws_vpc" "test" { + provider = aws + + include_resource = true +} diff --git a/internal/service/ec2/vpc_list_test.go b/internal/service/ec2/vpc_list_test.go index 6c99f28618ac..0e0a84051f75 100644 --- a/internal/service/ec2/vpc_list_test.go +++ b/internal/service/ec2/vpc_list_test.go @@ -4,6 +4,7 @@ package ec2_test import ( + "fmt" "testing" "github.com/YakDriver/regexache" @@ -86,6 +87,94 @@ func TestAccVPC_List_basic(t *testing.T) { }) } +func TestAccVPC_List_includeResource(t *testing.T) { + ctx := acctest.Context(t) + + resourceName1 := "aws_vpc.test[0]" + rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix) + + id1 := tfstatecheck.StateValue() + + identity1 := tfstatecheck.Identity() + + acctest.ParallelTest(ctx, t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_14_0), + }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + CheckDestroy: testAccCheckVPCDestroy(ctx, t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + // Step 1: Setup + { + ConfigDirectory: config.StaticDirectory("testdata/VPC/list_include_resource"), + ConfigVariables: config.Variables{ + "resource_count": config.IntegerVariable(1), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + "Name": config.StringVariable(rName), + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + ConfigStateChecks: []statecheck.StateCheck{ + identity1.GetIdentity(resourceName1), + id1.GetStateValue(resourceName1, tfjsonpath.New(names.AttrID)), + tfstatecheck.ExpectRegionalARNFormat(resourceName1, tfjsonpath.New(names.AttrARN), "ec2", "vpc/{id}"), + }, + }, + + // Step 2: Query + { + Query: true, + ConfigDirectory: config.StaticDirectory("testdata/VPC/list_basic"), + ConfigVariables: config.Variables{ + "resource_count": config.IntegerVariable(1), + acctest.CtResourceTags: config.MapVariable(map[string]config.Variable{ + "Name": config.StringVariable(rName), + acctest.CtKey1: config.StringVariable(acctest.CtValue1), + }), + }, + QueryResultChecks: []querycheck.QueryResultCheck{ + tfquerycheck.ExpectIdentityFunc("aws_vpc.test", identity1.Checks()), + querycheck.ExpectResourceDisplayName("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity1.Checks()), knownvalue.StringRegexp(regexache.MustCompile(fmt.Sprintf("^%s \\(vpc-[a-z0-9]+\\)$", rName)))), + querycheck.ExpectResourceKnownValues("aws_vpc.test", tfqueryfilter.ByResourceIdentityFunc(identity1.Checks()), []querycheck.KnownValueCheck{ + tfquerycheck.KnownValueCheck(tfjsonpath.New(names.AttrARN), tfknownvalue.RegionalARNRegexp("ec2", regexache.MustCompile(`vpc/vpc-[a-z0-9]+$`))), + tfquerycheck.KnownValueCheck(tfjsonpath.New("assign_generated_ipv6_cidr_block"), knownvalue.Bool(false)), + tfquerycheck.KnownValueCheck(tfjsonpath.New(names.AttrCIDRBlock), knownvalue.NotNull()), + tfquerycheck.KnownValueCheck(tfjsonpath.New("default_network_acl_id"), knownvalue.NotNull()), + tfquerycheck.KnownValueCheck(tfjsonpath.New("default_route_table_id"), knownvalue.NotNull()), + tfquerycheck.KnownValueCheck(tfjsonpath.New("default_security_group_id"), knownvalue.NotNull()), + tfquerycheck.KnownValueCheck(tfjsonpath.New("dhcp_options_id"), knownvalue.NotNull()), + tfquerycheck.KnownValueCheck(tfjsonpath.New("enable_dns_hostnames"), knownvalue.Bool(false)), + tfquerycheck.KnownValueCheck(tfjsonpath.New("enable_dns_support"), knownvalue.Bool(true)), + tfquerycheck.KnownValueCheck(tfjsonpath.New("enable_network_address_usage_metrics"), knownvalue.Bool(false)), + tfquerycheck.KnownValueCheck(tfjsonpath.New(names.AttrID), id1.ValueCheck()), + tfquerycheck.KnownValueCheck(tfjsonpath.New("instance_tenancy"), knownvalue.StringExact("default")), + tfquerycheck.KnownValueCheck(tfjsonpath.New("ipv4_ipam_pool_id"), knownvalue.Null()), + tfquerycheck.KnownValueCheck(tfjsonpath.New("ipv4_netmask_length"), knownvalue.Null()), + tfquerycheck.KnownValueCheck(tfjsonpath.New("ipv6_association_id"), knownvalue.StringExact("")), + tfquerycheck.KnownValueCheck(tfjsonpath.New("ipv6_cidr_block"), knownvalue.StringExact("")), + tfquerycheck.KnownValueCheck(tfjsonpath.New("ipv6_cidr_block_network_border_group"), knownvalue.StringExact("")), + tfquerycheck.KnownValueCheck(tfjsonpath.New("ipv6_ipam_pool_id"), knownvalue.StringExact("")), + tfquerycheck.KnownValueCheck(tfjsonpath.New("ipv6_netmask_length"), knownvalue.Int32Exact(0)), + tfquerycheck.KnownValueCheck(tfjsonpath.New("main_route_table_id"), knownvalue.NotNull()), + tfquerycheck.KnownValueCheck(tfjsonpath.New(names.AttrOwnerID), tfknownvalue.AccountID()), + tfquerycheck.KnownValueCheck(tfjsonpath.New(names.AttrRegion), knownvalue.StringExact(acctest.Region())), + tfquerycheck.KnownValueCheck(tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + "Name": knownvalue.StringExact(rName), + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + tfquerycheck.KnownValueCheck(tfjsonpath.New(names.AttrTagsAll), knownvalue.MapExact(map[string]knownvalue.Check{ + "Name": knownvalue.StringExact(rName), + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }), + }, + }, + }, + }) +} + func TestAccVPC_List_regionOverride(t *testing.T) { ctx := acctest.Context(t) From 017065e70e075ef8b6f5df6ddd1c920febea1ead Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 14:49:48 -0700 Subject: [PATCH 06/14] Exposes `page` in list loop --- internal/service/ec2/vpc_list.go | 80 +++++++++++++------------------- 1 file changed, 32 insertions(+), 48 deletions(-) diff --git a/internal/service/ec2/vpc_list.go b/internal/service/ec2/vpc_list.go index e33daec14005..c597e19b85cb 100644 --- a/internal/service/ec2/vpc_list.go +++ b/internal/service/ec2/vpc_list.go @@ -6,7 +6,6 @@ package ec2 import ( "context" "fmt" - "iter" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ec2" @@ -142,66 +141,51 @@ func (l *vpcListResource) List(ctx context.Context, request list.ListRequest, st tflog.Info(ctx, "Listing resources") stream.Results = func(yield func(list.ListResult) bool) { - for vpc, err := range listVPCs(ctx, conn, &input) { + pages := ec2.NewDescribeVpcsPaginator(conn, &input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) if err != nil { result := fwdiag.NewListResultErrorDiagnostic(err) yield(result) return } - ctx := tflog.SetField(ctx, logging.ResourceAttributeKey(names.AttrID), aws.ToString(vpc.VpcId)) - - result := request.NewListResult(ctx) - - tags := keyValueTags(ctx, vpc.Tags) - setTagsOut(ctx, vpc.Tags) + for _, vpc := range page.Vpcs { + ctx := tflog.SetField(ctx, logging.ResourceAttributeKey(names.AttrID), aws.ToString(vpc.VpcId)) - rd := l.ResourceData() - rd.SetId(aws.ToString(vpc.VpcId)) + result := request.NewListResult(ctx) - tflog.Info(ctx, "Reading resource") - err := resourceVPCFlatten(ctx, awsClient, &vpc, rd) - if retry.NotFound(err) { - tflog.Warn(ctx, "Resource disappeared during listing, skipping") - continue - } - if err != nil { - result = fwdiag.NewListResultErrorDiagnostic(err) - yield(result) - return - } + tags := keyValueTags(ctx, vpc.Tags) + setTagsOut(ctx, vpc.Tags) - if v, ok := tags["Name"]; ok { - result.DisplayName = fmt.Sprintf("%s (%s)", v.ValueString(), aws.ToString(vpc.VpcId)) - } else { - result.DisplayName = aws.ToString(vpc.VpcId) - } + rd := l.ResourceData() + rd.SetId(aws.ToString(vpc.VpcId)) - l.SetResult(ctx, awsClient, request.IncludeResource, rd, &result) - if result.Diagnostics.HasError() { - yield(result) - return - } + tflog.Info(ctx, "Reading resource") + err := resourceVPCFlatten(ctx, awsClient, &vpc, rd) + if retry.NotFound(err) { + tflog.Warn(ctx, "Resource disappeared during listing, skipping") + continue + } + if err != nil { + result = fwdiag.NewListResultErrorDiagnostic(err) + yield(result) + return + } - if !yield(result) { - return - } - } - } -} + if v, ok := tags["Name"]; ok { + result.DisplayName = fmt.Sprintf("%s (%s)", v.ValueString(), aws.ToString(vpc.VpcId)) + } else { + result.DisplayName = aws.ToString(vpc.VpcId) + } -func listVPCs(ctx context.Context, conn *ec2.Client, input *ec2.DescribeVpcsInput) iter.Seq2[awstypes.Vpc, error] { - return func(yield func(awstypes.Vpc, error) bool) { - pages := ec2.NewDescribeVpcsPaginator(conn, input) - for pages.HasMorePages() { - page, err := pages.NextPage(ctx) - if err != nil { - yield(awstypes.Vpc{}, fmt.Errorf("listing EC2 VPCs: %w", err)) - return - } + l.SetResult(ctx, awsClient, request.IncludeResource, rd, &result) + if result.Diagnostics.HasError() { + yield(result) + return + } - for _, vpc := range page.Vpcs { - if !yield(vpc, nil) { + if !yield(result) { return } } From d29e8ee5b77815424815fec70f0e8e15529bb024 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 16:30:33 -0700 Subject: [PATCH 07/14] Adds multi-value EC2 filters --- internal/service/ec2/filters.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/internal/service/ec2/filters.go b/internal/service/ec2/filters.go index 79ced36720db..bf8dd066b633 100644 --- a/internal/service/ec2/filters.go +++ b/internal/service/ec2/filters.go @@ -283,3 +283,22 @@ func newAttributeFilterList(m map[string]string) []awstypes.Filter { return filters } + +func newMultiValueAttributeFilterList(m map[string][]string) []awstypes.Filter { + var filters []awstypes.Filter + + // Sort the filters by name to make the output deterministic. + names := tfmaps.Keys(m) + slices.Sort(names) + + for _, name := range names { + values := m[name] + if len(values) == 0 { + continue + } + + filters = append(filters, newFilter(name, values)) + } + + return filters +} From 5d375a57e939d43188ac44f1cde9b08f50b17a16 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 16:31:11 -0700 Subject: [PATCH 08/14] Adds batch finder for VPC default network ACLs --- internal/service/ec2/find.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 35ffe71e3054..1030471d1baf 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -1723,6 +1723,17 @@ func findVPCDefaultNetworkACL(ctx context.Context, conn *ec2.Client, id string) return findNetworkACL(ctx, conn, &input) } +func batchFindVPCDefaultNetworkACL(ctx context.Context, conn *ec2.Client, ids []string) (map[string]*awstypes.NetworkAcl, error) { + input := ec2.DescribeNetworkAclsInput{ + Filters: newMultiValueAttributeFilterList(map[string][]string{ + "default": {"true"}, + "vpc-id": ids, + }), + } + + return batchFindNetworkACL(ctx, conn, &input) +} + func findNATGateway(ctx context.Context, conn *ec2.Client, input *ec2.DescribeNatGatewaysInput) (*awstypes.NatGateway, error) { output, err := findNATGateways(ctx, conn, input) @@ -1850,6 +1861,21 @@ func findNetworkACL(ctx context.Context, conn *ec2.Client, input *ec2.DescribeNe return tfresource.AssertSingleValueResult(output) } +func batchFindNetworkACL(ctx context.Context, conn *ec2.Client, input *ec2.DescribeNetworkAclsInput) (map[string]*awstypes.NetworkAcl, error) { + output, err := findNetworkACLs(ctx, conn, input) + + if err != nil { + return nil, err + } + + results := make(map[string]*awstypes.NetworkAcl, len(output)) + for i, v := range output { + results[aws.ToString(v.VpcId)] = &output[i] + } + + return results, nil +} + func findNetworkACLs(ctx context.Context, conn *ec2.Client, input *ec2.DescribeNetworkAclsInput) ([]awstypes.NetworkAcl, error) { var output []awstypes.NetworkAcl From a6892b2c874069c5b70b90d864ef6047fc897843 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 16:41:32 -0700 Subject: [PATCH 09/14] Batches finding VPC default network ACLs --- internal/service/ec2/find.go | 6 +++--- internal/service/ec2/vpc_.go | 14 +++++++------- internal/service/ec2/vpc_list.go | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 1030471d1baf..812aed559f3e 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -1723,7 +1723,7 @@ func findVPCDefaultNetworkACL(ctx context.Context, conn *ec2.Client, id string) return findNetworkACL(ctx, conn, &input) } -func batchFindVPCDefaultNetworkACL(ctx context.Context, conn *ec2.Client, ids []string) (map[string]*awstypes.NetworkAcl, error) { +func batchFindVPCDefaultNetworkACLs(ctx context.Context, conn *ec2.Client, ids []string) (map[string]*awstypes.NetworkAcl, error) { input := ec2.DescribeNetworkAclsInput{ Filters: newMultiValueAttributeFilterList(map[string][]string{ "default": {"true"}, @@ -1731,7 +1731,7 @@ func batchFindVPCDefaultNetworkACL(ctx context.Context, conn *ec2.Client, ids [] }), } - return batchFindNetworkACL(ctx, conn, &input) + return batchFindNetworkACLs(ctx, conn, &input) } func findNATGateway(ctx context.Context, conn *ec2.Client, input *ec2.DescribeNatGatewaysInput) (*awstypes.NatGateway, error) { @@ -1861,7 +1861,7 @@ func findNetworkACL(ctx context.Context, conn *ec2.Client, input *ec2.DescribeNe return tfresource.AssertSingleValueResult(output) } -func batchFindNetworkACL(ctx context.Context, conn *ec2.Client, input *ec2.DescribeNetworkAclsInput) (map[string]*awstypes.NetworkAcl, error) { +func batchFindNetworkACLs(ctx context.Context, conn *ec2.Client, input *ec2.DescribeNetworkAclsInput) (map[string]*awstypes.NetworkAcl, error) { output, err := findNetworkACLs(ctx, conn, input) if err != nil { diff --git a/internal/service/ec2/vpc_.go b/internal/service/ec2/vpc_.go index 572bf9fab327..b4f392fdbe00 100644 --- a/internal/service/ec2/vpc_.go +++ b/internal/service/ec2/vpc_.go @@ -292,6 +292,13 @@ func resourceVPCRead(ctx context.Context, d *schema.ResourceData, meta any) diag diags = sdkdiag.AppendFromErr(diags, err) } + if v, err := findVPCDefaultNetworkACL(ctx, conn, d.Id()); err != nil { + // e.g. RAM-shared VPC. + log.Printf("[WARN] Error reading EC2 VPC (%s) default NACL: %s", d.Id(), err) + } else { + d.Set("default_network_acl_id", v.NetworkAclId) + } + return diags } @@ -684,13 +691,6 @@ func resourceVPCFlatten(ctx context.Context, client *conns.AWSClient, vpc *awsty d.Set("enable_network_address_usage_metrics", v) } - if v, err := findVPCDefaultNetworkACL(ctx, conn, d.Id()); err != nil { - // e.g. RAM-shared VPC. - log.Printf("[WARN] Error reading EC2 VPC (%s) default NACL: %s", d.Id(), err) - } else { - d.Set("default_network_acl_id", v.NetworkAclId) - } - if v, err := findVPCMainRouteTable(ctx, conn, d.Id()); err != nil { // e.g. RAM-shared VPC. log.Printf("[WARN] Error reading EC2 VPC (%s) main Route Table: %s", d.Id(), err) diff --git a/internal/service/ec2/vpc_list.go b/internal/service/ec2/vpc_list.go index c597e19b85cb..4c43f637ebe3 100644 --- a/internal/service/ec2/vpc_list.go +++ b/internal/service/ec2/vpc_list.go @@ -22,6 +22,7 @@ import ( fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" "github.com/hashicorp/terraform-provider-aws/internal/logging" "github.com/hashicorp/terraform-provider-aws/internal/retry" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" inttypes "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-sdk-go-v2/otelaws" @@ -150,6 +151,20 @@ func (l *vpcListResource) List(ctx context.Context, request list.ListRequest, st return } + vpcIDs := tfslices.ApplyToAll(page.Vpcs, func(v awstypes.Vpc) string { + return aws.ToString(v.VpcId) + }) + + var defaultNetworkACLs map[string]*awstypes.NetworkAcl + if request.IncludeResource { + defaultNetworkACLs, err = batchFindVPCDefaultNetworkACLs(ctx, conn, vpcIDs) + if err != nil { + result := fwdiag.NewListResultErrorDiagnostic(err) + yield(result) + return + } + } + for _, vpc := range page.Vpcs { ctx := tflog.SetField(ctx, logging.ResourceAttributeKey(names.AttrID), aws.ToString(vpc.VpcId)) @@ -173,6 +188,10 @@ func (l *vpcListResource) List(ctx context.Context, request list.ListRequest, st return } + if defaultNetworkACL, ok := defaultNetworkACLs[aws.ToString(vpc.VpcId)]; ok { + rd.Set("default_network_acl_id", defaultNetworkACL.NetworkAclId) + } + if v, ok := tags["Name"]; ok { result.DisplayName = fmt.Sprintf("%s (%s)", v.ValueString(), aws.ToString(vpc.VpcId)) } else { From 9218bc04a457c9f64f430881a1d93b08ded4352b Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 16:56:51 -0700 Subject: [PATCH 10/14] Only lists VPCs from the current account --- internal/service/ec2/vpc_list.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/service/ec2/vpc_list.go b/internal/service/ec2/vpc_list.go index 4c43f637ebe3..b95806c879a7 100644 --- a/internal/service/ec2/vpc_list.go +++ b/internal/service/ec2/vpc_list.go @@ -138,6 +138,10 @@ func (l *vpcListResource) List(ctx context.Context, request list.ListRequest, st Name: aws.String("is-default"), Values: []string{"false"}, }) + input.Filters = append(input.Filters, awstypes.Filter{ + Name: aws.String("owner-id"), + Values: []string{awsClient.AccountID(ctx)}, + }) tflog.Info(ctx, "Listing resources") From 4a1433aa53499c72599a69d6489f8469563b7f91 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 16:57:55 -0700 Subject: [PATCH 11/14] Batches finding VPC main route tables --- internal/service/ec2/find.go | 26 ++++++++++++++++++++++++++ internal/service/ec2/vpc_.go | 20 ++++++++++---------- internal/service/ec2/vpc_list.go | 15 +++++++++++++++ 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index 812aed559f3e..c2d1ee0b1168 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -1993,6 +1993,17 @@ func findVPCMainRouteTable(ctx context.Context, conn *ec2.Client, id string) (*a return findRouteTable(ctx, conn, &input) } +func batchFindVPCMainRouteTables(ctx context.Context, conn *ec2.Client, ids []string) (map[string]*awstypes.RouteTable, error) { + input := ec2.DescribeRouteTablesInput{ + Filters: newMultiValueAttributeFilterList(map[string][]string{ + "association.main": {"true"}, + "vpc-id": ids, + }), + } + + return batchFindRouteTables(ctx, conn, &input) +} + func findRouteTable(ctx context.Context, conn *ec2.Client, input *ec2.DescribeRouteTablesInput) (*awstypes.RouteTable, error) { output, err := findRouteTables(ctx, conn, input) @@ -2003,6 +2014,21 @@ func findRouteTable(ctx context.Context, conn *ec2.Client, input *ec2.DescribeRo return tfresource.AssertSingleValueResult(output) } +func batchFindRouteTables(ctx context.Context, conn *ec2.Client, input *ec2.DescribeRouteTablesInput) (map[string]*awstypes.RouteTable, error) { + output, err := findRouteTables(ctx, conn, input) + + if err != nil { + return nil, err + } + + results := make(map[string]*awstypes.RouteTable, len(output)) + for i, v := range output { + results[aws.ToString(v.VpcId)] = &output[i] + } + + return results, nil +} + func findRouteTables(ctx context.Context, conn *ec2.Client, input *ec2.DescribeRouteTablesInput) ([]awstypes.RouteTable, error) { var output []awstypes.RouteTable diff --git a/internal/service/ec2/vpc_.go b/internal/service/ec2/vpc_.go index b4f392fdbe00..a8428ad43fad 100644 --- a/internal/service/ec2/vpc_.go +++ b/internal/service/ec2/vpc_.go @@ -299,6 +299,16 @@ func resourceVPCRead(ctx context.Context, d *schema.ResourceData, meta any) diag d.Set("default_network_acl_id", v.NetworkAclId) } + if v, err := findVPCMainRouteTable(ctx, conn, d.Id()); err != nil { + // e.g. RAM-shared VPC. + log.Printf("[WARN] Error reading EC2 VPC (%s) main Route Table: %s", d.Id(), err) + d.Set("default_route_table_id", nil) + d.Set("main_route_table_id", nil) + } else { + d.Set("default_route_table_id", v.RouteTableId) + d.Set("main_route_table_id", v.RouteTableId) + } + return diags } @@ -691,16 +701,6 @@ func resourceVPCFlatten(ctx context.Context, client *conns.AWSClient, vpc *awsty d.Set("enable_network_address_usage_metrics", v) } - if v, err := findVPCMainRouteTable(ctx, conn, d.Id()); err != nil { - // e.g. RAM-shared VPC. - log.Printf("[WARN] Error reading EC2 VPC (%s) main Route Table: %s", d.Id(), err) - d.Set("default_route_table_id", nil) - d.Set("main_route_table_id", nil) - } else { - d.Set("default_route_table_id", v.RouteTableId) - d.Set("main_route_table_id", v.RouteTableId) - } - if v, err := findVPCDefaultSecurityGroup(ctx, conn, d.Id()); err != nil { // e.g. RAM-shared VPC. log.Printf("[WARN] Error reading EC2 VPC (%s) default Security Group: %s", d.Id(), err) diff --git a/internal/service/ec2/vpc_list.go b/internal/service/ec2/vpc_list.go index b95806c879a7..e14f6088bb37 100644 --- a/internal/service/ec2/vpc_list.go +++ b/internal/service/ec2/vpc_list.go @@ -169,6 +169,16 @@ func (l *vpcListResource) List(ctx context.Context, request list.ListRequest, st } } + var mainRouteTables map[string]*awstypes.RouteTable + if request.IncludeResource { + mainRouteTables, err = batchFindVPCMainRouteTables(ctx, conn, vpcIDs) + if err != nil { + result := fwdiag.NewListResultErrorDiagnostic(err) + yield(result) + return + } + } + for _, vpc := range page.Vpcs { ctx := tflog.SetField(ctx, logging.ResourceAttributeKey(names.AttrID), aws.ToString(vpc.VpcId)) @@ -196,6 +206,11 @@ func (l *vpcListResource) List(ctx context.Context, request list.ListRequest, st rd.Set("default_network_acl_id", defaultNetworkACL.NetworkAclId) } + if mainRouteTable, ok := mainRouteTables[aws.ToString(vpc.VpcId)]; ok { + rd.Set("default_route_table_id", mainRouteTable.RouteTableId) + rd.Set("main_route_table_id", mainRouteTable.RouteTableId) + } + if v, ok := tags["Name"]; ok { result.DisplayName = fmt.Sprintf("%s (%s)", v.ValueString(), aws.ToString(vpc.VpcId)) } else { From f2cbeeba3e1bf447e112d3cdab0213d861ce1641 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 17:00:14 -0700 Subject: [PATCH 12/14] Skips when associated remote resources dissapear --- internal/service/ec2/vpc_list.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/service/ec2/vpc_list.go b/internal/service/ec2/vpc_list.go index e14f6088bb37..cc4a1f4c00e4 100644 --- a/internal/service/ec2/vpc_list.go +++ b/internal/service/ec2/vpc_list.go @@ -204,11 +204,17 @@ func (l *vpcListResource) List(ctx context.Context, request list.ListRequest, st if defaultNetworkACL, ok := defaultNetworkACLs[aws.ToString(vpc.VpcId)]; ok { rd.Set("default_network_acl_id", defaultNetworkACL.NetworkAclId) + } else { + tflog.Warn(ctx, "Resource disappeared during listing, skipping") + continue } if mainRouteTable, ok := mainRouteTables[aws.ToString(vpc.VpcId)]; ok { rd.Set("default_route_table_id", mainRouteTable.RouteTableId) rd.Set("main_route_table_id", mainRouteTable.RouteTableId) + } else { + tflog.Warn(ctx, "Resource disappeared during listing, skipping") + continue } if v, ok := tags["Name"]; ok { From 2d11a0b33f7d07ef32adec099866881d39ffbfc5 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 17:09:36 -0700 Subject: [PATCH 13/14] Batches finding VPC default security groups --- internal/service/ec2/find.go | 26 ++++++++++++++++++++++++++ internal/service/ec2/vpc_.go | 20 ++++++++++---------- internal/service/ec2/vpc_list.go | 17 +++++++++++++++++ 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index c2d1ee0b1168..b83fe6be146c 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -1966,6 +1966,17 @@ func findVPCDefaultSecurityGroup(ctx context.Context, conn *ec2.Client, id strin return findSecurityGroup(ctx, conn, &input) } +func batchFindVPCDefaultSecurityGroups(ctx context.Context, conn *ec2.Client, ids []string) (map[string]*awstypes.SecurityGroup, error) { + input := ec2.DescribeSecurityGroupsInput{ + Filters: newMultiValueAttributeFilterList(map[string][]string{ + "group-name": {defaultSecurityGroupName}, + "vpc-id": ids, + }), + } + + return batchFindSecurityGroups(ctx, conn, &input) +} + func findVPCDHCPOptionsAssociation(ctx context.Context, conn *ec2.Client, vpcID string, dhcpOptionsID string) error { vpc, err := findVPCByID(ctx, conn, vpcID) @@ -2062,6 +2073,21 @@ func findSecurityGroup(ctx context.Context, conn *ec2.Client, input *ec2.Describ return tfresource.AssertSingleValueResult(output) } +func batchFindSecurityGroups(ctx context.Context, conn *ec2.Client, input *ec2.DescribeSecurityGroupsInput) (map[string]*awstypes.SecurityGroup, error) { + output, err := findSecurityGroups(ctx, conn, input) + + if err != nil { + return nil, err + } + + results := make(map[string]*awstypes.SecurityGroup, len(output)) + for i, v := range output { + results[aws.ToString(v.VpcId)] = &output[i] + } + + return results, nil +} + func findSecurityGroups(ctx context.Context, conn *ec2.Client, input *ec2.DescribeSecurityGroupsInput) ([]awstypes.SecurityGroup, error) { var output []awstypes.SecurityGroup diff --git a/internal/service/ec2/vpc_.go b/internal/service/ec2/vpc_.go index a8428ad43fad..bc2b45fb6f4e 100644 --- a/internal/service/ec2/vpc_.go +++ b/internal/service/ec2/vpc_.go @@ -309,6 +309,16 @@ func resourceVPCRead(ctx context.Context, d *schema.ResourceData, meta any) diag d.Set("main_route_table_id", v.RouteTableId) } + if v, err := findVPCDefaultSecurityGroup(ctx, conn, d.Id()); err != nil { + // e.g. RAM-shared VPC. + log.Printf("[WARN] Error reading EC2 VPC (%s) default Security Group: %s", d.Id(), err) + d.Set("default_security_group_id", nil) + } else { + d.Set("default_security_group_id", v.GroupId) + } + + setTagsOut(ctx, vpc.Tags) + return diags } @@ -701,14 +711,6 @@ func resourceVPCFlatten(ctx context.Context, client *conns.AWSClient, vpc *awsty d.Set("enable_network_address_usage_metrics", v) } - if v, err := findVPCDefaultSecurityGroup(ctx, conn, d.Id()); err != nil { - // e.g. RAM-shared VPC. - log.Printf("[WARN] Error reading EC2 VPC (%s) default Security Group: %s", d.Id(), err) - d.Set("default_security_group_id", nil) - } else { - d.Set("default_security_group_id", v.GroupId) - } - if ipv6CIDRBlockAssociation := defaultIPv6CIDRBlockAssociation(vpc, d.Get("ipv6_association_id").(string)); ipv6CIDRBlockAssociation == nil { d.Set("assign_generated_ipv6_cidr_block", nil) d.Set("ipv6_association_id", nil) @@ -748,8 +750,6 @@ func resourceVPCFlatten(ctx context.Context, client *conns.AWSClient, vpc *awsty } } - setTagsOut(ctx, vpc.Tags) - return nil } diff --git a/internal/service/ec2/vpc_list.go b/internal/service/ec2/vpc_list.go index cc4a1f4c00e4..94f8fb9e1d65 100644 --- a/internal/service/ec2/vpc_list.go +++ b/internal/service/ec2/vpc_list.go @@ -179,6 +179,16 @@ func (l *vpcListResource) List(ctx context.Context, request list.ListRequest, st } } + var defaultSecurityGroups map[string]*awstypes.SecurityGroup + if request.IncludeResource { + defaultSecurityGroups, err = batchFindVPCDefaultSecurityGroups(ctx, conn, vpcIDs) + if err != nil { + result := fwdiag.NewListResultErrorDiagnostic(err) + yield(result) + return + } + } + for _, vpc := range page.Vpcs { ctx := tflog.SetField(ctx, logging.ResourceAttributeKey(names.AttrID), aws.ToString(vpc.VpcId)) @@ -217,6 +227,13 @@ func (l *vpcListResource) List(ctx context.Context, request list.ListRequest, st continue } + if defaultSecurityGroup, ok := defaultSecurityGroups[aws.ToString(vpc.VpcId)]; ok { + rd.Set("default_security_group_id", defaultSecurityGroup.GroupId) + } else { + tflog.Warn(ctx, "Resource disappeared during listing, skipping") + continue + } + if v, ok := tags["Name"]; ok { result.DisplayName = fmt.Sprintf("%s (%s)", v.ValueString(), aws.ToString(vpc.VpcId)) } else { From d261cc78516c35c32c06cbf313354bdf74c3486a Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 13 Mar 2026 17:22:19 -0700 Subject: [PATCH 14/14] Only populates data and fetches VPC Attributes when resource data requested --- internal/service/ec2/vpc_list.go | 66 ++++++++++++++++---------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/internal/service/ec2/vpc_list.go b/internal/service/ec2/vpc_list.go index 94f8fb9e1d65..51effc3e2b14 100644 --- a/internal/service/ec2/vpc_list.go +++ b/internal/service/ec2/vpc_list.go @@ -200,38 +200,40 @@ func (l *vpcListResource) List(ctx context.Context, request list.ListRequest, st rd := l.ResourceData() rd.SetId(aws.ToString(vpc.VpcId)) - tflog.Info(ctx, "Reading resource") - err := resourceVPCFlatten(ctx, awsClient, &vpc, rd) - if retry.NotFound(err) { - tflog.Warn(ctx, "Resource disappeared during listing, skipping") - continue - } - if err != nil { - result = fwdiag.NewListResultErrorDiagnostic(err) - yield(result) - return - } - - if defaultNetworkACL, ok := defaultNetworkACLs[aws.ToString(vpc.VpcId)]; ok { - rd.Set("default_network_acl_id", defaultNetworkACL.NetworkAclId) - } else { - tflog.Warn(ctx, "Resource disappeared during listing, skipping") - continue - } - - if mainRouteTable, ok := mainRouteTables[aws.ToString(vpc.VpcId)]; ok { - rd.Set("default_route_table_id", mainRouteTable.RouteTableId) - rd.Set("main_route_table_id", mainRouteTable.RouteTableId) - } else { - tflog.Warn(ctx, "Resource disappeared during listing, skipping") - continue - } - - if defaultSecurityGroup, ok := defaultSecurityGroups[aws.ToString(vpc.VpcId)]; ok { - rd.Set("default_security_group_id", defaultSecurityGroup.GroupId) - } else { - tflog.Warn(ctx, "Resource disappeared during listing, skipping") - continue + if request.IncludeResource { + tflog.Info(ctx, "Reading resource") + err := resourceVPCFlatten(ctx, awsClient, &vpc, rd) + if retry.NotFound(err) { + tflog.Warn(ctx, "Resource disappeared during listing, skipping") + continue + } + if err != nil { + result = fwdiag.NewListResultErrorDiagnostic(err) + yield(result) + return + } + + if defaultNetworkACL, ok := defaultNetworkACLs[aws.ToString(vpc.VpcId)]; ok { + rd.Set("default_network_acl_id", defaultNetworkACL.NetworkAclId) + } else { + tflog.Warn(ctx, "Resource disappeared during listing, skipping") + continue + } + + if mainRouteTable, ok := mainRouteTables[aws.ToString(vpc.VpcId)]; ok { + rd.Set("default_route_table_id", mainRouteTable.RouteTableId) + rd.Set("main_route_table_id", mainRouteTable.RouteTableId) + } else { + tflog.Warn(ctx, "Resource disappeared during listing, skipping") + continue + } + + if defaultSecurityGroup, ok := defaultSecurityGroups[aws.ToString(vpc.VpcId)]; ok { + rd.Set("default_security_group_id", defaultSecurityGroup.GroupId) + } else { + tflog.Warn(ctx, "Resource disappeared during listing, skipping") + continue + } } if v, ok := tags["Name"]; ok {