Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions pkg/internal/tests/cross-tests/upgrade_state_check_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ type upgradeStateTestCase struct {
// would always pick the provider version recorded in the state to perform operations against. So these checks
// are possibly moot, but might be useful in the future if Pulumi behavior around refresh changes.
ExperimentalPulumiRefresh bool

// Do not auto-generate an Update function to test resources that do not support Update.
DoesNotSupportUpdate bool
}

type upgradeStateTestPhase string
Expand Down Expand Up @@ -164,6 +167,15 @@ func instrumentCustomizeDiff(t *testing.T, tc upgradeStateTestCase) upgradeState
}

func instrumentUpdate(t *testing.T, tc upgradeStateTestCase) upgradeStateTestCase {
if tc.DoesNotSupportUpdate {
r1 := *tc.Resource1
require.Nilf(t, r1.UpdateContext, "Resource1.UpdateContext is not compatible with DoesNotSupportUpdate")
r2 := *tc.Resource2
require.Nilf(t, r2.UpdateContext, "Resource2.UpdateContext is not compatible with DoesNotSupportUpdate")

return tc
}

r2 := *tc.Resource2
require.Nilf(t, r2.UpdateContext, "Resource2.UpdateContext cannot yet be set in tests")

Expand Down Expand Up @@ -388,15 +400,17 @@ func runUpgradeStateTestTF(t T, tc upgradeStateTestCase) []upgradeStateTrace {
tracker.phase = previewPhase
plan, err := tfd2.writePlanErr(t, tc.Resource2.Schema, defRtype, rname, inputs2, lifecycleArgs{})
if tc.ExpectFailure {
require.Errorf(t, err, "refresh should have failed")
require.Errorf(t, err, "plan should have failed")
return tracker.trace
}
require.NoErrorf(t, err, "refresh should not have failed")
require.NoErrorf(t, err, "plan should not have failed")
t.Logf("plan.StdOut: %s", plan.StdOut)

t.Logf("#### apply (similar to update)")
tracker.phase = updatePhase
err = tfd2.driver.ApplyPlan(t, plan)
applyStdout, err := tfd2.driver.ApplyPlanReturnStdOut(t, plan)
require.NoError(t, err)
t.Logf("applyStdout: %s", string(applyStdout))

return tracker.trace
}
Expand Down
65 changes: 65 additions & 0 deletions pkg/internal/tests/cross-tests/upgrade_state_cross_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1065,3 +1065,68 @@
autogold.Expect([]upgradeStateTrace{}).Equal(t, result.pulumiUpgrades)
})
}

// See https://github.com/pulumi/pulumi-gcp/issues/3236
func TestUpgrade_FieldsAddedButUpdateNotSupported(t *testing.T) {
t.Parallel()
skipUnlessLinux(t)
//skipUnlessDeltasEnabled(t)

Check failure on line 1073 in pkg/internal/tests/cross-tests/upgrade_state_cross_test.go

View workflow job for this annotation

GitHub Actions / Test and Lint / lint

File is not properly formatted (gofumpt)

sch1 := map[string]*schema.Schema{
"name": {
Required: true,
ForceNew: true,
Type: schema.TypeString,
},
}

sch2 := map[string]*schema.Schema{
"name": {
Required: true,
ForceNew: true,
Type: schema.TypeString,
},
"as_paths": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"as_lists": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeInt,
},
},
"path_segment_type": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
}

res1 := &schema.Resource{Schema: sch1}
res2 := &schema.Resource{Schema: sch2}

configVal := func() map[string]any {
return map[string]any{
"name": "resource-1",
}
}

t.Run("same", func(t *testing.T) {
result := runUpgradeStateTest(t, upgradeStateTestCase{
Resource1: res1,
Resource2: res2,
Inputs1: configVal(),
Inputs2: configVal(),

DoesNotSupportUpdate: true,
SkipSchemaVersionAfterUpdateCheck: true,
})

autogold.Expect((*map[string]int)(nil)).Equal(t, result.pulumiUpResult.Summary.ResourceChanges)
})
}
26 changes: 13 additions & 13 deletions pkg/internal/tests/pulcheck/pulcheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2"
)

