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 }