Skip to content

Commit a913512

Browse files
committed
Prevent EnsureProviderValid from mutating
This function has caused repeated test failures with concurrent map mutations, the most recent of which is https://github.com/pulumi/pulumi-terraform-bridge/actions/runs/12772071950/job/35600764628?pr=2832. This commit converts the function to return a copy instead of mutating.
1 parent 5ed2021 commit a913512

File tree

3 files changed

+80
-48
lines changed

3 files changed

+80
-48
lines changed

pkg/internal/tests/pulcheck/pulcheck.go

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,39 @@ func resourceNeedsUpdate(res *schema.Resource) bool {
5252
return false
5353
}
5454

55+
func copyMap[K comparable, V any](m map[K]V, cp func(V) V) map[K]V {
56+
dst := make(map[K]V, len(m))
57+
for k, v := range m {
58+
dst[k] = cp(v)
59+
}
60+
return dst
61+
}
62+
63+
// WithValidProvider returns a copy of tfp, with all required fields filled with default
64+
// values.
65+
//
5566
// This is an experimental API.
56-
func EnsureProviderValid(t T, tfp *schema.Provider) {
67+
func WithValidProvider(t T, tfp *schema.Provider) *schema.Provider {
68+
if tfp == nil {
69+
return nil
70+
}
71+
72+
// Copy tfp as deep as we will mutate.
73+
{
74+
dst := *tfp // memcopy
75+
dst.ResourcesMap = copyMap(tfp.ResourcesMap, func(v *schema.Resource) *schema.Resource {
76+
cp := *v // memcopy
77+
cp.Schema = copyMap(cp.Schema, func(s *schema.Schema) *schema.Schema {
78+
cp := *s
79+
return &cp
80+
})
81+
return &cp
82+
})
83+
tfp = &dst
84+
}
85+
86+
// Now ensure that tfp is valid
87+
5788
for _, r := range tfp.ResourcesMap {
5889
if r.Schema["id"] == nil {
5990
r.Schema["id"] = &schema.Schema{
@@ -108,6 +139,8 @@ func EnsureProviderValid(t T, tfp *schema.Provider) {
108139
}
109140
}
110141
require.NoError(t, tfp.InternalValidate())
142+
143+
return tfp
111144
}
112145

113146
func ProviderServerFromInfo(
@@ -206,7 +239,7 @@ func BridgedProvider(t T, providerName string, tfp *schema.Provider, opts ...Bri
206239
opt(&options)
207240
}
208241

209-
EnsureProviderValid(t, tfp)
242+
tfp = WithValidProvider(t, tfp)
210243

211244
// If the PULUMI_ACCURATE_BRIDGE_PREVIEWS environment variable is set, use it to enable
212245
// accurate bridge previews.
@@ -230,10 +263,8 @@ func BridgedProvider(t T, providerName string, tfp *schema.Provider, opts ...Bri
230263
EnableAccurateBridgePreview: accurateBridgePreviews,
231264
Config: options.configInfo,
232265
}
233-
makeToken := func(module, name string) (string, error) {
234-
return tokens.MakeStandard(providerName)(module, name)
235-
}
236-
provider.MustComputeTokens(tokens.SingleModule(providerName, "index", makeToken))
266+
provider.MustComputeTokens(tokens.SingleModule(providerName,
267+
"index", tokens.MakeStandard(providerName)))
237268

238269
return provider
239270
}

pkg/tests/import_test.go

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,54 +16,57 @@ import (
1616
"gopkg.in/yaml.v3"
1717

1818
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/tests/pulcheck"
19+
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/info"
1920
)
2021

2122
func TestFullyComputedNestedAttribute(t *testing.T) {
2223
t.Parallel()
23-
resMap := map[string]*schema.Resource{
24-
"prov_test": {
25-
Schema: map[string]*schema.Schema{
26-
"attached_disks": {
27-
Type: schema.TypeList,
28-
Optional: true,
29-
Elem: &schema.Resource{
30-
Schema: map[string]*schema.Schema{
31-
"name": {
32-
Optional: true,
33-
Type: schema.TypeString,
34-
},
35-
"key256": {
36-
Computed: true,
37-
Type: schema.TypeString,
24+
25+
bridgedProvider := func(importVal any) info.Provider {
26+
return pulcheck.BridgedProvider(t, "prov", &schema.Provider{
27+
ResourcesMap: map[string]*schema.Resource{
28+
"prov_test": {
29+
Schema: map[string]*schema.Schema{
30+
"attached_disks": {
31+
Type: schema.TypeList,
32+
Optional: true,
33+
Elem: &schema.Resource{
34+
Schema: map[string]*schema.Schema{
35+
"name": {
36+
Optional: true,
37+
Type: schema.TypeString,
38+
},
39+
"key256": {
40+
Computed: true,
41+
Type: schema.TypeString,
42+
},
43+
},
3844
},
3945
},
46+
"top_level_computed": {
47+
Type: schema.TypeString,
48+
Computed: true,
49+
},
4050
},
41-
},
42-
"top_level_computed": {
43-
Type: schema.TypeString,
44-
Computed: true,
45-
},
46-
},
47-
},
48-
}
49-
50-
importer := func(val any) func(context.Context, *schema.ResourceData, interface{}) ([]*schema.ResourceData, error) {
51-
return func(ctx context.Context, rd *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) {
52-
elMap := map[string]any{
53-
"name": "disk1",
54-
"key256": val,
55-
}
56-
err := rd.Set("attached_disks", []map[string]any{elMap})
57-
require.NoError(t, err)
51+
Importer: &schema.ResourceImporter{
52+
StateContext: func(ctx context.Context, rd *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) {
53+
elMap := map[string]any{
54+
"name": "disk1",
55+
"key256": importVal,
56+
}
57+
err := rd.Set("attached_disks", []map[string]any{elMap})
58+
require.NoError(t, err)
5859

59-
err = rd.Set("top_level_computed", "computed_val")
60-
require.NoError(t, err)
60+
err = rd.Set("top_level_computed", "computed_val")
61+
require.NoError(t, err)
6162

62-
return []*schema.ResourceData{rd}, nil
63-
}
63+
return []*schema.ResourceData{rd}, nil
64+
},
65+
},
66+
},
67+
},
68+
})
6469
}
65-
tfp := &schema.Provider{ResourcesMap: resMap}
66-
bridgedProvider := pulcheck.BridgedProvider(t, "prov", tfp)
6770

6871
program := `
6972
name: test
@@ -83,9 +86,7 @@ runtime: yaml
8386
},
8487
} {
8588
t.Run(tc.name, func(t *testing.T) {
86-
resMap["prov_test"].Importer = &schema.ResourceImporter{
87-
StateContext: importer(tc.importVal),
88-
}
89+
bridgedProvider := bridgedProvider(tc.importVal)
8990

9091
pt := pulcheck.PulCheck(t, bridgedProvider, program)
9192

pkg/tests/tfcheck/tfcheck.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func NewTfDriver(t pulcheck.T, dir, providerName string, prov any) *TFDriver {
7676
}
7777

7878
func newTfDriverSDK(t pulcheck.T, dir, providerName string, prov *schema.Provider) *TFDriver {
79-
pulcheck.EnsureProviderValid(t, prov)
79+
prov = pulcheck.WithValidProvider(t, prov)
8080
v6server, err := tf5to6server.UpgradeServer(context.Background(),
8181
func() tfprotov5.ProviderServer { return prov.GRPCProvider() })
8282
require.NoError(t, err)

0 commit comments

Comments
 (0)