@@ -2,17 +2,66 @@ package crosstests
22
33import (
44 "context"
5+ "encoding/json"
56 "fmt"
7+ "os"
8+ "path/filepath"
9+ "strconv"
610
11+ "github.com/hashicorp/terraform-plugin-go/tftypes"
712 "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
813 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tests/internal/pulcheck"
9- "github.com/stretchr/testify/assert "
14+ "github.com/pulumi/pulumi/sdk/v3/go/common/apitype "
1015 "github.com/stretchr/testify/require"
16+ "gotest.tools/v3/assert"
1117)
1218
13- func runPulumiUpgrade (t T , res1 , res2 * schema.Resource , config any ) {
14- prov1 := pulcheck .BridgedProvider (t , defProviderShortName , map [string ]* schema.Resource {defRtype : res1 })
15- prov2 := pulcheck .BridgedProvider (t , defProviderShortName , map [string ]* schema.Resource {defRtype : res2 })
19+ type upgradeStateTestCase struct {
20+ // Schema for the resource under test
21+ Resource * schema.Resource
22+
23+ Config1 any
24+ Config2 any
25+ ExpectEqual bool
26+ ObjectType * tftypes.Object
27+
28+ DisablePlanResourceChange bool
29+ }
30+
31+ func getVersionInState (t T , stack apitype.UntypedDeployment ) int {
32+ data , err := stack .Deployment .MarshalJSON ()
33+ require .NoError (t , err )
34+
35+ var stateMap map [string ]interface {}
36+ err = json .Unmarshal (data , & stateMap )
37+ require .NoError (t , err )
38+
39+ resourcesList := stateMap ["resources" ].([]interface {})
40+ require .Len (t , resourcesList , 3 )
41+ testResState := resourcesList [2 ].(map [string ]interface {})
42+ resOutputs := testResState ["outputs" ].(map [string ]interface {})
43+ metaVar := resOutputs ["__meta" ]
44+ if metaVar == nil {
45+ // If the resource does not have a meta field, assume the schema version is 0.
46+ return 0
47+ }
48+ meta := metaVar .(string )
49+ var metaMap map [string ]interface {}
50+ err = json .Unmarshal ([]byte (meta ), & metaMap )
51+ require .NoError (t , err )
52+ schemaVersion , err := strconv .ParseInt (metaMap ["schema_version" ].(string ), 10 , 64 )
53+ require .NoError (t , err )
54+ return int (schemaVersion )
55+ }
56+
57+ func runPulumiUpgrade (t T , res1 , res2 * schema.Resource , config1 , config2 any , disablePlanResourceChange bool ) (int , int ) {
58+ opts := []pulcheck.BridgedProviderOpt {}
59+ if disablePlanResourceChange {
60+ opts = append (opts , pulcheck .DisablePlanResourceChange ())
61+ }
62+
63+ prov1 := pulcheck .BridgedProvider (t , defProviderShortName , map [string ]* schema.Resource {defRtype : res1 }, opts ... )
64+ prov2 := pulcheck .BridgedProvider (t , defProviderShortName , map [string ]* schema.Resource {defRtype : res2 }, opts ... )
1665
1766 pd := & pulumiDriver {
1867 name : defProviderShortName ,
@@ -21,18 +70,29 @@ func runPulumiUpgrade(t T, res1, res2 *schema.Resource, config any) {
2170 objectType : nil ,
2271 }
2372
24- yamlProgram := pd .generateYAML (t , prov1 .P .ResourcesMap (), config )
73+ yamlProgram := pd .generateYAML (t , prov1 .P .ResourcesMap (), config1 )
2574 pt := pulcheck .PulCheck (t , prov1 , string (yamlProgram ))
26-
2775 pt .Up ()
76+ stack := pt .ExportStack ()
77+ schemaVersion1 := getVersionInState (t , stack )
78+
79+ yamlProgram = pd .generateYAML (t , prov2 .P .ResourcesMap (), config2 )
80+ p := filepath .Join (pt .CurrentStack ().Workspace ().WorkDir (), "Pulumi.yaml" )
81+ err := os .WriteFile (p , yamlProgram , 0o600 )
82+ require .NoErrorf (t , err , "writing Pulumi.yaml" )
2883
2984 handle , err := pulcheck .StartPulumiProvider (context .Background (), defProviderShortName , defProviderVer , prov2 )
3085 require .NoError (t , err )
3186 pt .CurrentStack ().Workspace ().SetEnvVar ("PULUMI_DEBUG_PROVIDERS" , fmt .Sprintf ("%s:%d" , defProviderShortName , handle .Port ))
3287 pt .Up ()
88+
89+ stack = pt .ExportStack ()
90+ schemaVersion2 := getVersionInState (t , stack )
91+
92+ return schemaVersion1 , schemaVersion2
3393}
3494
35- func runUpgradeStateInputCheck (t T , tc inputTestCase ) {
95+ func runUpgradeStateInputCheck (t T , tc upgradeStateTestCase ) {
3696 upgrades := make ([]schema.StateUpgrader , 0 )
3797 for i := 0 ; i < tc .Resource .SchemaVersion ; i ++ {
3898 upgrades = append (upgrades , schema.StateUpgrader {
@@ -72,13 +132,32 @@ func runUpgradeStateInputCheck(t T, tc inputTestCase) {
72132 tfwd := t .TempDir ()
73133
74134 tfd := newTfDriver (t , tfwd , defProviderShortName , defRtype , tc .Resource )
75- _ = tfd .writePlanApply (t , tc .Resource .Schema , defRtype , "example" , tc .Config )
135+ _ = tfd .writePlanApply (t , tc .Resource .Schema , defRtype , "example" , tc .Config1 )
76136
77137 tfd2 := newTfDriver (t , tfwd , defProviderShortName , defRtype , & upgradeRes )
78- _ = tfd2 .writePlanApply (t , tc .Resource .Schema , defRtype , "example" , tc .Config )
79-
80- runPulumiUpgrade (t , tc .Resource , & upgradeRes , tc .Config )
81-
82- assert .Len (t , upgradeRawStates , 2 )
83- assertValEqual (t , "UpgradeRawState" , upgradeRawStates [0 ], upgradeRawStates [1 ])
138+ _ = tfd2 .writePlanApply (t , tc .Resource .Schema , defRtype , "example" , tc .Config2 )
139+
140+ schemaVersion1 , schemaVersion2 := runPulumiUpgrade (t , tc .Resource , & upgradeRes , tc .Config1 , tc .Config2 , tc .DisablePlanResourceChange )
141+
142+ if tc .ExpectEqual {
143+ assert .Equal (t , schemaVersion1 , tc .Resource .SchemaVersion )
144+ // We never upgrade the state to the new version.
145+ // TODO: should we?
146+
147+ require .Len (t , upgradeRawStates , 2 )
148+ if len (upgradeRawStates ) != 2 {
149+ return
150+ }
151+ assertValEqual (t , "UpgradeRawState" , upgradeRawStates [0 ], upgradeRawStates [1 ])
152+
153+ } else {
154+ assert .Equal (t , schemaVersion1 , tc .Resource .SchemaVersion )
155+ assert .Equal (t , schemaVersion2 , upgradeRes .SchemaVersion )
156+ require .Len (t , upgradeRawStates , 4 )
157+ if len (upgradeRawStates ) != 4 {
158+ return
159+ }
160+ assertValEqual (t , "UpgradeRawState" , upgradeRawStates [0 ], upgradeRawStates [2 ])
161+ assertValEqual (t , "UpgradeRawState" , upgradeRawStates [1 ], upgradeRawStates [3 ])
162+ }
84163}
0 commit comments