kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/plugin6/grpc_provider_test.go (about) 1 package plugin6 2 3 import ( 4 "bytes" 5 "fmt" 6 "testing" 7 8 "github.com/golang/mock/gomock" 9 "github.com/google/go-cmp/cmp" 10 "github.com/google/go-cmp/cmp/cmpopts" 11 "kubeform.dev/terraform-backend-sdk/configs/hcl2shim" 12 "kubeform.dev/terraform-backend-sdk/providers" 13 "kubeform.dev/terraform-backend-sdk/tfdiags" 14 "github.com/zclconf/go-cty/cty" 15 16 mockproto "kubeform.dev/terraform-backend-sdk/plugin6/mock_proto" 17 proto "kubeform.dev/terraform-backend-sdk/tfplugin6" 18 ) 19 20 var _ providers.Interface = (*GRPCProvider)(nil) 21 22 var ( 23 equateEmpty = cmpopts.EquateEmpty() 24 typeComparer = cmp.Comparer(cty.Type.Equals) 25 valueComparer = cmp.Comparer(cty.Value.RawEquals) 26 ) 27 28 func mockProviderClient(t *testing.T) *mockproto.MockProviderClient { 29 ctrl := gomock.NewController(t) 30 client := mockproto.NewMockProviderClient(ctrl) 31 32 // we always need a GetSchema method 33 client.EXPECT().GetProviderSchema( 34 gomock.Any(), 35 gomock.Any(), 36 gomock.Any(), 37 ).Return(providerProtoSchema(), nil) 38 39 return client 40 } 41 42 func checkDiags(t *testing.T, d tfdiags.Diagnostics) { 43 t.Helper() 44 if d.HasErrors() { 45 t.Fatal(d.Err()) 46 } 47 } 48 49 func providerProtoSchema() *proto.GetProviderSchema_Response { 50 return &proto.GetProviderSchema_Response{ 51 Provider: &proto.Schema{ 52 Block: &proto.Schema_Block{ 53 Attributes: []*proto.Schema_Attribute{ 54 { 55 Name: "attr", 56 Type: []byte(`"string"`), 57 Required: true, 58 }, 59 }, 60 }, 61 }, 62 ResourceSchemas: map[string]*proto.Schema{ 63 "resource": { 64 Version: 1, 65 Block: &proto.Schema_Block{ 66 Attributes: []*proto.Schema_Attribute{ 67 { 68 Name: "attr", 69 Type: []byte(`"string"`), 70 Required: true, 71 }, 72 }, 73 }, 74 }, 75 }, 76 DataSourceSchemas: map[string]*proto.Schema{ 77 "data": { 78 Version: 1, 79 Block: &proto.Schema_Block{ 80 Attributes: []*proto.Schema_Attribute{ 81 { 82 Name: "attr", 83 Type: []byte(`"string"`), 84 Required: true, 85 }, 86 }, 87 }, 88 }, 89 }, 90 } 91 } 92 93 func TestGRPCProvider_GetSchema(t *testing.T) { 94 p := &GRPCProvider{ 95 client: mockProviderClient(t), 96 } 97 98 resp := p.GetProviderSchema() 99 checkDiags(t, resp.Diagnostics) 100 } 101 102 func TestGRPCProvider_PrepareProviderConfig(t *testing.T) { 103 client := mockProviderClient(t) 104 p := &GRPCProvider{ 105 client: client, 106 } 107 108 client.EXPECT().ValidateProviderConfig( 109 gomock.Any(), 110 gomock.Any(), 111 ).Return(&proto.ValidateProviderConfig_Response{}, nil) 112 113 cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"}) 114 resp := p.ValidateProviderConfig(providers.ValidateProviderConfigRequest{Config: cfg}) 115 checkDiags(t, resp.Diagnostics) 116 } 117 118 func TestGRPCProvider_ValidateResourceConfig(t *testing.T) { 119 client := mockProviderClient(t) 120 p := &GRPCProvider{ 121 client: client, 122 } 123 124 client.EXPECT().ValidateResourceConfig( 125 gomock.Any(), 126 gomock.Any(), 127 ).Return(&proto.ValidateResourceConfig_Response{}, nil) 128 129 cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"}) 130 resp := p.ValidateResourceConfig(providers.ValidateResourceConfigRequest{ 131 TypeName: "resource", 132 Config: cfg, 133 }) 134 checkDiags(t, resp.Diagnostics) 135 } 136 137 func TestGRPCProvider_ValidateDataResourceConfig(t *testing.T) { 138 client := mockProviderClient(t) 139 p := &GRPCProvider{ 140 client: client, 141 } 142 143 client.EXPECT().ValidateDataResourceConfig( 144 gomock.Any(), 145 gomock.Any(), 146 ).Return(&proto.ValidateDataResourceConfig_Response{}, nil) 147 148 cfg := hcl2shim.HCL2ValueFromConfigValue(map[string]interface{}{"attr": "value"}) 149 resp := p.ValidateDataResourceConfig(providers.ValidateDataResourceConfigRequest{ 150 TypeName: "data", 151 Config: cfg, 152 }) 153 checkDiags(t, resp.Diagnostics) 154 } 155 156 func TestGRPCProvider_UpgradeResourceState(t *testing.T) { 157 client := mockProviderClient(t) 158 p := &GRPCProvider{ 159 client: client, 160 } 161 162 client.EXPECT().UpgradeResourceState( 163 gomock.Any(), 164 gomock.Any(), 165 ).Return(&proto.UpgradeResourceState_Response{ 166 UpgradedState: &proto.DynamicValue{ 167 Msgpack: []byte("\x81\xa4attr\xa3bar"), 168 }, 169 }, nil) 170 171 resp := p.UpgradeResourceState(providers.UpgradeResourceStateRequest{ 172 TypeName: "resource", 173 Version: 0, 174 RawStateJSON: []byte(`{"old_attr":"bar"}`), 175 }) 176 checkDiags(t, resp.Diagnostics) 177 178 expected := cty.ObjectVal(map[string]cty.Value{ 179 "attr": cty.StringVal("bar"), 180 }) 181 182 if !cmp.Equal(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty) { 183 t.Fatal(cmp.Diff(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty)) 184 } 185 } 186 187 func TestGRPCProvider_UpgradeResourceStateJSON(t *testing.T) { 188 client := mockProviderClient(t) 189 p := &GRPCProvider{ 190 client: client, 191 } 192 193 client.EXPECT().UpgradeResourceState( 194 gomock.Any(), 195 gomock.Any(), 196 ).Return(&proto.UpgradeResourceState_Response{ 197 UpgradedState: &proto.DynamicValue{ 198 Json: []byte(`{"attr":"bar"}`), 199 }, 200 }, nil) 201 202 resp := p.UpgradeResourceState(providers.UpgradeResourceStateRequest{ 203 TypeName: "resource", 204 Version: 0, 205 RawStateJSON: []byte(`{"old_attr":"bar"}`), 206 }) 207 checkDiags(t, resp.Diagnostics) 208 209 expected := cty.ObjectVal(map[string]cty.Value{ 210 "attr": cty.StringVal("bar"), 211 }) 212 213 if !cmp.Equal(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty) { 214 t.Fatal(cmp.Diff(expected, resp.UpgradedState, typeComparer, valueComparer, equateEmpty)) 215 } 216 } 217 218 func TestGRPCProvider_Configure(t *testing.T) { 219 client := mockProviderClient(t) 220 p := &GRPCProvider{ 221 client: client, 222 } 223 224 client.EXPECT().ConfigureProvider( 225 gomock.Any(), 226 gomock.Any(), 227 ).Return(&proto.ConfigureProvider_Response{}, nil) 228 229 resp := p.ConfigureProvider(providers.ConfigureProviderRequest{ 230 Config: cty.ObjectVal(map[string]cty.Value{ 231 "attr": cty.StringVal("foo"), 232 }), 233 }) 234 checkDiags(t, resp.Diagnostics) 235 } 236 237 func TestGRPCProvider_Stop(t *testing.T) { 238 client := mockProviderClient(t) 239 p := &GRPCProvider{ 240 client: client, 241 } 242 243 client.EXPECT().StopProvider( 244 gomock.Any(), 245 gomock.Any(), 246 ).Return(&proto.StopProvider_Response{}, nil) 247 248 err := p.Stop() 249 if err != nil { 250 t.Fatal(err) 251 } 252 } 253 254 func TestGRPCProvider_ReadResource(t *testing.T) { 255 client := mockProviderClient(t) 256 p := &GRPCProvider{ 257 client: client, 258 } 259 260 client.EXPECT().ReadResource( 261 gomock.Any(), 262 gomock.Any(), 263 ).Return(&proto.ReadResource_Response{ 264 NewState: &proto.DynamicValue{ 265 Msgpack: []byte("\x81\xa4attr\xa3bar"), 266 }, 267 }, nil) 268 269 resp := p.ReadResource(providers.ReadResourceRequest{ 270 TypeName: "resource", 271 PriorState: cty.ObjectVal(map[string]cty.Value{ 272 "attr": cty.StringVal("foo"), 273 }), 274 }) 275 276 checkDiags(t, resp.Diagnostics) 277 278 expected := cty.ObjectVal(map[string]cty.Value{ 279 "attr": cty.StringVal("bar"), 280 }) 281 282 if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) { 283 t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty)) 284 } 285 } 286 287 func TestGRPCProvider_ReadResourceJSON(t *testing.T) { 288 client := mockProviderClient(t) 289 p := &GRPCProvider{ 290 client: client, 291 } 292 293 client.EXPECT().ReadResource( 294 gomock.Any(), 295 gomock.Any(), 296 ).Return(&proto.ReadResource_Response{ 297 NewState: &proto.DynamicValue{ 298 Json: []byte(`{"attr":"bar"}`), 299 }, 300 }, nil) 301 302 resp := p.ReadResource(providers.ReadResourceRequest{ 303 TypeName: "resource", 304 PriorState: cty.ObjectVal(map[string]cty.Value{ 305 "attr": cty.StringVal("foo"), 306 }), 307 }) 308 309 checkDiags(t, resp.Diagnostics) 310 311 expected := cty.ObjectVal(map[string]cty.Value{ 312 "attr": cty.StringVal("bar"), 313 }) 314 315 if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) { 316 t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty)) 317 } 318 } 319 320 func TestGRPCProvider_ReadEmptyJSON(t *testing.T) { 321 client := mockProviderClient(t) 322 p := &GRPCProvider{ 323 client: client, 324 } 325 326 client.EXPECT().ReadResource( 327 gomock.Any(), 328 gomock.Any(), 329 ).Return(&proto.ReadResource_Response{ 330 NewState: &proto.DynamicValue{ 331 Json: []byte(``), 332 }, 333 }, nil) 334 335 obj := cty.ObjectVal(map[string]cty.Value{ 336 "attr": cty.StringVal("foo"), 337 }) 338 resp := p.ReadResource(providers.ReadResourceRequest{ 339 TypeName: "resource", 340 PriorState: obj, 341 }) 342 343 checkDiags(t, resp.Diagnostics) 344 345 expected := cty.NullVal(obj.Type()) 346 347 if !cmp.Equal(expected, resp.NewState, typeComparer, valueComparer, equateEmpty) { 348 t.Fatal(cmp.Diff(expected, resp.NewState, typeComparer, valueComparer, equateEmpty)) 349 } 350 } 351 352 func TestGRPCProvider_PlanResourceChange(t *testing.T) { 353 client := mockProviderClient(t) 354 p := &GRPCProvider{ 355 client: client, 356 } 357 358 expectedPrivate := []byte(`{"meta": "data"}`) 359 360 client.EXPECT().PlanResourceChange( 361 gomock.Any(), 362 gomock.Any(), 363 ).Return(&proto.PlanResourceChange_Response{ 364 PlannedState: &proto.DynamicValue{ 365 Msgpack: []byte("\x81\xa4attr\xa3bar"), 366 }, 367 RequiresReplace: []*proto.AttributePath{ 368 { 369 Steps: []*proto.AttributePath_Step{ 370 { 371 Selector: &proto.AttributePath_Step_AttributeName{ 372 AttributeName: "attr", 373 }, 374 }, 375 }, 376 }, 377 }, 378 PlannedPrivate: expectedPrivate, 379 }, nil) 380 381 resp := p.PlanResourceChange(providers.PlanResourceChangeRequest{ 382 TypeName: "resource", 383 PriorState: cty.ObjectVal(map[string]cty.Value{ 384 "attr": cty.StringVal("foo"), 385 }), 386 ProposedNewState: cty.ObjectVal(map[string]cty.Value{ 387 "attr": cty.StringVal("bar"), 388 }), 389 Config: cty.ObjectVal(map[string]cty.Value{ 390 "attr": cty.StringVal("bar"), 391 }), 392 }) 393 394 checkDiags(t, resp.Diagnostics) 395 396 expectedState := cty.ObjectVal(map[string]cty.Value{ 397 "attr": cty.StringVal("bar"), 398 }) 399 400 if !cmp.Equal(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty) { 401 t.Fatal(cmp.Diff(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty)) 402 } 403 404 expectedReplace := `[]cty.Path{cty.Path{cty.GetAttrStep{Name:"attr"}}}` 405 replace := fmt.Sprintf("%#v", resp.RequiresReplace) 406 if expectedReplace != replace { 407 t.Fatalf("expected %q, got %q", expectedReplace, replace) 408 } 409 410 if !bytes.Equal(expectedPrivate, resp.PlannedPrivate) { 411 t.Fatalf("expected %q, got %q", expectedPrivate, resp.PlannedPrivate) 412 } 413 } 414 415 func TestGRPCProvider_PlanResourceChangeJSON(t *testing.T) { 416 client := mockProviderClient(t) 417 p := &GRPCProvider{ 418 client: client, 419 } 420 421 expectedPrivate := []byte(`{"meta": "data"}`) 422 423 client.EXPECT().PlanResourceChange( 424 gomock.Any(), 425 gomock.Any(), 426 ).Return(&proto.PlanResourceChange_Response{ 427 PlannedState: &proto.DynamicValue{ 428 Json: []byte(`{"attr":"bar"}`), 429 }, 430 RequiresReplace: []*proto.AttributePath{ 431 { 432 Steps: []*proto.AttributePath_Step{ 433 { 434 Selector: &proto.AttributePath_Step_AttributeName{ 435 AttributeName: "attr", 436 }, 437 }, 438 }, 439 }, 440 }, 441 PlannedPrivate: expectedPrivate, 442 }, nil) 443 444 resp := p.PlanResourceChange(providers.PlanResourceChangeRequest{ 445 TypeName: "resource", 446 PriorState: cty.ObjectVal(map[string]cty.Value{ 447 "attr": cty.StringVal("foo"), 448 }), 449 ProposedNewState: cty.ObjectVal(map[string]cty.Value{ 450 "attr": cty.StringVal("bar"), 451 }), 452 Config: cty.ObjectVal(map[string]cty.Value{ 453 "attr": cty.StringVal("bar"), 454 }), 455 }) 456 457 checkDiags(t, resp.Diagnostics) 458 459 expectedState := cty.ObjectVal(map[string]cty.Value{ 460 "attr": cty.StringVal("bar"), 461 }) 462 463 if !cmp.Equal(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty) { 464 t.Fatal(cmp.Diff(expectedState, resp.PlannedState, typeComparer, valueComparer, equateEmpty)) 465 } 466 467 expectedReplace := `[]cty.Path{cty.Path{cty.GetAttrStep{Name:"attr"}}}` 468 replace := fmt.Sprintf("%#v", resp.RequiresReplace) 469 if expectedReplace != replace { 470 t.Fatalf("expected %q, got %q", expectedReplace, replace) 471 } 472 473 if !bytes.Equal(expectedPrivate, resp.PlannedPrivate) { 474 t.Fatalf("expected %q, got %q", expectedPrivate, resp.PlannedPrivate) 475 } 476 } 477 478 func TestGRPCProvider_ApplyResourceChange(t *testing.T) { 479 client := mockProviderClient(t) 480 p := &GRPCProvider{ 481 client: client, 482 } 483 484 expectedPrivate := []byte(`{"meta": "data"}`) 485 486 client.EXPECT().ApplyResourceChange( 487 gomock.Any(), 488 gomock.Any(), 489 ).Return(&proto.ApplyResourceChange_Response{ 490 NewState: &proto.DynamicValue{ 491 Msgpack: []byte("\x81\xa4attr\xa3bar"), 492 }, 493 Private: expectedPrivate, 494 }, nil) 495 496 resp := p.ApplyResourceChange(providers.ApplyResourceChangeRequest{ 497 TypeName: "resource", 498 PriorState: cty.ObjectVal(map[string]cty.Value{ 499 "attr": cty.StringVal("foo"), 500 }), 501 PlannedState: cty.ObjectVal(map[string]cty.Value{ 502 "attr": cty.StringVal("bar"), 503 }), 504 Config: cty.ObjectVal(map[string]cty.Value{ 505 "attr": cty.StringVal("bar"), 506 }), 507 PlannedPrivate: expectedPrivate, 508 }) 509 510 checkDiags(t, resp.Diagnostics) 511 512 expectedState := cty.ObjectVal(map[string]cty.Value{ 513 "attr": cty.StringVal("bar"), 514 }) 515 516 if !cmp.Equal(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty) { 517 t.Fatal(cmp.Diff(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty)) 518 } 519 520 if !bytes.Equal(expectedPrivate, resp.Private) { 521 t.Fatalf("expected %q, got %q", expectedPrivate, resp.Private) 522 } 523 } 524 func TestGRPCProvider_ApplyResourceChangeJSON(t *testing.T) { 525 client := mockProviderClient(t) 526 p := &GRPCProvider{ 527 client: client, 528 } 529 530 expectedPrivate := []byte(`{"meta": "data"}`) 531 532 client.EXPECT().ApplyResourceChange( 533 gomock.Any(), 534 gomock.Any(), 535 ).Return(&proto.ApplyResourceChange_Response{ 536 NewState: &proto.DynamicValue{ 537 Json: []byte(`{"attr":"bar"}`), 538 }, 539 Private: expectedPrivate, 540 }, nil) 541 542 resp := p.ApplyResourceChange(providers.ApplyResourceChangeRequest{ 543 TypeName: "resource", 544 PriorState: cty.ObjectVal(map[string]cty.Value{ 545 "attr": cty.StringVal("foo"), 546 }), 547 PlannedState: cty.ObjectVal(map[string]cty.Value{ 548 "attr": cty.StringVal("bar"), 549 }), 550 Config: cty.ObjectVal(map[string]cty.Value{ 551 "attr": cty.StringVal("bar"), 552 }), 553 PlannedPrivate: expectedPrivate, 554 }) 555 556 checkDiags(t, resp.Diagnostics) 557 558 expectedState := cty.ObjectVal(map[string]cty.Value{ 559 "attr": cty.StringVal("bar"), 560 }) 561 562 if !cmp.Equal(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty) { 563 t.Fatal(cmp.Diff(expectedState, resp.NewState, typeComparer, valueComparer, equateEmpty)) 564 } 565 566 if !bytes.Equal(expectedPrivate, resp.Private) { 567 t.Fatalf("expected %q, got %q", expectedPrivate, resp.Private) 568 } 569 } 570 571 func TestGRPCProvider_ImportResourceState(t *testing.T) { 572 client := mockProviderClient(t) 573 p := &GRPCProvider{ 574 client: client, 575 } 576 577 expectedPrivate := []byte(`{"meta": "data"}`) 578 579 client.EXPECT().ImportResourceState( 580 gomock.Any(), 581 gomock.Any(), 582 ).Return(&proto.ImportResourceState_Response{ 583 ImportedResources: []*proto.ImportResourceState_ImportedResource{ 584 { 585 TypeName: "resource", 586 State: &proto.DynamicValue{ 587 Msgpack: []byte("\x81\xa4attr\xa3bar"), 588 }, 589 Private: expectedPrivate, 590 }, 591 }, 592 }, nil) 593 594 resp := p.ImportResourceState(providers.ImportResourceStateRequest{ 595 TypeName: "resource", 596 ID: "foo", 597 }) 598 599 checkDiags(t, resp.Diagnostics) 600 601 expectedResource := providers.ImportedResource{ 602 TypeName: "resource", 603 State: cty.ObjectVal(map[string]cty.Value{ 604 "attr": cty.StringVal("bar"), 605 }), 606 Private: expectedPrivate, 607 } 608 609 imported := resp.ImportedResources[0] 610 if !cmp.Equal(expectedResource, imported, typeComparer, valueComparer, equateEmpty) { 611 t.Fatal(cmp.Diff(expectedResource, imported, typeComparer, valueComparer, equateEmpty)) 612 } 613 } 614 func TestGRPCProvider_ImportResourceStateJSON(t *testing.T) { 615 client := mockProviderClient(t) 616 p := &GRPCProvider{ 617 client: client, 618 } 619 620 expectedPrivate := []byte(`{"meta": "data"}`) 621 622 client.EXPECT().ImportResourceState( 623 gomock.Any(), 624 gomock.Any(), 625 ).Return(&proto.ImportResourceState_Response{ 626 ImportedResources: []*proto.ImportResourceState_ImportedResource{ 627 { 628 TypeName: "resource", 629 State: &proto.DynamicValue{ 630 Json: []byte(`{"attr":"bar"}`), 631 }, 632 Private: expectedPrivate, 633 }, 634 }, 635 }, nil) 636 637 resp := p.ImportResourceState(providers.ImportResourceStateRequest{ 638 TypeName: "resource", 639 ID: "foo", 640 }) 641 642 checkDiags(t, resp.Diagnostics) 643 644 expectedResource := providers.ImportedResource{ 645 TypeName: "resource", 646 State: cty.ObjectVal(map[string]cty.Value{ 647 "attr": cty.StringVal("bar"), 648 }), 649 Private: expectedPrivate, 650 } 651 652 imported := resp.ImportedResources[0] 653 if !cmp.Equal(expectedResource, imported, typeComparer, valueComparer, equateEmpty) { 654 t.Fatal(cmp.Diff(expectedResource, imported, typeComparer, valueComparer, equateEmpty)) 655 } 656 } 657 658 func TestGRPCProvider_ReadDataSource(t *testing.T) { 659 client := mockProviderClient(t) 660 p := &GRPCProvider{ 661 client: client, 662 } 663 664 client.EXPECT().ReadDataSource( 665 gomock.Any(), 666 gomock.Any(), 667 ).Return(&proto.ReadDataSource_Response{ 668 State: &proto.DynamicValue{ 669 Msgpack: []byte("\x81\xa4attr\xa3bar"), 670 }, 671 }, nil) 672 673 resp := p.ReadDataSource(providers.ReadDataSourceRequest{ 674 TypeName: "data", 675 Config: cty.ObjectVal(map[string]cty.Value{ 676 "attr": cty.StringVal("foo"), 677 }), 678 }) 679 680 checkDiags(t, resp.Diagnostics) 681 682 expected := cty.ObjectVal(map[string]cty.Value{ 683 "attr": cty.StringVal("bar"), 684 }) 685 686 if !cmp.Equal(expected, resp.State, typeComparer, valueComparer, equateEmpty) { 687 t.Fatal(cmp.Diff(expected, resp.State, typeComparer, valueComparer, equateEmpty)) 688 } 689 } 690 691 func TestGRPCProvider_ReadDataSourceJSON(t *testing.T) { 692 client := mockProviderClient(t) 693 p := &GRPCProvider{ 694 client: client, 695 } 696 697 client.EXPECT().ReadDataSource( 698 gomock.Any(), 699 gomock.Any(), 700 ).Return(&proto.ReadDataSource_Response{ 701 State: &proto.DynamicValue{ 702 Json: []byte(`{"attr":"bar"}`), 703 }, 704 }, nil) 705 706 resp := p.ReadDataSource(providers.ReadDataSourceRequest{ 707 TypeName: "data", 708 Config: cty.ObjectVal(map[string]cty.Value{ 709 "attr": cty.StringVal("foo"), 710 }), 711 }) 712 713 checkDiags(t, resp.Diagnostics) 714 715 expected := cty.ObjectVal(map[string]cty.Value{ 716 "attr": cty.StringVal("bar"), 717 }) 718 719 if !cmp.Equal(expected, resp.State, typeComparer, valueComparer, equateEmpty) { 720 t.Fatal(cmp.Diff(expected, resp.State, typeComparer, valueComparer, equateEmpty)) 721 } 722 }