Skip to content

Commit

Permalink
Move InferPulumiValue to crosstestsimpl
Browse files Browse the repository at this point in the history
InferPulumiValue was made public in a previous commit, but it shouldn't really be exposed
to end users of cross-tests, so this commit moved it to it's own package.
  • Loading branch information
iwahbe committed Nov 1, 2024
1 parent d001f90 commit 4ba9f31
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 127 deletions.
107 changes: 0 additions & 107 deletions pkg/internal/tests/cross-tests/adapt.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,120 +17,13 @@
package crosstests

import (
"context"
"fmt"
"math/big"

"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
"github.com/stretchr/testify/require"
"github.com/zclconf/go-cty/cty"

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/convert"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/info"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/unstable/logging"
)

// InferPulumiValue generates a Pulumi value that is semantically equivalent to v.
//
// InferPulumiValue takes into account schema information.
func InferPulumiValue(t T, schema shim.SchemaMap, infos map[string]*info.Schema, v cty.Value) resource.PropertyMap {
if v.IsNull() {
return nil
}
decoder, err := convert.NewObjectDecoder(convert.ObjectSchema{
SchemaMap: schema,
SchemaInfos: infos,
})
require.NoError(t, err)

ctx := logging.InitLogging(context.Background(), logging.LogOptions{})
// There is not yet a way to opt out of marking schema secrets, so the resulting map might have secrets marked.
pm, err := convert.DecodePropertyMap(ctx, decoder, ctyToTftypes(v))
require.NoError(t, err)
return pm
}

func ctyToTftypes(v cty.Value) tftypes.Value {
typ := v.Type()
if !v.IsKnown() {
return tftypes.NewValue(ctyTypeToTfType(typ), tftypes.UnknownValue)
}
if v.IsNull() {
return tftypes.NewValue(ctyTypeToTfType(typ), nil)
}
switch {
case typ.Equals(cty.String):
return tftypes.NewValue(ctyTypeToTfType(typ), v.AsString())
case typ.Equals(cty.Bool):
return tftypes.NewValue(ctyTypeToTfType(typ), v.True())
case typ.Equals(cty.Number):
return tftypes.NewValue(ctyTypeToTfType(typ), v.AsBigFloat())

case typ.IsListType():
src := v.AsValueSlice()
dst := make([]tftypes.Value, len(src))
for i, v := range src {
dst[i] = ctyToTftypes(v)
}
return tftypes.NewValue(ctyTypeToTfType(typ), dst)
case typ.IsSetType():
src := v.AsValueSet().Values()
dst := make([]tftypes.Value, len(src))
for i, v := range src {
dst[i] = ctyToTftypes(v)
}
return tftypes.NewValue(ctyTypeToTfType(typ), dst)
case typ.IsMapType():
src := v.AsValueMap()
dst := make(map[string]tftypes.Value, len(src))
for k, v := range src {
dst[k] = ctyToTftypes(v)
}
return tftypes.NewValue(ctyTypeToTfType(typ), dst)
case typ.IsObjectType():
src := v.AsValueMap()
dst := make(map[string]tftypes.Value, len(src))
for k, v := range src {
dst[k] = ctyToTftypes(v)
}
return tftypes.NewValue(ctyTypeToTfType(typ), dst)
default:
panic(fmt.Sprintf("unknown type %s", typ.GoString()))
}
}

func ctyTypeToTfType(typ cty.Type) tftypes.Type {
switch {
case typ.Equals(cty.String):
return tftypes.String
case typ.Equals(cty.Bool):
return tftypes.Bool
case typ.Equals(cty.Number):
return tftypes.Number
case typ == cty.DynamicPseudoType:
return tftypes.DynamicPseudoType

case typ.IsListType():
return tftypes.List{ElementType: ctyTypeToTfType(typ.ElementType())}
case typ.IsSetType():
return tftypes.Set{ElementType: ctyTypeToTfType(typ.ElementType())}
case typ.IsMapType():
return tftypes.Map{ElementType: ctyTypeToTfType(typ.ElementType())}
case typ.IsObjectType():
src := typ.AttributeTypes()
dst := make(map[string]tftypes.Type, len(src))
for k, v := range src {
dst[k] = ctyTypeToTfType(v)
}
return tftypes.Object{AttributeTypes: dst}
default:
panic(fmt.Sprintf("unknown type %s", typ.GoString()))
}
}

