github.com/myhau/pulumi/pkg/v3@v3.70.2-0.20221116134521-f2775972e587/resource/deploy/providers/registry_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 providers 16 17 import ( 18 "errors" 19 "fmt" 20 "testing" 21 22 "github.com/blang/semver" 23 24 "github.com/stretchr/testify/assert" 25 26 "github.com/pulumi/pulumi/sdk/v3/go/common/diag" 27 "github.com/pulumi/pulumi/sdk/v3/go/common/resource" 28 "github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin" 29 "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" 30 "github.com/pulumi/pulumi/sdk/v3/go/common/workspace" 31 ) 32 33 type testPluginHost struct { 34 t *testing.T 35 provider func(pkg tokens.Package, version *semver.Version) (plugin.Provider, error) 36 closeProvider func(provider plugin.Provider) error 37 } 38 39 func (host *testPluginHost) SignalCancellation() error { 40 return nil 41 } 42 func (host *testPluginHost) Close() error { 43 return nil 44 } 45 func (host *testPluginHost) ServerAddr() string { 46 host.t.Fatalf("Host RPC address not available") 47 return "" 48 } 49 func (host *testPluginHost) Log(sev diag.Severity, urn resource.URN, msg string, streamID int32) { 50 host.t.Logf("[%v] %v@%v: %v", sev, urn, streamID, msg) 51 } 52 func (host *testPluginHost) LogStatus(sev diag.Severity, urn resource.URN, msg string, streamID int32) { 53 host.t.Logf("[%v] %v@%v: %v", sev, urn, streamID, msg) 54 } 55 func (host *testPluginHost) Analyzer(nm tokens.QName) (plugin.Analyzer, error) { 56 return nil, errors.New("unsupported") 57 } 58 func (host *testPluginHost) PolicyAnalyzer(name tokens.QName, path string, 59 opts *plugin.PolicyAnalyzerOptions) (plugin.Analyzer, error) { 60 return nil, errors.New("unsupported") 61 } 62 func (host *testPluginHost) ListAnalyzers() []plugin.Analyzer { 63 return nil 64 } 65 func (host *testPluginHost) Provider(pkg tokens.Package, version *semver.Version) (plugin.Provider, error) { 66 return host.provider(pkg, version) 67 } 68 func (host *testPluginHost) CloseProvider(provider plugin.Provider) error { 69 return host.closeProvider(provider) 70 } 71 func (host *testPluginHost) LanguageRuntime(runtime string) (plugin.LanguageRuntime, error) { 72 return nil, errors.New("unsupported") 73 } 74 func (host *testPluginHost) EnsurePlugins(plugins []workspace.PluginSpec, kinds plugin.Flags) error { 75 return nil 76 } 77 func (host *testPluginHost) InstallPlugin(plugin workspace.PluginSpec) error { 78 return nil 79 } 80 func (host *testPluginHost) ResolvePlugin( 81 kind workspace.PluginKind, name string, version *semver.Version) (*workspace.PluginInfo, error) { 82 return nil, nil 83 } 84 85 func (host *testPluginHost) GetProjectPlugins() []workspace.ProjectPlugin { 86 return nil 87 } 88 89 func (host *testPluginHost) GetRequiredPlugins(info plugin.ProgInfo, 90 kinds plugin.Flags) ([]workspace.PluginInfo, error) { 91 return nil, nil 92 } 93 94 type testProvider struct { 95 pkg tokens.Package 96 version semver.Version 97 configured bool 98 checkConfig func(resource.URN, resource.PropertyMap, 99 resource.PropertyMap, bool) (resource.PropertyMap, []plugin.CheckFailure, error) 100 diffConfig func(resource.URN, resource.PropertyMap, resource.PropertyMap, bool, []string) (plugin.DiffResult, error) 101 config func(resource.PropertyMap) error 102 } 103 104 func (prov *testProvider) SignalCancellation() error { 105 return nil 106 } 107 func (prov *testProvider) Close() error { 108 return nil 109 } 110 func (prov *testProvider) Pkg() tokens.Package { 111 return prov.pkg 112 } 113 func (prov *testProvider) GetSchema(version int) ([]byte, error) { 114 return []byte("{}"), nil 115 } 116 func (prov *testProvider) CheckConfig(urn resource.URN, olds, 117 news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) { 118 return prov.checkConfig(urn, olds, news, allowUnknowns) 119 } 120 func (prov *testProvider) DiffConfig(urn resource.URN, olds, news resource.PropertyMap, 121 allowUnknowns bool, ignoreChanges []string) (plugin.DiffResult, error) { 122 return prov.diffConfig(urn, olds, news, allowUnknowns, ignoreChanges) 123 } 124 func (prov *testProvider) Configure(inputs resource.PropertyMap) error { 125 if err := prov.config(inputs); err != nil { 126 return err 127 } 128 prov.configured = true 129 return nil 130 } 131 func (prov *testProvider) Check(urn resource.URN, 132 olds, news resource.PropertyMap, _ bool, _ []byte) (resource.PropertyMap, []plugin.CheckFailure, error) { 133 return nil, nil, errors.New("unsupported") 134 } 135 func (prov *testProvider) Create(urn resource.URN, props resource.PropertyMap, timeout float64, 136 preview bool) (resource.ID, resource.PropertyMap, resource.Status, error) { 137 return "", nil, resource.StatusOK, errors.New("unsupported") 138 } 139 func (prov *testProvider) Read(urn resource.URN, id resource.ID, 140 inputs, state resource.PropertyMap) (plugin.ReadResult, resource.Status, error) { 141 return plugin.ReadResult{}, resource.StatusUnknown, errors.New("unsupported") 142 } 143 func (prov *testProvider) Diff(urn resource.URN, id resource.ID, 144 olds resource.PropertyMap, news resource.PropertyMap, _ bool, _ []string) (plugin.DiffResult, error) { 145 return plugin.DiffResult{}, errors.New("unsupported") 146 } 147 func (prov *testProvider) Update(urn resource.URN, id resource.ID, 148 olds resource.PropertyMap, news resource.PropertyMap, timeout float64, 149 ignoreChanges []string, preview bool) (resource.PropertyMap, resource.Status, error) { 150 return nil, resource.StatusOK, errors.New("unsupported") 151 } 152 func (prov *testProvider) Delete(urn resource.URN, 153 id resource.ID, props resource.PropertyMap, timeout float64) (resource.Status, error) { 154 return resource.StatusOK, errors.New("unsupported") 155 } 156 func (prov *testProvider) Construct(info plugin.ConstructInfo, typ tokens.Type, name tokens.QName, parent resource.URN, 157 inputs resource.PropertyMap, options plugin.ConstructOptions) (plugin.ConstructResult, error) { 158 return plugin.ConstructResult{}, errors.New("unsupported") 159 } 160 func (prov *testProvider) Invoke(tok tokens.ModuleMember, 161 args resource.PropertyMap) (resource.PropertyMap, []plugin.CheckFailure, error) { 162 return nil, nil, errors.New("unsupported") 163 } 164 func (prov *testProvider) StreamInvoke( 165 tok tokens.ModuleMember, args resource.PropertyMap, 166 onNext func(resource.PropertyMap) error) ([]plugin.CheckFailure, error) { 167 168 return nil, fmt.Errorf("not implemented") 169 } 170 func (prov *testProvider) Call(tok tokens.ModuleMember, args resource.PropertyMap, info plugin.CallInfo, 171 options plugin.CallOptions) (plugin.CallResult, error) { 172 return plugin.CallResult{}, errors.New("unsupported") 173 } 174 func (prov *testProvider) GetPluginInfo() (workspace.PluginInfo, error) { 175 return workspace.PluginInfo{ 176 Name: "testProvider", 177 Version: &prov.version, 178 }, nil 179 } 180 181 type providerLoader struct { 182 pkg tokens.Package 183 version semver.Version 184 load func() (plugin.Provider, error) 185 } 186 187 func newPluginHost(t *testing.T, loaders []*providerLoader) plugin.Host { 188 return &testPluginHost{ 189 t: t, 190 provider: func(pkg tokens.Package, ver *semver.Version) (plugin.Provider, error) { 191 var best *providerLoader 192 for _, l := range loaders { 193 if l.pkg != pkg { 194 continue 195 } 196 197 if ver != nil && l.version.LT(*ver) { 198 continue 199 } 200 if best == nil || l.version.GT(best.version) { 201 best = l 202 } 203 } 204 if best == nil { 205 return nil, nil 206 } 207 return best.load() 208 }, 209 closeProvider: func(provider plugin.Provider) error { 210 return nil 211 }, 212 } 213 } 214 215 func newLoader(t *testing.T, pkg, version string, 216 load func(tokens.Package, semver.Version) (plugin.Provider, error)) *providerLoader { 217 218 var ver semver.Version 219 if version != "" { 220 v, err := semver.ParseTolerant(version) 221 assert.NoError(t, err) 222 ver = v 223 } 224 return &providerLoader{ 225 pkg: tokens.Package(pkg), 226 version: ver, 227 load: func() (plugin.Provider, error) { 228 return load(tokens.Package(pkg), ver) 229 }, 230 } 231 } 232 233 func newSimpleLoader(t *testing.T, pkg, version string, config func(resource.PropertyMap) error) *providerLoader { 234 if config == nil { 235 config = func(resource.PropertyMap) error { 236 return nil 237 } 238 } 239 return newLoader(t, pkg, version, func(pkg tokens.Package, ver semver.Version) (plugin.Provider, error) { 240 return &testProvider{ 241 pkg: pkg, 242 version: ver, 243 checkConfig: func(urn resource.URN, olds, 244 news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) { 245 return news, nil, nil 246 }, 247 diffConfig: func(urn resource.URN, olds, news resource.PropertyMap, 248 allowUnknowns bool, ignoreChanges []string) (plugin.DiffResult, error) { 249 return plugin.DiffResult{}, nil 250 }, 251 config: config, 252 }, nil 253 }) 254 } 255 256 func newProviderState(pkg, name, id string, delete bool, inputs resource.PropertyMap) *resource.State { 257 typ := MakeProviderType(tokens.Package(pkg)) 258 urn := resource.NewURN("test", "test", "", typ, tokens.QName(name)) 259 if inputs == nil { 260 inputs = resource.PropertyMap{} 261 } 262 return &resource.State{ 263 Type: typ, 264 URN: urn, 265 Custom: true, 266 Delete: delete, 267 ID: resource.ID(id), 268 Inputs: inputs, 269 } 270 } 271 272 func TestNewRegistryNoOldState(t *testing.T) { 273 t.Parallel() 274 275 r, err := NewRegistry(&testPluginHost{}, nil, false, nil) 276 assert.NoError(t, err) 277 assert.NotNil(t, r) 278 279 r, err = NewRegistry(&testPluginHost{}, nil, true, nil) 280 assert.NoError(t, err) 281 assert.NotNil(t, r) 282 } 283 284 func TestNewRegistryOldState(t *testing.T) { 285 t.Parallel() 286 287 olds := []*resource.State{ 288 // Two providers from package A, each with a unique name and ID 289 newProviderState("pkgA", "a", "id1", false, nil), 290 newProviderState("pkgA", "b", "id2", false, nil), 291 // Two providers from package B, each with a unique name and ID 292 newProviderState("pkgB", "a", "id1", false, nil), 293 newProviderState("pkgB", "b", "id2", false, nil), 294 // Two providers from package C, both with the same name but with unique IDs and one marked for deletion 295 newProviderState("pkgC", "a", "id1", false, nil), 296 newProviderState("pkgC", "a", "id2", true, nil), 297 // One provider from package D with a version 298 newProviderState("pkgD", "a", "id1", false, resource.PropertyMap{ 299 "version": resource.NewStringProperty("1.0.0"), 300 }), 301 } 302 loaders := []*providerLoader{ 303 newSimpleLoader(t, "pkgA", "", nil), 304 newSimpleLoader(t, "pkgB", "", nil), 305 newSimpleLoader(t, "pkgC", "", nil), 306 newSimpleLoader(t, "pkgD", "1.0.0", nil), 307 } 308 host := newPluginHost(t, loaders) 309 310 r, err := NewRegistry(host, olds, false, nil) 311 assert.NoError(t, err) 312 assert.NotNil(t, r) 313 314 assert.Equal(t, len(olds), len(r.providers)) 315 316 for _, old := range olds { 317 ref, err := NewReference(old.URN, old.ID) 318 assert.NoError(t, err) 319 320 p, ok := r.GetProvider(ref) 321 assert.True(t, ok) 322 assert.NotNil(t, p) 323 324 assert.True(t, p.(*testProvider).configured) 325 326 assert.Equal(t, GetProviderPackage(old.Type), p.Pkg()) 327 328 ver, err := GetProviderVersion(old.Inputs) 329 assert.NoError(t, err) 330 if ver != nil { 331 info, err := p.GetPluginInfo() 332 assert.NoError(t, err) 333 assert.True(t, info.Version.GTE(*ver)) 334 } 335 } 336 } 337 338 func TestNewRegistryOldStateNoProviders(t *testing.T) { 339 t.Parallel() 340 341 olds := []*resource.State{ 342 newProviderState("pkgA", "a", "id1", false, nil), 343 } 344 host := newPluginHost(t, []*providerLoader{}) 345 346 r, err := NewRegistry(host, olds, false, nil) 347 assert.Error(t, err) 348 assert.Nil(t, r) 349 } 350 351 func TestNewRegistryOldStateWrongPackage(t *testing.T) { 352 t.Parallel() 353 354 olds := []*resource.State{ 355 newProviderState("pkgA", "a", "id1", false, nil), 356 } 357 loaders := []*providerLoader{ 358 newSimpleLoader(t, "pkgB", "", nil), 359 } 360 host := newPluginHost(t, loaders) 361 362 r, err := NewRegistry(host, olds, false, nil) 363 assert.Error(t, err) 364 assert.Nil(t, r) 365 } 366 367 func TestNewRegistryOldStateWrongVersion(t *testing.T) { 368 t.Parallel() 369 370 olds := []*resource.State{ 371 newProviderState("pkgA", "a", "id1", false, resource.PropertyMap{ 372 "version": resource.NewStringProperty("1.0.0"), 373 }), 374 } 375 loaders := []*providerLoader{ 376 newSimpleLoader(t, "pkgA", "0.5.0", nil), 377 } 378 host := newPluginHost(t, loaders) 379 380 r, err := NewRegistry(host, olds, false, nil) 381 assert.Error(t, err) 382 assert.Nil(t, r) 383 } 384 385 func TestNewRegistryOldStateNoID(t *testing.T) { 386 t.Parallel() 387 388 olds := []*resource.State{ 389 newProviderState("pkgA", "a", "", false, nil), 390 } 391 loaders := []*providerLoader{ 392 newSimpleLoader(t, "pkgA", "", nil), 393 } 394 host := newPluginHost(t, loaders) 395 396 r, err := NewRegistry(host, olds, false, nil) 397 assert.Error(t, err) 398 assert.Nil(t, r) 399 } 400 401 func TestNewRegistryOldStateUnknownID(t *testing.T) { 402 t.Parallel() 403 404 olds := []*resource.State{ 405 newProviderState("pkgA", "a", UnknownID, false, nil), 406 } 407 loaders := []*providerLoader{ 408 newSimpleLoader(t, "pkgA", "", nil), 409 } 410 host := newPluginHost(t, loaders) 411 412 r, err := NewRegistry(host, olds, false, nil) 413 assert.Error(t, err) 414 assert.Nil(t, r) 415 } 416 417 func TestNewRegistryOldStateDuplicates(t *testing.T) { 418 t.Parallel() 419 420 olds := []*resource.State{ 421 newProviderState("pkgA", "a", "id1", false, nil), 422 newProviderState("pkgA", "a", "id1", false, nil), 423 } 424 loaders := []*providerLoader{ 425 newSimpleLoader(t, "pkgA", "", nil), 426 } 427 host := newPluginHost(t, loaders) 428 429 r, err := NewRegistry(host, olds, false, nil) 430 assert.Error(t, err) 431 assert.Nil(t, r) 432 } 433 434 func TestCRUD(t *testing.T) { 435 t.Parallel() 436 437 olds := []*resource.State{ 438 newProviderState("pkgA", "a", "id1", false, nil), 439 newProviderState("pkgB", "a", "id1", false, nil), 440 newProviderState("pkgC", "a", "id1", false, nil), 441 } 442 loaders := []*providerLoader{ 443 newSimpleLoader(t, "pkgA", "", nil), 444 newSimpleLoader(t, "pkgB", "", nil), 445 newSimpleLoader(t, "pkgC", "", nil), 446 } 447 host := newPluginHost(t, loaders) 448 449 r, err := NewRegistry(host, olds, false, nil) 450 assert.NoError(t, err) 451 assert.NotNil(t, r) 452 453 assert.Equal(t, len(olds), len(r.providers)) 454 455 for _, old := range olds { 456 ref, err := NewReference(old.URN, old.ID) 457 assert.NoError(t, err) 458 459 p, ok := r.GetProvider(ref) 460 assert.True(t, ok) 461 assert.NotNil(t, p) 462 463 assert.Equal(t, GetProviderPackage(old.Type), p.Pkg()) 464 } 465 466 // Create a new provider for each package. 467 for _, l := range loaders { 468 typ := MakeProviderType(l.pkg) 469 urn := resource.NewURN("test", "test", "", typ, "b") 470 olds, news := resource.PropertyMap{}, resource.PropertyMap{} 471 timeout := float64(120) 472 473 // Check 474 inputs, failures, err := r.Check(urn, olds, news, false, nil) 475 assert.NoError(t, err) 476 assert.Equal(t, news, inputs) 477 assert.Empty(t, failures) 478 479 // Since this is not a preview, the provider should not yet be configured. 480 p, ok := r.GetProvider(Reference{urn: urn, id: UnknownID}) 481 assert.True(t, ok) 482 assert.False(t, p.(*testProvider).configured) 483 484 // Create 485 id, outs, status, err := r.Create(urn, inputs, timeout, false) 486 assert.NoError(t, err) 487 assert.NotEqual(t, "", id) 488 assert.NotEqual(t, UnknownID, id) 489 assert.Equal(t, resource.PropertyMap{}, outs) 490 assert.Equal(t, resource.StatusOK, status) 491 492 p2, ok := r.GetProvider(Reference{urn: urn, id: id}) 493 assert.True(t, ok) 494 assert.Equal(t, p, p2) 495 assert.True(t, p2.(*testProvider).configured) 496 } 497 498 // Update the existing provider for the first entry in olds. 499 { 500 urn, id := olds[0].URN, olds[0].ID 501 olds, news := olds[0].Inputs, olds[0].Inputs 502 timeout := float64(120) 503 504 // Fetch the old provider instance. 505 old, ok := r.GetProvider(Reference{urn: urn, id: id}) 506 assert.True(t, ok) 507 508 // Check 509 inputs, failures, err := r.Check(urn, olds, news, false, nil) 510 assert.NoError(t, err) 511 assert.Equal(t, news, inputs) 512 assert.Empty(t, failures) 513 514 // Since this is not a preview, the provider should not yet be configured. 515 p, ok := r.GetProvider(Reference{urn: urn, id: UnknownID}) 516 assert.True(t, ok) 517 assert.False(t, p == old) 518 assert.False(t, p.(*testProvider).configured) 519 520 // Diff 521 diff, err := r.Diff(urn, id, olds, news, false, nil) 522 assert.NoError(t, err) 523 assert.Equal(t, plugin.DiffResult{Changes: plugin.DiffNone}, diff) 524 525 // The old provider should still be registered. 526 p2, ok := r.GetProvider(Reference{urn: urn, id: id}) 527 assert.True(t, ok) 528 assert.Equal(t, old, p2) 529 530 // Update 531 outs, status, err := r.Update(urn, id, olds, inputs, timeout, nil, false) 532 assert.NoError(t, err) 533 assert.Equal(t, resource.PropertyMap{}, outs) 534 assert.Equal(t, resource.StatusOK, status) 535 536 p3, ok := r.GetProvider(Reference{urn: urn, id: id}) 537 assert.True(t, ok) 538 assert.True(t, p3 == p) 539 assert.True(t, p3.(*testProvider).configured) 540 } 541 542 // Delete the existing provider for the last entry in olds. 543 { 544 urn, id := olds[len(olds)-1].URN, olds[len(olds)-1].ID 545 timeout := float64(120) 546 547 // Fetch the old provider instance. 548 _, ok := r.GetProvider(Reference{urn: urn, id: id}) 549 assert.True(t, ok) 550 551 // Delete 552 status, err := r.Delete(urn, id, resource.PropertyMap{}, timeout) 553 assert.NoError(t, err) 554 assert.Equal(t, resource.StatusOK, status) 555 556 _, ok = r.GetProvider(Reference{urn: urn, id: id}) 557 assert.False(t, ok) 558 } 559 } 560 561 func TestCRUDPreview(t *testing.T) { 562 t.Parallel() 563 564 olds := []*resource.State{ 565 newProviderState("pkgA", "a", "id1", false, nil), 566 newProviderState("pkgB", "a", "id1", false, nil), 567 newProviderState("pkgC", "a", "id1", false, nil), 568 newProviderState("pkgD", "a", "id1", false, nil), 569 } 570 loaders := []*providerLoader{ 571 newSimpleLoader(t, "pkgA", "", nil), 572 newSimpleLoader(t, "pkgB", "", nil), 573 newSimpleLoader(t, "pkgC", "", nil), 574 newLoader(t, "pkgD", "", func(pkg tokens.Package, ver semver.Version) (plugin.Provider, error) { 575 return &testProvider{ 576 pkg: pkg, 577 version: ver, 578 checkConfig: func(urn resource.URN, olds, 579 news resource.PropertyMap, allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) { 580 return news, nil, nil 581 }, 582 diffConfig: func(urn resource.URN, olds, news resource.PropertyMap, 583 allowUnknowns bool, ignoreChanges []string) (plugin.DiffResult, error) { 584 // Always reuquire replacement. 585 return plugin.DiffResult{ReplaceKeys: []resource.PropertyKey{"id"}}, nil 586 }, 587 config: func(inputs resource.PropertyMap) error { 588 return nil 589 }, 590 }, nil 591 }), 592 } 593 host := newPluginHost(t, loaders) 594 595 r, err := NewRegistry(host, olds, true, nil) 596 assert.NoError(t, err) 597 assert.NotNil(t, r) 598 599 assert.Equal(t, len(olds), len(r.providers)) 600 601 for _, old := range olds { 602 ref, err := NewReference(old.URN, old.ID) 603 assert.NoError(t, err) 604 605 p, ok := r.GetProvider(ref) 606 assert.True(t, ok) 607 assert.NotNil(t, p) 608 609 assert.Equal(t, GetProviderPackage(old.Type), p.Pkg()) 610 } 611 612 // Create a new provider for each package. 613 for _, l := range loaders { 614 typ := MakeProviderType(l.pkg) 615 urn := resource.NewURN("test", "test", "", typ, "b") 616 olds, news := resource.PropertyMap{}, resource.PropertyMap{} 617 618 // Check 619 inputs, failures, err := r.Check(urn, olds, news, false, nil) 620 assert.NoError(t, err) 621 assert.Equal(t, news, inputs) 622 assert.Empty(t, failures) 623 624 // The provider should not be configured: configuration will occur during the previewed Create. 625 p, ok := r.GetProvider(Reference{urn: urn, id: UnknownID}) 626 assert.True(t, ok) 627 assert.False(t, p.(*testProvider).configured) 628 } 629 630 // Update the existing provider for the first entry in olds. 631 { 632 urn, id := olds[0].URN, olds[0].ID 633 olds, news := olds[0].Inputs, olds[0].Inputs 634 635 // Fetch the old provider instance. 636 old, ok := r.GetProvider(Reference{urn: urn, id: id}) 637 assert.True(t, ok) 638 639 // Check 640 inputs, failures, err := r.Check(urn, olds, news, false, nil) 641 assert.NoError(t, err) 642 assert.Equal(t, news, inputs) 643 assert.Empty(t, failures) 644 645 // The provider should remain unconfigured. 646 p, ok := r.GetProvider(Reference{urn: urn, id: UnknownID}) 647 assert.True(t, ok) 648 assert.False(t, p == old) 649 assert.False(t, p.(*testProvider).configured) 650 651 // Diff 652 diff, err := r.Diff(urn, id, olds, news, false, nil) 653 assert.NoError(t, err) 654 assert.Equal(t, plugin.DiffResult{Changes: plugin.DiffNone}, diff) 655 656 // The original provider should be used because the config did not change. 657 p2, ok := r.GetProvider(Reference{urn: urn, id: id}) 658 assert.True(t, ok) 659 assert.True(t, p2 == old) 660 assert.False(t, p2 == p) 661 } 662 663 // Replace the existing provider for the last entry in olds. 664 { 665 urn, id := olds[len(olds)-1].URN, olds[len(olds)-1].ID 666 olds, news := olds[len(olds)-1].Inputs, olds[len(olds)-1].Inputs 667 668 // Fetch the old provider instance. 669 old, ok := r.GetProvider(Reference{urn: urn, id: id}) 670 assert.True(t, ok) 671 672 // Check 673 inputs, failures, err := r.Check(urn, olds, news, false, nil) 674 assert.NoError(t, err) 675 assert.Equal(t, news, inputs) 676 assert.Empty(t, failures) 677 678 // The provider should remain unconfigured. 679 p, ok := r.GetProvider(Reference{urn: urn, id: UnknownID}) 680 assert.True(t, ok) 681 assert.False(t, p == old) 682 assert.False(t, p.(*testProvider).configured) 683 684 // Diff 685 diff, err := r.Diff(urn, id, olds, news, false, nil) 686 assert.NoError(t, err) 687 assert.True(t, diff.Replace()) 688 689 // The new provider should be not be registered; the registered provider should still be the original. 690 p2, ok := r.GetProvider(Reference{urn: urn, id: id}) 691 assert.True(t, ok) 692 assert.True(t, p2 == old) 693 assert.False(t, p2 == p) 694 } 695 } 696 697 func TestCRUDNoProviders(t *testing.T) { 698 t.Parallel() 699 700 host := newPluginHost(t, []*providerLoader{}) 701 702 r, err := NewRegistry(host, []*resource.State{}, false, nil) 703 assert.NoError(t, err) 704 assert.NotNil(t, r) 705 706 typ := MakeProviderType("pkgA") 707 urn := resource.NewURN("test", "test", "", typ, "b") 708 olds, news := resource.PropertyMap{}, resource.PropertyMap{} 709 710 // Check 711 inputs, failures, err := r.Check(urn, olds, news, false, nil) 712 assert.Error(t, err) 713 assert.Empty(t, failures) 714 assert.Nil(t, inputs) 715 } 716 717 func TestCRUDWrongPackage(t *testing.T) { 718 t.Parallel() 719 720 loaders := []*providerLoader{ 721 newSimpleLoader(t, "pkgB", "", nil), 722 } 723 host := newPluginHost(t, loaders) 724 725 r, err := NewRegistry(host, []*resource.State{}, false, nil) 726 assert.NoError(t, err) 727 assert.NotNil(t, r) 728 729 typ := MakeProviderType("pkgA") 730 urn := resource.NewURN("test", "test", "", typ, "b") 731 olds, news := resource.PropertyMap{}, resource.PropertyMap{} 732 733 // Check 734 inputs, failures, err := r.Check(urn, olds, news, false, nil) 735 assert.Error(t, err) 736 assert.Empty(t, failures) 737 assert.Nil(t, inputs) 738 } 739 740 func TestCRUDWrongVersion(t *testing.T) { 741 t.Parallel() 742 743 loaders := []*providerLoader{ 744 newSimpleLoader(t, "pkgA", "0.5.0", nil), 745 } 746 host := newPluginHost(t, loaders) 747 748 r, err := NewRegistry(host, []*resource.State{}, false, nil) 749 assert.NoError(t, err) 750 assert.NotNil(t, r) 751 752 typ := MakeProviderType("pkgA") 753 urn := resource.NewURN("test", "test", "", typ, "b") 754 olds, news := resource.PropertyMap{}, resource.PropertyMap{"version": resource.NewStringProperty("1.0.0")} 755 756 // Check 757 inputs, failures, err := r.Check(urn, olds, news, false, nil) 758 assert.Error(t, err) 759 assert.Empty(t, failures) 760 assert.Nil(t, inputs) 761 } 762 763 func TestCRUDBadVersionNotString(t *testing.T) { 764 t.Parallel() 765 766 loaders := []*providerLoader{ 767 newSimpleLoader(t, "pkgA", "1.0.0", nil), 768 } 769 host := newPluginHost(t, loaders) 770 771 r, err := NewRegistry(host, []*resource.State{}, false, nil) 772 assert.NoError(t, err) 773 assert.NotNil(t, r) 774 775 typ := MakeProviderType("pkgA") 776 urn := resource.NewURN("test", "test", "", typ, "b") 777 olds, news := resource.PropertyMap{}, resource.PropertyMap{"version": resource.NewBoolProperty(true)} 778 779 // Check 780 inputs, failures, err := r.Check(urn, olds, news, false, nil) 781 assert.NoError(t, err) 782 assert.Len(t, failures, 1) 783 assert.Equal(t, "version", string(failures[0].Property)) 784 assert.Nil(t, inputs) 785 } 786 787 func TestCRUDBadVersion(t *testing.T) { 788 t.Parallel() 789 790 loaders := []*providerLoader{ 791 newSimpleLoader(t, "pkgA", "1.0.0", nil), 792 } 793 host := newPluginHost(t, loaders) 794 795 r, err := NewRegistry(host, []*resource.State{}, false, nil) 796 assert.NoError(t, err) 797 assert.NotNil(t, r) 798 799 typ := MakeProviderType("pkgA") 800 urn := resource.NewURN("test", "test", "", typ, "b") 801 olds, news := resource.PropertyMap{}, resource.PropertyMap{"version": resource.NewStringProperty("foo")} 802 803 // Check 804 inputs, failures, err := r.Check(urn, olds, news, false, nil) 805 assert.NoError(t, err) 806 assert.Len(t, failures, 1) 807 assert.Equal(t, "version", string(failures[0].Property)) 808 assert.Nil(t, inputs) 809 }