github.com/myhau/pulumi/pkg/v3@v3.70.2-0.20221116134521-f2775972e587/resource/deploy/source_query_test.go (about) 1 // Copyright 2016-2018, Pulumi Corporation. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package deploy 16 17 import ( 18 "context" 19 "testing" 20 21 pbempty "github.com/golang/protobuf/ptypes/empty" 22 "github.com/pulumi/pulumi/sdk/v3/go/common/util/result" 23 pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" 24 "github.com/stretchr/testify/assert" 25 ) 26 27 func TestQuerySource_Trivial_Wait(t *testing.T) { 28 t.Parallel() 29 30 // Trivial querySource returns immediately with `Wait()`, even with multiple invocations. 31 32 // Success case. 33 resmon1 := mockQueryResmon{} 34 qs1, _ := newTestQuerySource(&resmon1, func(*querySource) result.Result { 35 return nil 36 }) 37 38 qs1.forkRun() 39 40 res := qs1.Wait() 41 assert.Nil(t, res) 42 assert.False(t, resmon1.cancelled) 43 44 res = qs1.Wait() 45 assert.Nil(t, res) 46 assert.False(t, resmon1.cancelled) 47 48 // Failure case. 49 resmon2 := mockQueryResmon{} 50 qs2, _ := newTestQuerySource(&resmon2, func(*querySource) result.Result { 51 return result.Error("failed") 52 }) 53 54 qs2.forkRun() 55 56 res = qs2.Wait() 57 assert.False(t, res.IsBail()) 58 assert.NotNil(t, res.Error()) 59 assert.False(t, resmon2.cancelled) 60 61 res = qs2.Wait() 62 assert.False(t, res.IsBail()) 63 assert.NotNil(t, res.Error()) 64 assert.False(t, resmon2.cancelled) 65 } 66 67 func TestQuerySource_Async_Wait(t *testing.T) { 68 t.Parallel() 69 70 // `Wait()` executes asynchronously. 71 72 // Success case. 73 // 74 // test blocks until querySource signals execution has started 75 // -> querySource blocks until test acknowledges querySource's signal 76 // -> test blocks on `Wait()` until querySource completes. 77 qs1Start, qs1StartAck := make(chan interface{}), make(chan interface{}) 78 resmon1 := mockQueryResmon{} 79 qs1, _ := newTestQuerySource(&resmon1, func(*querySource) result.Result { 80 qs1Start <- struct{}{} 81 <-qs1StartAck 82 return nil 83 }) 84 85 qs1.forkRun() 86 87 // Wait until querySource starts, then acknowledge starting. 88 <-qs1Start 89 go func() { 90 qs1StartAck <- struct{}{} 91 }() 92 93 // Wait for querySource to complete. 94 res := qs1.Wait() 95 assert.Nil(t, res) 96 assert.False(t, resmon1.cancelled) 97 98 res = qs1.Wait() 99 assert.Nil(t, res) 100 assert.False(t, resmon1.cancelled) 101 102 // Cancellation case. 103 // 104 // test blocks until querySource signals execution has started 105 // -> querySource blocks until test acknowledges querySource's signal 106 // -> test blocks on `Wait()` until querySource completes. 107 qs2Start, qs2StartAck := make(chan interface{}), make(chan interface{}) 108 resmon2 := mockQueryResmon{} 109 qs2, cancelQs2 := newTestQuerySource(&resmon2, func(*querySource) result.Result { 110 qs2Start <- struct{}{} 111 // Block forever. 112 <-qs2StartAck 113 return nil 114 }) 115 116 qs2.forkRun() 117 118 // Wait until querySource starts, then cancel. 119 <-qs2Start 120 go func() { 121 cancelQs2() 122 }() 123 124 // Wait for querySource to complete. 125 res = qs2.Wait() 126 assert.Nil(t, res) 127 assert.True(t, resmon2.cancelled) 128 129 res = qs2.Wait() 130 assert.Nil(t, res) 131 assert.True(t, resmon2.cancelled) 132 } 133 134 func TestQueryResourceMonitor_UnsupportedOperations(t *testing.T) { 135 t.Parallel() 136 137 rm := &queryResmon{} 138 139 _, err := rm.ReadResource(context.TODO(), nil) 140 assert.Error(t, err) 141 assert.Equal(t, "Query mode does not support reading resources", err.Error()) 142 143 _, err = rm.RegisterResource(context.TODO(), nil) 144 assert.Error(t, err) 145 assert.Equal(t, "Query mode does not support creating, updating, or deleting resources", err.Error()) 146 147 _, err = rm.RegisterResourceOutputs(context.TODO(), nil) 148 assert.Error(t, err) 149 assert.Equal(t, "Query mode does not support registering resource operations", err.Error()) 150 } 151 152 // 153 // Test querySoruce constructor. 154 // 155 156 func newTestQuerySource(mon SourceResourceMonitor, 157 runLangPlugin func(*querySource) result.Result) (*querySource, context.CancelFunc) { 158 159 cancel, cancelFunc := context.WithCancel(context.Background()) 160 161 return &querySource{ 162 mon: mon, 163 runLangPlugin: runLangPlugin, 164 langPluginFinChan: make(chan result.Result), 165 cancel: cancel, 166 }, cancelFunc 167 } 168 169 // 170 // Mock resource monitor. 171 // 172 173 type mockQueryResmon struct { 174 cancelled bool 175 } 176 177 var _ SourceResourceMonitor = (*mockQueryResmon)(nil) 178 179 func (rm *mockQueryResmon) Address() string { 180 panic("not implemented") 181 } 182 func (rm *mockQueryResmon) Cancel() error { 183 rm.cancelled = true 184 return nil 185 } 186 func (rm *mockQueryResmon) Invoke(ctx context.Context, 187 req *pulumirpc.ResourceInvokeRequest) (*pulumirpc.InvokeResponse, error) { 188 189 panic("not implemented") 190 } 191 func (rm *mockQueryResmon) Call(ctx context.Context, 192 req *pulumirpc.CallRequest) (*pulumirpc.CallResponse, error) { 193 194 panic("not implemented") 195 } 196 func (rm *mockQueryResmon) ReadResource(ctx context.Context, 197 req *pulumirpc.ReadResourceRequest) (*pulumirpc.ReadResourceResponse, error) { 198 199 panic("not implemented") 200 } 201 func (rm *mockQueryResmon) RegisterResource(ctx context.Context, 202 req *pulumirpc.RegisterResourceRequest) (*pulumirpc.RegisterResourceResponse, error) { 203 204 panic("not implemented") 205 } 206 func (rm *mockQueryResmon) RegisterResourceOutputs(ctx context.Context, 207 req *pulumirpc.RegisterResourceOutputsRequest) (*pbempty.Empty, error) { 208 209 panic("not implemented") 210 }