// Copyright 2016-2023, Pulumi Corporation. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package deploy import ( "context" "errors" "fmt" "testing" "github.com/blang/semver" "github.com/pulumi/pulumi/pkg/v3/resource/deploy/deploytest" "github.com/pulumi/pulumi/pkg/v3/resource/deploy/providers" "github.com/pulumi/pulumi/sdk/v3/go/common/resource" "github.com/pulumi/pulumi/sdk/v3/go/common/resource/config" "github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin" "github.com/pulumi/pulumi/sdk/v3/go/common/tokens" "github.com/stretchr/testify/assert" ) func TestImportDeployment(t *testing.T) { t.Parallel() t.Run("NewImportDeployment", func(t *testing.T) { t.Parallel() t.Run("error in migrate providers", func(t *testing.T) { t.Parallel() var decrypterCalled bool _, err := NewImportDeployment(&plugin.Context{}, &Target{ Snapshot: &Snapshot{ Resources: []*resource.State{ { URN: "urn:pulumi:stack::project::type::oldName", Custom: true, }, }, }, Name: tokens.MustParseStackName("target-name"), Config: config.Map{ config.MustMakeKey("", "secret"): config.NewSecureValue("secret"), }, Decrypter: &decrypterMock{ DecryptValueF: func(ctx context.Context, ciphertext string) (string, error) { decrypterCalled = true return "", fmt.Errorf("expected fail") }, }, }, "projectName", nil, true) assert.ErrorContains(t, err, "could not fetch configuration for default provider") assert.True(t, decrypterCalled) }) }) } func TestImporter(t *testing.T) { t.Parallel() t.Run("registerProviders", func(t *testing.T) { t.Parallel() t.Run("incorrect package type specified", func(t *testing.T) { t.Parallel() i := &importer{ deployment: &Deployment{ imports: []Import{ { Type: "::", }, }, target: &Target{ Name: tokens.MustParseStackName("stack-name"), }, source: &nullSource{ project: "project-name", }, }, } _, _, err := i.registerProviders(context.Background()) assert.ErrorContains(t, err, "incorrect package type specified") }) t.Run("ensure provider is called correctly", func(t *testing.T) { t.Parallel() version := semver.MustParse("1.0.0") expectedErr := errors.New("expected error") i := &importer{ deployment: &Deployment{ goals: &goalMap{}, ctx: &plugin.Context{Diag: &deploytest.NoopSink{}}, target: &Target{ Name: tokens.MustParseStackName("stack-name"), }, source: &nullSource{}, providers: providers.NewRegistry(&mockHost{ ProviderF: func(pkg tokens.Package, version *semver.Version) (plugin.Provider, error) { assert.Equal(t, tokens.Package("foo"), pkg) assert.Equal(t, "1.0.0", version.String()) return nil, expectedErr }, }, true, nil), imports: []Import{ { Version: &version, PluginDownloadURL: "download-url", PluginChecksums: map[string][]byte{ "a": {}, "b": {}, "c": {}, }, Type: "foo:bar:Bar", }, }, }, } _, _, err := i.registerProviders(context.Background()) assert.ErrorIs(t, err, expectedErr) }) }) t.Run("importResources", func(t *testing.T) { t.Parallel() t.Run("registerExistingResources", func(t *testing.T) { t.Parallel() t.Run("ok", func(t *testing.T) { t.Parallel() ctx, cancel := context.WithCancel(context.Background()) cancel() i := &importer{ executor: &stepExecutor{ ctx: ctx, }, deployment: &Deployment{ prev: &Snapshot{ Resources: []*resource.State{ { URN: "some-urn", }, }, }, goals: &goalMap{}, source: &nullSource{}, target: &Target{}, imports: []Import{ {}, }, }, } assert.NoError(t, i.importResources(ctx)) }) }) t.Run("getOrCreateStackResource", func(t *testing.T) { t.Parallel() t.Run("ok", func(t *testing.T) { t.Parallel() ctx, cancel := context.WithCancel(context.Background()) cancel() i := &importer{ executor: &stepExecutor{ ctx: ctx, }, deployment: &Deployment{ source: &nullSource{}, target: &Target{ Name: tokens.MustParseStackName("stack-name"), }, imports: []Import{ {}, }, }, } assert.NoError(t, i.importResources(ctx)) }) t.Run("ignore existing delete resources", func(t *testing.T) { t.Parallel() ctx, cancel := context.WithCancel(context.Background()) cancel() i := &importer{ executor: &stepExecutor{ ctx: ctx, }, deployment: &Deployment{ prev: &Snapshot{ Resources: []*resource.State{ { Delete: true, }, }, }, // goals is left nil as nothing should be added to it. goals: nil, source: &nullSource{}, target: &Target{ Name: tokens.MustParseStackName("stack-name"), }, imports: []Import{ {}, }, }, } assert.NoError(t, i.importResources(ctx)) }) }) }) }