Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pulumiTest Integration tests #2052

Merged
merged 25 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
11d6900
integration tests poc
VenelinMartinov Jun 3, 2024
85b8527
fix test
VenelinMartinov Jun 3, 2024
7dd99fa
refactor tests
VenelinMartinov Jun 6, 2024
8727586
lint
VenelinMartinov Jun 6, 2024
28bfadb
go mod tidy
VenelinMartinov Jun 6, 2024
1ba4c87
hide function
VenelinMartinov Jun 6, 2024
b9271d6
move things about
VenelinMartinov Jun 6, 2024
3864781
fix invalid tf provider
VenelinMartinov Jun 6, 2024
db35f45
finish test
VenelinMartinov Jun 6, 2024
2f06781
add some experimental comments
VenelinMartinov Jun 6, 2024
08d78d3
make test schema valid
VenelinMartinov Jun 6, 2024
9761d63
accidental public var
VenelinMartinov Jun 6, 2024
b775cc6
lint
VenelinMartinov Jun 6, 2024
6d81799
move skip unless linux
VenelinMartinov Jun 6, 2024
b3e2c63
Merge branch 'master' into vvm/pulumiTest_integration_tests
VenelinMartinov Jun 6, 2024
76b4d17
bad merge and fix types
VenelinMartinov Jun 6, 2024
03e4b08
lint
VenelinMartinov Jun 6, 2024
6a78016
Revert "move skip unless linux"
VenelinMartinov Jun 6, 2024
ce0133d
Merge branch 'master' into vvm/pulumiTest_integration_tests
VenelinMartinov Jun 6, 2024
4acec2c
skip on windows
VenelinMartinov Jun 6, 2024
0bd1b5b
bad merge
VenelinMartinov Jun 7, 2024
6226f7b
Merge branch 'master' into vvm/pulumiTest_integration_tests
VenelinMartinov Jun 7, 2024
9d74df1
Update pkg/tests/cross-tests/defaults.go
VenelinMartinov Jun 7, 2024
a5ff06c
move pulcheck to internal
VenelinMartinov Jun 7, 2024
aa2be4b
Merge branch 'vvm/pulumiTest_integration_tests' of github.com:pulumi/…
VenelinMartinov Jun 7, 2024
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
30 changes: 30 additions & 0 deletions pkg/tests/cross-tests/assert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package crosstests

import (
"github.com/hashicorp/go-cty/cty"
"github.com/stretchr/testify/require"
)

func FailNotEqual(t T, name string, tfVal, pulVal any) {
t.Logf(name + " not equal!")
t.Logf("TF value %s", tfVal)
t.Logf("PU value %s", pulVal)
t.Fail()
}

func assertCtyValEqual(t T, name string, tfVal, pulVal cty.Value) {
if !tfVal.RawEquals(pulVal) {
FailNotEqual(t, name, tfVal.GoString(), pulVal.GoString())
}
}

func assertValEqual(t T, name string, tfVal, pulVal any) {
// usually plugin-sdk schema types
if hasEqualTfVal, ok := tfVal.(interface{ Equal(interface{}) bool }); ok {
if !hasEqualTfVal.Equal(pulVal) {
FailNotEqual(t, name, tfVal, pulVal)
}
} else {
require.Equal(t, tfVal, pulVal, "Values for key %s do not match", name)
}
}
3 changes: 1 addition & 2 deletions pkg/tests/cross-tests/cross_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,7 @@ func TestSetReordering(t *testing.T) {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
Optional: true,
Type: schema.TypeString,
},
},
},
Expand Down
9 changes: 9 additions & 0 deletions pkg/tests/cross-tests/defaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package crosstests

const (
defProviderShortName = "crossprovider"
defRtype = "crossprovider_test_res"
defRtok = "TestRes"
defRtoken = defProviderShortName + ":index:" + defRtok
defProviderVer = "0.0.1"
)
64 changes: 17 additions & 47 deletions pkg/tests/cross-tests/diff_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@
package crosstests

