Skip to content

Commit 21367c8

Browse files
committed
chore: begin work on test engine to compare against tf cli
1 parent a13d060 commit 21367c8

File tree

4 files changed

+213
-1
lines changed

4 files changed

+213
-1
lines changed

go.mod

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ go 1.23.5
55
require (
66
github.com/aquasecurity/trivy v0.58.2
77
github.com/coder/serpent v0.10.0
8+
github.com/hashicorp/go-version v1.7.0
9+
github.com/hashicorp/hc-install v0.9.1
810
github.com/hashicorp/hcl/v2 v2.23.0
11+
github.com/hashicorp/terraform-exec v0.22.0
912
github.com/hashicorp/terraform-json v0.24.0
1013
github.com/jedib0t/go-pretty/v6 v6.6.5
1114
github.com/stretchr/testify v1.10.0
@@ -25,6 +28,7 @@ require (
2528
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
2629
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.48.1 // indirect
2730
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.48.1 // indirect
31+
github.com/ProtonMail/go-crypto v1.1.5 // indirect
2832
github.com/agext/levenshtein v1.2.3 // indirect
2933
github.com/apparentlymart/go-cidr v1.1.0 // indirect
3034
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
@@ -35,6 +39,7 @@ require (
3539
github.com/bmatcuk/doublestar/v4 v4.8.1 // indirect
3640
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
3741
github.com/cespare/xxhash/v2 v2.3.0 // indirect
42+
github.com/cloudflare/circl v1.5.0 // indirect
3843
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect
3944
github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 // indirect
4045
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
@@ -53,9 +58,9 @@ require (
5358
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
5459
github.com/hashicorp/go-getter v1.7.8 // indirect
5560
github.com/hashicorp/go-multierror v1.1.1 // indirect
61+
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
5662
github.com/hashicorp/go-safetemp v1.0.0 // indirect
5763
github.com/hashicorp/go-uuid v1.0.3 // indirect
58-
github.com/hashicorp/go-version v1.7.0 // indirect
5964
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
6065
github.com/klauspost/compress v1.17.11 // indirect
6166
github.com/liamg/memoryfs v1.6.0 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,8 +923,12 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n
923923
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
924924
github.com/hashicorp/go-getter v1.7.8 h1:mshVHx1Fto0/MydBekWan5zUipGq7jO0novchgMmSiY=
925925
github.com/hashicorp/go-getter v1.7.8/go.mod h1:2c6CboOEb9jG6YvmC9xdD+tyAFsrUaJPedwXDGr0TM4=
926+
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
927+
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
926928
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
927929
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
930+
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
931+
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
928932
github.com/hashicorp/go-safetemp v1.0.0 h1:2HR189eFNrjHQyENnQMMpCiBAsRxzbTMIgBhEyExpmo=
929933
github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
930934
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
@@ -934,8 +938,12 @@ github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKe
934938
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
935939
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
936940
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
941+
github.com/hashicorp/hc-install v0.9.1 h1:gkqTfE3vVbafGQo6VZXcy2v5yoz2bE0+nhZXruCuODQ=
942+
github.com/hashicorp/hc-install v0.9.1/go.mod h1:pWWvN/IrfeBK4XPeXXYkL6EjMufHkCK5DvwxeLKuBf0=
937943
github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
938944
github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
945+
github.com/hashicorp/terraform-exec v0.22.0 h1:G5+4Sz6jYZfRYUCg6eQgDsqTzkNXV+fP8l+uRmZHj64=
946+
github.com/hashicorp/terraform-exec v0.22.0/go.mod h1:bjVbsncaeh8jVdhttWYZuBGj21FcYw6Ia/XfHcNO7lQ=
939947
github.com/hashicorp/terraform-json v0.24.0 h1:rUiyF+x1kYawXeRth6fKFm/MdfBS6+lW4NbeATsYz8Q=
940948
github.com/hashicorp/terraform-json v0.24.0/go.mod h1:Nfj5ubo9xbu9uiAoZVBsNOjvNKB66Oyrvtit74kC7ow=
941949
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=

internal/verify/exec.go

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
package verify
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"os"
8+
"path/filepath"
9+
"testing"
10+
"time"
11+
12+
"github.com/hashicorp/go-version"
13+
"github.com/hashicorp/hc-install/product"
14+
"github.com/hashicorp/hc-install/releases"
15+
"github.com/hashicorp/hc-install/src"
16+
"github.com/hashicorp/terraform-exec/tfexec"
17+
"github.com/stretchr/testify/require"
18+
)
19+
20+
type WorkingExecutable struct {
21+
Executable
22+
WorkingDir string
23+
TF *tfexec.Terraform
24+
}
25+
26+
type Executable struct {
27+
ExecPath string
28+
Version string
29+
DirPath string
30+
31+
ins src.Installable
32+
}
33+
34+
func (e Executable) WorkingDir(dir string) (WorkingExecutable, error) {
35+
tf, err := tfexec.NewTerraform(dir, e.ExecPath)
36+
if err != nil {
37+
return WorkingExecutable{}, fmt.Errorf("create terraform exec: %w", err)
38+
}
39+
40+
return WorkingExecutable{
41+
Executable: e,
42+
WorkingDir: dir,
43+
TF: tf,
44+
}, nil
45+
}
46+
47+
//func (e WorkingExecutable) Init(ctx context.Context) error {
48+
// e.TF.Init(ctx, tfexec.Upgrade(true))
49+
//}
50+
51+
// TerraformTestVersions returns a list of Terraform versions to test.
52+
func TerraformTestVersions(ctx context.Context) []src.Installable {
53+
lv := LatestTerraformVersion(ctx)
54+
return []src.Installable{
55+
lv,
56+
}
57+
}
58+
59+
func InstallTerraforms(ctx context.Context, t *testing.T, installables ...src.Installable) []Executable {
60+
// All terraform versions are installed in the same root directory
61+
root := t.TempDir()
62+
execPaths := make([]Executable, 0, len(installables))
63+
64+
for _, installable := range installables {
65+
ex := Executable{
66+
ins: installable,
67+
}
68+
switch tfi := installable.(type) {
69+
case *releases.ExactVersion:
70+
ver := tfi.Version.String()
71+
t.Logf("Installing Terraform %s", ver)
72+
tfi.InstallDir = filepath.Join(root, ver)
73+
74+
err := os.Mkdir(tfi.InstallDir, 0o755)
75+
require.NoErrorf(t, err, "tf install %q", ver)
76+
77+
ex.Version = ver
78+
ex.DirPath = tfi.InstallDir
79+
case *releases.LatestVersion:
80+
t.Logf("Installing latest Terraform")
81+
ver := "latest"
82+
tfi.InstallDir = filepath.Join(root, ver)
83+
84+
err := os.Mkdir(tfi.InstallDir, 0o755)
85+
require.NoErrorf(t, err, "tf install %q", ver)
86+
87+
ex.Version = ver
88+
ex.DirPath = tfi.InstallDir
89+
default:
90+
// We only support the types we know about
91+
t.Fatalf("unknown installable type %T", tfi)
92+
}
93+
94+
execPath, err := installable.Install(ctx)
95+
require.NoErrorf(t, err, "tf install")
96+
ex.ExecPath = execPath
97+
98+
execPaths = append(execPaths, ex)
99+
}
100+
101+
return execPaths
102+
}
103+
104+
func LatestTerraformVersion(ctx context.Context) *releases.LatestVersion {
105+
return &releases.LatestVersion{
106+
Product: product.Terraform,
107+
}
108+
}
109+
110+
// TerraformVersions will return all versions that match the constraints plus the
111+
// current latest version.
112+
func TerraformVersions(ctx context.Context, constraints version.Constraints) ([]*releases.ExactVersion, error) {
113+
if len(constraints) == 0 {
114+
return nil, fmt.Errorf("no constraints provided, don't fetch everything")
115+
}
116+
117+
srcs, err := (&releases.Versions{
118+
Product: product.Terraform,
119+
Enterprise: nil,
120+
Constraints: constraints,
121+
ListTimeout: time.Second * 60,
122+
Install: releases.InstallationOptions{
123+
Timeout: 0,
124+
Dir: "",
125+
SkipChecksumVerification: false,
126+
},
127+
}).List(ctx)
128+
if err != nil {
129+
return nil, fmt.Errorf("failed to list Terraform versions: %w", err)
130+
}
131+
132+
include := make([]*releases.ExactVersion, 0)
133+
for _, src := range srcs {
134+
ev, ok := src.(*releases.ExactVersion)
135+
if !ok {
136+
return nil, fmt.Errorf("failed to cast src to ExactVersion, type was %T", src)
137+
}
138+
139+
include = append(include, ev)
140+
}
141+
142+
return include, nil
143+
}
144+
145+
func Apply() {
146+
installer := &releases.ExactVersion{
147+
Product: product.Terraform,
148+
Version: version.Must(version.NewVersion("1.0.6")),
149+
}
150+
151+
execPath, err := installer.Install(context.Background())
152+
if err != nil {
153+
log.Fatalf("error installing Terraform: %s", err)
154+
}
155+
156+
workingDir := "/path/to/working/dir"
157+
tf, err := tfexec.NewTerraform(workingDir, execPath)
158+
if err != nil {
159+
log.Fatalf("error running NewTerraform: %s", err)
160+
}
161+
162+
err = tf.Init(context.Background(), tfexec.Upgrade(true))
163+
if err != nil {
164+
log.Fatalf("error running Init: %s", err)
165+
}
166+
167+
state, err := tf.Show(context.Background())
168+
if err != nil {
169+
log.Fatalf("error running Show: %s", err)
170+
}
171+
172+
fmt.Println(state.FormatVersion) // "0.1"
173+
}

preview_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package preview_test
33
import (
44
"context"
55
"fmt"
6+
"io/fs"
67
"os"
78
"path/filepath"
89
"testing"
@@ -13,9 +14,34 @@ import (
1314
"github.com/zclconf/go-cty/cty/gocty"
1415

1516
"github.com/coder/preview"
17+
"github.com/coder/preview/internal/verify"
1618
"github.com/coder/preview/types"
1719
)
1820

21+
// Test_VerifyPreview will fully evaluate with `terraform apply`
22+
// and verify the output of `preview` against the tfstate. This
23+
// is the e2e test for the preview package.
24+
func Test_VerifyPreview(t *testing.T) {
25+
t.Parallel()
26+
27+
ctx, cancel := context.WithCancel(context.Background())
28+
defer cancel()
29+
30+
versions := verify.TerraformTestVersions(ctx)
31+
tfexecs := verify.InstallTerraforms(ctx, t, versions...)
32+
33+
dirFs := os.DirFS("testdata")
34+
entries, err := fs.ReadDir(dirFs, ".")
35+
require.NoError(t, err)
36+
37+
for _, entry := range entries {
38+
if !entry.IsDir() {
39+
t.Logf("skipping non directory file %q", entry.Name())
40+
}
41+
42+
}
43+
}
44+
1945
func TestFoo(t *testing.T) {
2046
ty, err := gocty.ImpliedType([]any{1, 2, 3})
2147
require.NoError(t, err)

0 commit comments

Comments
 (0)