Skip to content

Commit 45e5bcc

Browse files
Fix flaky tests by disabling automatic plugin acquisition for all tests (#2190)
Disable automatic acquisition globally in the repository - this should ensure we do not use the GH API during tests and make our tests here a lot more robust. Instead manually install all required plugins in the Makefile as a dependency of the tests. This ensures we only do it once and do not spam the GH API with redundant requests causing test flakes. I've hit this more than 5 times on separate PRs in the last few days. It's seriously slowing down progress in the repo. When we do hit the GH rate limit, we have to wait for up to an hour for it to reset. ~Skip `TestConvertViaPulumiCLI` until pulumi/pulumi#16469 is addressed.~ ~Skip `TestResourceWithoutID` until #2191 is addressed.~ Looks like we were using the wrong env variable name... One of the tests was also absolutely spamming the GH API: https://github.com/pulumi/pulumi-terraform-bridge/actions/runs/9973182117/job/27557985796?pr=2190 Latest failures: https://github.com/pulumi/pulumi-terraform-bridge/actions/runs/9972810153/job/27556840950?pr=2186 fixes #2191
1 parent 4fbc7ed commit 45e5bcc

File tree

9 files changed

+95
-106
lines changed

9 files changed

+95
-106
lines changed

Makefile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
SHELL := sh
22
PROJECT := github.com/pulumi/pulumi-terraform-bridge
33
TESTPARALLELISM := 10
4+
export PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION := true
45

56
PROJECT_DIR := $(patsubst %/,%,$(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
67

8+
install_plugins::
9+
pulumi plugin install converter terraform 1.0.18
10+
pulumi plugin install resource random 4.16.3
11+
pulumi plugin install resource aws 6.22.2
12+
pulumi plugin install resource archive 0.0.4
13+
pulumi plugin install resource wavefront 3.0.0
14+
pulumi plugin install resource equinix 0.6.0 --server github://api.github.com/equinix
15+
716
build::
817
go mod tidy
918
go build ${PROJECT}/v3/pkg/...
@@ -19,7 +28,7 @@ lint:
1928
lint_fix:
2029
go run scripts/build.go fix-lint
2130

22-
test::
31+
test:: install_plugins
2332
@mkdir -p bin
2433
go build -o bin ./internal/testing/pulumi-terraform-bridge-test-provider
2534
PULUMI_TERRAFORM_BRIDGE_TEST_PROVIDER=$(shell pwd)/bin/pulumi-terraform-bridge-test-provider \

pf/Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
TESTPARALLELISM := 10
2+
export PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION := true
23

3-
build.tests::
4+
install_plugins::
5+
pulumi plugin install resource random 4.16.3
6+
7+
build.tests:: install_plugins
48
go test -test.run NONE
59
cd tests && go test -test.run NONE
610
cd tests/integration && go test -test.run NONE

pf/tests/integration/program_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import (
3030
"github.com/pulumi/pulumi/pkg/v3/testing/integration"
3131
"github.com/stretchr/testify/require"
3232
"sourcegraph.com/sourcegraph/appdash"
33+
34+
"github.com/pulumi/pulumi-terraform-bridge/v3/unstable/testutil"
3335
)
3436

3537
func TestBasicProgram(t *testing.T) {
@@ -223,6 +225,9 @@ func TestResourceWithoutID(t *testing.T) {
223225
integration.ProgramTest(t, &integration.ProgramTestOptions{
224226
Env: []string{fmt.Sprintf("PATH=%s", bin)},
225227
Dir: filepath.Join("..", "testdata", "resource-without-id"),
228+
LocalProviders: []integration.LocalDependency{
229+
testutil.RandomProvider(t),
230+
},
226231
})
227232
}
228233

pkg/tests/acc_provider_config_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,20 @@ import (
1919

2020
"github.com/pulumi/pulumi/pkg/v3/testing/integration"
2121
"github.com/stretchr/testify/assert"
22+
23+
"github.com/pulumi/pulumi-terraform-bridge/v3/unstable/testutil"
2224
)
2325

2426
func TestAccProviderConfig(t *testing.T) {
2527
opts := accTestOptions(t).With(integration.ProgramTestOptions{
2628
Dir: "provider-config",
27-
2829
ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {
2930
assert.Equal(t, stack.Outputs["generatedRandomString"],
3031
stack.Outputs["providerRandomString"])
3132
},
33+
LocalProviders: []integration.LocalDependency{
34+
testutil.RandomProvider(t),
35+
},
3236
})
3337
integration.ProgramTest(t, &opts)
3438
}

pkg/tests/internal/pulcheck/pulcheck.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ func PulCheck(t T, bridgedProvider info.Provider, program string) *pulumitest.Pu
185185
require.NoError(t, err)
186186

187187
opts := []opttest.Option{
188-
opttest.Env("DISABLE_AUTOMATIC_PLUGIN_ACQUISITION", "true"),
188+
opttest.Env("PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION", "true"),
189189
opttest.TestInPlace(),
190190
opttest.SkipInstall(),
191191
opttest.AttachProvider(

pkg/tests/main_test.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import (
2828
"github.com/pulumi/pulumi/pkg/v3/testing/integration"
2929
)
3030

31+
var localTestProviders []integration.LocalDependency
32+
3133
func TestMain(m *testing.M) {
3234
if err := setupIntegrationTests(); err != nil {
3335
log.Fatal(err)
@@ -56,7 +58,9 @@ func accTestOptions(t *testing.T) *integration.ProgramTestOptions {
5658
return &integration.ProgramTestOptions{
5759
Env: []string{
5860
fmt.Sprintf("PATH=%s", filepath.Join(cwd, "..", "..", "bin")),
61+
"PULUMI_DISABLE_AUTOMATIC_PLUGIN_ACQUISITION=true",
5962
},
63+
LocalProviders: localTestProviders,
6064
}
6165
}
6266

@@ -72,16 +76,21 @@ func ensureCompiledTestProviders(wd string) error {
7276

7377
internalErrorMsg := "Internal validation of the provider failed"
7478

79+
internal := func(segments ...string) string {
80+
return filepath.Join(append([]string{wd, "..", "..", "internal"}, segments...)...)
81+
}
7582
testProviders := []testProvider{
7683
{
7784
"tpsdkv2",
78-
filepath.Join(wd, "..", "..", "internal", "testprovider_sdkv2",
79-
"cmd", "pulumi-resource-tpsdkv2"),
80-
filepath.Join(wd, "..", "..", "internal", "testprovider_sdkv2",
81-
"cmd", "pulumi-tfgen-tpsdkv2"), nil,
85+
internal("testprovider_sdkv2", "cmd", "pulumi-resource-tpsdkv2"),
86+
internal("testprovider_sdkv2", "cmd", "pulumi-tfgen-tpsdkv2"),
87+
nil,
8288
},
8389
{
84-
"testprovider_invschema", filepath.Join(wd, "..", "..", "internal", "testprovider_invalid_schema", "cmd", "pulumi-resource-tpinvschema"), filepath.Join(wd, "..", "..", "internal", "testprovider_invalid_schema", "cmd", "pulumi-tfgen-tpinvschema"), &internalErrorMsg,
90+
"testprovider_invschema",
91+
internal("testprovider_invalid_schema", "cmd", "pulumi-resource-tpinvschema"),
92+
internal("testprovider_invalid_schema", "cmd", "pulumi-tfgen-tpinvschema"),
93+
&internalErrorMsg,
8594
},
8695
}
8796

@@ -143,6 +152,10 @@ func ensureCompiledTestProviders(wd string) error {
143152
fmt.Println(stderr)
144153
return fmt.Errorf("provider build failed for %s: %w", p.name, err)
145154
}
155+
localTestProviders = append(localTestProviders, integration.LocalDependency{
156+
Package: p.name,
157+
Path: bin, // The path to the directory that contains the binary, not the binary
158+
})
146159
}
147160
}
148161

pkg/tfgen/convert_cli_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ func TestConvertViaPulumiCLI(t *testing.T) {
5656
t.Skipf("Skipping on Windows due to a test setup issue")
5757
}
5858
t.Setenv("PULUMI_CONVERT", "1")
59-
t.Setenv("DISABLE_AUTOMATIC_PLUGIN_ACQUISITION", "true")
6059

6160
simpleResourceTF := `
6261
resource "simple_resource" "a_resource" {

pkg/tfgen/docs_test.go

Lines changed: 2 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"fmt"
2323
"io"
2424
"os"
25-
"os/exec"
2625
"path/filepath"
2726
"runtime"
2827
"strings"
@@ -1290,8 +1289,6 @@ func TestConvertExamples(t *testing.T) {
12901289
name string
12911290
path examplePath
12921291

1293-
needsProviders map[string]pluginDesc
1294-
12951292
language *Language
12961293
}
12971294

@@ -1302,19 +1299,13 @@ func TestConvertExamples(t *testing.T) {
13021299
fullPath: "#/resources/wavefront:index/dashboardJson:DashboardJson",
13031300
token: "wavefront:index/dashboardJson:DashboardJson",
13041301
},
1305-
needsProviders: map[string]pluginDesc{
1306-
"wavefront": {version: "3.0.0"},
1307-
},
13081302
},
13091303
{
13101304
name: "golang_wavefront_dashboard_json",
13111305
path: examplePath{
13121306
fullPath: "#/resources/wavefront:index/dashboardJson:DashboardJson",
13131307
token: "wavefront:index/dashboardJson:DashboardJson",
13141308
},
1315-
needsProviders: map[string]pluginDesc{
1316-
"wavefront": {version: "3.0.0"},
1317-
},
13181309
language: ref(Golang),
13191310
},
13201311
{
@@ -1323,39 +1314,19 @@ func TestConvertExamples(t *testing.T) {
13231314
fullPath: "#/resources/equinix:fabric:Connection",
13241315
token: "equinix:fabric:Connection",
13251316
},
1326-
needsProviders: map[string]pluginDesc{
1327-
"equinix": {
1328-
pluginDownloadURL: "github://api.github.com/equinix",
1329-
version: "0.6.0",
1330-
},
1331-
},
13321317
},
13331318
{
13341319
name: "aws_lambda_function",
13351320
path: examplePath{
13361321
fullPath: "#/resources/aws:lambda/function:Function",
13371322
token: "aws:lambda/function:Function",
13381323
},
1339-
needsProviders: map[string]pluginDesc{
1340-
"aws": {
1341-
pluginDownloadURL: "github://api.github.com/pulumi",
1342-
version: "6.22.2",
1343-
},
1344-
"archive": {
1345-
pluginDownloadURL: "github://api.github.com/pulumi",
1346-
version: "0.0.4",
1347-
},
1348-
},
13491324
},
13501325
}
13511326

13521327
for _, tc := range testCases {
13531328
tc := tc
13541329

1355-
t.Run(fmt.Sprintf("%s/setup", tc.name), func(t *testing.T) {
1356-
ensureProvidersInstalled(t, tc.needsProviders)
1357-
})
1358-
13591330
t.Run(tc.name, func(t *testing.T) {
13601331
inmem := afero.NewMemMapFs()
13611332
info := testprovider.ProviderMiniRandom()
@@ -1413,9 +1384,8 @@ func TestConvertExamplesInner(t *testing.T) {
14131384
assert.NoError(t, err)
14141385

14151386
type testCase struct {
1416-
name string
1417-
path examplePath
1418-
needsProviders map[string]pluginDesc
1387+
name string
1388+
path examplePath
14191389
}
14201390

14211391
testCases := []testCase{
@@ -1438,10 +1408,6 @@ func TestConvertExamplesInner(t *testing.T) {
14381408
for _, tc := range testCases {
14391409
tc := tc
14401410

1441-
t.Run(fmt.Sprintf("%s/setup", tc.name), func(t *testing.T) {
1442-
ensureProvidersInstalled(t, tc.needsProviders)
1443-
})
1444-
14451411
t.Run(tc.name, func(t *testing.T) {
14461412
docs, err := os.ReadFile(filepath.Join("test_data", "convertExamples",
14471413
fmt.Sprintf("%s.md", tc.name)))
@@ -1461,11 +1427,6 @@ func TestConvertExamplesInner(t *testing.T) {
14611427
}
14621428
}
14631429

1464-
type pluginDesc struct {
1465-
version string
1466-
pluginDownloadURL string
1467-
}
1468-
14691430
func TestFindFencesAndHeaders(t *testing.T) {
14701431
if runtime.GOOS == "windows" {
14711432
t.Skipf("Skipping on windows to avoid failing on incorrect newline handling")
@@ -1530,61 +1491,6 @@ func TestFindFencesAndHeaders(t *testing.T) {
15301491

15311492
}
15321493

1533-
func ensureProvidersInstalled(t *testing.T, needsProviders map[string]pluginDesc) {
1534-
pulumi, err := exec.LookPath("pulumi")
1535-
require.NoError(t, err)
1536-
1537-
t.Logf("pulumi plugin ls --json")
1538-
cmd := exec.Command(pulumi, "plugin", "ls", "--json")
1539-
var buf bytes.Buffer
1540-
cmd.Stdout = &buf
1541-
err = cmd.Run()
1542-
require.NoError(t, err)
1543-
1544-
type plugin struct {
1545-
Name string `json:"name"`
1546-
Version string `json:"version"`
1547-
}
1548-
1549-
var installedPlugins []plugin
1550-
err = json.Unmarshal(buf.Bytes(), &installedPlugins)
1551-
require.NoError(t, err)
1552-
1553-
for name, desc := range needsProviders {
1554-
count := 0
1555-
matched := false
1556-
1557-
for _, p := range installedPlugins {
1558-
if p.Name == name {
1559-
count++
1560-
}
1561-
if p.Name == name && p.Version == desc.version {
1562-
matched = true
1563-
}
1564-
}
1565-
1566-
alreadyInstalled := count == 1 && matched
1567-
if alreadyInstalled {
1568-
continue
1569-
}
1570-
1571-
if count > 0 {
1572-
t.Logf("pulumi plugin rm resource %s", name)
1573-
err = exec.Command(pulumi, "plugin", "rm", "resource", name).Run()
1574-
require.NoError(t, err)
1575-
}
1576-
1577-
args := []string{"plugin", "install", "resource", name, desc.version}
1578-
if desc.pluginDownloadURL != "" {
1579-
args = append(args, "--server", desc.pluginDownloadURL)
1580-
}
1581-
cmd := exec.Command(pulumi, args...)
1582-
t.Logf("Exec: %s", cmd)
1583-
err = cmd.Run()
1584-
require.NoError(t, err)
1585-
}
1586-
}
1587-
15881494
func TestExampleGeneration(t *testing.T) {
15891495
info := testprovider.ProviderMiniRandom()
15901496

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2016-2023, Pulumi Corporation.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package testutil
16+
17+
import (
18+
"os"
19+
"path/filepath"
20+
"testing"
21+
22+
"github.com/blang/semver"
23+
"github.com/pulumi/pulumi/pkg/v3/testing/integration"
24+
"github.com/pulumi/pulumi/sdk/v3/go/common/apitype"
25+
"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
26+
"github.com/pulumi/pulumi/sdk/v3/go/common/diag/colors"
27+
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
28+
"github.com/stretchr/testify/require"
29+
)
30+
31+
// RandomProvider returns a [integration.LocalDependency] reference to the random provider
32+
// installed via `make install_plugins`.
33+
func RandomProvider(t *testing.T) integration.LocalDependency {
34+
return pluginDependency(t, "random", semver.Version{Major: 4, Minor: 16, Patch: 3})
35+
}
36+
37+
func pluginDependency(t *testing.T, name string, version semver.Version) integration.LocalDependency {
38+
path, err := workspace.GetPluginPath(
39+
diag.DefaultSink(os.Stdout, os.Stderr, diag.FormatOptions{
40+
Color: colors.Never,
41+
}),
42+
apitype.ResourcePlugin, name, &version, nil)
43+
require.NoError(t, err,
44+
`The %s provider at this version should have been installed by "make install_plugins"`, name)
45+
return integration.LocalDependency{
46+
Package: name,
47+
Path: filepath.Dir(path),
48+
}
49+
}

0 commit comments

Comments
 (0)