import (
"context"
"os"
"path/filepath"

"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/pulumi/providertest/providers"
"github.com/pulumi/providertest/pulumitest"
"github.com/pulumi/providertest/pulumitest/opttest"
shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tests/internal/pulcheck"
"github.com/pulumi/pulumi/sdk/v3/go/auto"
"github.com/pulumi/pulumi/sdk/v3/go/common/apitype"
"github.com/stretchr/testify/assert"
Expand All @@ -47,58 +45,30 @@ type diffTestCase struct {
}

func runDiffCheck(t T, tc diffTestCase) {
var (
providerShortName = "crossprovider"
rtype = "crossprovider_testres"
rtok = "TestRes"
rtoken = providerShortName + ":index:" + rtok
providerVer = "0.0.1"
)

tfwd := t.TempDir()

tfd := newTfDriver(t, tfwd, providerShortName, rtype, tc.Resource)
_ = tfd.writePlanApply(t, tc.Resource.Schema, rtype, "example", tc.Config1)
tfDiffPlan := tfd.writePlanApply(t, tc.Resource.Schema, rtype, "example", tc.Config2)

tfp := &schema.Provider{
ResourcesMap: map[string]*schema.Resource{
rtype: tc.Resource,
},
}
tfd := newTfDriver(t, tfwd, defProviderShortName, defRtype, tc.Resource)
_ = tfd.writePlanApply(t, tc.Resource.Schema, defRtype, "example", tc.Config1)
tfDiffPlan := tfd.writePlanApply(t, tc.Resource.Schema, defRtype, "example", tc.Config2)

shimProvider := shimv2.NewProvider(tfp, shimv2.WithPlanResourceChange(
func(tfResourceType string) bool { return true },
))
resMap := map[string]*schema.Resource{defRtype: tc.Resource}
bridgedProvider := pulcheck.BridgedProvider(t, defProviderShortName, resMap)

pd := &pulumiDriver{
name: providerShortName,
version: providerVer,
shimProvider: shimProvider,
pulumiResourceToken: rtoken,
tfResourceName: rtype,
name: defProviderShortName,
pulumiResourceToken: defRtoken,
tfResourceName: defRtype,
objectType: nil,
}

puwd := t.TempDir()
pd.writeYAML(t, puwd, tc.Config1)

pt := pulumitest.NewPulumiTest(t, puwd,
opttest.TestInPlace(),
opttest.SkipInstall(),
opttest.AttachProvider(
providerShortName,
func(ctx context.Context, pt providers.PulumiTest) (providers.Port, error) {
handle, err := pd.startPulumiProvider(ctx)
require.NoError(t, err)
return providers.Port(handle.Port), nil
},
),
)
yamlProgram := pd.generateYAML(t, bridgedProvider.P.ResourcesMap(), tc.Config1)
pt := pulcheck.PulCheck(t, bridgedProvider, string(yamlProgram))

pt.Up()

pd.writeYAML(t, puwd, tc.Config2)
yamlProgram = pd.generateYAML(t, bridgedProvider.P.ResourcesMap(), tc.Config2)
p := filepath.Join(pt.CurrentStack().Workspace().WorkDir(), "Pulumi.yaml")
err := os.WriteFile(p, yamlProgram, 0o600)
require.NoErrorf(t, err, "writing Pulumi.yaml")
x := pt.Up()

tfAction := tfd.parseChangesFromTFPlan(*tfDiffPlan)
Expand Down
96 changes: 11 additions & 85 deletions pkg/tests/cross-tests/input_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,10 @@ package crosstests
import (
"context"

"github.com/hashicorp/go-cty/cty"
"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/pulumi/providertest/providers"
"github.com/pulumi/providertest/pulumitest"
"github.com/pulumi/providertest/pulumitest/opttest"
shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2"
"github.com/stretchr/testify/require"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tests/internal/pulcheck"
)

// Adapted from diff_check.go
Expand All @@ -35,46 +30,9 @@ type inputTestCase struct {
ObjectType *tftypes.Object
}

func FailNotEqual(t T, name string, tfVal, pulVal any) {
t.Logf(name + " not equal!")
t.Logf("TF value %s", tfVal)
t.Logf("PU value %s", pulVal)
t.Fail()
}

func assertCtyValEqual(t T, name string, tfVal, pulVal cty.Value) {
if !tfVal.RawEquals(pulVal) {
FailNotEqual(t, name, tfVal.GoString(), pulVal.GoString())
}
}

func assertValEqual(t T, name string, tfVal, pulVal any) {
// usually plugin-sdk schema types
if hasEqualTfVal, ok := tfVal.(interface{ Equal(interface{}) bool }); ok {
if !hasEqualTfVal.Equal(pulVal) {
FailNotEqual(t, name, tfVal, pulVal)
}
} else {
require.Equal(t, tfVal, pulVal, "Values for key %s do not match", name)
}
}

func ensureProviderValid(t T, tfp *schema.Provider) {
for _, r := range tfp.ResourcesMap {
//nolint:staticcheck
if r.Read == nil && r.ReadContext == nil {
r.ReadContext = func(_ context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
return nil
}
}
}
require.NoError(t, tfp.InternalValidate())
}

// Adapted from diff_check.go
func runCreateInputCheck(t T, tc inputTestCase) {
//nolint:staticcheck
if tc.Resource.CreateContext != nil || tc.Resource.Create != nil {
if tc.Resource.CreateContext != nil {
t.Errorf("Create methods should not be set for these tests!")
}

Expand All @@ -89,55 +47,23 @@ func runCreateInputCheck(t T, tc inputTestCase) {
rd.SetId("someid") // CreateContext must pick an ID
return make(diag.Diagnostics, 0)
}
var (
providerShortName = "crossprovider"
rtype = "crossprovider_testres"
rtok = "TestRes"
rtoken = providerShortName + ":index:" + rtok
providerVer = "0.0.1"
)

tfwd := t.TempDir()

tfd := newTfDriver(t, tfwd, providerShortName, rtype, tc.Resource)
tfd.writePlanApply(t, tc.Resource.Schema, rtype, "example", tc.Config)

tfp := &schema.Provider{
ResourcesMap: map[string]*schema.Resource{
rtype: tc.Resource,
},
}
ensureProviderValid(t, tfp)

shimProvider := shimv2.NewProvider(tfp, shimv2.WithPlanResourceChange(
func(tfResourceType string) bool { return true },
))
tfd := newTfDriver(t, tfwd, defProviderShortName, defRtype, tc.Resource)
tfd.writePlanApply(t, tc.Resource.Schema, defRtype, "example", tc.Config)

resMap := map[string]*schema.Resource{defRtype: tc.Resource}
bridgedProvider := pulcheck.BridgedProvider(t, defProviderShortName, resMap)
pd := &pulumiDriver{
name: providerShortName,
version: providerVer,
shimProvider: shimProvider,
pulumiResourceToken: rtoken,
tfResourceName: rtype,
name: defProviderShortName,
pulumiResourceToken: defRtoken,
tfResourceName: defRtype,
objectType: tc.ObjectType,
}
yamlProgram := pd.generateYAML(t, bridgedProvider.P.ResourcesMap(), tc.Config)

puwd := t.TempDir()
pd.writeYAML(t, puwd, tc.Config)

pt := pulumitest.NewPulumiTest(t, puwd,
opttest.TestInPlace(),
opttest.SkipInstall(),
opttest.AttachProvider(
providerShortName,
func(ctx context.Context, pt providers.PulumiTest) (providers.Port, error) {
handle, err := pd.startPulumiProvider(ctx)
require.NoError(t, err)
return providers.Port(handle.Port), nil
},
),
opttest.Env("DISABLE_AUTOMATIC_PLUGIN_ACQUISITION", "true"),
)
pt := pulcheck.PulCheck(t, bridgedProvider, string(yamlProgram))

pt.Up()

Expand Down
70 changes: 3 additions & 67 deletions pkg/tests/cross-tests/pu_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,83 +15,21 @@
package crosstests

import (
"context"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"

"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfgen"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
pulumidiag "github.com/pulumi/pulumi/sdk/v3/go/common/diag"
"github.com/pulumi/pulumi/sdk/v3/go/common/diag/colors"
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/rpcutil"
pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
"gopkg.in/yaml.v3"
)

type pulumiDriver struct {
name string
version string
shimProvider shim.Provider
pulumiResourceToken string
tfResourceName string
objectType *tftypes.Object
}

func (pd *pulumiDriver) providerInfo() tfbridge.ProviderInfo {
return tfbridge.ProviderInfo{
Name: pd.name,
P: pd.shimProvider,

Resources: map[string]*tfbridge.ResourceInfo{
pd.tfResourceName: {
Tok: tokens.Type(pd.pulumiResourceToken),
},
},
}
}

func (pd *pulumiDriver) startPulumiProvider(ctx context.Context) (*rpcutil.ServeHandle, error) {
info := pd.providerInfo()

sink := pulumidiag.DefaultSink(io.Discard, io.Discard, pulumidiag.FormatOptions{
Color: colors.Never,
})

schema, err := tfgen.GenerateSchema(info, sink)
if err != nil {
return nil, fmt.Errorf("tfgen.GenerateSchema failed: %w", err)
}

schemaBytes, err := json.MarshalIndent(schema, "", " ")
if err != nil {
return nil, fmt.Errorf("json.MarshalIndent(schema, ..) failed: %w", err)
}

prov := tfbridge.NewProvider(ctx, nil, pd.name, pd.version, info.P, info, schemaBytes)

handle, err := rpcutil.ServeWithOptions(rpcutil.ServeOptions{
Init: func(srv *grpc.Server) error {
pulumirpc.RegisterResourceProviderServer(srv, prov)
return nil
},
})
if err != nil {
return nil, fmt.Errorf("rpcutil.ServeWithOptions failed: %w", err)
}

return &handle, nil
}

func (pd *pulumiDriver) writeYAML(t T, workdir string, tfConfig any) {
res := pd.shimProvider.ResourcesMap().Get(pd.tfResourceName)
func (pd *pulumiDriver) generateYAML(t T, resMap shim.ResourceMap, tfConfig any) []byte {
res := resMap.Get(pd.tfResourceName)
schema := res.Schema()

data, err := generateYaml(schema, pd.pulumiResourceToken, pd.objectType, tfConfig)
Expand All @@ -100,7 +38,5 @@ func (pd *pulumiDriver) writeYAML(t T, workdir string, tfConfig any) {
b, err := yaml.Marshal(data)
require.NoErrorf(t, err, "marshaling Pulumi.yaml")
t.Logf("\n\n%s", b)
p := filepath.Join(workdir, "Pulumi.yaml")
err = os.WriteFile(p, b, 0o600)
require.NoErrorf(t, err, "writing Pulumi.yaml")
return b
}
1 change: 1 addition & 0 deletions pkg/tests/cross-tests/t.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
type T interface {
Logf(string, ...any)
TempDir() string
Skip(...any)
require.TestingT
assert.TestingT
pulumitest.PT
Expand Down
Loading