github.com/opentofu/opentofu@v1.7.1/internal/plugin/grpc_provisioner_test.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package plugin 7 8 import ( 9 "io" 10 "testing" 11 12 "github.com/golang/mock/gomock" 13 "github.com/google/go-cmp/cmp" 14 "github.com/google/go-cmp/cmp/cmpopts" 15 "github.com/opentofu/opentofu/internal/configs/hcl2shim" 16 "github.com/opentofu/opentofu/internal/provisioners" 17 proto "github.com/opentofu/opentofu/internal/tfplugin5" 18 "github.com/zclconf/go-cty/cty" 19 20 mockproto "github.com/opentofu/opentofu/internal/plugin/mock_proto" 21 ) 22 23 var _ provisioners.Interface = (*GRPCProvisioner)(nil) 24 25 var ( 26 equateEmpty = cmpopts.EquateEmpty() 27 typeComparer = cmp.Comparer(cty.Type.Equals) 28 valueComparer = cmp.Comparer(cty.Value.RawEquals) 29 ) 30 31 func mockProvisionerClient(t *testing.T) *mockproto.MockProvisionerClient { 32 ctrl := gomock.NewController(t) 33 client := mockproto.NewMockProvisionerClient(ctrl) 34 35 // we always need a GetSchema method 36 client.EXPECT().GetSchema( 37 gomock.Any(), 38 gomock.Any(), 39 ).Return(provisionerProtoSchema(), nil) 40 41 return client 42 } 43 44 func provisionerProtoSchema() *proto.GetProvisionerSchema_Response { 45 return &proto.GetProvisionerSchema_Response{ 46 Provisioner: &proto.Schema{ 47 Block: &proto.Schema_Block{ 48 Attributes: []*proto.Schema_Attribute{ 49 { 50 Name: "attr", 51 Type: []byte(`"string"`), 52 Required: true, 53 }, 54 }, 55 }, 56 }, 57 } 58 } 59 60 func TestGRPCProvisioner_GetSchema(t *testing.T) { 61 p := &GRPCProvisioner{ 62 client: mockProvisionerClient(t), 63 } 64 65 resp := p.GetSchema() 66 checkDiags(t, resp.Diagnostics) 67 } 68 69 func TestGRPCProvisioner_ValidateProvisionerConfig(t *testing.T) { 70 client := mockProvisionerClient(t) 71 p := &GRPCProvisioner{ 72 client: client, 73 } 74 75 client.EXPECT().ValidateProvisionerConfig( 76 gomock.Any(), 77 gomock.Any(), 78 ).Return(&proto.ValidateProvisionerConfig_Response{}, nil) 79 80 cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"}) 81 resp := p.ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{Config: cfg}) 82 checkDiags(t, resp.Diagnostics) 83 } 84 85 func TestGRPCProvisioner_ProvisionResource(t *testing.T) { 86 ctrl := gomock.NewController(t) 87 client := mockproto.NewMockProvisionerClient(ctrl) 88 89 // we always need a GetSchema method 90 client.EXPECT().GetSchema( 91 gomock.Any(), 92 gomock.Any(), 93 ).Return(provisionerProtoSchema(), nil) 94 95 stream := mockproto.NewMockProvisioner_ProvisionResourceClient(ctrl) 96 stream.EXPECT().Recv().Return(&proto.ProvisionResource_Response{ 97 Output: "provisioned", 98 }, io.EOF) 99 100 client.EXPECT().ProvisionResource( 101 gomock.Any(), 102 gomock.Any(), 103 ).Return(stream, nil) 104 105 p := &GRPCProvisioner{ 106 client: client, 107 } 108 109 rec := &provisionRecorder{} 110 111 resp := p.ProvisionResource(provisioners.ProvisionResourceRequest{ 112 Config: cty.ObjectVal(map[string]cty.Value{ 113 "attr": cty.StringVal("value"), 114 }), 115 Connection: cty.EmptyObjectVal, 116 UIOutput: rec, 117 }) 118 119 if resp.Diagnostics.HasErrors() { 120 t.Fatal(resp.Diagnostics.Err()) 121 } 122 123 if len(rec.output) == 0 || rec.output[0] != "provisioned" { 124 t.Fatalf("expected %q, got %q", []string{"provisioned"}, rec.output) 125 } 126 } 127 128 type provisionRecorder struct { 129 output []string 130 } 131 132 func (r *provisionRecorder) Output(s string) { 133 r.output = append(r.output, s) 134 } 135 136 func TestGRPCProvisioner_Stop(t *testing.T) { 137 ctrl := gomock.NewController(t) 138 client := mockproto.NewMockProvisionerClient(ctrl) 139 p := &GRPCProvisioner{ 140 client: client, 141 } 142 143 client.EXPECT().Stop( 144 gomock.Any(), 145 gomock.Any(), 146 ).Return(&proto.Stop_Response{}, nil) 147 148 err := p.Stop() 149 if err != nil { 150 t.Fatal(err) 151 } 152 }