This commit adds CLI support for resource providers to provide partial state upon failure. For resource providers that model resource operations across multiple API calls, the Provider RPC interface can now accomodate saving bags of state for resource operations that failed. This is a common pattern for Terraform-backed providers that try to do post-creation steps on resource as part of Create or Update resource operations.
82 lines
3.2 KiB
Go
82 lines
3.2 KiB
Go
// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
|
|
|
|
package ints
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/pulumi/pulumi/pkg/resource"
|
|
"github.com/pulumi/pulumi/pkg/testing/integration"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// TestPartialState tests that the engine persists partial state of a resource if a provider
|
|
// provides partial state alongside a resource creation or update error.
|
|
//
|
|
// The setup of this test uses a dynamic provider that will partially fail if a resource's state
|
|
// value is the number 4.
|
|
func TestPartialState(t *testing.T) {
|
|
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
|
Dir: "step1",
|
|
Dependencies: []string{"@pulumi/pulumi"},
|
|
Quick: true,
|
|
ExpectFailure: true,
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
// The first update tries to create a resource with state 4. This fails partially.
|
|
assert.NotNil(t, stackInfo.Deployment)
|
|
assert.Equal(t, 2, len(stackInfo.Deployment.Resources))
|
|
stackRes := stackInfo.Deployment.Resources[0]
|
|
assert.Equal(t, resource.RootStackType, stackRes.URN.Type())
|
|
a := stackInfo.Deployment.Resources[1]
|
|
|
|
// We should still have persisted the resource and its outputs to the snapshot.
|
|
assert.Equal(t, "doomed", string(a.URN.Name()))
|
|
assert.Equal(t, 4.0, a.Outputs["state"].(float64))
|
|
},
|
|
EditDirs: []integration.EditDir{
|
|
{
|
|
Dir: "step2",
|
|
Additive: true,
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
// The next update deletes the resource. We should successfully delete it.
|
|
assert.NotNil(t, stackInfo.Deployment)
|
|
assert.Equal(t, 1, len(stackInfo.Deployment.Resources))
|
|
stackRes := stackInfo.Deployment.Resources[0]
|
|
assert.Equal(t, resource.RootStackType, stackRes.URN.Type())
|
|
},
|
|
},
|
|
{
|
|
Dir: "step3",
|
|
Additive: true,
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
// Step 3 creates a resource with state 5, which succeeds.
|
|
assert.NotNil(t, stackInfo.Deployment)
|
|
assert.Equal(t, 2, len(stackInfo.Deployment.Resources))
|
|
stackRes := stackInfo.Deployment.Resources[0]
|
|
assert.Equal(t, resource.RootStackType, stackRes.URN.Type())
|
|
a := stackInfo.Deployment.Resources[1]
|
|
assert.Equal(t, "not-doomed", string(a.URN.Name()))
|
|
assert.Equal(t, 5.0, a.Outputs["state"].(float64))
|
|
},
|
|
},
|
|
{
|
|
Dir: "step4",
|
|
Additive: true,
|
|
ExpectFailure: true,
|
|
ExtraRuntimeValidation: func(t *testing.T, stackInfo integration.RuntimeValidationStackInfo) {
|
|
// Step 4 updates the resource to have state 4, which fails partially.
|
|
assert.NotNil(t, stackInfo.Deployment)
|
|
assert.Equal(t, 2, len(stackInfo.Deployment.Resources))
|
|
stackRes := stackInfo.Deployment.Resources[0]
|
|
assert.Equal(t, resource.RootStackType, stackRes.URN.Type())
|
|
a := stackInfo.Deployment.Resources[1]
|
|
|
|
// We should have persisted the updated resource's new outputs
|
|
// to the snapshot.
|
|
assert.Equal(t, "not-doomed", string(a.URN.Name()))
|
|
assert.Equal(t, 4.0, a.Outputs["state"].(float64))
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|