github.com/opentofu/opentofu@v1.7.1/internal/cloudplugin/cloudplugin1/grpc_client_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 cloudplugin1
     7  
     8  import (
     9  	"bytes"
    10  	"context"
    11  	"errors"
    12  	"fmt"
    13  	"io"
    14  	"testing"
    15  
    16  	"github.com/golang/mock/gomock"
    17  	"github.com/opentofu/opentofu/internal/cloudplugin/cloudproto1"
    18  	"github.com/opentofu/opentofu/internal/cloudplugin/mock_cloudproto1"
    19  )
    20  
    21  var mockError = "this is a mock error"
    22  
    23  func testGRPCloudClient(t *testing.T, ctrl *gomock.Controller, client *mock_cloudproto1.MockCommandService_ExecuteClient, executeError error) *GRPCCloudClient {
    24  	t.Helper()
    25  
    26  	if client != nil && executeError != nil {
    27  		t.Fatal("one of client or executeError must be nil")
    28  	}
    29  
    30  	result := mock_cloudproto1.NewMockCommandServiceClient(ctrl)
    31  
    32  	result.EXPECT().Execute(
    33  		gomock.Any(),
    34  		gomock.Any(),
    35  		gomock.Any(),
    36  	).Return(client, executeError)
    37  
    38  	return &GRPCCloudClient{
    39  		client:  result,
    40  		context: context.Background(),
    41  	}
    42  }
    43  
    44  func Test_GRPCCloudClient_ExecuteError(t *testing.T) {
    45  	ctrl := gomock.NewController(t)
    46  	gRPCClient := testGRPCloudClient(t, ctrl, nil, errors.New(mockError))
    47  
    48  	buffer := bytes.Buffer{}
    49  	exitCode := gRPCClient.Execute([]string{"example"}, io.Discard, &buffer)
    50  
    51  	if exitCode != 1 {
    52  		t.Fatalf("expected exit %d, got %d", 1, exitCode)
    53  	}
    54  
    55  	if buffer.String() != mockError {
    56  		t.Errorf("expected error %q, got %q", mockError, buffer.String())
    57  	}
    58  }
    59  
    60  func Test_GRPCCloudClient_Execute_RecvError(t *testing.T) {
    61  	ctrl := gomock.NewController(t)
    62  	executeClient := mock_cloudproto1.NewMockCommandService_ExecuteClient(ctrl)
    63  	executeClient.EXPECT().Recv().Return(nil, errors.New(mockError))
    64  
    65  	gRPCClient := testGRPCloudClient(t, ctrl, executeClient, nil)
    66  
    67  	buffer := bytes.Buffer{}
    68  	exitCode := gRPCClient.Execute([]string{"example"}, io.Discard, &buffer)
    69  
    70  	if exitCode != 1 {
    71  		t.Fatalf("expected exit %d, got %d", 1, exitCode)
    72  	}
    73  
    74  	mockRecvError := fmt.Sprintf("Failed to receive command response from cloudplugin: %s", mockError)
    75  
    76  	if buffer.String() != mockRecvError {
    77  		t.Errorf("expected error %q, got %q", mockRecvError, buffer.String())
    78  	}
    79  }
    80  
    81  func Test_GRPCCloudClient_Execute_Invalid_Exit(t *testing.T) {
    82  	ctrl := gomock.NewController(t)
    83  	executeClient := mock_cloudproto1.NewMockCommandService_ExecuteClient(ctrl)
    84  
    85  	executeClient.EXPECT().Recv().Return(
    86  		&cloudproto1.CommandResponse{
    87  			Data: &cloudproto1.CommandResponse_ExitCode{
    88  				ExitCode: 3_000,
    89  			},
    90  		}, nil,
    91  	)
    92  
    93  	gRPCClient := testGRPCloudClient(t, ctrl, executeClient, nil)
    94  
    95  	exitCode := gRPCClient.Execute([]string{"example"}, io.Discard, io.Discard)
    96  
    97  	if exitCode != 255 {
    98  		t.Fatalf("expected exit %q, got %q", 255, exitCode)
    99  	}
   100  }
   101  
   102  func Test_GRPCCloudClient_Execute(t *testing.T) {
   103  	ctrl := gomock.NewController(t)
   104  	executeClient := mock_cloudproto1.NewMockCommandService_ExecuteClient(ctrl)
   105  
   106  	gomock.InOrder(
   107  		executeClient.EXPECT().Recv().Return(
   108  			&cloudproto1.CommandResponse{
   109  				Data: &cloudproto1.CommandResponse_Stdout{
   110  					Stdout: []byte("firstcall\n"),
   111  				},
   112  			}, nil,
   113  		),
   114  		executeClient.EXPECT().Recv().Return(
   115  			&cloudproto1.CommandResponse{
   116  				Data: &cloudproto1.CommandResponse_Stdout{
   117  					Stdout: []byte("secondcall\n"),
   118  				},
   119  			}, nil,
   120  		),
   121  		executeClient.EXPECT().Recv().Return(
   122  			&cloudproto1.CommandResponse{
   123  				Data: &cloudproto1.CommandResponse_ExitCode{
   124  					ExitCode: 99,
   125  				},
   126  			}, nil,
   127  		),
   128  	)
   129  
   130  	gRPCClient := testGRPCloudClient(t, ctrl, executeClient, nil)
   131  
   132  	stdoutBuffer := bytes.Buffer{}
   133  	exitCode := gRPCClient.Execute([]string{"example"}, &stdoutBuffer, io.Discard)
   134  
   135  	if exitCode != 99 {
   136  		t.Fatalf("expected exit %q, got %q", 99, exitCode)
   137  	}
   138  
   139  	if stdoutBuffer.String() != "firstcall\nsecondcall\n" {
   140  		t.Errorf("expected output %q, got %q", "firstcall\nsecondcall\n", stdoutBuffer.String())
   141  	}
   142  }