Skip to content

Commit c57aebd

Browse files
PF integration tests using pulumitest (#2186)
This adds some utility functions which allow simple integration testing in the PF bridge, similar to the tests in pkg: https://github.com/pulumi/pulumi-terraform-bridge/blob/f317dc4a503d3430fbe13f3af964207f0a17616e/pkg/tests/schema_pulumi_test.go#L19 Builds on `pulumitest`, the `providerbuilder` tools and the `pulcheck` code under `pkg` originally adapted from the cross tests. Allows integration tests to be written against PF, where the schema and the yaml program are specified concisely in the test and pulumitest is used for the actions which allows quite a bit of freedom in expressing pulumi operations.
1 parent 59ab72c commit c57aebd

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package tfbridgetests
2+
3+
import (
4+
"testing"
5+
6+
pschema "github.com/hashicorp/terraform-plugin-framework/provider/schema"
7+
rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
8+
"github.com/pulumi/pulumi-terraform-bridge/pf/tests/internal/providerbuilder"
9+
)
10+
11+
func TestBasic(t *testing.T) {
12+
provBuilder := providerbuilder.Provider{
13+
TypeName: "prov",
14+
Version: "0.0.1",
15+
ProviderSchema: pschema.Schema{},
16+
AllResources: []providerbuilder.Resource{
17+
{
18+
Name: "test",
19+
ResourceSchema: rschema.Schema{
20+
Attributes: map[string]rschema.Attribute{
21+
"s": rschema.StringAttribute{Optional: true},
22+
},
23+
},
24+
},
25+
},
26+
}
27+
28+
prov := bridgedProvider(&provBuilder)
29+
30+
program := `
31+
name: test
32+
runtime: yaml
33+
resources:
34+
mainRes:
35+
type: prov:index:Test
36+
properties:
37+
s: "hello"`
38+
39+
pt := pulCheck(t, prov, program)
40+
41+
pt.Up()
42+
}

pf/tests/util.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,31 @@ package tfbridgetests
1616

1717
import (
1818
"context"
19+
"fmt"
20+
"os"
21+
"path/filepath"
22+
"runtime"
23+
"strings"
1924
"testing"
2025

26+
"github.com/hashicorp/terraform-plugin-framework/path"
27+
"github.com/hashicorp/terraform-plugin-framework/resource"
28+
rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
29+
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
2130
"github.com/stretchr/testify/require"
31+
"google.golang.org/grpc"
2232

33+
"github.com/pulumi/providertest/providers"
34+
"github.com/pulumi/providertest/pulumitest"
35+
"github.com/pulumi/providertest/pulumitest/opttest"
36+
"github.com/pulumi/pulumi/sdk/v3/go/common/util/rpcutil"
2337
pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go"
2438

39+
"github.com/pulumi/pulumi-terraform-bridge/pf/tests/internal/providerbuilder"
2540
"github.com/pulumi/pulumi-terraform-bridge/pf/tfbridge"
2641
tfbridge0 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
42+
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/info"
43+
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/tokens"
2744
)
2845

2946
func newProviderServer(t *testing.T, info tfbridge0.ProviderInfo) pulumirpc.ResourceProviderServer {
@@ -41,3 +58,83 @@ func newMuxedProviderServer(t *testing.T, info tfbridge0.ProviderInfo) pulumirpc
4158
require.NoError(t, err)
4259
return p
4360
}
61+
62+
func ensureProviderValid(prov *providerbuilder.Provider) {
63+
for i := range prov.AllResources {
64+
r := &prov.AllResources[i]
65+
if r.ResourceSchema.Attributes["id"] == nil {
66+
r.ResourceSchema.Attributes["id"] = rschema.StringAttribute{Computed: true}
67+
}
68+
if r.CreateFunc == nil {
69+
r.CreateFunc = func(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
70+
resp.State = tfsdk.State(req.Config)
71+
resp.State.SetAttribute(ctx, path.Root("id"), "test-id")
72+
}
73+
}
74+
}
75+
76+
}
77+
78+
func bridgedProvider(prov *providerbuilder.Provider) info.Provider {
79+
ensureProviderValid(prov)
80+
shimProvider := tfbridge.ShimProvider(prov)
81+
82+
provider := tfbridge0.ProviderInfo{
83+
P: shimProvider,
84+
Name: prov.TypeName,
85+
Version: "0.0.1",
86+
MetadataInfo: &tfbridge0.MetadataInfo{},
87+
}
88+
89+
provider.MustComputeTokens(tokens.SingleModule(prov.TypeName, "index", tokens.MakeStandard(prov.TypeName)))
90+
91+
return provider
92+
}
93+
94+
func startPulumiProvider(t *testing.T, providerInfo tfbridge0.ProviderInfo) (*rpcutil.ServeHandle, error) {
95+
prov := newProviderServer(t, providerInfo)
96+
97+
handle, err := rpcutil.ServeWithOptions(rpcutil.ServeOptions{
98+
Init: func(srv *grpc.Server) error {
99+
pulumirpc.RegisterResourceProviderServer(srv, prov)
100+
return nil
101+
},
102+
})
103+
if err != nil {
104+
return nil, fmt.Errorf("rpcutil.ServeWithOptions failed: %w", err)
105+
}
106+
107+
return &handle, nil
108+
}
109+
110+
func skipUnlessLinux(t *testing.T) {
111+
if ci, ok := os.LookupEnv("CI"); ok && ci == "true" && !strings.Contains(strings.ToLower(runtime.GOOS), "linux") {
112+
// TODO[pulumi/pulumi-terraform-bridge#2221]
113+
t.Skip("Skipping on non-Linux platforms")
114+
}
115+
}
116+
117+
func pulCheck(t *testing.T, bridgedProvider info.Provider, program string) *pulumitest.PulumiTest {
118+
skipUnlessLinux(t)
119+
puwd := t.TempDir()
120+
p := filepath.Join(puwd, "Pulumi.yaml")
121+
122+
err := os.WriteFile(p, []byte(program), 0o600)
123+
require.NoError(t, err)
124+
125+
opts := []opttest.Option{
126+
opttest.Env("DISABLE_AUTOMATIC_PLUGIN_ACQUISITION", "true"),
127+
opttest.TestInPlace(),
128+
opttest.SkipInstall(),
129+
opttest.AttachProvider(
130+
bridgedProvider.Name,
131+
func(ctx context.Context, pt providers.PulumiTest) (providers.Port, error) {
132+
handle, err := startPulumiProvider(t, bridgedProvider)
133+
require.NoError(t, err)
134+
return providers.Port(handle.Port), nil
135+
},
136+
),
137+
}
138+
139+
return pulumitest.NewPulumiTest(t, puwd, opts...)
140+
}

0 commit comments

Comments
 (0)