package plugin import ( "io" "testing" "github.com/golang/mock/gomock" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/hashicorp/terraform/internal/configs/hcl2shim" "github.com/hashicorp/terraform/internal/provisioners" proto "github.com/hashicorp/terraform/internal/tfplugin5" "github.com/zclconf/go-cty/cty" mockproto "github.com/hashicorp/terraform/internal/plugin/mock_proto" ) var _ provisioners.Interface = (*GRPCProvisioner)(nil) var ( equateEmpty = cmpopts.EquateEmpty() typeComparer = cmp.Comparer(cty.Type.Equals) valueComparer = cmp.Comparer(cty.Value.RawEquals) ) func mockProvisionerClient(t *testing.T) *mockproto.MockProvisionerClient { ctrl := gomock.NewController(t) client := mockproto.NewMockProvisionerClient(ctrl) // we always need a GetSchema method client.EXPECT().GetSchema( gomock.Any(), gomock.Any(), ).Return(provisionerProtoSchema(), nil) return client } func provisionerProtoSchema() *proto.GetProvisionerSchema_Response { return &proto.GetProvisionerSchema_Response{ Provisioner: &proto.Schema{ Block: &proto.Schema_Block{ Attributes: []*proto.Schema_Attribute{ { Name: "attr", Type: []byte(`"string"`), Required: true, }, }, }, }, } } func TestGRPCProvisioner_GetSchema(t *testing.T) { p := &GRPCProvisioner{ client: mockProvisionerClient(t), } resp := p.GetSchema() checkDiags(t, resp.Diagnostics) } func TestGRPCProvisioner_ValidateProvisionerConfig(t *testing.T) { client := mockProvisionerClient(t) p := &GRPCProvisioner{ client: client, } client.EXPECT().ValidateProvisionerConfig( gomock.Any(), gomock.Any(), ).Return(&proto.ValidateProvisionerConfig_Response{}, nil) cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"}) resp := p.ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{Config: cfg}) checkDiags(t, resp.Diagnostics) } func TestGRPCProvisioner_ProvisionResource(t *testing.T) { ctrl := gomock.NewController(t) client := mockproto.NewMockProvisionerClient(ctrl) // we always need a GetSchema method client.EXPECT().GetSchema( gomock.Any(), gomock.Any(), ).Return(provisionerProtoSchema(), nil) stream := mockproto.NewMockProvisioner_ProvisionResourceClient(ctrl) stream.EXPECT().Recv().Return(&proto.ProvisionResource_Response{ Output: "provisioned", }, io.EOF) client.EXPECT().ProvisionResource( gomock.Any(), gomock.Any(), ).Return(stream, nil) p := &GRPCProvisioner{ client: client, } rec := &provisionRecorder{} resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{ Config: cty.ObjectVal(map[string]cty.Value{ "attr": cty.StringVal("value"), }), Connection: cty.EmptyObjectVal, UIOutput: rec, }) if resp.Diagnostics.HasErrors() { t.Fatal(resp.Diagnostics.Err()) } if len(rec.output) == 0 || rec.output[0] != "provisioned" { t.Fatalf("expected %q, got %q", []string{"provisioned"}, rec.output) } } type provisionRecorder struct { output []string } func (r *provisionRecorder) Output(s string) { r.output = append(r.output, s) } func TestGRPCProvisioner_Stop(t *testing.T) { ctrl := gomock.NewController(t) client := mockproto.NewMockProvisionerClient(ctrl) p := &GRPCProvisioner{ client: client, } client.EXPECT().Stop( gomock.Any(), gomock.Any(), ).Return(&proto.Stop_Response{}, nil) err := p.Stop() if err != nil { t.Fatal(err) } }