github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-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/muratcelep/terraform/not-internal/configs/configschema" 12 "github.com/muratcelep/terraform/not-internal/configs/hcl2shim" 13 "github.com/muratcelep/terraform/not-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 not-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.ConfigureProviderCalled { 301 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ReadResource %q", r.TypeName)) 302 return resp 303 } 304 305 if p.ReadResourceFn != nil { 306 return p.ReadResourceFn(r) 307 } 308 309 if p.ReadResourceResponse != nil { 310 resp = *p.ReadResourceResponse 311 312 // Make sure the NewState conforms to the schema. 313 // This isn't always the case for the existing tests. 314 schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] 315 if !ok { 316 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) 317 return resp 318 } 319 320 newState, err := schema.Block.CoerceValue(resp.NewState) 321 if err != nil { 322 resp.Diagnostics = resp.Diagnostics.Append(err) 323 } 324 resp.NewState = newState 325 return resp 326 } 327 328 // otherwise just return the same state we received 329 resp.NewState = r.PriorState 330 resp.Private = r.Private 331 return resp 332 } 333 334 func (p *MockProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { 335 p.Lock() 336 defer p.Unlock() 337 338 if !p.ConfigureProviderCalled { 339 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before PlanResourceChange %q", r.TypeName)) 340 return resp 341 } 342 343 p.PlanResourceChangeCalled = true 344 p.PlanResourceChangeRequest = r 345 346 if p.PlanResourceChangeFn != nil { 347 return p.PlanResourceChangeFn(r) 348 } 349 350 if p.PlanResourceChangeResponse != nil { 351 return *p.PlanResourceChangeResponse 352 } 353 354 schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] 355 if !ok { 356 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) 357 return resp 358 } 359 360 // The default plan behavior is to accept the proposed value, and mark all 361 // nil computed attributes as unknown. 362 val, err := cty.Transform(r.ProposedNewState, func(path cty.Path, v cty.Value) (cty.Value, error) { 363 // We're only concerned with known null values, which can be computed 364 // by the provider. 365 if !v.IsKnown() { 366 return v, nil 367 } 368 369 attrSchema := schema.Block.AttributeByPath(path) 370 if attrSchema == nil { 371 // this is an intermediate path which does not represent an attribute 372 return v, nil 373 } 374 375 // get the current configuration value, to detect when a 376 // computed+optional attributes has become unset 377 configVal, err := path.Apply(r.Config) 378 if err != nil { 379 return v, err 380 } 381 382 switch { 383 case attrSchema.Computed && !attrSchema.Optional && v.IsNull(): 384 // this is the easy path, this value is not yet set, and _must_ be computed 385 return cty.UnknownVal(v.Type()), nil 386 387 case attrSchema.Computed && attrSchema.Optional && !v.IsNull() && configVal.IsNull(): 388 // If an optional+computed value has gone from set to unset, it 389 // becomes computed. (this was not possible to do with legacy 390 // providers) 391 return cty.UnknownVal(v.Type()), nil 392 } 393 394 return v, nil 395 }) 396 if err != nil { 397 resp.Diagnostics = resp.Diagnostics.Append(err) 398 return resp 399 } 400 401 resp.PlannedPrivate = r.PriorPrivate 402 resp.PlannedState = val 403 404 return resp 405 } 406 407 func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { 408 p.Lock() 409 p.ApplyResourceChangeCalled = true 410 p.ApplyResourceChangeRequest = r 411 p.Unlock() 412 413 if !p.ConfigureProviderCalled { 414 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ApplyResourceChange %q", r.TypeName)) 415 return resp 416 } 417 418 if p.ApplyResourceChangeFn != nil { 419 return p.ApplyResourceChangeFn(r) 420 } 421 422 if p.ApplyResourceChangeResponse != nil { 423 return *p.ApplyResourceChangeResponse 424 } 425 426 schema, ok := p.getProviderSchema().ResourceTypes[r.TypeName] 427 if !ok { 428 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", r.TypeName)) 429 return resp 430 } 431 432 // if the value is nil, we return that directly to correspond to a delete 433 if r.PlannedState.IsNull() { 434 resp.NewState = cty.NullVal(schema.Block.ImpliedType()) 435 return resp 436 } 437 438 val, err := schema.Block.CoerceValue(r.PlannedState) 439 if err != nil { 440 resp.Diagnostics = resp.Diagnostics.Append(err) 441 return resp 442 } 443 444 // the default behavior will be to create the minimal valid apply value by 445 // setting unknowns (which correspond to computed attributes) to a zero 446 // value. 447 val, _ = cty.Transform(val, func(path cty.Path, v cty.Value) (cty.Value, error) { 448 if !v.IsKnown() { 449 ty := v.Type() 450 switch { 451 case ty == cty.String: 452 return cty.StringVal(""), nil 453 case ty == cty.Number: 454 return cty.NumberIntVal(0), nil 455 case ty == cty.Bool: 456 return cty.False, nil 457 case ty.IsMapType(): 458 return cty.MapValEmpty(ty.ElementType()), nil 459 case ty.IsListType(): 460 return cty.ListValEmpty(ty.ElementType()), nil 461 default: 462 return cty.NullVal(ty), nil 463 } 464 } 465 return v, nil 466 }) 467 468 resp.NewState = val 469 resp.Private = r.PlannedPrivate 470 471 return resp 472 } 473 474 func (p *MockProvider) ImportResourceState(r providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) { 475 p.Lock() 476 defer p.Unlock() 477 478 if !p.ConfigureProviderCalled { 479 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ImportResourceState %q", r.TypeName)) 480 return resp 481 } 482 483 p.ImportResourceStateCalled = true 484 p.ImportResourceStateRequest = r 485 if p.ImportResourceStateFn != nil { 486 return p.ImportResourceStateFn(r) 487 } 488 489 if p.ImportResourceStateResponse != nil { 490 resp = *p.ImportResourceStateResponse 491 // fixup the cty value to match the schema 492 for i, res := range resp.ImportedResources { 493 schema, ok := p.getProviderSchema().ResourceTypes[res.TypeName] 494 if !ok { 495 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("no schema found for %q", res.TypeName)) 496 return resp 497 } 498 499 var err error 500 res.State, err = schema.Block.CoerceValue(res.State) 501 if err != nil { 502 resp.Diagnostics = resp.Diagnostics.Append(err) 503 return resp 504 } 505 506 resp.ImportedResources[i] = res 507 } 508 } 509 510 return resp 511 } 512 513 func (p *MockProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { 514 p.Lock() 515 defer p.Unlock() 516 517 if !p.ConfigureProviderCalled { 518 resp.Diagnostics = resp.Diagnostics.Append(fmt.Errorf("Configure not called before ReadDataSource %q", r.TypeName)) 519 return resp 520 } 521 522 p.ReadDataSourceCalled = true 523 p.ReadDataSourceRequest = r 524 525 if p.ReadDataSourceFn != nil { 526 return p.ReadDataSourceFn(r) 527 } 528 529 if p.ReadDataSourceResponse != nil { 530 resp = *p.ReadDataSourceResponse 531 } 532 533 return resp 534 } 535 536 func (p *MockProvider) Close() error { 537 p.CloseCalled = true 538 return p.CloseError 539 }