mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 01:41:48 -06:00
cb2e9119aa
Signed-off-by: namgyalangmo <75657887+namgyalangmo@users.noreply.github.com>
886 lines
22 KiB
Go
886 lines
22 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package plugin6
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/opentofu/opentofu/internal/addrs"
|
|
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
"github.com/opentofu/opentofu/internal/configs/hcl2shim"
|
|
"github.com/opentofu/opentofu/internal/providers"
|
|
"github.com/opentofu/opentofu/internal/tfdiags"
|
|
"github.com/zclconf/go-cty/cty"
|
|
|
|
mockproto "github.com/opentofu/opentofu/internal/plugin6/mock_proto"
|
|
proto "github.com/opentofu/opentofu/internal/tfplugin6"
|
|
)
|
|
|
|
var _ providers.Interface = (*GRPCProvider)(nil)
|
|
|
|
var (
|
|
equateEmpty = cmpopts.EquateEmpty()
|
|
typeComparer = cmp.Comparer(cty.Type.Equals)
|
|
valueComparer = cmp.Comparer(cty.Value.RawEquals)
|
|
)
|
|
|
|
func mockProviderClient(t *testing.T) *mockproto.MockProviderClient {
|
|
ctrl := gomock.NewController(t)
|
|
client := mockproto.NewMockProviderClient(ctrl)
|
|
|
|
// we always need a GetSchema method
|
|
client.EXPECT().GetProviderSchema(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(providerProtoSchema(), nil)
|
|
|
|
return client
|
|
}
|
|
|
|
func checkDiags(t *testing.T, d tfdiags.Diagnostics) {
|
|
t.Helper()
|
|
if d.HasErrors() {
|
|
t.Fatal(d.Err())
|
|
}
|
|
}
|
|
|
|
// checkDiagsHasError ensures error diagnostics are present or fails the test.
|
|
func checkDiagsHasError(t *testing.T, d tfdiags.Diagnostics) {
|
|
t.Helper()
|
|
|
|
if !d.HasErrors() {
|
|
t.Fatal("expected error diagnostics")
|
|
}
|
|
}
|
|
|
|
func providerProtoSchema() *proto.GetProviderSchema_Response {
|
|
return &proto.GetProviderSchema_Response{
|
|
Provider: &proto.Schema{
|
|
Block: &proto.Schema_Block{
|
|
Attributes: []*proto.Schema_Attribute{
|
|
{
|
|
Name: "attr",
|
|
Type: []byte(`"string"`),
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
ResourceSchemas: map[string]*proto.Schema{
|
|
"resource": {
|
|
Version: 1,
|
|
Block: &proto.Schema_Block{
|
|
Attributes: []*proto.Schema_Attribute{
|
|
{
|
|
Name: "attr",
|
|
Type: []byte(`"string"`),
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
DataSourceSchemas: map[string]*proto.Schema{
|
|
"data": {
|
|
Version: 1,
|
|
Block: &proto.Schema_Block{
|
|
Attributes: []*proto.Schema_Attribute{
|
|
{
|
|
Name: "attr",
|
|
Type: []byte(`"string"`),
|
|
Required: true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_GetSchema(t *testing.T) {
|
|
p := &GRPCProvider{
|
|
client: mockProviderClient(t),
|
|
}
|
|
|
|
resp := p.GetProviderSchema()
|
|
checkDiags(t, resp.Diagnostics)
|
|
}
|
|
|
|
// Ensure that gRPC errors are returned early.
|
|
// Reference: https://github.com/hashicorp/terraform/issues/31047
|
|
func TestGRPCProvider_GetSchema_GRPCError(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
client := mockproto.NewMockProviderClient(ctrl)
|
|
|
|
client.EXPECT().GetProviderSchema(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.GetProviderSchema_Response{}, fmt.Errorf("test error"))
|
|
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
resp := p.GetProviderSchema()
|
|
|
|
checkDiagsHasError(t, resp.Diagnostics)
|
|
}
|
|
|
|
// Ensure that provider error diagnostics are returned early.
|
|
// Reference: https://github.com/hashicorp/terraform/issues/31047
|
|
func TestGRPCProvider_GetSchema_ResponseErrorDiagnostic(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
client := mockproto.NewMockProviderClient(ctrl)
|
|
|
|
client.EXPECT().GetProviderSchema(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.GetProviderSchema_Response{
|
|
Diagnostics: []*proto.Diagnostic{
|
|
{
|
|
Severity: proto.Diagnostic_ERROR,
|
|
Summary: "error summary",
|
|
Detail: "error detail",
|
|
},
|
|
},
|
|
// Trigger potential panics
|
|
Provider: &proto.Schema{},
|
|
}, nil)
|
|
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
resp := p.GetProviderSchema()
|
|
|
|
checkDiagsHasError(t, resp.Diagnostics)
|
|
}
|
|
|
|
func TestGRPCProvider_GetSchema_GlobalCacheEnabled(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
client := mockproto.NewMockProviderClient(ctrl)
|
|
// The SchemaCache is global and is saved between test runs
|
|
providers.SchemaCache = providers.NewMockSchemaCache()
|
|
|
|
providerAddr := addrs.Provider{
|
|
Namespace: "namespace",
|
|
Type: "type",
|
|
}
|
|
|
|
mockedProviderResponse := &proto.Schema{Version: 2, Block: &proto.Schema_Block{}}
|
|
|
|
client.EXPECT().GetProviderSchema(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Times(1).Return(&proto.GetProviderSchema_Response{
|
|
Provider: mockedProviderResponse,
|
|
ServerCapabilities: &proto.GetProviderSchema_ServerCapabilities{GetProviderSchemaOptional: true},
|
|
}, nil)
|
|
|
|
// Run GetProviderTwice, expect GetSchema to be called once
|
|
// Re-initialize the provider before each run to avoid usage of the local cache
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
Addr: providerAddr,
|
|
}
|
|
resp := p.GetProviderSchema()
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
if !cmp.Equal(resp.Provider.Version, mockedProviderResponse.Version) {
|
|
t.Fatal(cmp.Diff(resp.Provider.Version, mockedProviderResponse.Version))
|
|
}
|
|
|
|
p = &GRPCProvider{
|
|
client: client,
|
|
Addr: providerAddr,
|
|
}
|
|
resp = p.GetProviderSchema()
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
if !cmp.Equal(resp.Provider.Version, mockedProviderResponse.Version) {
|
|
t.Fatal(cmp.Diff(resp.Provider.Version, mockedProviderResponse.Version))
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_GetSchema_GlobalCacheDisabled(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
client := mockproto.NewMockProviderClient(ctrl)
|
|
// The SchemaCache is global and is saved between test runs
|
|
providers.SchemaCache = providers.NewMockSchemaCache()
|
|
|
|
providerAddr := addrs.Provider{
|
|
Namespace: "namespace",
|
|
Type: "type",
|
|
}
|
|
|
|
mockedProviderResponse := &proto.Schema{Version: 2, Block: &proto.Schema_Block{}}
|
|
|
|
client.EXPECT().GetProviderSchema(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Times(2).Return(&proto.GetProviderSchema_Response{
|
|
Provider: mockedProviderResponse,
|
|
ServerCapabilities: &proto.GetProviderSchema_ServerCapabilities{GetProviderSchemaOptional: false},
|
|
}, nil)
|
|
|
|
// Run GetProviderTwice, expect GetSchema to be called once
|
|
// Re-initialize the provider before each run to avoid usage of the local cache
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
Addr: providerAddr,
|
|
}
|
|
resp := p.GetProviderSchema()
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
if !cmp.Equal(resp.Provider.Version, mockedProviderResponse.Version) {
|
|
t.Fatal(cmp.Diff(resp.Provider.Version, mockedProviderResponse.Version))
|
|
}
|
|
|
|
p = &GRPCProvider{
|
|
client: client,
|
|
Addr: providerAddr,
|
|
}
|
|
resp = p.GetProviderSchema()
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
if !cmp.Equal(resp.Provider.Version, mockedProviderResponse.Version) {
|
|
t.Fatal(cmp.Diff(resp.Provider.Version, mockedProviderResponse.Version))
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_PrepareProviderConfig(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().ValidateProviderConfig(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ValidateProviderConfig_Response{}, nil)
|
|
|
|
cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
|
|
resp := p.ValidateProviderConfig(providers.ValidateProviderConfigRequest{Config: cfg})
|
|
checkDiags(t, resp.Diagnostics)
|
|
}
|
|
|
|
func TestGRPCProvider_ValidateResourceConfig(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().ValidateResourceConfig(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ValidateResourceConfig_Response{}, nil)
|
|
|
|
cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
|
|
resp := p.ValidateResourceConfig(providers.ValidateResourceConfigRequest{
|
|
TypeName: "resource",
|
|
Config: cfg,
|
|
})
|
|
checkDiags(t, resp.Diagnostics)
|
|
}
|
|
|
|
func TestGRPCProvider_ValidateDataResourceConfig(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().ValidateDataResourceConfig(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ValidateDataResourceConfig_Response{}, nil)
|
|
|
|
cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"})
|
|
resp := p.ValidateDataResourceConfig(providers.ValidateDataResourceConfigRequest{
|
|
TypeName: "data",
|
|
Config: cfg,
|
|
})
|
|
checkDiags(t, resp.Diagnostics)
|
|
}
|
|
|
|
func TestGRPCProvider_UpgradeResourceState(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().UpgradeResourceState(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.UpgradeResourceState_Response{
|
|
UpgradedState: &proto.DynamicValue{
|
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
|
},
|
|
}, nil)
|
|
|
|
resp := p.UpgradeResourceState(providers.UpgradeResourceStateRequest{
|
|
TypeName: "resource",
|
|
Version: 0,
|
|
RawStateJSON: []byte(`{"old_attr":"bar"}`),
|
|
})
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expected := cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
})
|
|
|
|
if !cmp.Equal(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_UpgradeResourceStateJSON(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().UpgradeResourceState(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.UpgradeResourceState_Response{
|
|
UpgradedState: &proto.DynamicValue{
|
|
Json: []byte(`{"attr":"bar"}`),
|
|
},
|
|
}, nil)
|
|
|
|
resp := p.UpgradeResourceState(providers.UpgradeResourceStateRequest{
|
|
TypeName: "resource",
|
|
Version: 0,
|
|
RawStateJSON: []byte(`{"old_attr":"bar"}`),
|
|
})
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expected := cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
})
|
|
|
|
if !cmp.Equal(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_Configure(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().ConfigureProvider(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ConfigureProvider_Response{}, nil)
|
|
|
|
resp := p.ConfigureProvider(providers.ConfigureProviderRequest{
|
|
Config: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("foo"),
|
|
}),
|
|
})
|
|
checkDiags(t, resp.Diagnostics)
|
|
}
|
|
|
|
func TestGRPCProvider_Stop(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
client := mockproto.NewMockProviderClient(ctrl)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().StopProvider(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.StopProvider_Response{}, nil)
|
|
|
|
err := p.Stop()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_ReadResource(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().ReadResource(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ReadResource_Response{
|
|
NewState: &proto.DynamicValue{
|
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
|
},
|
|
}, nil)
|
|
|
|
resp := p.ReadResource(providers.ReadResourceRequest{
|
|
TypeName: "resource",
|
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("foo"),
|
|
}),
|
|
})
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expected := cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
})
|
|
|
|
if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_ReadResourceJSON(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().ReadResource(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ReadResource_Response{
|
|
NewState: &proto.DynamicValue{
|
|
Json: []byte(`{"attr":"bar"}`),
|
|
},
|
|
}, nil)
|
|
|
|
resp := p.ReadResource(providers.ReadResourceRequest{
|
|
TypeName: "resource",
|
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("foo"),
|
|
}),
|
|
})
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expected := cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
})
|
|
|
|
if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_ReadEmptyJSON(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().ReadResource(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ReadResource_Response{
|
|
NewState: &proto.DynamicValue{
|
|
Json: []byte(``),
|
|
},
|
|
}, nil)
|
|
|
|
obj := cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("foo"),
|
|
})
|
|
resp := p.ReadResource(providers.ReadResourceRequest{
|
|
TypeName: "resource",
|
|
PriorState: obj,
|
|
})
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expected := cty.NullVal(obj.Type())
|
|
|
|
if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_PlanResourceChange(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
|
|
|
client.EXPECT().PlanResourceChange(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.PlanResourceChange_Response{
|
|
PlannedState: &proto.DynamicValue{
|
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
|
},
|
|
RequiresReplace: []*proto.AttributePath{
|
|
{
|
|
Steps: []*proto.AttributePath_Step{
|
|
{
|
|
Selector: &proto.AttributePath_Step_AttributeName{
|
|
AttributeName: "attr",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
PlannedPrivate: expectedPrivate,
|
|
}, nil)
|
|
|
|
resp := p.PlanResourceChange(providers.PlanResourceChangeRequest{
|
|
TypeName: "resource",
|
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("foo"),
|
|
}),
|
|
ProposedNewState: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
}),
|
|
Config: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
}),
|
|
})
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expectedState := cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
})
|
|
|
|
if !cmp.Equal(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
|
|
expectedReplace := `[]cty.Path{cty.Path{cty.GetAttrStep{Name:"attr"}}}`
|
|
replace := fmt.Sprintf("%#v", resp.RequiresReplace)
|
|
if expectedReplace != replace {
|
|
t.Fatalf("expected %q, got %q", expectedReplace, replace)
|
|
}
|
|
|
|
if !bytes.Equal(expectedPrivate, resp.PlannedPrivate) {
|
|
t.Fatalf("expected %q, got %q", expectedPrivate, resp.PlannedPrivate)
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_PlanResourceChangeJSON(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
|
|
|
client.EXPECT().PlanResourceChange(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.PlanResourceChange_Response{
|
|
PlannedState: &proto.DynamicValue{
|
|
Json: []byte(`{"attr":"bar"}`),
|
|
},
|
|
RequiresReplace: []*proto.AttributePath{
|
|
{
|
|
Steps: []*proto.AttributePath_Step{
|
|
{
|
|
Selector: &proto.AttributePath_Step_AttributeName{
|
|
AttributeName: "attr",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
PlannedPrivate: expectedPrivate,
|
|
}, nil)
|
|
|
|
resp := p.PlanResourceChange(providers.PlanResourceChangeRequest{
|
|
TypeName: "resource",
|
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("foo"),
|
|
}),
|
|
ProposedNewState: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
}),
|
|
Config: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
}),
|
|
})
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expectedState := cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
})
|
|
|
|
if !cmp.Equal(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
|
|
expectedReplace := `[]cty.Path{cty.Path{cty.GetAttrStep{Name:"attr"}}}`
|
|
replace := fmt.Sprintf("%#v", resp.RequiresReplace)
|
|
if expectedReplace != replace {
|
|
t.Fatalf("expected %q, got %q", expectedReplace, replace)
|
|
}
|
|
|
|
if !bytes.Equal(expectedPrivate, resp.PlannedPrivate) {
|
|
t.Fatalf("expected %q, got %q", expectedPrivate, resp.PlannedPrivate)
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_ApplyResourceChange(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
|
|
|
client.EXPECT().ApplyResourceChange(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ApplyResourceChange_Response{
|
|
NewState: &proto.DynamicValue{
|
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
|
},
|
|
Private: expectedPrivate,
|
|
}, nil)
|
|
|
|
resp := p.ApplyResourceChange(providers.ApplyResourceChangeRequest{
|
|
TypeName: "resource",
|
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("foo"),
|
|
}),
|
|
PlannedState: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
}),
|
|
Config: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
}),
|
|
PlannedPrivate: expectedPrivate,
|
|
})
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expectedState := cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
})
|
|
|
|
if !cmp.Equal(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
|
|
if !bytes.Equal(expectedPrivate, resp.Private) {
|
|
t.Fatalf("expected %q, got %q", expectedPrivate, resp.Private)
|
|
}
|
|
}
|
|
func TestGRPCProvider_ApplyResourceChangeJSON(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
|
|
|
client.EXPECT().ApplyResourceChange(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ApplyResourceChange_Response{
|
|
NewState: &proto.DynamicValue{
|
|
Json: []byte(`{"attr":"bar"}`),
|
|
},
|
|
Private: expectedPrivate,
|
|
}, nil)
|
|
|
|
resp := p.ApplyResourceChange(providers.ApplyResourceChangeRequest{
|
|
TypeName: "resource",
|
|
PriorState: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("foo"),
|
|
}),
|
|
PlannedState: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
}),
|
|
Config: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
}),
|
|
PlannedPrivate: expectedPrivate,
|
|
})
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expectedState := cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
})
|
|
|
|
if !cmp.Equal(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
|
|
if !bytes.Equal(expectedPrivate, resp.Private) {
|
|
t.Fatalf("expected %q, got %q", expectedPrivate, resp.Private)
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_ImportResourceState(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
|
|
|
client.EXPECT().ImportResourceState(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ImportResourceState_Response{
|
|
ImportedResources: []*proto.ImportResourceState_ImportedResource{
|
|
{
|
|
TypeName: "resource",
|
|
State: &proto.DynamicValue{
|
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
|
},
|
|
Private: expectedPrivate,
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
resp := p.ImportResourceState(providers.ImportResourceStateRequest{
|
|
TypeName: "resource",
|
|
ID: "foo",
|
|
})
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expectedResource := providers.ImportedResource{
|
|
TypeName: "resource",
|
|
State: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
}),
|
|
Private: expectedPrivate,
|
|
}
|
|
|
|
imported := resp.ImportedResources[0]
|
|
if !cmp.Equal(expectedResource, imported, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expectedResource, imported, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
}
|
|
func TestGRPCProvider_ImportResourceStateJSON(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
expectedPrivate := []byte(`{"meta": "data"}`)
|
|
|
|
client.EXPECT().ImportResourceState(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ImportResourceState_Response{
|
|
ImportedResources: []*proto.ImportResourceState_ImportedResource{
|
|
{
|
|
TypeName: "resource",
|
|
State: &proto.DynamicValue{
|
|
Json: []byte(`{"attr":"bar"}`),
|
|
},
|
|
Private: expectedPrivate,
|
|
},
|
|
},
|
|
}, nil)
|
|
|
|
resp := p.ImportResourceState(providers.ImportResourceStateRequest{
|
|
TypeName: "resource",
|
|
ID: "foo",
|
|
})
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expectedResource := providers.ImportedResource{
|
|
TypeName: "resource",
|
|
State: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
}),
|
|
Private: expectedPrivate,
|
|
}
|
|
|
|
imported := resp.ImportedResources[0]
|
|
if !cmp.Equal(expectedResource, imported, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expectedResource, imported, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_ReadDataSource(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().ReadDataSource(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ReadDataSource_Response{
|
|
State: &proto.DynamicValue{
|
|
Msgpack: []byte("\x81\xa4attr\xa3bar"),
|
|
},
|
|
}, nil)
|
|
|
|
resp := p.ReadDataSource(providers.ReadDataSourceRequest{
|
|
TypeName: "data",
|
|
Config: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("foo"),
|
|
}),
|
|
})
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expected := cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
})
|
|
|
|
if !cmp.Equal(expected, resp.State, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expected, resp.State, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
}
|
|
|
|
func TestGRPCProvider_ReadDataSourceJSON(t *testing.T) {
|
|
client := mockProviderClient(t)
|
|
p := &GRPCProvider{
|
|
client: client,
|
|
}
|
|
|
|
client.EXPECT().ReadDataSource(
|
|
gomock.Any(),
|
|
gomock.Any(),
|
|
).Return(&proto.ReadDataSource_Response{
|
|
State: &proto.DynamicValue{
|
|
Json: []byte(`{"attr":"bar"}`),
|
|
},
|
|
}, nil)
|
|
|
|
resp := p.ReadDataSource(providers.ReadDataSourceRequest{
|
|
TypeName: "data",
|
|
Config: cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("foo"),
|
|
}),
|
|
})
|
|
|
|
checkDiags(t, resp.Diagnostics)
|
|
|
|
expected := cty.ObjectVal(map[string]cty.Value{
|
|
"attr": cty.StringVal("bar"),
|
|
})
|
|
|
|
if !cmp.Equal(expected, resp.State, typeComparer, valueComparer, equateEmpty) {
|
|
t.Fatal(cmp.Diff(expected, resp.State, typeComparer, valueComparer, equateEmpty))
|
|
}
|
|
}
|