When a resource fails to initialize (i.e., it is successfully created, but fails to transition to a fully-initialized state), and a user subsequently runs `pulumi update` without changing that resource, our CLI will fail to warn the user that this resource is not initialized. This commit begins the process of allowing our CLI to report this by storing a list of initialization errors in the checkpoint.
86 lines
3.3 KiB
Go
86 lines
3.3 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))
|
|
assert.Equal(t, []string{"state can't be 4"}, a.InitErrors)
|
|
},
|
|
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))
|
|
assert.Nil(t, nil)
|
|
},
|
|
},
|
|
{
|
|
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))
|
|
assert.Equal(t, []string{"state can't be 4"}, a.InitErrors)
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|