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

Rapid generator for schema-value pairs #1801

Merged
merged 45 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
fe7e530
Start writing a Rapid generator for type-value pairs
t0yv0 Mar 27, 2024
af033da
Toward rapid tests over diff
t0yv0 Mar 27, 2024
e96246b
Fixes
t0yv0 Mar 27, 2024
998a846
Turn off pesky logging
t0yv0 Mar 27, 2024
0433b44
Implement cleanup
t0yv0 Mar 27, 2024
f17b14f
Facility to write actual HCL surface syntax
t0yv0 Mar 27, 2024
302098b
Adapt tftypes.Value to cty.Value
t0yv0 Mar 27, 2024
f7dd197
Quick builders for tftypes.Value
t0yv0 Mar 28, 2024
121076e
Fixes to block writing
t0yv0 Mar 28, 2024
f32a780
Separate TF driver
t0yv0 Mar 28, 2024
bb3452a
Remove quick.go
t0yv0 Mar 28, 2024
d66b6f0
More adapters
t0yv0 Mar 28, 2024
0161bf7
Helper files
t0yv0 Mar 28, 2024
8f4fcd7
Clean up cross_test
t0yv0 Mar 28, 2024
180f6a3
Generate generators
t0yv0 Mar 28, 2024
896c6c5
WIP on rapid
t0yv0 Mar 28, 2024
93ed749
tfwrite support for nested blocks
t0yv0 Apr 2, 2024
67a7c50
wip
t0yv0 Apr 2, 2024
b6ab534
Fix object repr
t0yv0 Apr 2, 2024
df6ca0b
Remove debug println
t0yv0 Apr 2, 2024
0d255a9
Fixes to pretty-printing
t0yv0 Apr 2, 2024
4e3eef9
Progress
t0yv0 Apr 2, 2024
09041dd
Misc
t0yv0 Apr 2, 2024
dea5f25
Simplify diff
t0yv0 Apr 2, 2024
f70e5c7
More attr and block generators
t0yv0 Apr 2, 2024
1f82d12
Pretty-printing improved
t0yv0 Apr 9, 2024
f080620
WIP
t0yv0 Apr 10, 2024
86050a4
Fix pretty-printing type traversal
t0yv0 Apr 11, 2024
52b564a
Do not use tabs in pp
t0yv0 Apr 11, 2024
61c2d85
More pretty-printing fixes
t0yv0 Apr 11, 2024
424be58
Fix empty list/set/etc adapters
t0yv0 Apr 11, 2024
b3079d6
Pretty-print schemas the quick way
t0yv0 Apr 11, 2024
7d9af83
Eliminate secrets from the tests
t0yv0 Apr 11, 2024
a7b960a
Link the right providertest version
t0yv0 Apr 11, 2024
19ee528
Pin empty required list panic
t0yv0 Apr 11, 2024
65915a7
Do not test in CI yet
t0yv0 Apr 11, 2024
15521f7
Lint etc
t0yv0 Apr 11, 2024
488a977
Docs for pretty.go
t0yv0 Apr 11, 2024
ddef975
Document adapt.go
t0yv0 Apr 11, 2024
991182e
Cleanup
t0yv0 Apr 11, 2024
37b22a9
Copyright
t0yv0 Apr 11, 2024
525c31a
Grammar
t0yv0 Apr 11, 2024
4624b95
PR Feedback
t0yv0 Apr 12, 2024
8571b80
More PR feedback
t0yv0 Apr 12, 2024
8c9933b
Fix panic
t0yv0 Apr 12, 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
201 changes: 201 additions & 0 deletions pkg/tests/cross-tests/adapt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
// 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.

// Adapters for converting morally equivalent typed representations of TF values for integrating with all the libraries
// cross-testing is using.
package crosstests

import (
"math/big"

"github.com/hashicorp/terraform-plugin-go/tftypes"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
"github.com/zclconf/go-cty/cty"
)

type typeAdapter struct {
typ tftypes.Type
}

func (ta *typeAdapter) ToCty() cty.Type {
t := ta.typ
switch {
case t.Is(tftypes.String):
return cty.String
case t.Is(tftypes.Number):
return cty.Number
case t.Is(tftypes.Bool):
return cty.Bool
case t.Is(tftypes.List{}):
return cty.List(fromType(t.(tftypes.List).ElementType).ToCty())
case t.Is(tftypes.Set{}):
return cty.Set(fromType(t.(tftypes.Set).ElementType).ToCty())
case t.Is(tftypes.Map{}):
return cty.Map(fromType(t.(tftypes.Map).ElementType).ToCty())
case t.Is(tftypes.Object{}):
fields := map[string]cty.Type{}
for k, v := range t.(tftypes.Object).AttributeTypes {
fields[k] = fromType(v).ToCty()
}
return cty.Object(fields)
default:
contract.Failf("unexpected type %v", t)
return cty.NilType
}
}

