github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/internal/terraform/provider_mock.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "sync" 6 7 "github.com/zclconf/go-cty/cty" 8 ctyjson "github.com/zclconf/go-cty/cty/json" 9 "github.com/zclconf/go-cty/cty/msgpack" 10 11 "github.com/iaas-resource-provision/iaas-rpc/internal/configs/configschema" 12 "github.com/iaas-resource-provision/iaas-rpc/internal/configs/hcl2shim" 13 "github.com/iaas-resource-provision/iaas-rpc/internal/providers" 14 ) 15 16 var _ providers.Interface = (*MockProvider)(nil) 17 18 // MockProvider implements providers.Interface but mocks out all the 19 // calls for testing purposes. 20 type MockProvider struct { 21 sync.Mutex 22 23 // Anything you want, in case you need to store extra data with the mock. 24 Meta interface{} 25 26 GetProviderSchemaCalled bool 27 GetProviderSchemaResponse *providers.GetProviderSchemaResponse 28 29 ValidateProviderConfigCalled bool 30 ValidateProviderConfigResponse *providers.ValidateProviderConfigResponse 31 ValidateProviderConfigRequest providers.ValidateProviderConfigRequest 32 ValidateProviderConfigFn func(providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse 33 34 ValidateResourceConfigCalled bool 35 ValidateResourceConfigTypeName string 36 ValidateResourceConfigResponse *providers.ValidateResourceConfigResponse 37 ValidateResourceConfigRequest providers.ValidateResourceConfigRequest 38 ValidateResourceConfigFn func(providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse 39 40 ValidateDataResourceConfigCalled bool 41 ValidateDataResourceConfigTypeName string 42 ValidateDataResourceConfigResponse *providers.ValidateDataResourceConfigResponse 43 ValidateDataResourceConfigRequest providers.ValidateDataResourceConfigRequest 44 ValidateDataResourceConfigFn func(providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse 45 46 UpgradeResourceStateCalled bool 47 UpgradeResourceStateTypeName string 48 UpgradeResourceStateResponse *providers.UpgradeResourceStateResponse 49 UpgradeResourceStateRequest providers.UpgradeResourceStateRequest 50 UpgradeResourceStateFn func(providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse 51 52 ConfigureProviderCalled bool 53 ConfigureProviderResponse *providers.ConfigureProviderResponse 54 ConfigureProviderRequest providers.ConfigureProviderRequest 55 ConfigureProviderFn func(providers.ConfigureProviderRequest) providers.ConfigureProviderResponse 56 57 StopCalled bool 58 StopFn func() error 59 StopResponse error 60 61 ReadResourceCalled bool 62 ReadResourceResponse *providers.ReadResourceResponse 63 ReadResourceRequest providers.ReadResourceRequest 64 ReadResourceFn func(providers.ReadResourceRequest) providers.ReadResourceResponse 65 66 PlanResourceChangeCalled bool 67 PlanResourceChangeResponse *providers.PlanResourceChangeResponse 68 PlanResourceChangeRequest providers.PlanResourceChangeRequest 69 PlanResourceChangeFn func(providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse 70 71 ApplyResourceChangeCalled bool 72 ApplyResourceChangeResponse *providers.ApplyResourceChangeResponse 73 ApplyResourceChangeRequest providers.ApplyResourceChangeRequest 74 ApplyResourceChangeFn func(providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse 75 76 ImportResourceStateCalled bool 77 ImportResourceStateResponse *providers.ImportResourceStateResponse 78 ImportResourceStateRequest providers.ImportResourceStateRequest 79 ImportResourceStateFn func(providers.ImportResourceStateRequest) providers.ImportResourceStateResponse 80 81 ReadDataSourceCalled bool 82 ReadDataSourceResponse *providers.ReadDataSourceResponse 83 ReadDataSourceRequest providers.ReadDataSourceRequest 84 ReadDataSourceFn func(providers.ReadDataSourceRequest) providers.ReadDataSourceResponse 85 86 CloseCalled bool 87 CloseError error 88 } 89 90 func (p *MockProvider) GetProviderSchema() providers.GetProviderSchemaResponse { 91 p.Lock() 92 defer p.Unlock() 93 p.GetProviderSchemaCalled = true 94 return p.getProviderSchema() 95 } 96 97 func (p *MockProvider) getProviderSchema() providers.GetProviderSchemaResponse { 98 // This version of getProviderSchema doesn't do any locking, so it's suitable to 99 // call from other methods of this mock as long as they are already 100 // holding the lock. 101 if p.GetProviderSchemaResponse != nil { 102 return *p.GetProviderSchemaResponse 103 } 104 105 return providers.GetProviderSchemaResponse{ 106 Provider: providers.Schema{}, 107 DataSources: map[string]providers.Schema{}, 108 ResourceTypes: map[string]providers.Schema{}, 109 } 110 } 111 112 // ProviderSchema is a helper to convert from the internal GetProviderSchemaResponse to 113 // a ProviderSchema. 114 func (p *MockProvider) ProviderSchema() *ProviderSchema { 115 resp := p.getProviderSchema() 116 117 schema := &ProviderSchema{ 118 Provider: resp.Provider.Block, 119 ProviderMeta: resp.ProviderMeta.Block, 120 ResourceTypes: map[string]*configschema.Block{}, 121 DataSources: map[string]*configschema.Block{}, 122 ResourceTypeSchemaVersions: map[string]uint64{}, 123 } 124 125 for resType, s := range resp.ResourceTypes { 126 schema.ResourceTypes[resType] = s.Block 127 schema.ResourceTypeSchemaVersions[resType] = uint64(s.Version) 128 } 129 130 for dataSource, s := range resp.DataSources { 131 schema.DataSources[dataSource] = s.Block 132 } 133 134 return schema 135 } 136 137 func (p *MockProvider) ValidateProviderConfig(r providers.ValidateProviderConfigRequest) (resp providers.ValidateProviderConfigResponse) { 138 p.Lock() 139 defer p.Unlock() 140 141 p.ValidateProviderConfigCalled = true 142 p.ValidateProviderConfigRequest = r 143 if p.ValidateProviderConfigFn != nil { 144 return p.ValidateProviderConfigFn(r) 145 } 146 147 if p.ValidateProviderConfigResponse != nil { 148 return *p.ValidateProviderConfigResponse 149 } 150 151 resp.PreparedConfig = r.Config 152 return resp 153 } 154 155 func (p *MockProvider) ValidateResourceConfig(r providers.ValidateResourceConfigRequest) (resp providers.ValidateResourceConfigResponse) { 156 p.Lock() 157 defer p.Unlock() 158 159 p.ValidateResourceConfigCalled = true 160 p.ValidateResourceConfigRequest = r 161 162 // Marshall the value to replicate behavior by the GRPC protocol, 163 // and return any relevant errors 164 resourceSchema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] 165 if !ok { 166 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) 167 return resp 168 } 169 170 _, err := msgpack.Marshal(r.Config, resourceSchema.Block.ImpliedType()) 171 if err != nil { 172 resp.Diagnostics = resp.Diagnostics.Append(err) 173 return resp 174 } 175 176 if p.ValidateResourceConfigFn != nil { 177 return p.ValidateResourceConfigFn(r) 178 } 179 180 if p.ValidateResourceConfigResponse != nil { 181 return *p.ValidateResourceConfigResponse 182 } 183 184 return resp 185 } 186 187 func (p *MockProvider) ValidateDataResourceConfig(r providers.ValidateDataResourceConfigRequest) (resp providers.ValidateDataResourceConfigResponse) { 188 p.Lock() 189 defer p.Unlock() 190 191 p.ValidateDataResourceConfigCalled = true 192 p.ValidateDataResourceConfigRequest = r 193 194 // Marshall the value to replicate behavior by the GRPC protocol 195 dataSchema, ok := p.getProviderSchema().DataSources[r.TypeName] 196 if !ok { 197 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) 198 return resp 199 } 200 _, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType()) 201 if err != nil { 202 resp.Diagnostics = resp.Diagnostics.Append(err) 203 return resp 204 } 205 206 if p.ValidateDataResourceConfigFn != nil { 207 return p.ValidateDataResourceConfigFn(r) 208 } 209 210 if p.ValidateDataResourceConfigResponse != nil { 211 return *p.ValidateDataResourceConfigResponse 212 } 213 214 return resp 215 } 216 217 func (p *MockProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) { 218 p.Lock() 219 defer p.Unlock() 220 221 schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] 222 if !ok { 223 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) 224 return resp 225 } 226 227 schemaType := schema.Block.ImpliedType() 228 229 p.UpgradeResourceStateCalled = true 230 p.UpgradeResourceStateRequest = r 231 232 if p.UpgradeResourceStateFn != nil { 233 return p.UpgradeResourceStateFn(r) 234 } 235 236 if p.UpgradeResourceStateResponse != nil { 237 return *p.UpgradeResourceStateResponse 238 } 239 240 switch { 241 case r.RawStateFlatmap != nil: 242 v, err := hcl2shim.HCL2ValueFromFlatmap(r.RawStateFlatmap, schemaType) 243 if err != nil { 244 resp.Diagnostics = resp.Diagnostics.Append(err) 245 return resp 246 } 247 resp.UpgradedState = v 248 case len(r.RawStateJSON) > 0: 249 v, err := ctyjson.Unmarshal(r.RawStateJSON, schemaType) 250 251 if err != nil { 252 resp.Diagnostics = resp.Diagnostics.Append(err) 253 return resp 254 } 255 resp.UpgradedState = v 256 } 257 258 return resp 259 } 260 261 func (p *MockProvider) ConfigureProvider(r providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { 262 p.Lock() 263 defer p.Unlock() 264 265 p.ConfigureProviderCalled = true 266 p.ConfigureProviderRequest = r 267 268 if p.ConfigureProviderFn != nil { 269 return p.ConfigureProviderFn(r) 270 } 271 272 if p.ConfigureProviderResponse != nil { 273 return *p.ConfigureProviderResponse 274 } 275 276 return resp 277 } 278 279 func (p *MockProvider) Stop() error { 280 // We intentionally don't lock in this one because the whole point of this 281 // method is to be called concurrently with another operation that can 282 // be cancelled. The provider itself is responsible for handling 283 // any concurrency concerns in this case. 284 285 p.StopCalled = true 286 if p.StopFn != nil { 287 return p.StopFn() 288 } 289 290 return p.StopResponse 291 } 292 293 func (p *MockProvider) ReadResource(r providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { 294 p.Lock() 295 defer p.Unlock() 296 297 p.ReadResourceCalled = true 298 p.ReadResourceRequest = r 299 300 if p.ReadResourceFn != nil { 301 return p.ReadResourceFn(r) 302 } 303 304 if p.ReadResourceResponse != nil { 305 resp = *p.ReadResourceResponse 306 307 // Make sure the NewState conforms to the schema. 308 // This isn't always the case for the existing tests. 309 schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] 310 if !ok { 311 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) 312 return resp 313 } 314 315 newState, err := schema.Block.CoerceValue(resp.NewState) 316 if err != nil { 317 resp.Diagnostics = resp.Diagnostics.Append(err) 318 } 319 resp.NewState = newState 320 return resp 321 } 322 323 // otherwise just return the same state we received 324 resp.NewState = r.PriorState 325 resp.Private = r.Private 326 return resp 327 } 328 329 func (p *MockProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { 330 p.Lock() 331 defer p.Unlock() 332 333 p.PlanResourceChangeCalled = true 334 p.PlanResourceChangeRequest = r 335 336 if p.PlanResourceChangeFn != nil { 337 return p.PlanResourceChangeFn(r) 338 } 339 340 if p.PlanResourceChangeResponse != nil { 341 return *p.PlanResourceChangeResponse 342 } 343 344 schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] 345 if !ok { 346 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) 347 return resp 348 } 349 350 // The default plan behavior is to accept the proposed value, and mark all 351 // nil computed attributes as unknown. 352 val, err := cty.Transform(r.ProposedNewState, func(path cty.Path, v cty.Value) (cty.Value, error) { 353 // We're only concerned with known null values, which can be computed 354 // by the provider. 355 if !v.IsKnown() { 356 return v, nil 357 } 358 359 attrSchema := schema.Block.AttributeByPath(path) 360 if attrSchema == nil { 361 // this is an intermediate path which does not represent an attribute 362 return v, nil 363 } 364 365 // get the current configuration value, to detect when a 366 // computed+optional attributes has become unset 367 configVal, err := path.Apply(r.Config) 368 if err != nil { 369 return v, err 370 } 371 372 switch { 373 case attrSchema.Computed && !attrSchema.Optional && v.IsNull(): 374 // this is the easy path, this value is not yet set, and _must_ be computed 375 return cty.UnknownVal(v.Type()), nil 376 377 case attrSchema.Computed && attrSchema.Optional && !v.IsNull() && configVal.IsNull(): 378 // If an optional+computed value has gone from set to unset, it 379 // becomes computed. (this was not possible to do with legacy 380 // providers) 381 return cty.UnknownVal(v.Type()), nil 382 } 383 384 return v, nil 385 }) 386 if err != nil { 387 resp.Diagnostics = resp.Diagnostics.Append(err) 388 return resp 389 } 390 391 resp.PlannedPrivate = r.PriorPrivate 392 resp.PlannedState = val 393 394 return resp 395 } 396 397 func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { 398 p.Lock() 399 p.ApplyResourceChangeCalled = true 400 p.ApplyResourceChangeRequest = r 401 p.Unlock() 402 403 if p.ApplyResourceChangeFn != nil { 404 return p.ApplyResourceChangeFn(r) 405 } 406 407 if p.ApplyResourceChangeResponse != nil { 408 return *p.ApplyResourceChangeResponse 409 } 410 411 schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] 412 if !ok { 413 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) 414 return resp 415 } 416 417 // if the value is nil, we return that directly to correspond to a delete 418 if r.PlannedState.IsNull() { 419 resp.NewState = cty.NullVal(schema.Block.ImpliedType()) 420 return resp 421 } 422 423 val, err := schema.Block.CoerceValue(r.PlannedState) 424 if err != nil { 425 resp.Diagnostics = resp.Diagnostics.Append(err) 426 return resp 427 } 428 429 // the default behavior will be to create the minimal valid apply value by 430 // setting unknowns (which correspond to computed attributes) to a zero 431 // value. 432 val, _ = cty.Transform(val, func(path cty.Path, v cty.Value) (cty.Value, error) { 433 if !v.IsKnown() { 434 ty := v.Type() 435 switch { 436 case ty == cty.String: 437 return cty.StringVal(""), nil 438 case ty == cty.Number: 439 return cty.NumberIntVal(0), nil 440 case ty == cty.Bool: 441 return cty.False, nil 442 case ty.IsMapType(): 443 return cty.MapValEmpty(ty.ElementType()), nil 444 case ty.IsListType(): 445 return cty.ListValEmpty(ty.ElementType()), nil 446 default: 447 return cty.NullVal(ty), nil 448 } 449 } 450 return v, nil 451 }) 452 453 resp.NewState = val 454 resp.Private = r.PlannedPrivate 455 456 return resp 457 } 458 459 func (p *MockProvider) ImportResourceState(r providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) { 460 p.Lock() 461 defer p.Unlock() 462 463 p.ImportResourceStateCalled = true 464 p.ImportResourceStateRequest = r 465 if p.ImportResourceStateFn != nil { 466 return p.ImportResourceStateFn(r) 467 } 468 469 if p.ImportResourceStateResponse != nil { 470 resp = *p.ImportResourceStateResponse 471 // fixup the cty value to match the schema 472 for i, res := range resp.ImportedResources { 473 schema, ok := p.getProviderSchema().ResourceTypes[res.TypeName] 474 if !ok { 475 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", res.TypeName)) 476 return resp 477 } 478 479 var err error 480 res.State, err = schema.Block.CoerceValue(res.State) 481 if err != nil { 482 resp.Diagnostics = resp.Diagnostics.Append(err) 483 return resp 484 } 485 486 resp.ImportedResources[i] = res 487 } 488 } 489 490 return resp 491 } 492 493 func (p *MockProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { 494 p.Lock() 495 defer p.Unlock() 496 497 p.ReadDataSourceCalled = true 498 p.ReadDataSourceRequest = r 499 500 if p.ReadDataSourceFn != nil { 501 return p.ReadDataSourceFn(r) 502 } 503 504 if p.ReadDataSourceResponse != nil { 505 resp = *p.ReadDataSourceResponse 506 } 507 508 return resp 509 } 510 511 func (p *MockProvider) Close() error { 512 p.CloseCalled = true 513 return p.CloseError 514 }