func propNeedsUpdate(prop *schema.Schema) bool {

Check failure on line 33 in pkg/internal/tests/pulcheck/pulcheck.go

View workflow job for this annotation

GitHub Actions / Test and Lint / lint

func propNeedsUpdate is unused (unused)
if prop.Computed && !prop.Optional {
return false
}
Expand All @@ -42,7 +42,7 @@

// resourceNeedsUpdate returns true if the TF SDK schema validation would consider the
// resource to need an update method.
func resourceNeedsUpdate(res *schema.Resource) bool {

Check failure on line 45 in pkg/internal/tests/pulcheck/pulcheck.go

View workflow job for this annotation

GitHub Actions / Test and Lint / lint

func resourceNeedsUpdate is unused (unused)
// If any of the properties need an update, then the resource needs an update.
for _, s := range res.Schema {
if propNeedsUpdate(s) {
Expand Down Expand Up @@ -99,12 +99,12 @@
// This is necessary to work around a bug in the TF SDK schema validation where some resources which
// do need an Update method will instead be flagged as not needing an Update method.
// See https://github.com/pulumi/pulumi-terraform-bridge/pull/2723#issuecomment-2541518646
if !resourceNeedsUpdate(r) {
r.Schema["update_prop"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
}
}
// if !resourceNeedsUpdate(r) {
// r.Schema["update_prop"] = &schema.Schema{
// Type: schema.TypeString,
// Optional: true,
// }
// }

if r.ReadContext == nil {
r.ReadContext = func(_ context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
Expand All @@ -130,13 +130,13 @@

// Because of the no-op update_prop property added above, all resources will now
// need an Update method.
if r.UpdateContext == nil {
r.UpdateContext = func(
ctx context.Context, rd *schema.ResourceData, i interface{},
) diag.Diagnostics {
return diag.Diagnostics{}
}
}
// if r.UpdateContext == nil {
// r.UpdateContext = func(
// ctx context.Context, rd *schema.ResourceData, i interface{},
// ) diag.Diagnostics {
// return diag.Diagnostics{}
// }
// }
}
require.NoError(t, tfp.InternalValidate())

Expand Down
14 changes: 9 additions & 5 deletions pkg/tests/tfcheck/tfcheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,11 @@ func (d *TFDriver) Write(t pulcheck.T, program string) {
require.NoErrorf(t, err, "writing test.tf")
}

// Plans an operation. This sets -refresh=false which is not the default behavior in Terraform but it better matches
// Plans an operation. This sets which is not the default behavior in Terraform but it better matches
// the target behavior that bridged providers currently emulate.
func (d *TFDriver) Plan(t pulcheck.T) (*TFPlan, error) {
planFile := filepath.Join(d.cwd, "test.tfplan")
planStdoutBytes, err := d.execTf(t, "plan", "-refresh=false", "-out", planFile, "-no-color")
planStdoutBytes, err := d.execTf(t, "plan", "-out", planFile, "-no-color")
if err != nil {
return nil, err
}
Expand All @@ -152,20 +152,24 @@ func (d *TFDriver) Plan(t pulcheck.T) (*TFPlan, error) {
return &tp, nil
}

// Executes apply. This sets -refresh=false which is not the default behavior in Terraform but it better matches the
// Executes apply. This sets which is not the default behavior in Terraform but it better matches the
// target behavior that bridged providers currently emulate. Unlike [ApplyPlan] this operation will recompute the plan
// on the fly.
func (d *TFDriver) Apply(t pulcheck.T) error {
_, err := d.execTf(t, "apply", "-auto-approve", "-refresh=false")
_, err := d.execTf(t, "apply", "-auto-approve")
return err
}

// Apply a given plan.
func (d *TFDriver) ApplyPlan(t pulcheck.T, plan *TFPlan) error {
_, err := d.execTf(t, "apply", "-auto-approve", "-refresh=false", plan.PlanFile)
_, err := d.execTf(t, "apply", "-auto-approve", plan.PlanFile)
return err
}

func (d *TFDriver) ApplyPlanReturnStdOut(t pulcheck.T, plan *TFPlan) ([]byte, error) {
return d.execTf(t, "apply", "-auto-approve", plan.PlanFile)
}

func (d *TFDriver) Refresh(t pulcheck.T) error {
_, err := d.execTf(t, "refresh")
return err
Expand Down
7 changes: 4 additions & 3 deletions pkg/tfgen/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ func getRepoPath(gitHost string, org string, provider string, version string) (_
command.Dir = curWd
output, err := command.CombinedOutput()
if err != nil {
msg := "error running 'go mod download -json' in %q dir for module: %w\n\nOutput: %s"
return "", fmt.Errorf(msg, curWd, err, output)
msg := "error running 'go mod download -json %q' in %q dir for module: %w\n\nOutput: %s"
return "", fmt.Errorf(msg, moduleCoordinates, curWd, err, output)
}

target := struct {
Expand All @@ -170,7 +170,8 @@ func getRepoPath(gitHost string, org string, provider string, version string) (_
}{}

if err := json.Unmarshal(output, &target); err != nil {
return "", fmt.Errorf("error parsing output of 'go mod download -json' for module: %w", err)
return "", fmt.Errorf("error parsing output of 'go mod download -json %q' for module: %w",
moduleCoordinates, err)
}

if target.Error != "" {
Expand Down
Loading