diff --git a/previewProviderUpgrade.go b/previewProviderUpgrade.go index 88bf16b..ff50ead 100644 --- a/previewProviderUpgrade.go +++ b/previewProviderUpgrade.go @@ -32,12 +32,23 @@ func PreviewProviderUpgrade(pulumiTest *pulumitest.PulumiTest, providerName stri test.T().Logf("writing grpc log to %s", grpcLogPath) grptLog.WriteTo(grpcLogPath) }, - optrun.WithOpts(opttest.NewStackOptions(optnewstack.EnableAutoDestroy())), optrun.WithCache(filepath.Join(cacheDir, "stack.json")), - optrun.WithOpts(options.BaselineOpts...)) + optrun.WithOpts( + opttest.NewStackOptions(optnewstack.EnableAutoDestroy()), + baselineProviderOpt(options, providerName, baselineVersion)), + optrun.WithOpts(options.BaselineOpts...), + ) return previewTest.Preview() } +func baselineProviderOpt(options optproviderupgrade.PreviewProviderUpgradeOptions, providerName string, baselineVersion string) opttest.Option { + if options.DisableAttach { + return opttest.DownloadProviderVersion(providerName, baselineVersion) + } else { + return opttest.AttachDownloadedPlugin(providerName, baselineVersion) + } +} + func getCacheDir(options optproviderupgrade.PreviewProviderUpgradeOptions, programName string, baselineVersion string) string { var cacheDir string for _, pathTemplateElement := range options.CacheDirTemplate { diff --git a/providers/providerInterceptProxy.go b/providers/providerInterceptProxy.go index 85e7a28..c53687b 100644 --- a/providers/providerInterceptProxy.go +++ b/providers/providerInterceptProxy.go @@ -57,7 +57,8 @@ func NewProviderInterceptProxy(ctx context.Context, downstreamProviderPort Port, fmt.Sprintf("127.0.0.1:%d", downstreamProviderPort), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithUnaryInterceptor(rpcutil.OpenTracingClientInterceptor()), - grpc.WithStreamInterceptor(rpcutil.OpenTracingStreamClientInterceptor())) + grpc.WithStreamInterceptor(rpcutil.OpenTracingStreamClientInterceptor()), + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(1024*1024*400))) if err != nil { return nil, err } diff --git a/providers/providerInterceptProxy_test.go b/providers/providerInterceptProxy_test.go index 0efddb9..be42746 100644 --- a/providers/providerInterceptProxy_test.go +++ b/providers/providerInterceptProxy_test.go @@ -10,6 +10,7 @@ import ( "github.com/pulumi/providertest/pulumitest/opttest" pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "google.golang.org/protobuf/types/known/emptypb" ) @@ -17,26 +18,29 @@ func TestProviderInterceptProxy(t *testing.T) { t.Parallel() ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) - var didAttach, didForward bool - mockFactory := providers.ProviderMockFactory(ctx, providers.ProviderMocks{ - Attach: func(ctx context.Context, in *pulumirpc.PluginAttach) (*emptypb.Empty, error) { - didForward = true - return &emptypb.Empty{}, nil - }, - Create: func(ctx context.Context, in *pulumirpc.CreateRequest) (*pulumirpc.CreateResponse, error) { - // Return without error to indicate success. - return &pulumirpc.CreateResponse{}, nil - }, - }) - interceptedFactory := providers.ProviderInterceptFactory(ctx, mockFactory, providers.ProviderInterceptors{ + var didAttach bool + // Ensure plugin is downloaded so YAML can look up its schema + _, err := providers.DownloadPluginBinary("azure-native", "2.10.0") + require.NoError(t, err) + + interceptedFactory := providers.ProviderInterceptFactory(ctx, providers.DownloadPluginBinaryFactory("azure-native", "2.10.0"), providers.ProviderInterceptors{ Attach: func(ctx context.Context, in *pulumirpc.PluginAttach, client pulumirpc.ResourceProviderClient) (*emptypb.Empty, error) { didAttach = true return client.Attach(ctx, in) }, + Configure: func(ctx context.Context, in *pulumirpc.ConfigureRequest, client pulumirpc.ResourceProviderClient) (*pulumirpc.ConfigureResponse, error) { + // Skip checking the real configuration + return &pulumirpc.ConfigureResponse{}, nil + }, + Check: func(ctx context.Context, in *pulumirpc.CheckRequest, client pulumirpc.ResourceProviderClient) (*pulumirpc.CheckResponse, error) { + // Skip checking the real configuration + return &pulumirpc.CheckResponse{Inputs: in.News}, nil + }, }) - test := pulumitest.NewPulumiTest(t, filepath.Join("..", "pulumitest", "testdata", "yaml_program"), opttest.AttachProvider("random", interceptedFactory)) + test := pulumitest.NewPulumiTest(t, + filepath.Join("..", "pulumitest", "testdata", "yaml_azure"), + opttest.AttachProvider("azure-native", interceptedFactory)) test.Preview() assert.True(t, didAttach, "expected Attach to be called in proxy") - assert.True(t, didForward, "expected Attach to be called in downstream provider") } diff --git a/providers/providerMock.go b/providers/providerMock.go index adedd9a..f00dc51 100644 --- a/providers/providerMock.go +++ b/providers/providerMock.go @@ -36,14 +36,14 @@ type ProviderMocks struct { } // ProviderInterceptFactory creates a new provider factory that can be used to intercept calls to a downstream provider. -func ProviderMockFactory(ctx context.Context, mocks ProviderMocks) ProviderFactory { +func ProviderMockFactory(mocks ProviderMocks) ProviderFactory { return ResourceProviderFactory(func() (rpc.ResourceProviderServer, error) { - return NewProviderMock(ctx, mocks) + return NewProviderMock(mocks) }) } // NewProviderMock creates a new provider proxy that can be used to intercept calls to a downstream provider. -func NewProviderMock(ctx context.Context, mocks ProviderMocks) (rpc.ResourceProviderServer, error) { +func NewProviderMock(mocks ProviderMocks) (rpc.ResourceProviderServer, error) { return &providerMock{ mocks: mocks, }, nil @@ -92,12 +92,7 @@ func (i *providerMock) Configure(ctx context.Context, in *rpc.ConfigureRequest) if i.mocks.Configure != nil { return i.mocks.Configure(ctx, in) } - return &rpc.ConfigureResponse{ - AcceptSecrets: true, - SupportsPreview: true, - AcceptResources: true, - AcceptOutputs: true, - }, nil + return &rpc.ConfigureResponse{}, nil } func (i *providerMock) Construct(ctx context.Context, in *rpc.ConstructRequest) (*rpc.ConstructResponse, error) { diff --git a/providers/providerMock_test.go b/providers/providerMock_test.go new file mode 100644 index 0000000..6172f91 --- /dev/null +++ b/providers/providerMock_test.go @@ -0,0 +1,71 @@ +package providers_test + +import ( + "context" + "path/filepath" + "testing" + + "github.com/pulumi/providertest/providers" + "github.com/pulumi/providertest/pulumitest" + "github.com/pulumi/providertest/pulumitest/opttest" + pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" + "github.com/stretchr/testify/assert" + "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/structpb" +) + +func TestProviderMock(t *testing.T) { + t.Parallel() + source := filepath.Join("..", "pulumitest", "testdata", "python_gcp") + + t.Run("defaults", func(t *testing.T) { + test := pulumitest.NewPulumiTest(t, source, + opttest.AttachProvider("gcp", + providers.ProviderMockFactory(providers.ProviderMocks{}))) + test.Preview() + }) + + t.Run("with mocks", func(t *testing.T) { + var attached, configured, checkedConfig, checked, created bool + test := pulumitest.NewPulumiTest(t, source, + opttest.AttachProvider("gcp", + providers.ProviderMockFactory(providers.ProviderMocks{ + Attach: func(ctx context.Context, in *pulumirpc.PluginAttach) (*emptypb.Empty, error) { + attached = true + return &emptypb.Empty{}, nil + }, + Configure: func(ctx context.Context, in *pulumirpc.ConfigureRequest) (*pulumirpc.ConfigureResponse, error) { + configured = true + return &pulumirpc.ConfigureResponse{}, nil + }, + CheckConfig: func(ctx context.Context, in *pulumirpc.CheckRequest) (*pulumirpc.CheckResponse, error) { + checkedConfig = true + return &pulumirpc.CheckResponse{}, nil + }, + Check: func(ctx context.Context, in *pulumirpc.CheckRequest) (*pulumirpc.CheckResponse, error) { + checked = true + return &pulumirpc.CheckResponse{Inputs: in.News}, nil + }, + Create: func(ctx context.Context, in *pulumirpc.CreateRequest) (*pulumirpc.CreateResponse, error) { + created = true + return &pulumirpc.CreateResponse{Id: "fake-id", Properties: &structpb.Struct{ + Fields: map[string]*structpb.Value{ + "url": { + Kind: &structpb.Value_StringValue{StringValue: "fake-url"}, + }, + }, + }}, nil + }, + Delete: func(ctx context.Context, in *pulumirpc.DeleteRequest) (*emptypb.Empty, error) { + return &emptypb.Empty{}, nil + }, + }))) + test.Preview() + test.Up() + assert.True(t, attached, "expected Attach to be called in mock") + assert.True(t, configured, "expected Configure to be called in mock") + assert.True(t, checkedConfig, "expected CheckConfig to be called in mock") + assert.True(t, checked, "expected Check to be called in mock") + assert.True(t, created, "expected Create to be called in mock") + }) +} diff --git a/pulumitest/testdata/python_gcp/.gitignore b/pulumitest/testdata/python_gcp/.gitignore new file mode 100644 index 0000000..b664ab4 --- /dev/null +++ b/pulumitest/testdata/python_gcp/.gitignore @@ -0,0 +1,2 @@ +*.pyc +venv/ \ No newline at end of file diff --git a/pulumitest/testdata/python_gcp/Pulumi.yaml b/pulumitest/testdata/python_gcp/Pulumi.yaml new file mode 100644 index 0000000..e59269c --- /dev/null +++ b/pulumitest/testdata/python_gcp/Pulumi.yaml @@ -0,0 +1,3 @@ +name: yaml_gcp +runtime: python +description: A minimal Google Cloud Pulumi YAML program diff --git a/pulumitest/testdata/python_gcp/__main__.py b/pulumitest/testdata/python_gcp/__main__.py new file mode 100644 index 0000000..2522f51 --- /dev/null +++ b/pulumitest/testdata/python_gcp/__main__.py @@ -0,0 +1,6 @@ +import pulumi +import pulumi_gcp as gcp + +provider = gcp.Provider("provider") +my_bucket = gcp.storage.Bucket("my-bucket", location="US") +pulumi.export("bucketName", my_bucket.url) diff --git a/pulumitest/testdata/python_gcp/requirements.txt b/pulumitest/testdata/python_gcp/requirements.txt new file mode 100644 index 0000000..7c64591 --- /dev/null +++ b/pulumitest/testdata/python_gcp/requirements.txt @@ -0,0 +1,2 @@ +pulumi>=3.0.0,<4.0.0 +pulumi-gcp==7.6.0 diff --git a/replay/replay_test.go b/replay/replay_test.go index bf138ec..5b9a99b 100644 --- a/replay/replay_test.go +++ b/replay/replay_test.go @@ -22,7 +22,7 @@ func TestReplayNormalizesCheckFailureOrder(t *testing.T) { {Property: "A", Reason: "A-failed"}, } - p, err := providers.NewProviderMock(context.Background(), providers.ProviderMocks{ + p, err := providers.NewProviderMock(providers.ProviderMocks{ CheckConfig: func(ctx context.Context, in *pulumirpc.CheckRequest) (*pulumirpc.CheckResponse, error) { return &pulumirpc.CheckResponse{Failures: failures}, nil }, @@ -124,7 +124,7 @@ func TestReplayNormalizesCheckFailureOrder(t *testing.T) { } func TestMatchingErrors(t *testing.T) { - p, err := providers.NewProviderMock(context.Background(), providers.ProviderMocks{ + p, err := providers.NewProviderMock(providers.ProviderMocks{ Check: func(ctx context.Context, in *pulumirpc.CheckRequest) (*pulumirpc.CheckResponse, error) { return &pulumirpc.CheckResponse{}, fmt.Errorf("An error has occurred") },