github.com/opentofu/opentofu@v1.7.1/internal/legacy/tofu/provider_mock.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 tofu 7 8 import ( 9 "encoding/json" 10 "sync" 11 12 "github.com/zclconf/go-cty/cty" 13 ctyjson "github.com/zclconf/go-cty/cty/json" 14 15 "github.com/opentofu/opentofu/internal/configs/hcl2shim" 16 "github.com/opentofu/opentofu/internal/providers" 17 ) 18 19 var _ providers.Interface = (*MockProvider)(nil) 20 21 // MockProvider implements providers.Interface but mocks out all the 22 // calls for testing purposes. 23 type MockProvider struct { 24 sync.Mutex 25 26 // Anything you want, in case you need to store extra data with the mock. 27 Meta interface{} 28 29 GetSchemaCalled bool 30 GetSchemaReturn *ProviderSchema // This is using ProviderSchema directly rather than providers.GetProviderSchemaResponse for compatibility with old tests 31 32 ValidateProviderConfigCalled bool 33 ValidateProviderConfigResponse providers.ValidateProviderConfigResponse 34 ValidateProviderConfigRequest providers.ValidateProviderConfigRequest 35 ValidateProviderConfigFn func(providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse 36 37 ValidateResourceConfigCalled bool 38 ValidateResourceConfigTypeName string 39 ValidateResourceConfigResponse providers.ValidateResourceConfigResponse 40 ValidateResourceConfigRequest providers.ValidateResourceConfigRequest 41 ValidateResourceConfigFn func(providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse 42 43 ValidateDataResourceConfigCalled bool 44 ValidateDataResourceConfigTypeName string 45 ValidateDataResourceConfigResponse providers.ValidateDataResourceConfigResponse 46 ValidateDataResourceConfigRequest providers.ValidateDataResourceConfigRequest 47 ValidateDataResourceConfigFn func(providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse 48 49 UpgradeResourceStateCalled bool 50 UpgradeResourceStateTypeName string 51 UpgradeResourceStateResponse providers.UpgradeResourceStateResponse 52 UpgradeResourceStateRequest providers.UpgradeResourceStateRequest 53 UpgradeResourceStateFn func(providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse 54 55 ConfigureProviderCalled bool 56 ConfigureProviderResponse providers.ConfigureProviderResponse 57 ConfigureProviderRequest providers.ConfigureProviderRequest 58 ConfigureProviderFn func(providers.ConfigureProviderRequest) providers.ConfigureProviderResponse 59 60 StopCalled bool 61 StopFn func() error 62 StopResponse error 63 64 ReadResourceCalled bool 65 ReadResourceResponse providers.ReadResourceResponse 66 ReadResourceRequest providers.ReadResourceRequest 67 ReadResourceFn func(providers.ReadResourceRequest) providers.ReadResourceResponse 68 69 PlanResourceChangeCalled bool 70 PlanResourceChangeResponse providers.PlanResourceChangeResponse 71 PlanResourceChangeRequest providers.PlanResourceChangeRequest 72 PlanResourceChangeFn func(providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse 73 74 ApplyResourceChangeCalled bool 75 ApplyResourceChangeResponse providers.ApplyResourceChangeResponse 76 ApplyResourceChangeRequest providers.ApplyResourceChangeRequest 77 ApplyResourceChangeFn func(providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse 78 79 ImportResourceStateCalled bool 80 ImportResourceStateResponse providers.ImportResourceStateResponse 81 ImportResourceStateRequest providers.ImportResourceStateRequest 82 ImportResourceStateFn func(providers.ImportResourceStateRequest) providers.ImportResourceStateResponse 83 // Legacy return type for existing tests, which will be shimmed into an 84 // ImportResourceStateResponse if set 85 ImportStateReturn []*InstanceState 86 87 ReadDataSourceCalled bool 88 ReadDataSourceResponse providers.ReadDataSourceResponse 89 ReadDataSourceRequest providers.ReadDataSourceRequest 90 ReadDataSourceFn func(providers.ReadDataSourceRequest) providers.ReadDataSourceResponse 91 92 CloseCalled bool 93 CloseError error 94 } 95 96 func (p *MockProvider) GetProviderSchema() providers.GetProviderSchemaResponse { 97 p.Lock() 98 defer p.Unlock() 99 p.GetSchemaCalled = true 100 return p.getSchema() 101 } 102 103 func (p *MockProvider) getSchema() providers.GetProviderSchemaResponse { 104 // This version of getSchema doesn't do any locking, so it's suitable to 105 // call from other methods of this mock as long as they are already 106 // holding the lock. 107 108 ret := providers.GetProviderSchemaResponse{ 109 Provider: providers.Schema{}, 110 DataSources: map[string]providers.Schema{}, 111 ResourceTypes: map[string]providers.Schema{}, 112 } 113 if p.GetSchemaReturn != nil { 114 ret.Provider.Block = p.GetSchemaReturn.Provider 115 ret.ProviderMeta.Block = p.GetSchemaReturn.ProviderMeta 116 for n, s := range p.GetSchemaReturn.DataSources { 117 ret.DataSources[n] = providers.Schema{ 118 Block: s, 119 } 120 } 121 for n, s := range p.GetSchemaReturn.ResourceTypes { 122 ret.ResourceTypes[n] = providers.Schema{ 123 Version: int64(p.GetSchemaReturn.ResourceTypeSchemaVersions[n]), 124 Block: s, 125 } 126 } 127 } 128 129 return ret 130 } 131 132 func (p *MockProvider) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse { 133 p.Lock() 134 defer p.Unlock() 135 136 p.ValidateProviderConfigCalled = true 137 p.ValidateProviderConfigRequest = r 138 if p.ValidateProviderConfigFn != nil { 139 return p.ValidateProviderConfigFn(r) 140 } 141 return p.ValidateProviderConfigResponse 142 } 143 144 func (p *MockProvider) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse { 145 p.Lock() 146 defer p.Unlock() 147 148 p.ValidateResourceConfigCalled = true 149 p.ValidateResourceConfigRequest = r 150 151 if p.ValidateResourceConfigFn != nil { 152 return p.ValidateResourceConfigFn(r) 153 } 154 155 return p.ValidateResourceConfigResponse 156 } 157 158 func (p *MockProvider) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse { 159 p.Lock() 160 defer p.Unlock() 161 162 p.ValidateDataResourceConfigCalled = true 163 p.ValidateDataResourceConfigRequest = r 164 165 if p.ValidateDataResourceConfigFn != nil { 166 return p.ValidateDataResourceConfigFn(r) 167 } 168 169 return p.ValidateDataResourceConfigResponse 170 } 171 172 func (p *MockProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse { 173 p.Lock() 174 defer p.Unlock() 175 176 schemas := p.getSchema() 177 schema := schemas.ResourceTypes[r.TypeName] 178 schemaType := schema.Block.ImpliedType() 179 180 p.UpgradeResourceStateCalled = true 181 p.UpgradeResourceStateRequest = r 182 183 if p.UpgradeResourceStateFn != nil { 184 return p.UpgradeResourceStateFn(r) 185 } 186 187 resp := p.UpgradeResourceStateResponse 188 189 if resp.UpgradedState == cty.NilVal { 190 switch { 191 case r.RawStateFlatmap != nil: 192 v, err := hcl2shim.HCL2ValueFromFlatmap(r.RawStateFlatmap, schemaType) 193 if err != nil { 194 resp.Diagnostics = resp.Diagnostics.Append(err) 195 return resp 196 } 197 resp.UpgradedState = v 198 case len(r.RawStateJSON) > 0: 199 v, err := ctyjson.Unmarshal(r.RawStateJSON, schemaType) 200 201 if err != nil { 202 resp.Diagnostics = resp.Diagnostics.Append(err) 203 return resp 204 } 205 resp.UpgradedState = v 206 } 207 } 208 return resp 209 } 210 211 func (p *MockProvider) ConfigureProvider(r providers.ConfigureProviderRequest) providers.ConfigureProviderResponse { 212 p.Lock() 213 defer p.Unlock() 214 215 p.ConfigureProviderCalled = true 216 p.ConfigureProviderRequest = r 217 218 if p.ConfigureProviderFn != nil { 219 return p.ConfigureProviderFn(r) 220 } 221 222 return p.ConfigureProviderResponse 223 } 224 225 func (p *MockProvider) Stop() error { 226 // We intentionally don't lock in this one because the whole point of this 227 // method is to be called concurrently with another operation that can 228 // be cancelled. The provider itself is responsible for handling 229 // any concurrency concerns in this case. 230 231 p.StopCalled = true 232 if p.StopFn != nil { 233 return p.StopFn() 234 } 235 236 return p.StopResponse 237 } 238 239 func (p *MockProvider) ReadResource(r providers.ReadResourceRequest) providers.ReadResourceResponse { 240 p.Lock() 241 defer p.Unlock() 242 243 p.ReadResourceCalled = true 244 p.ReadResourceRequest = r 245 246 if p.ReadResourceFn != nil { 247 return p.ReadResourceFn(r) 248 } 249 250 resp := p.ReadResourceResponse 251 if resp.NewState != cty.NilVal { 252 // make sure the NewState fits the schema 253 // This isn't always the case for the existing tests 254 newState, err := p.GetSchemaReturn.ResourceTypes[r.TypeName].CoerceValue(resp.NewState) 255 if err != nil { 256 panic(err) 257 } 258 resp.NewState = newState 259 return resp 260 } 261 262 // just return the same state we received 263 resp.NewState = r.PriorState 264 return resp 265 } 266 267 func (p *MockProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse { 268 p.Lock() 269 defer p.Unlock() 270 271 p.PlanResourceChangeCalled = true 272 p.PlanResourceChangeRequest = r 273 274 if p.PlanResourceChangeFn != nil { 275 return p.PlanResourceChangeFn(r) 276 } 277 278 return p.PlanResourceChangeResponse 279 } 280 281 func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse { 282 p.Lock() 283 p.ApplyResourceChangeCalled = true 284 p.ApplyResourceChangeRequest = r 285 p.Unlock() 286 287 if p.ApplyResourceChangeFn != nil { 288 return p.ApplyResourceChangeFn(r) 289 } 290 291 return p.ApplyResourceChangeResponse 292 } 293 294 func (p *MockProvider) ImportResourceState(r providers.ImportResourceStateRequest) providers.ImportResourceStateResponse { 295 p.Lock() 296 defer p.Unlock() 297 298 if p.ImportStateReturn != nil { 299 for _, is := range p.ImportStateReturn { 300 if is.Attributes == nil { 301 is.Attributes = make(map[string]string) 302 } 303 is.Attributes["id"] = is.ID 304 305 typeName := is.Ephemeral.Type 306 // Use the requested type if the resource has no type of it's own. 307 // We still return the empty type, which will error, but this prevents a panic. 308 if typeName == "" { 309 typeName = r.TypeName 310 } 311 312 schema := p.GetSchemaReturn.ResourceTypes[typeName] 313 if schema == nil { 314 panic("no schema found for " + typeName) 315 } 316 317 private, err := json.Marshal(is.Meta) 318 if err != nil { 319 panic(err) 320 } 321 322 state, err := hcl2shim.HCL2ValueFromFlatmap(is.Attributes, schema.ImpliedType()) 323 if err != nil { 324 panic(err) 325 } 326 327 state, err = schema.CoerceValue(state) 328 if err != nil { 329 panic(err) 330 } 331 332 p.ImportResourceStateResponse.ImportedResources = append( 333 p.ImportResourceStateResponse.ImportedResources, 334 providers.ImportedResource{ 335 TypeName: is.Ephemeral.Type, 336 State: state, 337 Private: private, 338 }) 339 } 340 } 341 342 p.ImportResourceStateCalled = true 343 p.ImportResourceStateRequest = r 344 if p.ImportResourceStateFn != nil { 345 return p.ImportResourceStateFn(r) 346 } 347 348 return p.ImportResourceStateResponse 349 } 350 351 func (p *MockProvider) ReadDataSource(r providers.ReadDataSourceRequest) providers.ReadDataSourceResponse { 352 p.Lock() 353 defer p.Unlock() 354 355 p.ReadDataSourceCalled = true 356 p.ReadDataSourceRequest = r 357 358 if p.ReadDataSourceFn != nil { 359 return p.ReadDataSourceFn(r) 360 } 361 362 return p.ReadDataSourceResponse 363 } 364 365 func (p *MockProvider) GetFunctions() providers.GetFunctionsResponse { 366 panic("Not Implemented") 367 } 368 369 func (p *MockProvider) CallFunction(r providers.CallFunctionRequest) providers.CallFunctionResponse { 370 panic("Not Implemented") 371 } 372 373 func (p *MockProvider) Close() error { 374 p.CloseCalled = true 375 return p.CloseError 376 }