func (ta *typeAdapter) NewValue(value any) tftypes.Value {
t := ta.typ
if value == nil {
return tftypes.NewValue(t, nil)
}
switch t := value.(type) {
case tftypes.Value:
return t
case *tftypes.Value:
return *t
}
switch {
case t.Is(tftypes.List{}):
elT := t.(tftypes.List).ElementType
switch v := value.(type) {
case []any:
values := []tftypes.Value{}
for _, el := range v {
values = append(values, fromType(elT).NewValue(el))
}
return tftypes.NewValue(t, values)
}
case t.Is(tftypes.Set{}):
elT := t.(tftypes.Set).ElementType
switch v := value.(type) {
case []any:
values := []tftypes.Value{}
for _, el := range v {
values = append(values, fromType(elT).NewValue(el))
}
return tftypes.NewValue(t, values)
}
case t.Is(tftypes.Map{}):
elT := t.(tftypes.Map).ElementType
switch v := value.(type) {
case map[string]any:
values := map[string]tftypes.Value{}
for k, el := range v {
values[k] = fromType(elT).NewValue(el)
}
return tftypes.NewValue(t, values)
}
case t.Is(tftypes.Object{}):
aT := t.(tftypes.Object).AttributeTypes
switch v := value.(type) {
case map[string]any:
values := map[string]tftypes.Value{}
for k, el := range v {
values[k] = fromType(aT[k]).NewValue(el)
}
return tftypes.NewValue(t, values)
}
}
return tftypes.NewValue(t, value)
}

func fromType(t tftypes.Type) *typeAdapter {
return &typeAdapter{t}
}

type valueAdapter struct {
value tftypes.Value
}

func (va *valueAdapter) ToCty() cty.Value {
v := va.value
t := v.Type()
switch {
case v.IsNull():
return cty.NullVal(fromType(t).ToCty())
case !v.IsKnown():
return cty.UnknownVal(fromType(t).ToCty())
case t.Is(tftypes.String):
var s string
err := v.As(&s)
contract.AssertNoErrorf(err, "unexpected error converting string")
return cty.StringVal(s)
case t.Is(tftypes.Number):
var n *big.Float
err := v.As(&n)
contract.AssertNoErrorf(err, "unexpected error converting number")
return cty.NumberVal(n)
case t.Is(tftypes.Bool):
var b bool
err := v.As(&b)
contract.AssertNoErrorf(err, "unexpected error converting bool")
return cty.BoolVal(b)
case t.Is(tftypes.List{}):
var vals []tftypes.Value
err := v.As(&vals)
contract.AssertNoErrorf(err, "unexpected error converting list")
if len(vals) == 0 {
return cty.ListValEmpty(fromType(t).ToCty())
}
outVals := make([]cty.Value, len(vals))
for i, el := range vals {
outVals[i] = fromValue(el).ToCty()
}
return cty.ListVal(outVals)
case t.Is(tftypes.Set{}):
var vals []tftypes.Value
err := v.As(&vals)
if len(vals) == 0 {
return cty.SetValEmpty(fromType(t).ToCty())
}
contract.AssertNoErrorf(err, "unexpected error converting set")
outVals := make([]cty.Value, len(vals))
for i, el := range vals {
outVals[i] = fromValue(el).ToCty()
}
return cty.SetVal(outVals)
case t.Is(tftypes.Map{}):
var vals map[string]tftypes.Value
err := v.As(&vals)
if len(vals) == 0 {
return cty.MapValEmpty(fromType(t).ToCty())
}
contract.AssertNoErrorf(err, "unexpected error converting map")
outVals := make(map[string]cty.Value, len(vals))
for k, el := range vals {
outVals[k] = fromValue(el).ToCty()
}
return cty.MapVal(outVals)
case t.Is(tftypes.Object{}):
var vals map[string]tftypes.Value
err := v.As(&vals)
if len(vals) == 0 {
return cty.EmptyObjectVal
}
contract.AssertNoErrorf(err, "unexpected error converting object")
outVals := make(map[string]cty.Value, len(vals))
for k, el := range vals {
outVals[k] = fromValue(el).ToCty()
}
return cty.ObjectVal(outVals)
default:
contract.Failf("unexpected type %v", t)
return cty.NilVal
}
}

func fromValue(v tftypes.Value) *valueAdapter {
return &valueAdapter{v}
}
28 changes: 28 additions & 0 deletions pkg/tests/cross-tests/ci.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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

// Helpers to disable failing CI runs.
package crosstests

import (
"os"
"runtime"
"strings"
"testing"
)

func skipUnlessLinux(t *testing.T) {
if ci, ok := os.LookupEnv("CI"); ok && ci == "true" && !strings.Contains(strings.ToLower(runtime.GOOS), "linux") {
t.Skip("Skipping on non-Linux platforms as our CI does not yet install Terraform CLI required for these tests")
}
}
Loading