Skip to content
Closed
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
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/hashicorp/logutils v1.0.0
github.com/hashicorp/terraform-exec v0.23.0
github.com/hashicorp/terraform-json v0.25.0
github.com/hashicorp/terraform-plugin-go v0.28.0
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0
github.com/mitchellh/go-testing-interface v1.14.1
Expand All @@ -36,7 +36,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-plugin v1.6.3 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/terraform-registry-address v0.2.5 // indirect
github.com/hashicorp/terraform-registry-address v0.3.0 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
Expand All @@ -50,13 +50,13 @@ require (
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
golang.org/x/mod v0.25.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.26.0 // indirect
golang.org/x/tools v0.33.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
google.golang.org/grpc v1.72.1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect
google.golang.org/grpc v1.73.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
)
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,15 @@ github.com/hashicorp/terraform-json v0.25.0 h1:rmNqc/CIfcWawGiwXmRuiXJKEiJu1ntGo
github.com/hashicorp/terraform-json v0.25.0/go.mod h1:sMKS8fiRDX4rVlR6EJUMudg1WcanxCMoWwTLkgZP/vc=
github.com/hashicorp/terraform-plugin-go v0.28.0 h1:zJmu2UDwhVN0J+J20RE5huiF3XXlTYVIleaevHZgKPA=
github.com/hashicorp/terraform-plugin-go v0.28.0/go.mod h1:FDa2Bb3uumkTGSkTFpWSOwWJDwA7bf3vdP3ltLDTH6o=
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1 h1:ZId6oWG8VTKhz207quE/Xh8a3HuoLtM/QkcSSypekIQ=
github.com/hashicorp/terraform-plugin-go v0.29.0-alpha.1/go.mod h1:hL//wLEfYo0YVt0TC/VLzia/ADQQto3HEm4/jX2gkdY=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 h1:NFPMacTrY/IdcIcnUB+7hsore1ZaRWU9cnB6jFoBnIM=
github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0/go.mod h1:QYmYnLfsosrxjCnGY1p9c7Zj6n9thnEE+7RObeYs3fA=
github.com/hashicorp/terraform-registry-address v0.2.5 h1:2GTftHqmUhVOeuu9CW3kwDkRe4pcBDq0uuK5VJngU1M=
github.com/hashicorp/terraform-registry-address v0.2.5/go.mod h1:PpzXWINwB5kuVS5CA7m1+eO2f1jKb5ZDIxrOPfpnGkg=
github.com/hashicorp/terraform-registry-address v0.3.0/go.mod h1:jRGCMiLaY9zii3GLC7hqpSnwhfnCN5yzvY0hh4iCGbM=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
Expand Down Expand Up @@ -175,6 +178,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down Expand Up @@ -216,8 +220,10 @@ google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAs
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA=
google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
Expand Down
118 changes: 118 additions & 0 deletions helper/resource/query/examplecloud_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package query_test

import (
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testprovider"
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/resource"
"github.com/hashicorp/terraform-plugin-testing/internal/teststep"
)

