mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-26 00:41:27 -06:00
new terraform_data managed resource
Replace and enhance the `null_resource` functionality with a new `terraform_data` managed resource.
This commit is contained in:
parent
ec6451a82a
commit
3b73ed3348
@ -8,13 +8,7 @@ import (
|
||||
)
|
||||
|
||||
// Provider is an implementation of providers.Interface
|
||||
type Provider struct {
|
||||
// Provider is the schema for the provider itself.
|
||||
Schema providers.Schema
|
||||
|
||||
// DataSources maps the data source name to that data source's schema.
|
||||
DataSources map[string]providers.Schema
|
||||
}
|
||||
type Provider struct{}
|
||||
|
||||
// NewProvider returns a new terraform provider
|
||||
func NewProvider() providers.Interface {
|
||||
@ -27,6 +21,9 @@ func (p *Provider) GetProviderSchema() providers.GetProviderSchemaResponse {
|
||||
DataSources: map[string]providers.Schema{
|
||||
"terraform_remote_state": dataSourceRemoteStateGetSchema(),
|
||||
},
|
||||
ResourceTypes: map[string]providers.Schema{
|
||||
"terraform_data": dataStoreResourceSchema(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,26 +96,26 @@ func (p *Provider) Stop() error {
|
||||
// instance state whose schema version is less than the one reported by the
|
||||
// currently-used version of the corresponding provider, and the upgraded
|
||||
// result is used for any further processing.
|
||||
func (p *Provider) UpgradeResourceState(providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse {
|
||||
panic("unimplemented - terraform_remote_state has no resources")
|
||||
func (p *Provider) UpgradeResourceState(req providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse {
|
||||
return upgradeDataStoreResourceState(req)
|
||||
}
|
||||
|
||||
// ReadResource refreshes a resource and returns its current state.
|
||||
func (p *Provider) ReadResource(providers.ReadResourceRequest) providers.ReadResourceResponse {
|
||||
panic("unimplemented - terraform_remote_state has no resources")
|
||||
func (p *Provider) ReadResource(req providers.ReadResourceRequest) providers.ReadResourceResponse {
|
||||
return readDataStoreResourceState(req)
|
||||
}
|
||||
|
||||
// PlanResourceChange takes the current state and proposed state of a
|
||||
// resource, and returns the planned final state.
|
||||
func (p *Provider) PlanResourceChange(providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
|
||||
panic("unimplemented - terraform_remote_state has no resources")
|
||||
func (p *Provider) PlanResourceChange(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
|
||||
return planDataStoreResourceChange(req)
|
||||
}
|
||||
|
||||
// ApplyResourceChange takes the planned state for a resource, which may
|
||||
// yet contain unknown computed values, and applies the changes returning
|
||||
// the final state.
|
||||
func (p *Provider) ApplyResourceChange(providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
|
||||
panic("unimplemented - terraform_remote_state has no resources")
|
||||
func (p *Provider) ApplyResourceChange(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
|
||||
return applyDataStoreResourceChange(req)
|
||||
}
|
||||
|
||||
// ImportResourceState requests that the given resource be imported.
|
||||
@ -127,11 +124,8 @@ func (p *Provider) ImportResourceState(providers.ImportResourceStateRequest) pro
|
||||
}
|
||||
|
||||
// ValidateResourceConfig is used to to validate the resource configuration values.
|
||||
func (p *Provider) ValidateResourceConfig(providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
|
||||
// At this moment there is nothing to configure for the terraform provider,
|
||||
// so we will happily return without taking any action
|
||||
var res providers.ValidateResourceConfigResponse
|
||||
return res
|
||||
func (p *Provider) ValidateResourceConfig(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
|
||||
return validateDataStoreResourceConfig(req)
|
||||
}
|
||||
|
||||
// Close is a noop for this provider, since it's run in-process.
|
||||
|
146
internal/builtin/providers/terraform/resource_data.go
Normal file
146
internal/builtin/providers/terraform/resource_data.go
Normal file
@ -0,0 +1,146 @@
|
||||
package terraform
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/hashicorp/terraform/internal/configs/configschema"
|
||||
"github.com/hashicorp/terraform/internal/providers"
|
||||
"github.com/hashicorp/terraform/internal/tfdiags"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
ctyjson "github.com/zclconf/go-cty/cty/json"
|
||||
)
|
||||
|
||||
func dataStoreResourceSchema() providers.Schema {
|
||||
return providers.Schema{
|
||||
Block: &configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"input": {Type: cty.DynamicPseudoType, Optional: true},
|
||||
"output": {Type: cty.DynamicPseudoType, Computed: true},
|
||||
"trigger": {Type: cty.DynamicPseudoType, Optional: true},
|
||||
"id": {Type: cty.String, Computed: true},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func validateDataStoreResourceConfig(req providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) {
|
||||
if req.Config.IsNull() {
|
||||
return resp
|
||||
}
|
||||
|
||||
// Core does not currently validate computed values are not set in the
|
||||
// configuration.
|
||||
for _, attr := range []string{"id", "output"} {
|
||||
if !req.Config.GetAttr(attr).IsNull() {
|
||||
resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf(`%q attribute is read-only`, attr))
|
||||
}
|
||||
}
|
||||
return resp
|
||||
}
|
||||
|
||||
func upgradeDataStoreResourceState(req providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
|
||||
ty := dataStoreResourceSchema().Block.ImpliedType()
|
||||
val, err := ctyjson.Unmarshal(req.RawStateJSON, ty)
|
||||
if err != nil {
|
||||
resp.Diagnostics = resp.Diagnostics.Append(err)
|
||||
return resp
|
||||
}
|
||||
|
||||
resp.UpgradedState = val
|
||||
return resp
|
||||
}
|
||||
|
||||
func readDataStoreResourceState(req providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
|
||||
resp.NewState = req.PriorState
|
||||
return resp
|
||||
}
|
||||
|
||||
func planDataStoreResourceChange(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
||||
if req.ProposedNewState.IsNull() {
|
||||
// destroy op
|
||||
resp.PlannedState = req.ProposedNewState
|
||||
return resp
|
||||
}
|
||||
|
||||
planned := req.ProposedNewState.AsValueMap()
|
||||
|
||||
input := req.ProposedNewState.GetAttr("input")
|
||||
trigger := req.ProposedNewState.GetAttr("trigger")
|
||||
|
||||
switch {
|
||||
case req.PriorState.IsNull():
|
||||
// Create
|
||||
// Set the id value to unknown.
|
||||
planned["id"] = cty.UnknownVal(cty.String)
|
||||
|
||||
// Only compute a new output if input has a non-null value.
|
||||
if !input.IsNull() {
|
||||
planned["output"] = cty.UnknownVal(input.Type())
|
||||
}
|
||||
|
||||
resp.PlannedState = cty.ObjectVal(planned)
|
||||
return resp
|
||||
|
||||
case !req.PriorState.GetAttr("trigger").RawEquals(trigger):
|
||||
// trigger changed, so we need to replace the entire instance
|
||||
resp.RequiresReplace = append(resp.RequiresReplace, cty.GetAttrPath("trigger"))
|
||||
planned["id"] = cty.UnknownVal(cty.String)
|
||||
|
||||
// We need to check the input for the replacement instance to compute a
|
||||
// new output.
|
||||
if input.IsNull() {
|
||||
planned["output"] = cty.NullVal(cty.DynamicPseudoType)
|
||||
} else {
|
||||
planned["output"] = cty.UnknownVal(input.Type())
|
||||
}
|
||||
|
||||
case !req.PriorState.GetAttr("input").RawEquals(input):
|
||||
// only input changed, so we only need to re-compute output
|
||||
planned["output"] = cty.UnknownVal(input.Type())
|
||||
}
|
||||
|
||||
resp.PlannedState = cty.ObjectVal(planned)
|
||||
return resp
|
||||
}
|
||||
|
||||
var testUUIDHook func() string
|
||||
|
||||
func applyDataStoreResourceChange(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
|
||||
if req.PlannedState.IsNull() {
|
||||
resp.NewState = req.PlannedState
|
||||
return resp
|
||||
}
|
||||
|
||||
newState := req.PlannedState.AsValueMap()
|
||||
|
||||
if !req.PlannedState.GetAttr("output").IsKnown() {
|
||||
newState["output"] = req.PlannedState.GetAttr("input")
|
||||
}
|
||||
|
||||
if !req.PlannedState.GetAttr("id").IsKnown() {
|
||||
idString, err := uuid.GenerateUUID()
|
||||
// Terraform would probably never get this far without a good random
|
||||
// source, but catch the error anyway.
|
||||
if err != nil {
|
||||
diag := tfdiags.AttributeValue(
|
||||
tfdiags.Error,
|
||||
"Error generating id",
|
||||
err.Error(),
|
||||
cty.GetAttrPath("id"),
|
||||
)
|
||||
|
||||
resp.Diagnostics = resp.Diagnostics.Append(diag)
|
||||
}
|
||||
|
||||
if testUUIDHook != nil {
|
||||
idString = testUUIDHook()
|
||||
}
|
||||
|
||||
newState["id"] = cty.StringVal(idString)
|
||||
}
|
||||
|
||||
resp.NewState = cty.ObjectVal(newState)
|
||||
|
||||
return resp
|
||||
}
|
366
internal/builtin/providers/terraform/resource_data_test.go
Normal file
366
internal/builtin/providers/terraform/resource_data_test.go
Normal file
@ -0,0 +1,366 @@
|
||||
package terraform
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/providers"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
ctyjson "github.com/zclconf/go-cty/cty/json"
|
||||
)
|
||||
|
||||
func TestManagedDataValidate(t *testing.T) {
|
||||
cfg := map[string]cty.Value{
|
||||
"input": cty.NullVal(cty.DynamicPseudoType),
|
||||
"output": cty.NullVal(cty.DynamicPseudoType),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.NullVal(cty.String),
|
||||
}
|
||||
|
||||
// empty
|
||||
req := providers.ValidateResourceConfigRequest{
|
||||
TypeName: "terraform_data",
|
||||
Config: cty.ObjectVal(cfg),
|
||||
}
|
||||
|
||||
resp := validateDataStoreResourceConfig(req)
|
||||
if resp.Diagnostics.HasErrors() {
|
||||
t.Error("empty config error:", resp.Diagnostics.ErrWithWarnings())
|
||||
}
|
||||
|
||||
// invalid computed values
|
||||
cfg["output"] = cty.StringVal("oops")
|
||||
req.Config = cty.ObjectVal(cfg)
|
||||
|
||||
resp = validateDataStoreResourceConfig(req)
|
||||
if !resp.Diagnostics.HasErrors() {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
||||
msg := resp.Diagnostics.Err().Error()
|
||||
if !strings.Contains(msg, "attribute is read-only") {
|
||||
t.Error("unexpected error", msg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagedDataUpgradeState(t *testing.T) {
|
||||
schema := dataStoreResourceSchema()
|
||||
ty := schema.Block.ImpliedType()
|
||||
|
||||
state := cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.ListVal([]cty.Value{
|
||||
cty.StringVal("a"), cty.StringVal("b"),
|
||||
}),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
})
|
||||
|
||||
jsState, err := ctyjson.Marshal(state, ty)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// empty
|
||||
req := providers.UpgradeResourceStateRequest{
|
||||
TypeName: "terraform_data",
|
||||
RawStateJSON: jsState,
|
||||
}
|
||||
|
||||
resp := upgradeDataStoreResourceState(req)
|
||||
if resp.Diagnostics.HasErrors() {
|
||||
t.Error("upgrade state error:", resp.Diagnostics.ErrWithWarnings())
|
||||
}
|
||||
|
||||
if !resp.UpgradedState.RawEquals(state) {
|
||||
t.Errorf("prior state was:\n%#v\nupgraded state is:\n%#v\n", state, resp.UpgradedState)
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagedDataRead(t *testing.T) {
|
||||
req := providers.ReadResourceRequest{
|
||||
TypeName: "terraform_data",
|
||||
PriorState: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.ListVal([]cty.Value{
|
||||
cty.StringVal("a"), cty.StringVal("b"),
|
||||
}),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
}
|
||||
|
||||
resp := readDataStoreResourceState(req)
|
||||
if resp.Diagnostics.HasErrors() {
|
||||
t.Fatal("unexpected error", resp.Diagnostics.ErrWithWarnings())
|
||||
}
|
||||
|
||||
if !resp.NewState.RawEquals(req.PriorState) {
|
||||
t.Errorf("prior state was:\n%#v\nnew state is:\n%#v\n", req.PriorState, resp.NewState)
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagedDataPlan(t *testing.T) {
|
||||
schema := dataStoreResourceSchema().Block
|
||||
ty := schema.ImpliedType()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
prior cty.Value
|
||||
proposed cty.Value
|
||||
planned cty.Value
|
||||
}{
|
||||
"create": {
|
||||
prior: cty.NullVal(ty),
|
||||
proposed: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.NullVal(cty.DynamicPseudoType),
|
||||
"output": cty.NullVal(cty.DynamicPseudoType),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.NullVal(cty.String),
|
||||
}),
|
||||
planned: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.NullVal(cty.DynamicPseudoType),
|
||||
"output": cty.NullVal(cty.DynamicPseudoType),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
},
|
||||
|
||||
"create-output": {
|
||||
prior: cty.NullVal(ty),
|
||||
proposed: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.NullVal(cty.DynamicPseudoType),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.NullVal(cty.String),
|
||||
}),
|
||||
planned: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.UnknownVal(cty.String),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
},
|
||||
|
||||
"update-input": {
|
||||
prior: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
proposed: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.UnknownVal(cty.List(cty.String)),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
planned: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.UnknownVal(cty.List(cty.String)),
|
||||
"output": cty.UnknownVal(cty.List(cty.String)),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
},
|
||||
|
||||
"update-trigger": {
|
||||
prior: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
proposed: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.StringVal("new-value"),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
planned: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.UnknownVal(cty.String),
|
||||
"trigger": cty.StringVal("new-value"),
|
||||
"id": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
},
|
||||
|
||||
"update-input-trigger": {
|
||||
prior: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.MapVal(map[string]cty.Value{
|
||||
"key": cty.StringVal("value"),
|
||||
}),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
proposed: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.MapVal(map[string]cty.Value{
|
||||
"key": cty.StringVal("new value"),
|
||||
}),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
planned: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
|
||||
"output": cty.UnknownVal(cty.List(cty.String)),
|
||||
"trigger": cty.MapVal(map[string]cty.Value{
|
||||
"key": cty.StringVal("new value"),
|
||||
}),
|
||||
"id": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
},
|
||||
} {
|
||||
t.Run("plan-"+name, func(t *testing.T) {
|
||||
req := providers.PlanResourceChangeRequest{
|
||||
TypeName: "terraform_data",
|
||||
PriorState: tc.prior,
|
||||
ProposedNewState: tc.proposed,
|
||||
}
|
||||
|
||||
resp := planDataStoreResourceChange(req)
|
||||
if resp.Diagnostics.HasErrors() {
|
||||
t.Fatal(resp.Diagnostics.ErrWithWarnings())
|
||||
}
|
||||
|
||||
if !resp.PlannedState.RawEquals(tc.planned) {
|
||||
t.Errorf("expected:\n%#v\ngot:\n%#v\n", tc.planned, resp.PlannedState)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagedDataApply(t *testing.T) {
|
||||
testUUIDHook = func() string {
|
||||
return "not-quite-unique"
|
||||
}
|
||||
defer func() {
|
||||
testUUIDHook = nil
|
||||
}()
|
||||
|
||||
schema := dataStoreResourceSchema().Block
|
||||
ty := schema.ImpliedType()
|
||||
|
||||
for name, tc := range map[string]struct {
|
||||
prior cty.Value
|
||||
planned cty.Value
|
||||
state cty.Value
|
||||
}{
|
||||
"create": {
|
||||
prior: cty.NullVal(ty),
|
||||
planned: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.NullVal(cty.DynamicPseudoType),
|
||||
"output": cty.NullVal(cty.DynamicPseudoType),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
state: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.NullVal(cty.DynamicPseudoType),
|
||||
"output": cty.NullVal(cty.DynamicPseudoType),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
},
|
||||
|
||||
"create-output": {
|
||||
prior: cty.NullVal(ty),
|
||||
planned: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.UnknownVal(cty.String),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
state: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
},
|
||||
|
||||
"update-input": {
|
||||
prior: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
planned: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
|
||||
"output": cty.UnknownVal(cty.List(cty.String)),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
state: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
|
||||
"output": cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
},
|
||||
|
||||
"update-trigger": {
|
||||
prior: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.NullVal(cty.DynamicPseudoType),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
planned: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.UnknownVal(cty.String),
|
||||
"trigger": cty.StringVal("new-value"),
|
||||
"id": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
state: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.StringVal("new-value"),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
},
|
||||
|
||||
"update-input-trigger": {
|
||||
prior: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.StringVal("input"),
|
||||
"output": cty.StringVal("input"),
|
||||
"trigger": cty.MapVal(map[string]cty.Value{
|
||||
"key": cty.StringVal("value"),
|
||||
}),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
planned: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
|
||||
"output": cty.UnknownVal(cty.List(cty.String)),
|
||||
"trigger": cty.MapVal(map[string]cty.Value{
|
||||
"key": cty.StringVal("new value"),
|
||||
}),
|
||||
"id": cty.UnknownVal(cty.String),
|
||||
}),
|
||||
state: cty.ObjectVal(map[string]cty.Value{
|
||||
"input": cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
|
||||
"output": cty.ListVal([]cty.Value{cty.StringVal("new-input")}),
|
||||
"trigger": cty.MapVal(map[string]cty.Value{
|
||||
"key": cty.StringVal("new value"),
|
||||
}),
|
||||
"id": cty.StringVal("not-quite-unique"),
|
||||
}),
|
||||
},
|
||||
} {
|
||||
t.Run("apply-"+name, func(t *testing.T) {
|
||||
req := providers.ApplyResourceChangeRequest{
|
||||
TypeName: "terraform_data",
|
||||
PriorState: tc.prior,
|
||||
PlannedState: tc.planned,
|
||||
}
|
||||
|
||||
resp := applyDataStoreResourceChange(req)
|
||||
if resp.Diagnostics.HasErrors() {
|
||||
t.Fatal(resp.Diagnostics.ErrWithWarnings())
|
||||
}
|
||||
|
||||
if !resp.NewState.RawEquals(tc.state) {
|
||||
t.Errorf("expected:\n%#v\ngot:\n%#v\n", tc.state, resp.NewState)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user