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-20251202-113347.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kind: FEATURES
body: 'querycheck: Adds `ExpectResourceKnownValues` query check to assert resource values on a filtered query result.'
time: 2025-12-02T11:33:47.606282+01:00
custom:
Issue: "583"
74 changes: 0 additions & 74 deletions querycheck/expect_known_value.go

This file was deleted.

93 changes: 93 additions & 0 deletions querycheck/expect_resource_known_values.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package querycheck

import (
"context"
"fmt"
tfjson "github.com/hashicorp/terraform-json"
"strings"

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

var _ QueryResultCheck = expectResourceKnownValues{}
var _ QueryResultCheckWithFilters = expectResourceKnownValues{}

type expectResourceKnownValues struct {
listResourceAddress string
filter queryfilter.QueryFilter
knownValueChecks []KnownValueCheck
}

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

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

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

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 res.ResourceObject == nil {
resp.Error = fmt.Errorf("%s - no resource object was returned, ensure `include_resource` has been set to `true` in the list resource config`", e.listResourceAddress)
return
}

for _, c := range e.knownValueChecks {
resource, err := tfjsonpath.Traverse(res.ResourceObject, c.Path)
if err != nil {
resp.Error = err
return
}

if err := c.KnownValue.CheckValue(resource); err != nil {
diags = append(diags, fmt.Errorf("error checking value for attribute at path: %s for resource with identity %s, err: %s", c.Path.String(), e.filter, err))
}
}

if diags != nil {
var diagsStr string
for _, diag := range diags {
diagsStr += diag.Error() + "; "
}
resp.Error = fmt.Errorf("the following errors were found while checking values: %s", diagsStr)
return
}
}

// ExpectResourceKnownValues returns a query check which asserts that a resource object identified by a query filter
// passes the given query checks.
//
// This query check can only be used with managed resources that support resource identity and query. Query is only supported in Terraform v1.14+
func ExpectResourceKnownValues(listResourceAddress string, filter queryfilter.QueryFilter, knownValues []KnownValueCheck) QueryResultCheck {
return expectResourceKnownValues{
listResourceAddress: listResourceAddress,
filter: filter,
knownValueChecks: knownValues,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ import (
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/providerserver"
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
"github.com/hashicorp/terraform-plugin-testing/querycheck"
"github.com/hashicorp/terraform-plugin-testing/querycheck/queryfilter"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
"github.com/hashicorp/terraform-plugin-testing/tfversion"
)

func TestExpectKnownValue(t *testing.T) {
func TestExpectResourceKnownValues(t *testing.T) {
t.Parallel()

r.UnitTest(t, r.TestCase{
Expand Down Expand Up @@ -67,19 +68,28 @@ func TestExpectKnownValue(t *testing.T) {
}
`,
QueryResultChecks: []querycheck.QueryResultCheck{
querycheck.ExpectKnownValue(
"examplecloud_containerette.test",
"banane",
tfjsonpath.New("instances"),
knownvalue.NumberExact(big.NewFloat(5)),
querycheck.ExpectResourceKnownValues(
"examplecloud_containerette.test", queryfilter.ByResourceIdentity(map[string]knownvalue.Check{
"name": knownvalue.StringExact("banane"),
"resource_group_name": knownvalue.StringExact("foo"),
}), []querycheck.KnownValueCheck{
{
tfjsonpath.New("instances"),
knownvalue.NumberExact(big.NewFloat(5)),
},
{
tfjsonpath.New("location"),
knownvalue.StringExact("westeurope"),
},
},
),
},
},
},
})
}

func TestExpectKnownValue_ValueIncorrect(t *testing.T) {
func TestExpectResourceKnownValues_ValueIncorrect(t *testing.T) {
t.Parallel()

r.UnitTest(t, r.TestCase{
Expand Down Expand Up @@ -128,14 +138,23 @@ func TestExpectKnownValue_ValueIncorrect(t *testing.T) {
}
`,
QueryResultChecks: []querycheck.QueryResultCheck{
querycheck.ExpectKnownValue(
"examplecloud_containerette.test",
"banane",
tfjsonpath.New("instances"),
knownvalue.NumberExact(big.NewFloat(4)),
querycheck.ExpectResourceKnownValues(
"examplecloud_containerette.test", queryfilter.ByResourceIdentity(map[string]knownvalue.Check{
"name": knownvalue.StringExact("banane"),
"resource_group_name": knownvalue.StringExact("foo"),
}), []querycheck.KnownValueCheck{
{
tfjsonpath.New("location"),
knownvalue.StringExact("westeurope"),
},
{
tfjsonpath.New("instances"),
knownvalue.NumberExact(big.NewFloat(4)),
},
},
),
},
ExpectError: regexp.MustCompile("the following errors were found while checking values: error checking value for attribute at path: instances for resource banane, err: expected value 4 for NumberExact check, got: 5;"),
ExpectError: regexp.MustCompile("the following errors were found while checking values: error checking value for attribute at path: instances for resource with identity .*, err: expected value 4 for NumberExact check, got: 5;"),
},
},
})
Expand Down
19 changes: 19 additions & 0 deletions querycheck/known_value.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package querycheck

import (
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
)

// KnownValueCheck represents a check of a known value at a specific JSON path
// and is used to specify multiple known value checks to assert against a
// single resource object returned by a query.
type KnownValueCheck struct {
// Path specifies the JSON path to check within the resource object.
Path tfjsonpath.Path
// KnownValue specifies the expected known value check to perform at the given path.
KnownValue knownvalue.Check
}