github.com/crossplane/upjet@v1.3.0/pkg/terraform/provider_runner_test.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package terraform
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"reflect"
    12  	"strings"
    13  	"sync"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/crossplane/crossplane-runtime/pkg/logging"
    18  	"github.com/crossplane/crossplane-runtime/pkg/test"
    19  	"github.com/google/go-cmp/cmp"
    20  	"github.com/pkg/errors"
    21  	clock "k8s.io/utils/clock/testing"
    22  	"k8s.io/utils/exec"
    23  	testingexec "k8s.io/utils/exec/testing"
    24  )
    25  
    26  func TestStartSharedServer(t *testing.T) {
    27  	testPath := "path"
    28  	testName := "provider-test"
    29  	testArgs := []string{"arg1", "arg2"}
    30  	testReattachConfig1 := `1|5|unix|test1|grpc|`
    31  	testReattachConfig2 := `1|5|unix|test2|grpc|`
    32  	testErr := errors.New("boom")
    33  	type args struct {
    34  		runner ProviderRunner
    35  	}
    36  	type want struct {
    37  		reattachConfig string
    38  		err            error
    39  	}
    40  	tests := map[string]struct {
    41  		args args
    42  		want want
    43  	}{
    44  		"NotConfiguredNoOp": {
    45  			args: args{
    46  				runner: NewNoOpProviderRunner(),
    47  			},
    48  		},
    49  		"SuccessfullyStarted": {
    50  			args: args{
    51  				runner: NewSharedProvider(WithNativeProviderLogger(logging.NewNopLogger()), WithNativeProviderPath(testPath),
    52  					WithNativeProviderName(testName), WithNativeProviderArgs(testArgs...), WithNativeProviderExecutor(newExecutorWithStoutPipe(testReattachConfig1, nil))),
    53  			},
    54  			want: want{
    55  				reattachConfig: fmt.Sprintf(`{"provider-test":{"Protocol":"grpc","ProtocolVersion":5,"Pid":%d,"Test": true,"Addr":{"Network": "unix","String": "test1"}}}`, os.Getpid()),
    56  			},
    57  		},
    58  		"AlreadyRunning": {
    59  			args: args{
    60  				runner: &SharedProvider{
    61  					nativeProviderPath: testPath,
    62  					reattachConfig:     "test1",
    63  					logger:             logging.NewNopLogger(),
    64  					executor:           newExecutorWithStoutPipe(testReattachConfig2, nil),
    65  					mu:                 &sync.Mutex{},
    66  				},
    67  			},
    68  			want: want{
    69  				reattachConfig: "test1",
    70  			},
    71  		},
    72  		"NativeProviderError": {
    73  			args: args{
    74  				runner: NewSharedProvider(WithNativeProviderLogger(logging.NewNopLogger()), WithNativeProviderPath(testPath),
    75  					WithNativeProviderName(testName), WithNativeProviderArgs(testArgs...), WithNativeProviderExecutor(newExecutorWithStoutPipe(testReattachConfig1, testErr))),
    76  			},
    77  			want: want{
    78  				err: testErr,
    79  			},
    80  		},
    81  		"NativeProviderTimeout": {
    82  			args: args{
    83  				runner: &SharedProvider{
    84  					nativeProviderPath: testPath,
    85  					logger:             logging.NewNopLogger(),
    86  					executor:           newExecutorWithStoutPipe("invalid", nil),
    87  					mu:                 &sync.Mutex{},
    88  					clock:              &fakeClock{},
    89  				},
    90  			},
    91  			want: want{
    92  				err: errors.Errorf(errFmtTimeout, reattachTimeout),
    93  			},
    94  		},
    95  	}
    96  	for name, tt := range tests {
    97  		t.Run(name, func(t *testing.T) {
    98  			reattachConfig, err := tt.args.runner.Start()
    99  			if diff := cmp.Diff(tt.want.err, err, test.EquateErrors()); diff != "" {
   100  				t.Errorf("\n%s\nStartSharedServer(): -want error, +got error:\n%s", name, diff)
   101  			}
   102  			if err != nil {
   103  				return
   104  			}
   105  			if diff := cmp.Diff(tt.want.reattachConfig, reattachConfig); diff != "" {
   106  				t.Errorf("\n%s\nStartSharedServer(): -want reattachConfig, +got reattachConfig:\n%s", name, diff)
   107  			}
   108  		})
   109  	}
   110  }
   111  
   112  type fakeClock struct {
   113  	clock.FakeClock
   114  }
   115  
   116  func (f *fakeClock) After(d time.Duration) <-chan time.Time {
   117  	defer func() {
   118  		f.Step(reattachTimeout)
   119  	}()
   120  	return f.FakeClock.After(d)
   121  }
   122  
   123  func newExecutorWithStoutPipe(reattachConfig string, err error) exec.Interface {
   124  	return &testingexec.FakeExec{
   125  		CommandScript: []testingexec.FakeCommandAction{
   126  			func(cmd string, args ...string) exec.Cmd {
   127  				return &testingexec.FakeCmd{
   128  					StdoutPipeResponse: testingexec.FakeStdIOPipeResponse{
   129  						ReadCloser: io.NopCloser(strings.NewReader(reattachConfig)),
   130  						Error:      err,
   131  					},
   132  				}
   133  			},
   134  		},
   135  	}
   136  }
   137  
   138  func TestWithNativeProviderArgs(t *testing.T) {
   139  	tests := map[string]struct {
   140  		args []string
   141  		want []string
   142  	}{
   143  		"NotConfigured": {},
   144  		"Configured": {
   145  			args: []string{"a", "b", "c"},
   146  			want: []string{"a", "b", "c"},
   147  		},
   148  	}
   149  	for name, tt := range tests {
   150  		t.Run(name, func(t *testing.T) {
   151  			sr := &SharedProvider{}
   152  			WithNativeProviderArgs(tt.args...)(sr)
   153  			if !reflect.DeepEqual(sr.nativeProviderArgs, tt.want) {
   154  				t.Errorf("WithNativeProviderArgs(tt.args) = %v, want %v", sr.nativeProviderArgs, tt.want)
   155  			}
   156  		})
   157  	}
   158  }
   159  
   160  func TestWithNativeProviderExecutor(t *testing.T) {
   161  	tests := map[string]struct {
   162  		executor exec.Interface
   163  		want     exec.Interface
   164  	}{
   165  		"NotConfigured": {},
   166  		"Configured": {
   167  			executor: &testingexec.FakeExec{},
   168  			want:     &testingexec.FakeExec{},
   169  		},
   170  	}
   171  	for name, tt := range tests {
   172  		t.Run(name, func(t *testing.T) {
   173  			sr := &SharedProvider{}
   174  			WithNativeProviderExecutor(tt.executor)(sr)
   175  			if !reflect.DeepEqual(sr.executor, tt.want) {
   176  				t.Errorf("WithNativeProviderExecutor(tt.executor) = %v, want %v", sr.executor, tt.want)
   177  			}
   178  		})
   179  	}
   180  }