Skip to content
Merged
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/unreleased/FEATURES-20251111-151917.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: FEATURES
body: 'queryfilter: Introduces new `queryfilter` package with interface and built-in query check filtering functionality.'
time: 2025-11-11T15:19:17.237154-05:00
custom:
Issue: "573"
5 changes: 5 additions & 0 deletions .changes/unreleased/FEATURES-20251111-152247.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: FEATURES
body: 'querycheck: Adds `ExpectResourceDisplayName` query check to assert a display name value on a filtered query result.'
time: 2025-11-11T15:22:47.472876-05:00
custom:
Issue: "573"
46 changes: 45 additions & 1 deletion helper/resource/query/query_checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/mitchellh/go-testing-interface"

"github.com/hashicorp/terraform-plugin-testing/querycheck"
"github.com/hashicorp/terraform-plugin-testing/querycheck/queryfilter"
)

func RunQueryChecks(ctx context.Context, t testing.T, query []tfjson.LogMsg, queryChecks []querycheck.QueryResultCheck) error {
Expand All @@ -38,10 +39,19 @@ func RunQueryChecks(ctx context.Context, t testing.T, query []tfjson.LogMsg, que
}
}

var reqQueryData []tfjson.ListResourceFoundData
for _, queryCheck := range queryChecks {
reqQueryData = found
if filterCheck, ok := queryCheck.(querycheck.QueryResultCheckWithFilters); ok {
filtered, err := runQueryFilters(ctx, filterCheck, reqQueryData)
if err != nil {
return err
}
reqQueryData = filtered
}
resp := querycheck.CheckQueryResponse{}
queryCheck.CheckQuery(ctx, querycheck.CheckQueryRequest{
Query: found,
Query: reqQueryData,
QuerySummary: &summary,
}, &resp)

Expand All @@ -50,3 +60,37 @@ func RunQueryChecks(ctx context.Context, t testing.T, query []tfjson.LogMsg, que

return errors.Join(result...)
}

func runQueryFilters(ctx context.Context, filterCheck querycheck.QueryResultCheckWithFilters, queryResults []tfjson.ListResourceFoundData) ([]tfjson.ListResourceFoundData, error) {
filters := filterCheck.QueryFilters(ctx)
filteredResults := make([]tfjson.ListResourceFoundData, 0)

// If there are no filters, just return the original results
if len(filters) == 0 {
return queryResults, nil
}

for _, result := range queryResults {
keepResult := false

for _, filter := range filters {

resp := queryfilter.FilterQueryResponse{}
filter.Filter(ctx, queryfilter.FilterQueryRequest{QueryItem: result}, &resp)

if resp.Include {
keepResult = true
}

if resp.Error != nil {
return nil, resp.Error
}
}

if keepResult {
filteredResults = append(filteredResults, result)
}
}

return filteredResults, nil
}
38 changes: 0 additions & 38 deletions querycheck/contains_name.go

This file was deleted.

139 changes: 0 additions & 139 deletions querycheck/contains_name_test.go

This file was deleted.

14 changes: 13 additions & 1 deletion querycheck/expect_identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,22 @@ func (e expectIdentity) CheckQuery(_ context.Context, req CheckQueryRequest, res
var errCollection []error
errCollection = append(errCollection, fmt.Errorf("an identity with the following attributes was not found"))

var keys []string

for k := range e.check {
keys = append(keys, k)
}

sort.SliceStable(keys, func(i, j int) bool {
return keys[i] < keys[j]
})

// wrap errors for each check
for attr, check := range e.check {
for _, attr := range keys {
check := e.check[attr]
errCollection = append(errCollection, fmt.Errorf("attribute %q: %s", attr, check))
}

errCollection = append(errCollection, fmt.Errorf("address: %s\n", e.listResourceAddress))
resp.Error = errors.Join(errCollection...)
}
Expand Down
70 changes: 70 additions & 0 deletions querycheck/expect_resource_display_name.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package querycheck

import (
"context"
"fmt"
"strings"

tfjson "github.com/hashicorp/terraform-json"

"github.com/hashicorp/terraform-plugin-testing/knownvalue"
"github.com/hashicorp/terraform-plugin-testing/querycheck/queryfilter"
)

var _ QueryResultCheck = expectResourceDisplayName{}
var _ QueryResultCheckWithFilters = expectResourceDisplayName{}

type expectResourceDisplayName struct {
listResourceAddress string
filter queryfilter.QueryFilter
displayName knownvalue.Check
}

func (e expectResourceDisplayName) QueryFilters(ctx context.Context) []queryfilter.QueryFilter {
if e.filter == nil {
return []queryfilter.QueryFilter{}
}

return []queryfilter.QueryFilter{
e.filter,
}
}

func (e expectResourceDisplayName) CheckQuery(_ context.Context, req CheckQueryRequest, resp *CheckQueryResponse) {
listRes := make([]tfjson.ListResourceFoundData, 0)
for _, result := range req.Query {
if strings.TrimPrefix(result.Address, "list.") == e.listResourceAddress {
listRes = append(listRes, result)
}
}

if len(listRes) == 0 {
resp.Error = fmt.Errorf("%s - no query results found after filtering", e.listResourceAddress)
return
}

if len(listRes) > 1 {
resp.Error = fmt.Errorf("%s - more than 1 query result found after filtering", e.listResourceAddress)
return
}
res := listRes[0]
if err := e.displayName.CheckValue(res.DisplayName); err != nil {
resp.Error = fmt.Errorf("error checking value for display name %s, err: %s", e.displayName.String(), err)
return
}

}

// ExpectResourceDisplayName returns a query check that asserts that a resource with a given display name exists within the returned results of the query.
//
// This query check can only be used with managed resources that support query. Query is only supported in Terraform v1.14+
func ExpectResourceDisplayName(listResourceAddress string, filter queryfilter.QueryFilter, displayName knownvalue.Check) QueryResultCheck {
return expectResourceDisplayName{
listResourceAddress: listResourceAddress,
filter: filter,
displayName: displayName,
}
}
Loading