func examplecloudResource() testprovider.Resource {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from ../importstate.

return testprovider.Resource{
CreateResponse: &resource.CreateResponse{
NewState: tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"id": tftypes.String,
"location": tftypes.String,
"name": tftypes.String,
},
},
map[string]tftypes.Value{
"id": tftypes.NewValue(tftypes.String, "westeurope/somevalue"),
"location": tftypes.NewValue(tftypes.String, "westeurope"),
"name": tftypes.NewValue(tftypes.String, "somevalue"),
},
),
NewIdentity: teststep.Pointer(tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"id": tftypes.String,
},
},
map[string]tftypes.Value{
"id": tftypes.NewValue(tftypes.String, "westeurope/somevalue"),
},
)),
},
ReadResponse: &resource.ReadResponse{
NewState: tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"id": tftypes.String,
"location": tftypes.String,
"name": tftypes.String,
},
},
map[string]tftypes.Value{
"id": tftypes.NewValue(tftypes.String, "westeurope/somevalue"),
"location": tftypes.NewValue(tftypes.String, "westeurope"),
"name": tftypes.NewValue(tftypes.String, "somevalue"),
},
),
NewIdentity: teststep.Pointer(tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"id": tftypes.String,
},
},
map[string]tftypes.Value{
"id": tftypes.NewValue(tftypes.String, "westeurope/somevalue"),
},
)),
},
ImportStateResponse: &resource.ImportStateResponse{
State: tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"id": tftypes.String,
"location": tftypes.String,
"name": tftypes.String,
},
},
map[string]tftypes.Value{
"id": tftypes.NewValue(tftypes.String, "westeurope/somevalue"),
"location": tftypes.NewValue(tftypes.String, "westeurope"),
"name": tftypes.NewValue(tftypes.String, "somevalue"),
},
),
Identity: teststep.Pointer(tftypes.NewValue(
tftypes.Object{
AttributeTypes: map[string]tftypes.Type{
"id": tftypes.String,
},
},
map[string]tftypes.Value{
"id": tftypes.NewValue(tftypes.String, "westeurope/somevalue"),
},
)),
},
SchemaResponse: &resource.SchemaResponse{
Schema: &tfprotov6.Schema{
Block: &tfprotov6.SchemaBlock{
Attributes: []*tfprotov6.SchemaAttribute{
ComputedStringAttribute("id"),
RequiredStringAttribute("location"),
RequiredStringAttribute("name"),
},
},
},
},
IdentitySchemaResponse: &resource.IdentitySchemaResponse{
Schema: &tfprotov6.ResourceIdentitySchema{
Version: 1,
IdentityAttributes: []*tfprotov6.ResourceIdentitySchemaAttribute{
{
Name: "id",
Type: tftypes.String,
RequiredForImport: true,
},
},
},
},
}
}
60 changes: 60 additions & 0 deletions helper/resource/query/query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package query_test

import (
"testing"

"github.com/hashicorp/terraform-plugin-go/tfprotov6"
r "github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testprovider"
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/list"
"github.com/hashicorp/terraform-plugin-testing/internal/testing/testsdk/providerserver"
"github.com/hashicorp/terraform-plugin-testing/tfversion"
)

func TestQuery(t *testing.T) {
t.Parallel()

r.UnitTest(t, r.TestCase{
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.SkipBelow(tfversion.Version1_13_0), // Query mode requires Terraform 1.13.0 or later
},
ProtoV6ProviderFactories: map[string]func() (tfprotov6.ProviderServer, error){
"examplecloud": providerserver.NewProviderServer(testprovider.Provider{
ListResources: map[string]testprovider.ListResource{
"examplecloud_containerette": {
SchemaResponse: &list.SchemaResponse{
Schema: &tfprotov6.Schema{
Block: &tfprotov6.SchemaBlock{
Attributes: []*tfprotov6.SchemaAttribute{
ComputedStringAttribute("id"),
},
},
},
},
ListResultsStream: &list.ListResultsStream{
Results: func(push func(list.ListResult) bool) {
},
},
},
},
Resources: map[string]testprovider.Resource{
"examplecloud_containerette": examplecloudResource(),
},
}),
},
Steps: []r.TestStep{
{
Query: true,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Query mode!

Config: `
provider "examplecloud" {}
list "examplecloud_containerette" "test" {
provider = examplecloud
config {
id = "bat"
}
}`,
},
},
})
}
66 changes: 66 additions & 0 deletions helper/resource/query/types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) HashiCorp, Inc.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from ../importstate.

// SPDX-License-Identifier: MPL-2.0

package query_test

import (
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/hashicorp/terraform-plugin-go/tftypes"
)

func RequiredBoolAttribute(name string) *tfprotov6.SchemaAttribute {
return &tfprotov6.SchemaAttribute{
Name: name,
Type: tftypes.Bool,
Required: true,
}
}

func OptionalComputedListAttribute(name string, elementType tftypes.Type) *tfprotov6.SchemaAttribute {
return &tfprotov6.SchemaAttribute{
Name: name,
Type: tftypes.List{ElementType: elementType},
Optional: true,
Computed: true,
}
}

func RequiredListAttribute(name string, elementType tftypes.Type) *tfprotov6.SchemaAttribute {
return &tfprotov6.SchemaAttribute{
Name: name,
Type: tftypes.List{ElementType: elementType},
Required: true,
}
}