type typeAdapter struct {
typ tftypes.Type
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/internal/tests/cross-tests/configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/zclconf/go-cty/cty"
"gopkg.in/yaml.v3"

crosstestsimpl "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/tests/cross-tests/impl"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tests/pulcheck"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tests/tfcheck"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/info"
Expand Down Expand Up @@ -61,7 +62,7 @@ func Configure(
if opts.puConfig != nil {
puConfig = *opts.puConfig
} else {
puConfig = InferPulumiValue(t,
puConfig = crosstestsimpl.InferPulumiValue(t,
shimv2.NewSchemaMap(provider),
opts.resourceInfo.GetFields(),
tfConfig,
Expand Down
3 changes: 2 additions & 1 deletion pkg/internal/tests/cross-tests/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/zclconf/go-cty/cty"

crosstestsimpl "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/tests/cross-tests/impl"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tests/pulcheck"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/info"
shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2"
Expand Down Expand Up @@ -63,7 +64,7 @@ func Create(
if opts.puConfig != nil {
puConfig = *opts.puConfig
} else {
puConfig = InferPulumiValue(t,
puConfig = crosstestsimpl.InferPulumiValue(t,
shimv2.NewSchemaMap(resourceSchema),
opts.resourceInfo.GetFields(),
tfConfig,
Expand Down
5 changes: 3 additions & 2 deletions pkg/internal/tests/cross-tests/diff_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

crosstestsimpl "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/tests/cross-tests/impl"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tests/pulcheck"
)

Expand Down Expand Up @@ -85,12 +86,12 @@ func runDiffCheck(t T, tc diffTestCase) diffResult {
tfResourceName: defRtype,
}

yamlProgram := pd.generateYAML(t, InferPulumiValue(t,
yamlProgram := pd.generateYAML(t, crosstestsimpl.InferPulumiValue(t,
bridgedProvider.P.ResourcesMap().Get(defRtype).Schema(), nil, tfConfig1))
pt := pulcheck.PulCheck(t, bridgedProvider, string(yamlProgram))
pt.Up(t)

yamlProgram = pd.generateYAML(t, InferPulumiValue(t,
yamlProgram = pd.generateYAML(t, crosstestsimpl.InferPulumiValue(t,
bridgedProvider.P.ResourcesMap().Get(defRtype).Schema(), nil, tfConfig2))
err := os.WriteFile(filepath.Join(pt.CurrentStack().Workspace().WorkDir(), "Pulumi.yaml"), yamlProgram, 0o600)
require.NoErrorf(t, err, "writing Pulumi.yaml")
Expand Down
131 changes: 131 additions & 0 deletions pkg/internal/tests/cross-tests/impl/inferPulumiValue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// Copyright 2016-2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package crosstestsimpl (cross-tests implementation) contains code meant to be shared
// across cross-test implementations (SDKv2, PF) but not used by people writing tests
// themselves.
package crosstestsimpl

import (
"context"
"fmt"

"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/stretchr/testify/require"
"github.com/zclconf/go-cty/cty"

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/convert"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge/info"
shim "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim"
"github.com/pulumi/pulumi-terraform-bridge/v3/unstable/logging"
)

// InferPulumiValue generates a Pulumi value that is semantically equivalent to v.
//
// InferPulumiValue takes into account schema information.
func InferPulumiValue(t T, schema shim.SchemaMap, infos map[string]*info.Schema, v cty.Value) resource.PropertyMap {
if v.IsNull() {
return nil
}
decoder, err := convert.NewObjectDecoder(convert.ObjectSchema{
SchemaMap: schema,
SchemaInfos: infos,
})
require.NoError(t, err)

ctx := logging.InitLogging(context.Background(), logging.LogOptions{})
// There is not yet a way to opt out of marking schema secrets, so the resulting map might have secrets marked.
pm, err := convert.DecodePropertyMap(ctx, decoder, ctyToTftypes(v))
require.NoError(t, err)
return pm
}

func ctyToTftypes(v cty.Value) tftypes.Value {
typ := v.Type()
if !v.IsKnown() {
return tftypes.NewValue(ctyTypeToTfType(typ), tftypes.UnknownValue)
}
if v.IsNull() {
return tftypes.NewValue(ctyTypeToTfType(typ), nil)
}
switch {
case typ.Equals(cty.String):
return tftypes.NewValue(ctyTypeToTfType(typ), v.AsString())
case typ.Equals(cty.Bool):
return tftypes.NewValue(ctyTypeToTfType(typ), v.True())
case typ.Equals(cty.Number):
return tftypes.NewValue(ctyTypeToTfType(typ), v.AsBigFloat())

case typ.IsListType():
src := v.AsValueSlice()
dst := make([]tftypes.Value, len(src))
for i, v := range src {
dst[i] = ctyToTftypes(v)
}
return tftypes.NewValue(ctyTypeToTfType(typ), dst)
case typ.IsSetType():
src := v.AsValueSet().Values()
dst := make([]tftypes.Value, len(src))
for i, v := range src {
dst[i] = ctyToTftypes(v)
}
return tftypes.NewValue(ctyTypeToTfType(typ), dst)
case typ.IsMapType():
src := v.AsValueMap()
dst := make(map[string]tftypes.Value, len(src))
for k, v := range src {
dst[k] = ctyToTftypes(v)
}
return tftypes.NewValue(ctyTypeToTfType(typ), dst)
case typ.IsObjectType():
src := v.AsValueMap()
dst := make(map[string]tftypes.Value, len(src))
for k, v := range src {
dst[k] = ctyToTftypes(v)
}
return tftypes.NewValue(ctyTypeToTfType(typ), dst)
default:
panic(fmt.Sprintf("unknown type %s", typ.GoString()))
}
}

func ctyTypeToTfType(typ cty.Type) tftypes.Type {
switch {
case typ.Equals(cty.String):
return tftypes.String
case typ.Equals(cty.Bool):
return tftypes.Bool
case typ.Equals(cty.Number):
return tftypes.Number
case typ == cty.DynamicPseudoType:
return tftypes.DynamicPseudoType

case typ.IsListType():
return tftypes.List{ElementType: ctyTypeToTfType(typ.ElementType())}
case typ.IsSetType():
return tftypes.Set{ElementType: ctyTypeToTfType(typ.ElementType())}
case typ.IsMapType():
return tftypes.Map{ElementType: ctyTypeToTfType(typ.ElementType())}
case typ.IsObjectType():
src := typ.AttributeTypes()
dst := make(map[string]tftypes.Type, len(src))
for k, v := range src {
dst[k] = ctyTypeToTfType(v)
}
return tftypes.Object{AttributeTypes: dst}
default:
panic(fmt.Sprintf("unknown type %s", typ.GoString()))
}
}
31 changes: 31 additions & 0 deletions pkg/internal/tests/cross-tests/impl/t.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2016-2024, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package crosstestsimpl

import (
"github.com/pulumi/providertest/pulumitest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// Abstractions to allow tests to work against both *[testing.T] and [rapid.TB].
type T interface {
Logf(string, ...any)
TempDir() string
Skip(...any)
require.TestingT
assert.TestingT
pulumitest.PT
}
3 changes: 2 additions & 1 deletion pkg/internal/tests/cross-tests/puwrite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v3"

crosstestsimpl "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/tests/cross-tests/impl"
shimv2 "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfshim/sdk-v2"
)

Expand Down Expand Up @@ -124,7 +125,7 @@ runtime: yaml
))
schema := shimProvider.ResourcesMap().Get(rtype).Schema()
out, err := generateYaml(t, rtoken,
InferPulumiValue(t, schema, nil, coalesceInputs(t, tc.schema, tc.tfConfig)))
crosstestsimpl.InferPulumiValue(t, schema, nil, coalesceInputs(t, tc.schema, tc.tfConfig)))
require.NoError(t, err)
b, err := yaml.Marshal(out)
require.NoError(t, err)
Expand Down
14 changes: 2 additions & 12 deletions pkg/internal/tests/cross-tests/t.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// Abstractions to allow tests to work against both *testing.T and rapid.TB.
package crosstests

import (
"github.com/pulumi/providertest/pulumitest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
crosstestsimpl "github.com/pulumi/pulumi-terraform-bridge/v3/pkg/internal/tests/cross-tests/impl"
)

type T interface {
Logf(string, ...any)
TempDir() string
Skip(...any)
require.TestingT
assert.TestingT
pulumitest.PT
}
type T = crosstestsimpl.T
Loading

0 comments on commit 4ba9f31

Please sign in to comment.