func RequiredNumberAttribute(name string) *tfprotov6.SchemaAttribute {
return &tfprotov6.SchemaAttribute{
Name: name,
Type: tftypes.Number,
Required: true,
}
}

func ComputedStringAttribute(name string) *tfprotov6.SchemaAttribute {
return &tfprotov6.SchemaAttribute{
Name: name,
Type: tftypes.String,
Computed: true,
}
}

func OptionalStringAttribute(name string) *tfprotov6.SchemaAttribute {
return &tfprotov6.SchemaAttribute{
Name: name,
Type: tftypes.String,
Optional: true,
}
}

func RequiredStringAttribute(name string) *tfprotov6.SchemaAttribute {
return &tfprotov6.SchemaAttribute{
Name: name,
Type: tftypes.String,
Required: true,
}
}
2 changes: 2 additions & 0 deletions helper/resource/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,8 @@ type TestStep struct {
// for performing import testing where the prior TestStep configuration
// contained a provider outside the one under test.
ExternalProviders map[string]ExternalProvider

Query bool
}

// ConfigPlanChecks defines the different points in a Config TestStep when plan checks can be run.
Expand Down
40 changes: 39 additions & 1 deletion helper/resource/testing_new.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest
},
)

fmt.Println("Writing provider configuration:", c.providerConfig(ctx, false))
err := wd.SetConfig(ctx, config, nil)

if err != nil {
Expand Down Expand Up @@ -254,7 +255,10 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest

testStepConfig = teststep.Configuration(confRequest)

err = wd.SetConfig(ctx, testStepConfig, step.ConfigVariables)
if !step.Query {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For purposes of this PR, SetConfig and SetQuery are 2 different things because one writes/manages a .tf file and one writes/manages a .tfquery.hcl file.

Does if !step.Query feel right here? Likely not. The goal of this PR is more make-it-work than make-it-right/make-it-well-factored 😃

fmt.Println("Writing pre-switch configuration:", rawCfg)
err = wd.SetConfig(ctx, testStepConfig, step.ConfigVariables)
}

if err != nil {
logging.HelperResourceError(ctx,
Expand Down Expand Up @@ -356,6 +360,39 @@ func runNewTest(ctx context.Context, t testing.T, c TestCase, helper *plugintest
continue
}

if step.Query {
logging.HelperResourceTrace(ctx, "TestStep is Query mode")

queryConfigRequest := teststep.ConfigurationRequest{
Raw: &step.Config,
}
err := wd.SetQuery(ctx, teststep.Configuration(queryConfigRequest), step.ConfigVariables)
if err != nil {
t.Fatalf("Step %d/%d error setting query: %s", stepNumber, len(c.Steps), err)
}

err = runProviderCommand(ctx, t, wd, providers, func() error {
return wd.Init(ctx)
})
if err != nil {
t.Fatalf("Step %d/%d error running init: %s", stepNumber, len(c.Steps), err)
}

var queryOut []string
err = runProviderCommand(ctx, t, wd, providers, func() error {
var err error
queryOut, err = wd.Query(ctx)
return err
})
if err != nil {
fmt.Printf("Step %d/%d Query Output:\n%s\n", stepNumber, len(c.Steps), queryOut)
t.Fatalf("Step %d/%d error running query: %s", stepNumber, len(c.Steps), err)
}

fmt.Printf("Step %d/%d Query Output:\n%s\n", stepNumber, len(c.Steps), queryOut)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This simply echoes the Terraform output. So a test only fails if terraform query fails.

In the real world, we would make assertions, call "query checks," ...

continue
}

if cfg != nil {
logging.HelperResourceTrace(ctx, "TestStep is Config mode")

Expand Down Expand Up @@ -567,6 +604,7 @@ func testIDRefresh(ctx context.Context, t testing.T, c TestCase, wd *plugintest.

testStepConfigDefer := teststep.Configuration(confRequest)

fmt.Println("Writing the reset to original configuration:", rawCfg)
err = wd.SetConfig(ctx, testStepConfigDefer, step.ConfigVariables)

if err != nil {
Expand Down
Loading
Loading